18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
38c2ecf20Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
68c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
78c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
108c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
118c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
128c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
138c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
158c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*************************************\
208c2ecf20Sopenharmony_ci* DMA and interrupt masking functions *
218c2ecf20Sopenharmony_ci\*************************************/
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/**
248c2ecf20Sopenharmony_ci * DOC: DMA and interrupt masking functions
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
278c2ecf20Sopenharmony_ci * handle queue setup for 5210 chipset (rest are handled on qcu.c).
288c2ecf20Sopenharmony_ci * Also we setup interrupt mask register (IMR) and read the various interrupt
298c2ecf20Sopenharmony_ci * status registers (ISR).
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include "ath5k.h"
358c2ecf20Sopenharmony_ci#include "reg.h"
368c2ecf20Sopenharmony_ci#include "debug.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*********\
408c2ecf20Sopenharmony_ci* Receive *
418c2ecf20Sopenharmony_ci\*********/
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/**
448c2ecf20Sopenharmony_ci * ath5k_hw_start_rx_dma() - Start DMA receive
458c2ecf20Sopenharmony_ci * @ah:	The &struct ath5k_hw
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_civoid
488c2ecf20Sopenharmony_ciath5k_hw_start_rx_dma(struct ath5k_hw *ah)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
518c2ecf20Sopenharmony_ci	ath5k_hw_reg_read(ah, AR5K_CR);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/**
558c2ecf20Sopenharmony_ci * ath5k_hw_stop_rx_dma() - Stop DMA receive
568c2ecf20Sopenharmony_ci * @ah:	The &struct ath5k_hw
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_cistatic int
598c2ecf20Sopenharmony_ciath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	unsigned int i;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/*
668c2ecf20Sopenharmony_ci	 * It may take some time to disable the DMA receive unit
678c2ecf20Sopenharmony_ci	 */
688c2ecf20Sopenharmony_ci	for (i = 1000; i > 0 &&
698c2ecf20Sopenharmony_ci			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
708c2ecf20Sopenharmony_ci			i--)
718c2ecf20Sopenharmony_ci		udelay(100);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (!i)
748c2ecf20Sopenharmony_ci		ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
758c2ecf20Sopenharmony_ci				"failed to stop RX DMA !\n");
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return i ? 0 : -EBUSY;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/**
818c2ecf20Sopenharmony_ci * ath5k_hw_get_rxdp() - Get RX Descriptor's address
828c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_ciu32
858c2ecf20Sopenharmony_ciath5k_hw_get_rxdp(struct ath5k_hw *ah)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	return ath5k_hw_reg_read(ah, AR5K_RXDP);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/**
918c2ecf20Sopenharmony_ci * ath5k_hw_set_rxdp() - Set RX Descriptor's address
928c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
938c2ecf20Sopenharmony_ci * @phys_addr: RX descriptor address
948c2ecf20Sopenharmony_ci *
958c2ecf20Sopenharmony_ci * Returns -EIO if rx is active
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_ciint
988c2ecf20Sopenharmony_ciath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) {
1018c2ecf20Sopenharmony_ci		ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
1028c2ecf20Sopenharmony_ci				"tried to set RXDP while rx was active !\n");
1038c2ecf20Sopenharmony_ci		return -EIO;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
1078c2ecf20Sopenharmony_ci	return 0;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/**********\
1128c2ecf20Sopenharmony_ci* Transmit *
1138c2ecf20Sopenharmony_ci\**********/
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/**
1168c2ecf20Sopenharmony_ci * ath5k_hw_start_tx_dma() - Start DMA transmit for a specific queue
1178c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
1188c2ecf20Sopenharmony_ci * @queue: The hw queue number
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Start DMA transmit for a specific queue and since 5210 doesn't have
1218c2ecf20Sopenharmony_ci * QCU/DCU, set up queue parameters for 5210 here based on queue type (one
1228c2ecf20Sopenharmony_ci * queue for normal data and one queue for beacons). For queue setup
1238c2ecf20Sopenharmony_ci * on newer chips check out qcu.c. Returns -EINVAL if queue number is out
1248c2ecf20Sopenharmony_ci * of range or if queue is already disabled.
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci * NOTE: Must be called after setting up tx control descriptor for that
1278c2ecf20Sopenharmony_ci * queue (see below).
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_ciint
1308c2ecf20Sopenharmony_ciath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	u32 tx_queue;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* Return if queue is declared inactive */
1378c2ecf20Sopenharmony_ci	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
1388c2ecf20Sopenharmony_ci		return -EINVAL;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
1418c2ecf20Sopenharmony_ci		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		/*
1448c2ecf20Sopenharmony_ci		 * Set the queue by type on 5210
1458c2ecf20Sopenharmony_ci		 */
1468c2ecf20Sopenharmony_ci		switch (ah->ah_txq[queue].tqi_type) {
1478c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
1488c2ecf20Sopenharmony_ci			tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
1498c2ecf20Sopenharmony_ci			break;
1508c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
1518c2ecf20Sopenharmony_ci			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
1528c2ecf20Sopenharmony_ci			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
1538c2ecf20Sopenharmony_ci					AR5K_BSR);
1548c2ecf20Sopenharmony_ci			break;
1558c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
1568c2ecf20Sopenharmony_ci			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
1578c2ecf20Sopenharmony_ci			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V |
1588c2ecf20Sopenharmony_ci				AR5K_BCR_BDMAE, AR5K_BSR);
1598c2ecf20Sopenharmony_ci			break;
1608c2ecf20Sopenharmony_ci		default:
1618c2ecf20Sopenharmony_ci			return -EINVAL;
1628c2ecf20Sopenharmony_ci		}
1638c2ecf20Sopenharmony_ci		/* Start queue */
1648c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
1658c2ecf20Sopenharmony_ci		ath5k_hw_reg_read(ah, AR5K_CR);
1668c2ecf20Sopenharmony_ci	} else {
1678c2ecf20Sopenharmony_ci		/* Return if queue is disabled */
1688c2ecf20Sopenharmony_ci		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
1698c2ecf20Sopenharmony_ci			return -EIO;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		/* Start queue */
1728c2ecf20Sopenharmony_ci		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/**
1798c2ecf20Sopenharmony_ci * ath5k_hw_stop_tx_dma() - Stop DMA transmit on a specific queue
1808c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
1818c2ecf20Sopenharmony_ci * @queue: The hw queue number
1828c2ecf20Sopenharmony_ci *
1838c2ecf20Sopenharmony_ci * Stop DMA transmit on a specific hw queue and drain queue so we don't
1848c2ecf20Sopenharmony_ci * have any pending frames. Returns -EBUSY if we still have pending frames,
1858c2ecf20Sopenharmony_ci * -EINVAL if queue number is out of range or inactive.
1868c2ecf20Sopenharmony_ci */
1878c2ecf20Sopenharmony_cistatic int
1888c2ecf20Sopenharmony_ciath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	unsigned int i = 40;
1918c2ecf20Sopenharmony_ci	u32 tx_queue, pending;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* Return if queue is declared inactive */
1968c2ecf20Sopenharmony_ci	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
1978c2ecf20Sopenharmony_ci		return -EINVAL;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
2008c2ecf20Sopenharmony_ci		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		/*
2038c2ecf20Sopenharmony_ci		 * Set by queue type
2048c2ecf20Sopenharmony_ci		 */
2058c2ecf20Sopenharmony_ci		switch (ah->ah_txq[queue].tqi_type) {
2068c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
2078c2ecf20Sopenharmony_ci			tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
2088c2ecf20Sopenharmony_ci			break;
2098c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
2108c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
2118c2ecf20Sopenharmony_ci			/* XXX Fix me... */
2128c2ecf20Sopenharmony_ci			tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1;
2138c2ecf20Sopenharmony_ci			ath5k_hw_reg_write(ah, 0, AR5K_BSR);
2148c2ecf20Sopenharmony_ci			break;
2158c2ecf20Sopenharmony_ci		default:
2168c2ecf20Sopenharmony_ci			return -EINVAL;
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		/* Stop queue */
2208c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
2218c2ecf20Sopenharmony_ci		ath5k_hw_reg_read(ah, AR5K_CR);
2228c2ecf20Sopenharmony_ci	} else {
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		/*
2258c2ecf20Sopenharmony_ci		 * Enable DCU early termination to quickly
2268c2ecf20Sopenharmony_ci		 * flush any pending frames from QCU
2278c2ecf20Sopenharmony_ci		 */
2288c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
2298c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_DCU_EARLY);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		/*
2328c2ecf20Sopenharmony_ci		 * Schedule TX disable and wait until queue is empty
2338c2ecf20Sopenharmony_ci		 */
2348c2ecf20Sopenharmony_ci		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		/* Wait for queue to stop */
2378c2ecf20Sopenharmony_ci		for (i = 1000; i > 0 &&
2388c2ecf20Sopenharmony_ci		(AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue) != 0);
2398c2ecf20Sopenharmony_ci		i--)
2408c2ecf20Sopenharmony_ci			udelay(100);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
2438c2ecf20Sopenharmony_ci			ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
2448c2ecf20Sopenharmony_ci				"queue %i didn't stop !\n", queue);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		/* Check for pending frames */
2478c2ecf20Sopenharmony_ci		i = 1000;
2488c2ecf20Sopenharmony_ci		do {
2498c2ecf20Sopenharmony_ci			pending = ath5k_hw_reg_read(ah,
2508c2ecf20Sopenharmony_ci				AR5K_QUEUE_STATUS(queue)) &
2518c2ecf20Sopenharmony_ci				AR5K_QCU_STS_FRMPENDCNT;
2528c2ecf20Sopenharmony_ci			udelay(100);
2538c2ecf20Sopenharmony_ci		} while (--i && pending);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		/* For 2413+ order PCU to drop packets using
2568c2ecf20Sopenharmony_ci		 * QUIET mechanism */
2578c2ecf20Sopenharmony_ci		if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) &&
2588c2ecf20Sopenharmony_ci		    pending) {
2598c2ecf20Sopenharmony_ci			/* Set periodicity and duration */
2608c2ecf20Sopenharmony_ci			ath5k_hw_reg_write(ah,
2618c2ecf20Sopenharmony_ci				AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
2628c2ecf20Sopenharmony_ci				AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR),
2638c2ecf20Sopenharmony_ci				AR5K_QUIET_CTL2);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci			/* Enable quiet period for current TSF */
2668c2ecf20Sopenharmony_ci			ath5k_hw_reg_write(ah,
2678c2ecf20Sopenharmony_ci				AR5K_QUIET_CTL1_QT_EN |
2688c2ecf20Sopenharmony_ci				AR5K_REG_SM(ath5k_hw_reg_read(ah,
2698c2ecf20Sopenharmony_ci						AR5K_TSF_L32_5211) >> 10,
2708c2ecf20Sopenharmony_ci						AR5K_QUIET_CTL1_NEXT_QT_TSF),
2718c2ecf20Sopenharmony_ci				AR5K_QUIET_CTL1);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci			/* Force channel idle high */
2748c2ecf20Sopenharmony_ci			AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
2758c2ecf20Sopenharmony_ci					AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci			/* Wait a while and disable mechanism */
2788c2ecf20Sopenharmony_ci			udelay(400);
2798c2ecf20Sopenharmony_ci			AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
2808c2ecf20Sopenharmony_ci						AR5K_QUIET_CTL1_QT_EN);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci			/* Re-check for pending frames */
2838c2ecf20Sopenharmony_ci			i = 100;
2848c2ecf20Sopenharmony_ci			do {
2858c2ecf20Sopenharmony_ci				pending = ath5k_hw_reg_read(ah,
2868c2ecf20Sopenharmony_ci					AR5K_QUEUE_STATUS(queue)) &
2878c2ecf20Sopenharmony_ci					AR5K_QCU_STS_FRMPENDCNT;
2888c2ecf20Sopenharmony_ci				udelay(100);
2898c2ecf20Sopenharmony_ci			} while (--i && pending);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci			AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
2928c2ecf20Sopenharmony_ci					AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci			if (pending)
2958c2ecf20Sopenharmony_ci				ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
2968c2ecf20Sopenharmony_ci					"quiet mechanism didn't work q:%i !\n",
2978c2ecf20Sopenharmony_ci					queue);
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		/*
3018c2ecf20Sopenharmony_ci		 * Disable DCU early termination
3028c2ecf20Sopenharmony_ci		 */
3038c2ecf20Sopenharmony_ci		AR5K_REG_DISABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
3048c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_DCU_EARLY);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		/* Clear register */
3078c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
3088c2ecf20Sopenharmony_ci		if (pending) {
3098c2ecf20Sopenharmony_ci			ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
3108c2ecf20Sopenharmony_ci					"tx dma didn't stop (q:%i, frm:%i) !\n",
3118c2ecf20Sopenharmony_ci					queue, pending);
3128c2ecf20Sopenharmony_ci			return -EBUSY;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* TODO: Check for success on 5210 else return error */
3178c2ecf20Sopenharmony_ci	return 0;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci/**
3218c2ecf20Sopenharmony_ci * ath5k_hw_stop_beacon_queue() - Stop beacon queue
3228c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
3238c2ecf20Sopenharmony_ci * @queue: The queue number
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * Returns -EIO if queue didn't stop
3268c2ecf20Sopenharmony_ci */
3278c2ecf20Sopenharmony_ciint
3288c2ecf20Sopenharmony_ciath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	int ret;
3318c2ecf20Sopenharmony_ci	ret = ath5k_hw_stop_tx_dma(ah, queue);
3328c2ecf20Sopenharmony_ci	if (ret) {
3338c2ecf20Sopenharmony_ci		ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
3348c2ecf20Sopenharmony_ci				"beacon queue didn't stop !\n");
3358c2ecf20Sopenharmony_ci		return -EIO;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci	return 0;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci/**
3418c2ecf20Sopenharmony_ci * ath5k_hw_get_txdp() - Get TX Descriptor's address for a specific queue
3428c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
3438c2ecf20Sopenharmony_ci * @queue: The hw queue number
3448c2ecf20Sopenharmony_ci *
3458c2ecf20Sopenharmony_ci * Get TX descriptor's address for a specific queue. For 5210 we ignore
3468c2ecf20Sopenharmony_ci * the queue number and use tx queue type since we only have 2 queues.
3478c2ecf20Sopenharmony_ci * We use TXDP0 for normal data queue and TXDP1 for beacon queue.
3488c2ecf20Sopenharmony_ci * For newer chips with QCU/DCU we just read the corresponding TXDP register.
3498c2ecf20Sopenharmony_ci *
3508c2ecf20Sopenharmony_ci * XXX: Is TXDP read and clear ?
3518c2ecf20Sopenharmony_ci */
3528c2ecf20Sopenharmony_ciu32
3538c2ecf20Sopenharmony_ciath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	u16 tx_reg;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/*
3608c2ecf20Sopenharmony_ci	 * Get the transmit queue descriptor pointer from the selected queue
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	/*5210 doesn't have QCU*/
3638c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
3648c2ecf20Sopenharmony_ci		switch (ah->ah_txq[queue].tqi_type) {
3658c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
3668c2ecf20Sopenharmony_ci			tx_reg = AR5K_NOQCU_TXDP0;
3678c2ecf20Sopenharmony_ci			break;
3688c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
3698c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
3708c2ecf20Sopenharmony_ci			tx_reg = AR5K_NOQCU_TXDP1;
3718c2ecf20Sopenharmony_ci			break;
3728c2ecf20Sopenharmony_ci		default:
3738c2ecf20Sopenharmony_ci			return 0xffffffff;
3748c2ecf20Sopenharmony_ci		}
3758c2ecf20Sopenharmony_ci	} else {
3768c2ecf20Sopenharmony_ci		tx_reg = AR5K_QUEUE_TXDP(queue);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return ath5k_hw_reg_read(ah, tx_reg);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/**
3838c2ecf20Sopenharmony_ci * ath5k_hw_set_txdp() - Set TX Descriptor's address for a specific queue
3848c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
3858c2ecf20Sopenharmony_ci * @queue: The hw queue number
3868c2ecf20Sopenharmony_ci * @phys_addr: The physical address
3878c2ecf20Sopenharmony_ci *
3888c2ecf20Sopenharmony_ci * Set TX descriptor's address for a specific queue. For 5210 we ignore
3898c2ecf20Sopenharmony_ci * the queue number and we use tx queue type since we only have 2 queues
3908c2ecf20Sopenharmony_ci * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue.
3918c2ecf20Sopenharmony_ci * For newer chips with QCU/DCU we just set the corresponding TXDP register.
3928c2ecf20Sopenharmony_ci * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
3938c2ecf20Sopenharmony_ci * active.
3948c2ecf20Sopenharmony_ci */
3958c2ecf20Sopenharmony_ciint
3968c2ecf20Sopenharmony_ciath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	u16 tx_reg;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/*
4038c2ecf20Sopenharmony_ci	 * Set the transmit queue descriptor pointer register by type
4048c2ecf20Sopenharmony_ci	 * on 5210
4058c2ecf20Sopenharmony_ci	 */
4068c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
4078c2ecf20Sopenharmony_ci		switch (ah->ah_txq[queue].tqi_type) {
4088c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
4098c2ecf20Sopenharmony_ci			tx_reg = AR5K_NOQCU_TXDP0;
4108c2ecf20Sopenharmony_ci			break;
4118c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
4128c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
4138c2ecf20Sopenharmony_ci			tx_reg = AR5K_NOQCU_TXDP1;
4148c2ecf20Sopenharmony_ci			break;
4158c2ecf20Sopenharmony_ci		default:
4168c2ecf20Sopenharmony_ci			return -EINVAL;
4178c2ecf20Sopenharmony_ci		}
4188c2ecf20Sopenharmony_ci	} else {
4198c2ecf20Sopenharmony_ci		/*
4208c2ecf20Sopenharmony_ci		 * Set the transmit queue descriptor pointer for
4218c2ecf20Sopenharmony_ci		 * the selected queue on QCU for 5211+
4228c2ecf20Sopenharmony_ci		 * (this won't work if the queue is still active)
4238c2ecf20Sopenharmony_ci		 */
4248c2ecf20Sopenharmony_ci		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
4258c2ecf20Sopenharmony_ci			return -EIO;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		tx_reg = AR5K_QUEUE_TXDP(queue);
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* Set descriptor pointer */
4318c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci/**
4378c2ecf20Sopenharmony_ci * ath5k_hw_update_tx_triglevel() - Update tx trigger level
4388c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
4398c2ecf20Sopenharmony_ci * @increase: Flag to force increase of trigger level
4408c2ecf20Sopenharmony_ci *
4418c2ecf20Sopenharmony_ci * This function increases/decreases the tx trigger level for the tx fifo
4428c2ecf20Sopenharmony_ci * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
4438c2ecf20Sopenharmony_ci * the buffer and transmits its data. Lowering this results sending small
4448c2ecf20Sopenharmony_ci * frames more quickly but can lead to tx underruns, raising it a lot can
4458c2ecf20Sopenharmony_ci * result other problems. Right now we start with the lowest possible
4468c2ecf20Sopenharmony_ci * (64Bytes) and if we get tx underrun we increase it using the increase
4478c2ecf20Sopenharmony_ci * flag. Returns -EIO if we have reached maximum/minimum.
4488c2ecf20Sopenharmony_ci *
4498c2ecf20Sopenharmony_ci * XXX: Link this with tx DMA size ?
4508c2ecf20Sopenharmony_ci * XXX2: Use it to save interrupts ?
4518c2ecf20Sopenharmony_ci */
4528c2ecf20Sopenharmony_ciint
4538c2ecf20Sopenharmony_ciath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	u32 trigger_level, imr;
4568c2ecf20Sopenharmony_ci	int ret = -EIO;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/*
4598c2ecf20Sopenharmony_ci	 * Disable interrupts by setting the mask
4608c2ecf20Sopenharmony_ci	 */
4618c2ecf20Sopenharmony_ci	imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
4648c2ecf20Sopenharmony_ci			AR5K_TXCFG_TXFULL);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (!increase) {
4678c2ecf20Sopenharmony_ci		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
4688c2ecf20Sopenharmony_ci			goto done;
4698c2ecf20Sopenharmony_ci	} else
4708c2ecf20Sopenharmony_ci		trigger_level +=
4718c2ecf20Sopenharmony_ci			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/*
4748c2ecf20Sopenharmony_ci	 * Update trigger level on success
4758c2ecf20Sopenharmony_ci	 */
4768c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210)
4778c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
4788c2ecf20Sopenharmony_ci	else
4798c2ecf20Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
4808c2ecf20Sopenharmony_ci				AR5K_TXCFG_TXFULL, trigger_level);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	ret = 0;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cidone:
4858c2ecf20Sopenharmony_ci	/*
4868c2ecf20Sopenharmony_ci	 * Restore interrupt mask
4878c2ecf20Sopenharmony_ci	 */
4888c2ecf20Sopenharmony_ci	ath5k_hw_set_imr(ah, imr);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	return ret;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci/*******************\
4958c2ecf20Sopenharmony_ci* Interrupt masking *
4968c2ecf20Sopenharmony_ci\*******************/
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/**
4998c2ecf20Sopenharmony_ci * ath5k_hw_is_intr_pending() - Check if we have pending interrupts
5008c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
5018c2ecf20Sopenharmony_ci *
5028c2ecf20Sopenharmony_ci * Check if we have pending interrupts to process. Returns 1 if we
5038c2ecf20Sopenharmony_ci * have pending interrupts and 0 if we haven't.
5048c2ecf20Sopenharmony_ci */
5058c2ecf20Sopenharmony_cibool
5068c2ecf20Sopenharmony_ciath5k_hw_is_intr_pending(struct ath5k_hw *ah)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci/**
5128c2ecf20Sopenharmony_ci * ath5k_hw_get_isr() - Get interrupt status
5138c2ecf20Sopenharmony_ci * @ah: The @struct ath5k_hw
5148c2ecf20Sopenharmony_ci * @interrupt_mask: Driver's interrupt mask used to filter out
5158c2ecf20Sopenharmony_ci * interrupts in sw.
5168c2ecf20Sopenharmony_ci *
5178c2ecf20Sopenharmony_ci * This function is used inside our interrupt handler to determine the reason
5188c2ecf20Sopenharmony_ci * for the interrupt by reading Primary Interrupt Status Register. Returns an
5198c2ecf20Sopenharmony_ci * abstract interrupt status mask which is mostly ISR with some uncommon bits
5208c2ecf20Sopenharmony_ci * being mapped on some standard non hw-specific positions
5218c2ecf20Sopenharmony_ci * (check out &ath5k_int).
5228c2ecf20Sopenharmony_ci *
5238c2ecf20Sopenharmony_ci * NOTE: We do write-to-clear, so the active PISR/SISR bits at the time this
5248c2ecf20Sopenharmony_ci * function gets called are cleared on return.
5258c2ecf20Sopenharmony_ci */
5268c2ecf20Sopenharmony_ciint
5278c2ecf20Sopenharmony_ciath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	u32 data = 0;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/*
5328c2ecf20Sopenharmony_ci	 * Read interrupt status from Primary Interrupt
5338c2ecf20Sopenharmony_ci	 * Register.
5348c2ecf20Sopenharmony_ci	 *
5358c2ecf20Sopenharmony_ci	 * Note: PISR/SISR Not available on 5210
5368c2ecf20Sopenharmony_ci	 */
5378c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
5388c2ecf20Sopenharmony_ci		u32 isr = 0;
5398c2ecf20Sopenharmony_ci		isr = ath5k_hw_reg_read(ah, AR5K_ISR);
5408c2ecf20Sopenharmony_ci		if (unlikely(isr == AR5K_INT_NOCARD)) {
5418c2ecf20Sopenharmony_ci			*interrupt_mask = isr;
5428c2ecf20Sopenharmony_ci			return -ENODEV;
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci		/*
5468c2ecf20Sopenharmony_ci		 * Filter out the non-common bits from the interrupt
5478c2ecf20Sopenharmony_ci		 * status.
5488c2ecf20Sopenharmony_ci		 */
5498c2ecf20Sopenharmony_ci		*interrupt_mask = (isr & AR5K_INT_COMMON) & ah->ah_imr;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		/* Hanlde INT_FATAL */
5528c2ecf20Sopenharmony_ci		if (unlikely(isr & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
5538c2ecf20Sopenharmony_ci						| AR5K_ISR_DPERR)))
5548c2ecf20Sopenharmony_ci			*interrupt_mask |= AR5K_INT_FATAL;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		/*
5578c2ecf20Sopenharmony_ci		 * XXX: BMISS interrupts may occur after association.
5588c2ecf20Sopenharmony_ci		 * I found this on 5210 code but it needs testing. If this is
5598c2ecf20Sopenharmony_ci		 * true we should disable them before assoc and re-enable them
5608c2ecf20Sopenharmony_ci		 * after a successful assoc + some jiffies.
5618c2ecf20Sopenharmony_ci			interrupt_mask &= ~AR5K_INT_BMISS;
5628c2ecf20Sopenharmony_ci		 */
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		data = isr;
5658c2ecf20Sopenharmony_ci	} else {
5668c2ecf20Sopenharmony_ci		u32 pisr = 0;
5678c2ecf20Sopenharmony_ci		u32 pisr_clear = 0;
5688c2ecf20Sopenharmony_ci		u32 sisr0 = 0;
5698c2ecf20Sopenharmony_ci		u32 sisr1 = 0;
5708c2ecf20Sopenharmony_ci		u32 sisr2 = 0;
5718c2ecf20Sopenharmony_ci		u32 sisr3 = 0;
5728c2ecf20Sopenharmony_ci		u32 sisr4 = 0;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		/* Read PISR and SISRs... */
5758c2ecf20Sopenharmony_ci		pisr = ath5k_hw_reg_read(ah, AR5K_PISR);
5768c2ecf20Sopenharmony_ci		if (unlikely(pisr == AR5K_INT_NOCARD)) {
5778c2ecf20Sopenharmony_ci			*interrupt_mask = pisr;
5788c2ecf20Sopenharmony_ci			return -ENODEV;
5798c2ecf20Sopenharmony_ci		}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		sisr0 = ath5k_hw_reg_read(ah, AR5K_SISR0);
5828c2ecf20Sopenharmony_ci		sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1);
5838c2ecf20Sopenharmony_ci		sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2);
5848c2ecf20Sopenharmony_ci		sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3);
5858c2ecf20Sopenharmony_ci		sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		/*
5888c2ecf20Sopenharmony_ci		 * PISR holds the logical OR of interrupt bits
5898c2ecf20Sopenharmony_ci		 * from SISR registers:
5908c2ecf20Sopenharmony_ci		 *
5918c2ecf20Sopenharmony_ci		 * TXOK and TXDESC  -> Logical OR of TXOK and TXDESC
5928c2ecf20Sopenharmony_ci		 *			per-queue bits on SISR0
5938c2ecf20Sopenharmony_ci		 *
5948c2ecf20Sopenharmony_ci		 * TXERR and TXEOL -> Logical OR of TXERR and TXEOL
5958c2ecf20Sopenharmony_ci		 *			per-queue bits on SISR1
5968c2ecf20Sopenharmony_ci		 *
5978c2ecf20Sopenharmony_ci		 * TXURN -> Logical OR of TXURN per-queue bits on SISR2
5988c2ecf20Sopenharmony_ci		 *
5998c2ecf20Sopenharmony_ci		 * HIUERR -> Logical OR of MCABT, SSERR and DPER bits on SISR2
6008c2ecf20Sopenharmony_ci		 *
6018c2ecf20Sopenharmony_ci		 * BCNMISC -> Logical OR of TIM, CAB_END, DTIM_SYNC
6028c2ecf20Sopenharmony_ci		 *		BCN_TIMEOUT, CAB_TIMEOUT and DTIM
6038c2ecf20Sopenharmony_ci		 *		(and TSFOOR ?) bits on SISR2
6048c2ecf20Sopenharmony_ci		 *
6058c2ecf20Sopenharmony_ci		 * QCBRORN and QCBRURN -> Logical OR of QCBRORN and
6068c2ecf20Sopenharmony_ci		 *			QCBRURN per-queue bits on SISR3
6078c2ecf20Sopenharmony_ci		 * QTRIG -> Logical OR of QTRIG per-queue bits on SISR4
6088c2ecf20Sopenharmony_ci		 *
6098c2ecf20Sopenharmony_ci		 * If we clean these bits on PISR we 'll also clear all
6108c2ecf20Sopenharmony_ci		 * related bits from SISRs, e.g. if we write the TXOK bit on
6118c2ecf20Sopenharmony_ci		 * PISR we 'll clean all TXOK bits from SISR0 so if a new TXOK
6128c2ecf20Sopenharmony_ci		 * interrupt got fired for another queue while we were reading
6138c2ecf20Sopenharmony_ci		 * the interrupt registers and we write back the TXOK bit on
6148c2ecf20Sopenharmony_ci		 * PISR we 'll lose it. So make sure that we don't write back
6158c2ecf20Sopenharmony_ci		 * on PISR any bits that come from SISRs. Clearing them from
6168c2ecf20Sopenharmony_ci		 * SISRs will also clear PISR so no need to worry here.
6178c2ecf20Sopenharmony_ci		 */
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		/* XXX: There seems to be  an issue on some cards
6208c2ecf20Sopenharmony_ci		 *	with tx interrupt flags not being updated
6218c2ecf20Sopenharmony_ci		 *	on PISR despite that all Tx interrupt bits
6228c2ecf20Sopenharmony_ci		 * 	are cleared on SISRs. Since we handle all
6238c2ecf20Sopenharmony_ci		 *	Tx queues all together it shouldn't be an
6248c2ecf20Sopenharmony_ci		 *	issue if we clear Tx interrupt flags also
6258c2ecf20Sopenharmony_ci		 * 	on PISR to avoid that.
6268c2ecf20Sopenharmony_ci		 */
6278c2ecf20Sopenharmony_ci		pisr_clear = (pisr & ~AR5K_ISR_BITS_FROM_SISRS) |
6288c2ecf20Sopenharmony_ci					(pisr & AR5K_INT_TX_ALL);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		/*
6318c2ecf20Sopenharmony_ci		 * Write to clear them...
6328c2ecf20Sopenharmony_ci		 * Note: This means that each bit we write back
6338c2ecf20Sopenharmony_ci		 * to the registers will get cleared, leaving the
6348c2ecf20Sopenharmony_ci		 * rest unaffected. So this won't affect new interrupts
6358c2ecf20Sopenharmony_ci		 * we didn't catch while reading/processing, we 'll get
6368c2ecf20Sopenharmony_ci		 * them next time get_isr gets called.
6378c2ecf20Sopenharmony_ci		 */
6388c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, sisr0, AR5K_SISR0);
6398c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, sisr1, AR5K_SISR1);
6408c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, sisr2, AR5K_SISR2);
6418c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, sisr3, AR5K_SISR3);
6428c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, sisr4, AR5K_SISR4);
6438c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, pisr_clear, AR5K_PISR);
6448c2ecf20Sopenharmony_ci		/* Flush previous write */
6458c2ecf20Sopenharmony_ci		ath5k_hw_reg_read(ah, AR5K_PISR);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		/*
6488c2ecf20Sopenharmony_ci		 * Filter out the non-common bits from the interrupt
6498c2ecf20Sopenharmony_ci		 * status.
6508c2ecf20Sopenharmony_ci		 */
6518c2ecf20Sopenharmony_ci		*interrupt_mask = (pisr & AR5K_INT_COMMON) & ah->ah_imr;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci		/* We treat TXOK,TXDESC, TXERR and TXEOL
6558c2ecf20Sopenharmony_ci		 * the same way (schedule the tx tasklet)
6568c2ecf20Sopenharmony_ci		 * so we track them all together per queue */
6578c2ecf20Sopenharmony_ci		if (pisr & AR5K_ISR_TXOK)
6588c2ecf20Sopenharmony_ci			ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0,
6598c2ecf20Sopenharmony_ci						AR5K_SISR0_QCU_TXOK);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci		if (pisr & AR5K_ISR_TXDESC)
6628c2ecf20Sopenharmony_ci			ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0,
6638c2ecf20Sopenharmony_ci						AR5K_SISR0_QCU_TXDESC);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		if (pisr & AR5K_ISR_TXERR)
6668c2ecf20Sopenharmony_ci			ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1,
6678c2ecf20Sopenharmony_ci						AR5K_SISR1_QCU_TXERR);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		if (pisr & AR5K_ISR_TXEOL)
6708c2ecf20Sopenharmony_ci			ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1,
6718c2ecf20Sopenharmony_ci						AR5K_SISR1_QCU_TXEOL);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci		/* Currently this is not much useful since we treat
6748c2ecf20Sopenharmony_ci		 * all queues the same way if we get a TXURN (update
6758c2ecf20Sopenharmony_ci		 * tx trigger level) but we might need it later on*/
6768c2ecf20Sopenharmony_ci		if (pisr & AR5K_ISR_TXURN)
6778c2ecf20Sopenharmony_ci			ah->ah_txq_isr_txurn |= AR5K_REG_MS(sisr2,
6788c2ecf20Sopenharmony_ci						AR5K_SISR2_QCU_TXURN);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		/* Misc Beacon related interrupts */
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci		/* For AR5211 */
6838c2ecf20Sopenharmony_ci		if (pisr & AR5K_ISR_TIM)
6848c2ecf20Sopenharmony_ci			*interrupt_mask |= AR5K_INT_TIM;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci		/* For AR5212+ */
6878c2ecf20Sopenharmony_ci		if (pisr & AR5K_ISR_BCNMISC) {
6888c2ecf20Sopenharmony_ci			if (sisr2 & AR5K_SISR2_TIM)
6898c2ecf20Sopenharmony_ci				*interrupt_mask |= AR5K_INT_TIM;
6908c2ecf20Sopenharmony_ci			if (sisr2 & AR5K_SISR2_DTIM)
6918c2ecf20Sopenharmony_ci				*interrupt_mask |= AR5K_INT_DTIM;
6928c2ecf20Sopenharmony_ci			if (sisr2 & AR5K_SISR2_DTIM_SYNC)
6938c2ecf20Sopenharmony_ci				*interrupt_mask |= AR5K_INT_DTIM_SYNC;
6948c2ecf20Sopenharmony_ci			if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
6958c2ecf20Sopenharmony_ci				*interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
6968c2ecf20Sopenharmony_ci			if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
6978c2ecf20Sopenharmony_ci				*interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
6988c2ecf20Sopenharmony_ci		}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		/* Below interrupts are unlikely to happen */
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci		/* HIU = Host Interface Unit (PCI etc)
7038c2ecf20Sopenharmony_ci		 * Can be one of MCABT, SSERR, DPERR from SISR2 */
7048c2ecf20Sopenharmony_ci		if (unlikely(pisr & (AR5K_ISR_HIUERR)))
7058c2ecf20Sopenharmony_ci			*interrupt_mask |= AR5K_INT_FATAL;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci		/*Beacon Not Ready*/
7088c2ecf20Sopenharmony_ci		if (unlikely(pisr & (AR5K_ISR_BNR)))
7098c2ecf20Sopenharmony_ci			*interrupt_mask |= AR5K_INT_BNR;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci		/* A queue got CBR overrun */
7128c2ecf20Sopenharmony_ci		if (unlikely(pisr & (AR5K_ISR_QCBRORN))) {
7138c2ecf20Sopenharmony_ci			*interrupt_mask |= AR5K_INT_QCBRORN;
7148c2ecf20Sopenharmony_ci			ah->ah_txq_isr_qcborn |= AR5K_REG_MS(sisr3,
7158c2ecf20Sopenharmony_ci						AR5K_SISR3_QCBRORN);
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		/* A queue got CBR underrun */
7198c2ecf20Sopenharmony_ci		if (unlikely(pisr & (AR5K_ISR_QCBRURN))) {
7208c2ecf20Sopenharmony_ci			*interrupt_mask |= AR5K_INT_QCBRURN;
7218c2ecf20Sopenharmony_ci			ah->ah_txq_isr_qcburn |= AR5K_REG_MS(sisr3,
7228c2ecf20Sopenharmony_ci						AR5K_SISR3_QCBRURN);
7238c2ecf20Sopenharmony_ci		}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		/* A queue got triggered */
7268c2ecf20Sopenharmony_ci		if (unlikely(pisr & (AR5K_ISR_QTRIG))) {
7278c2ecf20Sopenharmony_ci			*interrupt_mask |= AR5K_INT_QTRIG;
7288c2ecf20Sopenharmony_ci			ah->ah_txq_isr_qtrig |= AR5K_REG_MS(sisr4,
7298c2ecf20Sopenharmony_ci						AR5K_SISR4_QTRIG);
7308c2ecf20Sopenharmony_ci		}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci		data = pisr;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	/*
7368c2ecf20Sopenharmony_ci	 * In case we didn't handle anything,
7378c2ecf20Sopenharmony_ci	 * print the register value.
7388c2ecf20Sopenharmony_ci	 */
7398c2ecf20Sopenharmony_ci	if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
7408c2ecf20Sopenharmony_ci		ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr);
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	return 0;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci/**
7468c2ecf20Sopenharmony_ci * ath5k_hw_set_imr() - Set interrupt mask
7478c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
7488c2ecf20Sopenharmony_ci * @new_mask: The new interrupt mask to be set
7498c2ecf20Sopenharmony_ci *
7508c2ecf20Sopenharmony_ci * Set the interrupt mask in hw to save interrupts. We do that by mapping
7518c2ecf20Sopenharmony_ci * ath5k_int bits to hw-specific bits to remove abstraction and writing
7528c2ecf20Sopenharmony_ci * Interrupt Mask Register.
7538c2ecf20Sopenharmony_ci */
7548c2ecf20Sopenharmony_cienum ath5k_int
7558c2ecf20Sopenharmony_ciath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
7568c2ecf20Sopenharmony_ci{
7578c2ecf20Sopenharmony_ci	enum ath5k_int old_mask, int_mask;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	old_mask = ah->ah_imr;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	/*
7628c2ecf20Sopenharmony_ci	 * Disable card interrupts to prevent any race conditions
7638c2ecf20Sopenharmony_ci	 * (they will be re-enabled afterwards if AR5K_INT GLOBAL
7648c2ecf20Sopenharmony_ci	 * is set again on the new mask).
7658c2ecf20Sopenharmony_ci	 */
7668c2ecf20Sopenharmony_ci	if (old_mask & AR5K_INT_GLOBAL) {
7678c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
7688c2ecf20Sopenharmony_ci		ath5k_hw_reg_read(ah, AR5K_IER);
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	/*
7728c2ecf20Sopenharmony_ci	 * Add additional, chipset-dependent interrupt mask flags
7738c2ecf20Sopenharmony_ci	 * and write them to the IMR (interrupt mask register).
7748c2ecf20Sopenharmony_ci	 */
7758c2ecf20Sopenharmony_ci	int_mask = new_mask & AR5K_INT_COMMON;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210) {
7788c2ecf20Sopenharmony_ci		/* Preserve per queue TXURN interrupt mask */
7798c2ecf20Sopenharmony_ci		u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
7808c2ecf20Sopenharmony_ci				& AR5K_SIMR2_QCU_TXURN;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		/* Fatal interrupt abstraction for 5211+ */
7838c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_FATAL) {
7848c2ecf20Sopenharmony_ci			int_mask |= AR5K_IMR_HIUERR;
7858c2ecf20Sopenharmony_ci			simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
7868c2ecf20Sopenharmony_ci				| AR5K_SIMR2_DPERR);
7878c2ecf20Sopenharmony_ci		}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		/* Misc beacon related interrupts */
7908c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_TIM)
7918c2ecf20Sopenharmony_ci			int_mask |= AR5K_IMR_TIM;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_TIM)
7948c2ecf20Sopenharmony_ci			simr2 |= AR5K_SISR2_TIM;
7958c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_DTIM)
7968c2ecf20Sopenharmony_ci			simr2 |= AR5K_SISR2_DTIM;
7978c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_DTIM_SYNC)
7988c2ecf20Sopenharmony_ci			simr2 |= AR5K_SISR2_DTIM_SYNC;
7998c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_BCN_TIMEOUT)
8008c2ecf20Sopenharmony_ci			simr2 |= AR5K_SISR2_BCN_TIMEOUT;
8018c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_CAB_TIMEOUT)
8028c2ecf20Sopenharmony_ci			simr2 |= AR5K_SISR2_CAB_TIMEOUT;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci		/*Beacon Not Ready*/
8058c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_BNR)
8068c2ecf20Sopenharmony_ci			int_mask |= AR5K_INT_BNR;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci		/* Note: Per queue interrupt masks
8098c2ecf20Sopenharmony_ci		 * are set via ath5k_hw_reset_tx_queue() (qcu.c) */
8108c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
8118c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	} else {
8148c2ecf20Sopenharmony_ci		/* Fatal interrupt abstraction for 5210 */
8158c2ecf20Sopenharmony_ci		if (new_mask & AR5K_INT_FATAL)
8168c2ecf20Sopenharmony_ci			int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
8178c2ecf20Sopenharmony_ci				| AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		/* Only common interrupts left for 5210 (no SIMRs) */
8208c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	/* If RXNOFRM interrupt is masked disable it
8248c2ecf20Sopenharmony_ci	 * by setting AR5K_RXNOFRM to zero */
8258c2ecf20Sopenharmony_ci	if (!(new_mask & AR5K_INT_RXNOFRM))
8268c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	/* Store new interrupt mask */
8298c2ecf20Sopenharmony_ci	ah->ah_imr = new_mask;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
8328c2ecf20Sopenharmony_ci	if (new_mask & AR5K_INT_GLOBAL) {
8338c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
8348c2ecf20Sopenharmony_ci		ath5k_hw_reg_read(ah, AR5K_IER);
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	return old_mask;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci/********************\
8428c2ecf20Sopenharmony_ci Init/Stop functions
8438c2ecf20Sopenharmony_ci\********************/
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/**
8468c2ecf20Sopenharmony_ci * ath5k_hw_dma_init() - Initialize DMA unit
8478c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
8488c2ecf20Sopenharmony_ci *
8498c2ecf20Sopenharmony_ci * Set DMA size and pre-enable interrupts
8508c2ecf20Sopenharmony_ci * (driver handles tx/rx buffer setup and
8518c2ecf20Sopenharmony_ci * dma start/stop)
8528c2ecf20Sopenharmony_ci *
8538c2ecf20Sopenharmony_ci * XXX: Save/restore RXDP/TXDP registers ?
8548c2ecf20Sopenharmony_ci */
8558c2ecf20Sopenharmony_civoid
8568c2ecf20Sopenharmony_ciath5k_hw_dma_init(struct ath5k_hw *ah)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	/*
8598c2ecf20Sopenharmony_ci	 * Set Rx/Tx DMA Configuration
8608c2ecf20Sopenharmony_ci	 *
8618c2ecf20Sopenharmony_ci	 * Set standard DMA size (128). Note that
8628c2ecf20Sopenharmony_ci	 * a DMA size of 512 causes rx overruns and tx errors
8638c2ecf20Sopenharmony_ci	 * on pci-e cards (tested on 5424 but since rx overruns
8648c2ecf20Sopenharmony_ci	 * also occur on 5416/5418 with madwifi we set 128
8658c2ecf20Sopenharmony_ci	 * for all PCI-E cards to be safe).
8668c2ecf20Sopenharmony_ci	 *
8678c2ecf20Sopenharmony_ci	 * XXX: need to check 5210 for this
8688c2ecf20Sopenharmony_ci	 * TODO: Check out tx trigger level, it's always 64 on dumps but I
8698c2ecf20Sopenharmony_ci	 * guess we can tweak it and see how it goes ;-)
8708c2ecf20Sopenharmony_ci	 */
8718c2ecf20Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210) {
8728c2ecf20Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
8738c2ecf20Sopenharmony_ci			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
8748c2ecf20Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
8758c2ecf20Sopenharmony_ci			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* Pre-enable interrupts on 5211/5212*/
8798c2ecf20Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210)
8808c2ecf20Sopenharmony_ci		ath5k_hw_set_imr(ah, ah->ah_imr);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci/**
8858c2ecf20Sopenharmony_ci * ath5k_hw_dma_stop() - stop DMA unit
8868c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
8878c2ecf20Sopenharmony_ci *
8888c2ecf20Sopenharmony_ci * Stop tx/rx DMA and interrupts. Returns
8898c2ecf20Sopenharmony_ci * -EBUSY if tx or rx dma failed to stop.
8908c2ecf20Sopenharmony_ci *
8918c2ecf20Sopenharmony_ci * XXX: Sometimes DMA unit hangs and we have
8928c2ecf20Sopenharmony_ci * stuck frames on tx queues, only a reset
8938c2ecf20Sopenharmony_ci * can fix that.
8948c2ecf20Sopenharmony_ci */
8958c2ecf20Sopenharmony_ciint
8968c2ecf20Sopenharmony_ciath5k_hw_dma_stop(struct ath5k_hw *ah)
8978c2ecf20Sopenharmony_ci{
8988c2ecf20Sopenharmony_ci	int i, qmax, err;
8998c2ecf20Sopenharmony_ci	err = 0;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	/* Disable interrupts */
9028c2ecf20Sopenharmony_ci	ath5k_hw_set_imr(ah, 0);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* Stop rx dma */
9058c2ecf20Sopenharmony_ci	err = ath5k_hw_stop_rx_dma(ah);
9068c2ecf20Sopenharmony_ci	if (err)
9078c2ecf20Sopenharmony_ci		return err;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* Clear any pending interrupts
9108c2ecf20Sopenharmony_ci	 * and disable tx dma */
9118c2ecf20Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210) {
9128c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
9138c2ecf20Sopenharmony_ci		qmax = AR5K_NUM_TX_QUEUES;
9148c2ecf20Sopenharmony_ci	} else {
9158c2ecf20Sopenharmony_ci		/* PISR/SISR Not available on 5210 */
9168c2ecf20Sopenharmony_ci		ath5k_hw_reg_read(ah, AR5K_ISR);
9178c2ecf20Sopenharmony_ci		qmax = AR5K_NUM_TX_QUEUES_NOQCU;
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	for (i = 0; i < qmax; i++) {
9218c2ecf20Sopenharmony_ci		err = ath5k_hw_stop_tx_dma(ah, i);
9228c2ecf20Sopenharmony_ci		/* -EINVAL -> queue inactive */
9238c2ecf20Sopenharmony_ci		if (err && err != -EINVAL)
9248c2ecf20Sopenharmony_ci			return err;
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	return 0;
9288c2ecf20Sopenharmony_ci}
929