162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "hw.h"
1862306a36Sopenharmony_ci#include "hw-ops.h"
1962306a36Sopenharmony_ci#include <linux/export.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
2262306a36Sopenharmony_ci					struct ath9k_tx_queue_info *qi)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	ath_dbg(ath9k_hw_common(ah), INTERRUPT,
2562306a36Sopenharmony_ci		"tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
2662306a36Sopenharmony_ci		ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
2762306a36Sopenharmony_ci		ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
2862306a36Sopenharmony_ci		ah->txurn_interrupt_mask);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	ENABLE_REGWRITE_BUFFER(ah);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	REG_WRITE(ah, AR_IMR_S0,
3362306a36Sopenharmony_ci		  SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
3462306a36Sopenharmony_ci		  | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
3562306a36Sopenharmony_ci	REG_WRITE(ah, AR_IMR_S1,
3662306a36Sopenharmony_ci		  SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
3762306a36Sopenharmony_ci		  | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
4062306a36Sopenharmony_ci	ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
4162306a36Sopenharmony_ci	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	REGWRITE_BUFFER_FLUSH(ah);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciu32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	return REG_READ(ah, AR_QTXDP(q));
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_gettxbuf);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_civoid ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	REG_WRITE(ah, AR_QTXDP(q), txdp);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_puttxbuf);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_civoid ath9k_hw_txstart(struct ath_hw *ah, u32 q)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	ath_dbg(ath9k_hw_common(ah), QUEUE, "Enable TXE on queue: %u\n", q);
6162306a36Sopenharmony_ci	REG_WRITE(ah, AR_Q_TXE, 1 << q);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_txstart);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciu32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	u32 npend;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
7062306a36Sopenharmony_ci	if (npend == 0) {
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		if (REG_READ(ah, AR_Q_TXE) & (1 << q))
7362306a36Sopenharmony_ci			npend = 1;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return npend;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_numtxpending);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/**
8162306a36Sopenharmony_ci * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * @ah: atheros hardware struct
8462306a36Sopenharmony_ci * @bIncTrigLevel: whether or not the frame trigger level should be updated
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * The frame trigger level specifies the minimum number of bytes,
8762306a36Sopenharmony_ci * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO
8862306a36Sopenharmony_ci * before the PCU will initiate sending the frame on the air. This can
8962306a36Sopenharmony_ci * mean we initiate transmit before a full frame is on the PCU TX FIFO.
9062306a36Sopenharmony_ci * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs
9162306a36Sopenharmony_ci * first)
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * Caution must be taken to ensure to set the frame trigger level based
9462306a36Sopenharmony_ci * on the DMA request size. For example if the DMA request size is set to
9562306a36Sopenharmony_ci * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because
9662306a36Sopenharmony_ci * there need to be enough space in the tx FIFO for the requested transfer
9762306a36Sopenharmony_ci * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set
9862306a36Sopenharmony_ci * the threshold to a value beyond 6, then the transmit will hang.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Current dual   stream devices have a PCU TX FIFO size of 8 KB.
10162306a36Sopenharmony_ci * Current single stream devices have a PCU TX FIFO size of 4 KB, however,
10262306a36Sopenharmony_ci * there is a hardware issue which forces us to use 2 KB instead so the
10362306a36Sopenharmony_ci * frame trigger level must not exceed 2 KB for these chipsets.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_cibool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	u32 txcfg, curLevel, newLevel;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (ah->tx_trig_level >= ah->config.max_txtrig_level)
11062306a36Sopenharmony_ci		return false;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	ath9k_hw_disable_interrupts(ah);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	txcfg = REG_READ(ah, AR_TXCFG);
11562306a36Sopenharmony_ci	curLevel = MS(txcfg, AR_FTRIG);
11662306a36Sopenharmony_ci	newLevel = curLevel;
11762306a36Sopenharmony_ci	if (bIncTrigLevel) {
11862306a36Sopenharmony_ci		if (curLevel < ah->config.max_txtrig_level)
11962306a36Sopenharmony_ci			newLevel++;
12062306a36Sopenharmony_ci	} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
12162306a36Sopenharmony_ci		newLevel--;
12262306a36Sopenharmony_ci	if (newLevel != curLevel)
12362306a36Sopenharmony_ci		REG_WRITE(ah, AR_TXCFG,
12462306a36Sopenharmony_ci			  (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	ath9k_hw_enable_interrupts(ah);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	ah->tx_trig_level = newLevel;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return newLevel != curLevel;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_civoid ath9k_hw_abort_tx_dma(struct ath_hw *ah)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	int maxdelay = 1000;
13762306a36Sopenharmony_ci	int i, q;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (ah->curchan) {
14062306a36Sopenharmony_ci		if (IS_CHAN_HALF_RATE(ah->curchan))
14162306a36Sopenharmony_ci			maxdelay *= 2;
14262306a36Sopenharmony_ci		else if (IS_CHAN_QUARTER_RATE(ah->curchan))
14362306a36Sopenharmony_ci			maxdelay *= 4;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
14962306a36Sopenharmony_ci	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
15062306a36Sopenharmony_ci	REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	for (q = 0; q < AR_NUM_QCU; q++) {
15362306a36Sopenharmony_ci		for (i = 0; i < maxdelay; i++) {
15462306a36Sopenharmony_ci			if (i)
15562306a36Sopenharmony_ci				udelay(5);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci			if (!ath9k_hw_numtxpending(ah, q))
15862306a36Sopenharmony_ci				break;
15962306a36Sopenharmony_ci		}
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
16362306a36Sopenharmony_ci	REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
16462306a36Sopenharmony_ci	REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	REG_WRITE(ah, AR_Q_TXD, 0);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cibool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci#define ATH9K_TX_STOP_DMA_TIMEOUT	1000    /* usec */
17362306a36Sopenharmony_ci#define ATH9K_TIME_QUANTUM		100     /* usec */
17462306a36Sopenharmony_ci	int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
17562306a36Sopenharmony_ci	int wait;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	REG_WRITE(ah, AR_Q_TXD, 1 << q);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	for (wait = wait_time; wait != 0; wait--) {
18062306a36Sopenharmony_ci		if (wait != wait_time)
18162306a36Sopenharmony_ci			udelay(ATH9K_TIME_QUANTUM);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci		if (ath9k_hw_numtxpending(ah, q) == 0)
18462306a36Sopenharmony_ci			break;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	REG_WRITE(ah, AR_Q_TXD, 0);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return wait != 0;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci#undef ATH9K_TX_STOP_DMA_TIMEOUT
19262306a36Sopenharmony_ci#undef ATH9K_TIME_QUANTUM
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_stop_dma_queue);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cibool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
19762306a36Sopenharmony_ci			    const struct ath9k_tx_queue_info *qinfo)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	u32 cw;
20062306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
20162306a36Sopenharmony_ci	struct ath9k_tx_queue_info *qi;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	qi = &ah->txq[q];
20462306a36Sopenharmony_ci	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
20562306a36Sopenharmony_ci		ath_dbg(common, QUEUE,
20662306a36Sopenharmony_ci			"Set TXQ properties, inactive queue: %u\n", q);
20762306a36Sopenharmony_ci		return false;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ath_dbg(common, QUEUE, "Set queue properties for: %u\n", q);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	qi->tqi_ver = qinfo->tqi_ver;
21362306a36Sopenharmony_ci	qi->tqi_subtype = qinfo->tqi_subtype;
21462306a36Sopenharmony_ci	qi->tqi_qflags = qinfo->tqi_qflags;
21562306a36Sopenharmony_ci	qi->tqi_priority = qinfo->tqi_priority;
21662306a36Sopenharmony_ci	if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
21762306a36Sopenharmony_ci		qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
21862306a36Sopenharmony_ci	else
21962306a36Sopenharmony_ci		qi->tqi_aifs = INIT_AIFS;
22062306a36Sopenharmony_ci	if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
22162306a36Sopenharmony_ci		cw = min(qinfo->tqi_cwmin, 1024U);
22262306a36Sopenharmony_ci		qi->tqi_cwmin = 1;
22362306a36Sopenharmony_ci		while (qi->tqi_cwmin < cw)
22462306a36Sopenharmony_ci			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
22562306a36Sopenharmony_ci	} else
22662306a36Sopenharmony_ci		qi->tqi_cwmin = qinfo->tqi_cwmin;
22762306a36Sopenharmony_ci	if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
22862306a36Sopenharmony_ci		cw = min(qinfo->tqi_cwmax, 1024U);
22962306a36Sopenharmony_ci		qi->tqi_cwmax = 1;
23062306a36Sopenharmony_ci		while (qi->tqi_cwmax < cw)
23162306a36Sopenharmony_ci			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
23262306a36Sopenharmony_ci	} else
23362306a36Sopenharmony_ci		qi->tqi_cwmax = INIT_CWMAX;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (qinfo->tqi_shretry != 0)
23662306a36Sopenharmony_ci		qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
23762306a36Sopenharmony_ci	else
23862306a36Sopenharmony_ci		qi->tqi_shretry = INIT_SH_RETRY;
23962306a36Sopenharmony_ci	if (qinfo->tqi_lgretry != 0)
24062306a36Sopenharmony_ci		qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
24162306a36Sopenharmony_ci	else
24262306a36Sopenharmony_ci		qi->tqi_lgretry = INIT_LG_RETRY;
24362306a36Sopenharmony_ci	qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
24462306a36Sopenharmony_ci	qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
24562306a36Sopenharmony_ci	qi->tqi_burstTime = qinfo->tqi_burstTime;
24662306a36Sopenharmony_ci	qi->tqi_readyTime = qinfo->tqi_readyTime;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	switch (qinfo->tqi_subtype) {
24962306a36Sopenharmony_ci	case ATH9K_WME_UPSD:
25062306a36Sopenharmony_ci		if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
25162306a36Sopenharmony_ci			qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
25262306a36Sopenharmony_ci		break;
25362306a36Sopenharmony_ci	default:
25462306a36Sopenharmony_ci		break;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return true;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_set_txq_props);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cibool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
26262306a36Sopenharmony_ci			    struct ath9k_tx_queue_info *qinfo)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
26562306a36Sopenharmony_ci	struct ath9k_tx_queue_info *qi;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	qi = &ah->txq[q];
26862306a36Sopenharmony_ci	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
26962306a36Sopenharmony_ci		ath_dbg(common, QUEUE,
27062306a36Sopenharmony_ci			"Get TXQ properties, inactive queue: %u\n", q);
27162306a36Sopenharmony_ci		return false;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	qinfo->tqi_qflags = qi->tqi_qflags;
27562306a36Sopenharmony_ci	qinfo->tqi_ver = qi->tqi_ver;
27662306a36Sopenharmony_ci	qinfo->tqi_subtype = qi->tqi_subtype;
27762306a36Sopenharmony_ci	qinfo->tqi_qflags = qi->tqi_qflags;
27862306a36Sopenharmony_ci	qinfo->tqi_priority = qi->tqi_priority;
27962306a36Sopenharmony_ci	qinfo->tqi_aifs = qi->tqi_aifs;
28062306a36Sopenharmony_ci	qinfo->tqi_cwmin = qi->tqi_cwmin;
28162306a36Sopenharmony_ci	qinfo->tqi_cwmax = qi->tqi_cwmax;
28262306a36Sopenharmony_ci	qinfo->tqi_shretry = qi->tqi_shretry;
28362306a36Sopenharmony_ci	qinfo->tqi_lgretry = qi->tqi_lgretry;
28462306a36Sopenharmony_ci	qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
28562306a36Sopenharmony_ci	qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
28662306a36Sopenharmony_ci	qinfo->tqi_burstTime = qi->tqi_burstTime;
28762306a36Sopenharmony_ci	qinfo->tqi_readyTime = qi->tqi_readyTime;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return true;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_get_txq_props);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ciint ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
29462306a36Sopenharmony_ci			  const struct ath9k_tx_queue_info *qinfo)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
29762306a36Sopenharmony_ci	struct ath9k_tx_queue_info *qi;
29862306a36Sopenharmony_ci	int q;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	switch (type) {
30162306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_BEACON:
30262306a36Sopenharmony_ci		q = ATH9K_NUM_TX_QUEUES - 1;
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_CAB:
30562306a36Sopenharmony_ci		q = ATH9K_NUM_TX_QUEUES - 2;
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_PSPOLL:
30862306a36Sopenharmony_ci		q = 1;
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_UAPSD:
31162306a36Sopenharmony_ci		q = ATH9K_NUM_TX_QUEUES - 3;
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_DATA:
31462306a36Sopenharmony_ci		q = qinfo->tqi_subtype;
31562306a36Sopenharmony_ci		break;
31662306a36Sopenharmony_ci	default:
31762306a36Sopenharmony_ci		ath_err(common, "Invalid TX queue type: %u\n", type);
31862306a36Sopenharmony_ci		return -1;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	ath_dbg(common, QUEUE, "Setup TX queue: %u\n", q);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	qi = &ah->txq[q];
32462306a36Sopenharmony_ci	if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
32562306a36Sopenharmony_ci		ath_err(common, "TX queue: %u already active\n", q);
32662306a36Sopenharmony_ci		return -1;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci	memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
32962306a36Sopenharmony_ci	qi->tqi_type = type;
33062306a36Sopenharmony_ci	qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
33162306a36Sopenharmony_ci	(void) ath9k_hw_set_txq_props(ah, q, qinfo);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return q;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_setuptxqueue);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic void ath9k_hw_clear_queue_interrupts(struct ath_hw *ah, u32 q)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	ah->txok_interrupt_mask &= ~(1 << q);
34062306a36Sopenharmony_ci	ah->txerr_interrupt_mask &= ~(1 << q);
34162306a36Sopenharmony_ci	ah->txdesc_interrupt_mask &= ~(1 << q);
34262306a36Sopenharmony_ci	ah->txeol_interrupt_mask &= ~(1 << q);
34362306a36Sopenharmony_ci	ah->txurn_interrupt_mask &= ~(1 << q);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cibool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
34962306a36Sopenharmony_ci	struct ath9k_tx_queue_info *qi;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	qi = &ah->txq[q];
35262306a36Sopenharmony_ci	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
35362306a36Sopenharmony_ci		ath_dbg(common, QUEUE, "Release TXQ, inactive queue: %u\n", q);
35462306a36Sopenharmony_ci		return false;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	ath_dbg(common, QUEUE, "Release TX queue: %u\n", q);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
36062306a36Sopenharmony_ci	ath9k_hw_clear_queue_interrupts(ah, q);
36162306a36Sopenharmony_ci	ath9k_hw_set_txq_interrupts(ah, qi);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return true;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_releasetxqueue);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cibool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
37062306a36Sopenharmony_ci	struct ath9k_tx_queue_info *qi;
37162306a36Sopenharmony_ci	u32 cwMin, chanCwMin, value;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	qi = &ah->txq[q];
37462306a36Sopenharmony_ci	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
37562306a36Sopenharmony_ci		ath_dbg(common, QUEUE, "Reset TXQ, inactive queue: %u\n", q);
37662306a36Sopenharmony_ci		return true;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
38262306a36Sopenharmony_ci		chanCwMin = INIT_CWMIN;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
38562306a36Sopenharmony_ci	} else
38662306a36Sopenharmony_ci		cwMin = qi->tqi_cwmin;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	ENABLE_REGWRITE_BUFFER(ah);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	REG_WRITE(ah, AR_DLCL_IFS(q),
39162306a36Sopenharmony_ci		  SM(cwMin, AR_D_LCL_IFS_CWMIN) |
39262306a36Sopenharmony_ci		  SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
39362306a36Sopenharmony_ci		  SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	REG_WRITE(ah, AR_DRETRY_LIMIT(q),
39662306a36Sopenharmony_ci		  SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
39762306a36Sopenharmony_ci		  SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
39862306a36Sopenharmony_ci		  SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (AR_SREV_9340(ah) && !AR_SREV_9340_13_OR_LATER(ah))
40362306a36Sopenharmony_ci		REG_WRITE(ah, AR_DMISC(q),
40462306a36Sopenharmony_ci			  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
40562306a36Sopenharmony_ci	else
40662306a36Sopenharmony_ci		REG_WRITE(ah, AR_DMISC(q),
40762306a36Sopenharmony_ci			  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (qi->tqi_cbrPeriod) {
41062306a36Sopenharmony_ci		REG_WRITE(ah, AR_QCBRCFG(q),
41162306a36Sopenharmony_ci			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
41262306a36Sopenharmony_ci			  SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
41362306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR |
41462306a36Sopenharmony_ci			    (qi->tqi_cbrOverflowLimit ?
41562306a36Sopenharmony_ci			     AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci	if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
41862306a36Sopenharmony_ci		REG_WRITE(ah, AR_QRDYTIMECFG(q),
41962306a36Sopenharmony_ci			  SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
42062306a36Sopenharmony_ci			  AR_Q_RDYTIMECFG_EN);
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	REG_WRITE(ah, AR_DCHNTIME(q),
42462306a36Sopenharmony_ci		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
42562306a36Sopenharmony_ci		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (qi->tqi_burstTime
42862306a36Sopenharmony_ci	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE))
42962306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE)
43262306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	REGWRITE_BUFFER_FLUSH(ah);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
43762306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	switch (qi->tqi_type) {
44062306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_BEACON:
44162306a36Sopenharmony_ci		ENABLE_REGWRITE_BUFFER(ah);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_QMISC(q),
44462306a36Sopenharmony_ci			    AR_Q_MISC_FSP_DBA_GATED
44562306a36Sopenharmony_ci			    | AR_Q_MISC_BEACON_USE
44662306a36Sopenharmony_ci			    | AR_Q_MISC_CBR_INCR_DIS1);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_DMISC(q),
44962306a36Sopenharmony_ci			    (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
45062306a36Sopenharmony_ci			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
45162306a36Sopenharmony_ci			    | AR_D_MISC_BEACON_USE
45262306a36Sopenharmony_ci			    | AR_D_MISC_POST_FR_BKOFF_DIS);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		REGWRITE_BUFFER_FLUSH(ah);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		/*
45762306a36Sopenharmony_ci		 * cwmin and cwmax should be 0 for beacon queue
45862306a36Sopenharmony_ci		 * but not for IBSS as we would create an imbalance
45962306a36Sopenharmony_ci		 * on beaconing fairness for participating nodes.
46062306a36Sopenharmony_ci		 */
46162306a36Sopenharmony_ci		if (AR_SREV_9300_20_OR_LATER(ah) &&
46262306a36Sopenharmony_ci		    ah->opmode != NL80211_IFTYPE_ADHOC) {
46362306a36Sopenharmony_ci			REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
46462306a36Sopenharmony_ci				  | SM(0, AR_D_LCL_IFS_CWMAX)
46562306a36Sopenharmony_ci				  | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
46662306a36Sopenharmony_ci		}
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_CAB:
46962306a36Sopenharmony_ci		ENABLE_REGWRITE_BUFFER(ah);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_QMISC(q),
47262306a36Sopenharmony_ci			    AR_Q_MISC_FSP_DBA_GATED
47362306a36Sopenharmony_ci			    | AR_Q_MISC_CBR_INCR_DIS1
47462306a36Sopenharmony_ci			    | AR_Q_MISC_CBR_INCR_DIS0);
47562306a36Sopenharmony_ci		value = (qi->tqi_readyTime -
47662306a36Sopenharmony_ci			 (ah->config.sw_beacon_response_time -
47762306a36Sopenharmony_ci			  ah->config.dma_beacon_response_time)) * 1024;
47862306a36Sopenharmony_ci		REG_WRITE(ah, AR_QRDYTIMECFG(q),
47962306a36Sopenharmony_ci			  value | AR_Q_RDYTIMECFG_EN);
48062306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_DMISC(q),
48162306a36Sopenharmony_ci			    (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
48262306a36Sopenharmony_ci			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		REGWRITE_BUFFER_FLUSH(ah);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		break;
48762306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_PSPOLL:
48862306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1);
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	case ATH9K_TX_QUEUE_UAPSD:
49162306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
49262306a36Sopenharmony_ci		break;
49362306a36Sopenharmony_ci	default:
49462306a36Sopenharmony_ci		break;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
49862306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_DMISC(q),
49962306a36Sopenharmony_ci			    SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
50062306a36Sopenharmony_ci			       AR_D_MISC_ARB_LOCKOUT_CNTRL) |
50162306a36Sopenharmony_ci			    AR_D_MISC_POST_FR_BKOFF_DIS);
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (AR_SREV_9300_20_OR_LATER(ah))
50562306a36Sopenharmony_ci		REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	ath9k_hw_clear_queue_interrupts(ah, q);
50862306a36Sopenharmony_ci	if (qi->tqi_qflags & TXQ_FLAG_TXINT_ENABLE) {
50962306a36Sopenharmony_ci		ah->txok_interrupt_mask |= 1 << q;
51062306a36Sopenharmony_ci		ah->txerr_interrupt_mask |= 1 << q;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci	if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
51362306a36Sopenharmony_ci		ah->txdesc_interrupt_mask |= 1 << q;
51462306a36Sopenharmony_ci	if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
51562306a36Sopenharmony_ci		ah->txeol_interrupt_mask |= 1 << q;
51662306a36Sopenharmony_ci	if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
51762306a36Sopenharmony_ci		ah->txurn_interrupt_mask |= 1 << q;
51862306a36Sopenharmony_ci	ath9k_hw_set_txq_interrupts(ah, qi);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return true;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_resettxqueue);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ciint ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
52562306a36Sopenharmony_ci			struct ath_rx_status *rs)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct ar5416_desc ads;
52862306a36Sopenharmony_ci	struct ar5416_desc *adsp = AR5416DESC(ds);
52962306a36Sopenharmony_ci	u32 phyerr;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
53262306a36Sopenharmony_ci		return -EINPROGRESS;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ads.u.rx = adsp->u.rx;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	rs->rs_status = 0;
53762306a36Sopenharmony_ci	rs->rs_flags = 0;
53862306a36Sopenharmony_ci	rs->enc_flags = 0;
53962306a36Sopenharmony_ci	rs->bw = RATE_INFO_BW_20;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
54262306a36Sopenharmony_ci	rs->rs_tstamp = ads.AR_RcvTimestamp;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
54562306a36Sopenharmony_ci		rs->rs_rssi = ATH9K_RSSI_BAD;
54662306a36Sopenharmony_ci		rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD;
54762306a36Sopenharmony_ci		rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD;
54862306a36Sopenharmony_ci		rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD;
54962306a36Sopenharmony_ci		rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD;
55062306a36Sopenharmony_ci		rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD;
55162306a36Sopenharmony_ci		rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;
55262306a36Sopenharmony_ci	} else {
55362306a36Sopenharmony_ci		rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
55462306a36Sopenharmony_ci		rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,
55562306a36Sopenharmony_ci						AR_RxRSSIAnt00);
55662306a36Sopenharmony_ci		rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,
55762306a36Sopenharmony_ci						AR_RxRSSIAnt01);
55862306a36Sopenharmony_ci		rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,
55962306a36Sopenharmony_ci						AR_RxRSSIAnt02);
56062306a36Sopenharmony_ci		rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,
56162306a36Sopenharmony_ci						AR_RxRSSIAnt10);
56262306a36Sopenharmony_ci		rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,
56362306a36Sopenharmony_ci						AR_RxRSSIAnt11);
56462306a36Sopenharmony_ci		rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,
56562306a36Sopenharmony_ci						AR_RxRSSIAnt12);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
56862306a36Sopenharmony_ci		rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
56962306a36Sopenharmony_ci	else
57062306a36Sopenharmony_ci		rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate);
57362306a36Sopenharmony_ci	rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	rs->rs_firstaggr = (ads.ds_rxstatus8 & AR_RxFirstAggr) ? 1 : 0;
57662306a36Sopenharmony_ci	rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
57762306a36Sopenharmony_ci	rs->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
57862306a36Sopenharmony_ci	rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/* directly mapped flags for ieee80211_rx_status */
58162306a36Sopenharmony_ci	rs->enc_flags |=
58262306a36Sopenharmony_ci		(ads.ds_rxstatus3 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0;
58362306a36Sopenharmony_ci	rs->bw = (ads.ds_rxstatus3 & AR_2040) ? RATE_INFO_BW_40 :
58462306a36Sopenharmony_ci						RATE_INFO_BW_20;
58562306a36Sopenharmony_ci	if (AR_SREV_9280_20_OR_LATER(ah))
58662306a36Sopenharmony_ci		rs->enc_flags |=
58762306a36Sopenharmony_ci			(ads.ds_rxstatus3 & AR_STBC) ?
58862306a36Sopenharmony_ci				/* we can only Nss=1 STBC */
58962306a36Sopenharmony_ci				(1 << RX_ENC_FLAG_STBC_SHIFT) : 0;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
59262306a36Sopenharmony_ci		rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
59362306a36Sopenharmony_ci	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
59462306a36Sopenharmony_ci		rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
59562306a36Sopenharmony_ci	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
59662306a36Sopenharmony_ci		rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
59962306a36Sopenharmony_ci		/*
60062306a36Sopenharmony_ci		 * Treat these errors as mutually exclusive to avoid spurious
60162306a36Sopenharmony_ci		 * extra error reports from the hardware. If a CRC error is
60262306a36Sopenharmony_ci		 * reported, then decryption and MIC errors are irrelevant,
60362306a36Sopenharmony_ci		 * the frame is going to be dropped either way
60462306a36Sopenharmony_ci		 */
60562306a36Sopenharmony_ci		if (ads.ds_rxstatus8 & AR_PHYErr) {
60662306a36Sopenharmony_ci			rs->rs_status |= ATH9K_RXERR_PHY;
60762306a36Sopenharmony_ci			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
60862306a36Sopenharmony_ci			rs->rs_phyerr = phyerr;
60962306a36Sopenharmony_ci		} else if (ads.ds_rxstatus8 & AR_CRCErr)
61062306a36Sopenharmony_ci			rs->rs_status |= ATH9K_RXERR_CRC;
61162306a36Sopenharmony_ci		else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
61262306a36Sopenharmony_ci			rs->rs_status |= ATH9K_RXERR_DECRYPT;
61362306a36Sopenharmony_ci		else if (ads.ds_rxstatus8 & AR_MichaelErr)
61462306a36Sopenharmony_ci			rs->rs_status |= ATH9K_RXERR_MIC;
61562306a36Sopenharmony_ci	} else {
61662306a36Sopenharmony_ci		if (ads.ds_rxstatus8 &
61762306a36Sopenharmony_ci		    (AR_CRCErr | AR_PHYErr | AR_DecryptCRCErr | AR_MichaelErr))
61862306a36Sopenharmony_ci			rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		/* Only up to MCS16 supported, everything above is invalid */
62162306a36Sopenharmony_ci		if (rs->rs_rate >= 0x90)
62262306a36Sopenharmony_ci			rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (ads.ds_rxstatus8 & AR_KeyMiss)
62662306a36Sopenharmony_ci		rs->rs_status |= ATH9K_RXERR_KEYMISS;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_rxprocdesc);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/*
63362306a36Sopenharmony_ci * This can stop or re-enables RX.
63462306a36Sopenharmony_ci *
63562306a36Sopenharmony_ci * If bool is set this will kill any frame which is currently being
63662306a36Sopenharmony_ci * transferred between the MAC and baseband and also prevent any new
63762306a36Sopenharmony_ci * frames from getting started.
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_cibool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	u32 reg;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (set) {
64462306a36Sopenharmony_ci		REG_SET_BIT(ah, AR_DIAG_SW,
64562306a36Sopenharmony_ci			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
64862306a36Sopenharmony_ci				   0, AH_WAIT_TIMEOUT)) {
64962306a36Sopenharmony_ci			REG_CLR_BIT(ah, AR_DIAG_SW,
65062306a36Sopenharmony_ci				    (AR_DIAG_RX_DIS |
65162306a36Sopenharmony_ci				     AR_DIAG_RX_ABORT));
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci			reg = REG_READ(ah, AR_OBS_BUS_1);
65462306a36Sopenharmony_ci			ath_err(ath9k_hw_common(ah),
65562306a36Sopenharmony_ci				"RX failed to go idle in 10 ms RXSM=0x%x\n",
65662306a36Sopenharmony_ci				reg);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci			return false;
65962306a36Sopenharmony_ci		}
66062306a36Sopenharmony_ci	} else {
66162306a36Sopenharmony_ci		REG_CLR_BIT(ah, AR_DIAG_SW,
66262306a36Sopenharmony_ci			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	return true;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_setrxabort);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_civoid ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	REG_WRITE(ah, AR_RXDP, rxdp);
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_putrxbuf);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_civoid ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	ath9k_enable_mib_counters(ah);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	ath9k_ani_reset(ah, is_scanning);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_startpcureceive);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_civoid ath9k_hw_abortpcurecv(struct ath_hw *ah)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	ath9k_hw_disable_mib_counters(ah);
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_abortpcurecv);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cibool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci#define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
69662306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
69762306a36Sopenharmony_ci	u32 mac_status, last_mac_status = 0;
69862306a36Sopenharmony_ci	int i;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/* Enable access to the DMA observation bus */
70162306a36Sopenharmony_ci	REG_WRITE(ah, AR_MACMISC,
70262306a36Sopenharmony_ci		  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
70362306a36Sopenharmony_ci		   (AR_MACMISC_MISC_OBS_BUS_1 <<
70462306a36Sopenharmony_ci		    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	REG_WRITE(ah, AR_CR, AR_CR_RXD);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* Wait for rx enable bit to go low */
70962306a36Sopenharmony_ci	for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
71062306a36Sopenharmony_ci		if ((REG_READ(ah, AR_CR) & AR_CR_RXE(ah)) == 0)
71162306a36Sopenharmony_ci			break;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		if (!AR_SREV_9300_20_OR_LATER(ah)) {
71462306a36Sopenharmony_ci			mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0;
71562306a36Sopenharmony_ci			if (mac_status == 0x1c0 && mac_status == last_mac_status) {
71662306a36Sopenharmony_ci				*reset = true;
71762306a36Sopenharmony_ci				break;
71862306a36Sopenharmony_ci			}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci			last_mac_status = mac_status;
72162306a36Sopenharmony_ci		}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		udelay(AH_TIME_QUANTUM);
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (i == 0) {
72762306a36Sopenharmony_ci		ath_err(common,
72862306a36Sopenharmony_ci			"DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
72962306a36Sopenharmony_ci			AH_RX_STOP_DMA_TIMEOUT / 1000,
73062306a36Sopenharmony_ci			REG_READ(ah, AR_CR),
73162306a36Sopenharmony_ci			REG_READ(ah, AR_DIAG_SW),
73262306a36Sopenharmony_ci			REG_READ(ah, AR_DMADBG_7));
73362306a36Sopenharmony_ci		return false;
73462306a36Sopenharmony_ci	} else {
73562306a36Sopenharmony_ci		return true;
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci#undef AH_RX_STOP_DMA_TIMEOUT
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_stopdmarecv);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ciint ath9k_hw_beaconq_setup(struct ath_hw *ah)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct ath9k_tx_queue_info qi;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	memset(&qi, 0, sizeof(qi));
74762306a36Sopenharmony_ci	qi.tqi_aifs = 1;
74862306a36Sopenharmony_ci	qi.tqi_cwmin = 0;
74962306a36Sopenharmony_ci	qi.tqi_cwmax = 0;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
75262306a36Sopenharmony_ci		qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_beaconq_setup);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cibool ath9k_hw_intrpend(struct ath_hw *ah)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	u32 host_isr;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (AR_SREV_9100(ah))
76362306a36Sopenharmony_ci		return true;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE(ah));
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (((host_isr & AR_INTR_MAC_IRQ) ||
76862306a36Sopenharmony_ci	     (host_isr & AR_INTR_ASYNC_MASK_MCI)) &&
76962306a36Sopenharmony_ci	    (host_isr != AR_INTR_SPURIOUS))
77062306a36Sopenharmony_ci		return true;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE(ah));
77362306a36Sopenharmony_ci	if ((host_isr & AR_INTR_SYNC_DEFAULT)
77462306a36Sopenharmony_ci	    && (host_isr != AR_INTR_SPURIOUS))
77562306a36Sopenharmony_ci		return true;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return false;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_intrpend);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_civoid ath9k_hw_kill_interrupts(struct ath_hw *ah)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ath_dbg(common, INTERRUPT, "disable IER\n");
78662306a36Sopenharmony_ci	REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
78762306a36Sopenharmony_ci	(void) REG_READ(ah, AR_IER);
78862306a36Sopenharmony_ci	if (!AR_SREV_9100(ah)) {
78962306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_ASYNC_ENABLE(ah), 0);
79062306a36Sopenharmony_ci		(void) REG_READ(ah, AR_INTR_ASYNC_ENABLE(ah));
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_SYNC_ENABLE(ah), 0);
79362306a36Sopenharmony_ci		(void) REG_READ(ah, AR_INTR_SYNC_ENABLE(ah));
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_kill_interrupts);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_civoid ath9k_hw_disable_interrupts(struct ath_hw *ah)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	if (!(ah->imask & ATH9K_INT_GLOBAL))
80162306a36Sopenharmony_ci		atomic_set(&ah->intr_ref_cnt, -1);
80262306a36Sopenharmony_ci	else
80362306a36Sopenharmony_ci		atomic_dec(&ah->intr_ref_cnt);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	ath9k_hw_kill_interrupts(ah);
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_disable_interrupts);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic void __ath9k_hw_enable_interrupts(struct ath_hw *ah)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
81262306a36Sopenharmony_ci	u32 sync_default = AR_INTR_SYNC_DEFAULT;
81362306a36Sopenharmony_ci	u32 async_mask;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
81662306a36Sopenharmony_ci	    AR_SREV_9561(ah))
81762306a36Sopenharmony_ci		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	async_mask = AR_INTR_MAC_IRQ;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	if (ah->imask & ATH9K_INT_MCI)
82262306a36Sopenharmony_ci		async_mask |= AR_INTR_ASYNC_MASK_MCI;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	ath_dbg(common, INTERRUPT, "enable IER\n");
82562306a36Sopenharmony_ci	REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
82662306a36Sopenharmony_ci	if (!AR_SREV_9100(ah)) {
82762306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_ASYNC_ENABLE(ah), async_mask);
82862306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_ASYNC_MASK(ah), async_mask);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_SYNC_ENABLE(ah), sync_default);
83162306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_SYNC_MASK(ah), sync_default);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci	ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
83462306a36Sopenharmony_ci		REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (ah->msi_enabled) {
83762306a36Sopenharmony_ci		u32 _msi_reg = 0;
83862306a36Sopenharmony_ci		u32 i = 0;
83962306a36Sopenharmony_ci		u32 msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		ath_dbg(ath9k_hw_common(ah), INTERRUPT,
84262306a36Sopenharmony_ci			"Enabling MSI, msi_mask=0x%X\n", ah->msi_mask);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah), ah->msi_mask);
84562306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK(ah), ah->msi_mask);
84662306a36Sopenharmony_ci		ath_dbg(ath9k_hw_common(ah), INTERRUPT,
84762306a36Sopenharmony_ci			"AR_INTR_PRIO_ASYNC_ENABLE=0x%X, AR_INTR_PRIO_ASYNC_MASK=0x%X\n",
84862306a36Sopenharmony_ci			REG_READ(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah)),
84962306a36Sopenharmony_ci			REG_READ(ah, AR_INTR_PRIO_ASYNC_MASK(ah)));
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		if (ah->msi_reg == 0)
85262306a36Sopenharmony_ci			ah->msi_reg = REG_READ(ah, AR_PCIE_MSI(ah));
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		ath_dbg(ath9k_hw_common(ah), INTERRUPT,
85562306a36Sopenharmony_ci			"AR_PCIE_MSI=0x%X, ah->msi_reg = 0x%X\n",
85662306a36Sopenharmony_ci			AR_PCIE_MSI(ah), ah->msi_reg);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci		i = 0;
85962306a36Sopenharmony_ci		do {
86062306a36Sopenharmony_ci			REG_WRITE(ah, AR_PCIE_MSI(ah),
86162306a36Sopenharmony_ci				  (ah->msi_reg | AR_PCIE_MSI_ENABLE)
86262306a36Sopenharmony_ci				  & msi_pend_addr_mask);
86362306a36Sopenharmony_ci			_msi_reg = REG_READ(ah, AR_PCIE_MSI(ah));
86462306a36Sopenharmony_ci			i++;
86562306a36Sopenharmony_ci		} while ((_msi_reg & AR_PCIE_MSI_ENABLE) == 0 && i < 200);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		if (i >= 200)
86862306a36Sopenharmony_ci			ath_err(ath9k_hw_common(ah),
86962306a36Sopenharmony_ci				"%s: _msi_reg = 0x%X\n",
87062306a36Sopenharmony_ci				__func__, _msi_reg);
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_civoid ath9k_hw_resume_interrupts(struct ath_hw *ah)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	if (!(ah->imask & ATH9K_INT_GLOBAL))
87962306a36Sopenharmony_ci		return;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	if (atomic_read(&ah->intr_ref_cnt) != 0) {
88262306a36Sopenharmony_ci		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
88362306a36Sopenharmony_ci			atomic_read(&ah->intr_ref_cnt));
88462306a36Sopenharmony_ci		return;
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	__ath9k_hw_enable_interrupts(ah);
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_resume_interrupts);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_civoid ath9k_hw_enable_interrupts(struct ath_hw *ah)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (!(ah->imask & ATH9K_INT_GLOBAL))
89662306a36Sopenharmony_ci		return;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
89962306a36Sopenharmony_ci		ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
90062306a36Sopenharmony_ci			atomic_read(&ah->intr_ref_cnt));
90162306a36Sopenharmony_ci		return;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	__ath9k_hw_enable_interrupts(ah);
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_enable_interrupts);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_civoid ath9k_hw_set_interrupts(struct ath_hw *ah)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	enum ath9k_int ints = ah->imask;
91162306a36Sopenharmony_ci	u32 mask, mask2;
91262306a36Sopenharmony_ci	struct ath9k_hw_capabilities *pCap = &ah->caps;
91362306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (!(ints & ATH9K_INT_GLOBAL))
91662306a36Sopenharmony_ci		ath9k_hw_disable_interrupts(ah);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (ah->msi_enabled) {
91962306a36Sopenharmony_ci		ath_dbg(common, INTERRUPT, "Clearing AR_INTR_PRIO_ASYNC_ENABLE\n");
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci		REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah), 0);
92262306a36Sopenharmony_ci		REG_READ(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah));
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	ath_dbg(common, INTERRUPT, "New interrupt mask 0x%x\n", ints);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	mask = ints & ATH9K_INT_COMMON;
92862306a36Sopenharmony_ci	mask2 = 0;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	ah->msi_mask = 0;
93162306a36Sopenharmony_ci	if (ints & ATH9K_INT_TX) {
93262306a36Sopenharmony_ci		ah->msi_mask |= AR_INTR_PRIO_TX;
93362306a36Sopenharmony_ci		if (ah->config.tx_intr_mitigation)
93462306a36Sopenharmony_ci			mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM;
93562306a36Sopenharmony_ci		else {
93662306a36Sopenharmony_ci			if (ah->txok_interrupt_mask)
93762306a36Sopenharmony_ci				mask |= AR_IMR_TXOK;
93862306a36Sopenharmony_ci			if (ah->txdesc_interrupt_mask)
93962306a36Sopenharmony_ci				mask |= AR_IMR_TXDESC;
94062306a36Sopenharmony_ci		}
94162306a36Sopenharmony_ci		if (ah->txerr_interrupt_mask)
94262306a36Sopenharmony_ci			mask |= AR_IMR_TXERR;
94362306a36Sopenharmony_ci		if (ah->txeol_interrupt_mask)
94462306a36Sopenharmony_ci			mask |= AR_IMR_TXEOL;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci	if (ints & ATH9K_INT_RX) {
94762306a36Sopenharmony_ci		ah->msi_mask |= AR_INTR_PRIO_RXLP | AR_INTR_PRIO_RXHP;
94862306a36Sopenharmony_ci		if (AR_SREV_9300_20_OR_LATER(ah)) {
94962306a36Sopenharmony_ci			mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP;
95062306a36Sopenharmony_ci			if (ah->config.rx_intr_mitigation) {
95162306a36Sopenharmony_ci				mask &= ~AR_IMR_RXOK_LP;
95262306a36Sopenharmony_ci				mask |=  AR_IMR_RXMINTR | AR_IMR_RXINTM;
95362306a36Sopenharmony_ci			} else {
95462306a36Sopenharmony_ci				mask |= AR_IMR_RXOK_LP;
95562306a36Sopenharmony_ci			}
95662306a36Sopenharmony_ci		} else {
95762306a36Sopenharmony_ci			if (ah->config.rx_intr_mitigation)
95862306a36Sopenharmony_ci				mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
95962306a36Sopenharmony_ci			else
96062306a36Sopenharmony_ci				mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
96162306a36Sopenharmony_ci		}
96262306a36Sopenharmony_ci		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
96362306a36Sopenharmony_ci			mask |= AR_IMR_GENTMR;
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	if (ints & ATH9K_INT_GENTIMER)
96762306a36Sopenharmony_ci		mask |= AR_IMR_GENTMR;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (ints & (ATH9K_INT_BMISC)) {
97062306a36Sopenharmony_ci		mask |= AR_IMR_BCNMISC;
97162306a36Sopenharmony_ci		if (ints & ATH9K_INT_TIM)
97262306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_TIM;
97362306a36Sopenharmony_ci		if (ints & ATH9K_INT_DTIM)
97462306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_DTIM;
97562306a36Sopenharmony_ci		if (ints & ATH9K_INT_DTIMSYNC)
97662306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_DTIMSYNC;
97762306a36Sopenharmony_ci		if (ints & ATH9K_INT_CABEND)
97862306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_CABEND;
97962306a36Sopenharmony_ci		if (ints & ATH9K_INT_TSFOOR)
98062306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_TSFOOR;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
98462306a36Sopenharmony_ci		mask |= AR_IMR_BCNMISC;
98562306a36Sopenharmony_ci		if (ints & ATH9K_INT_GTT)
98662306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_GTT;
98762306a36Sopenharmony_ci		if (ints & ATH9K_INT_CST)
98862306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_CST;
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
99262306a36Sopenharmony_ci		if (ints & ATH9K_INT_BB_WATCHDOG) {
99362306a36Sopenharmony_ci			mask |= AR_IMR_BCNMISC;
99462306a36Sopenharmony_ci			mask2 |= AR_IMR_S2_BB_WATCHDOG;
99562306a36Sopenharmony_ci		}
99662306a36Sopenharmony_ci	}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask);
99962306a36Sopenharmony_ci	REG_WRITE(ah, AR_IMR, mask);
100062306a36Sopenharmony_ci	ah->imrs2_reg &= ~(AR_IMR_S2_TIM |
100162306a36Sopenharmony_ci			   AR_IMR_S2_DTIM |
100262306a36Sopenharmony_ci			   AR_IMR_S2_DTIMSYNC |
100362306a36Sopenharmony_ci			   AR_IMR_S2_CABEND |
100462306a36Sopenharmony_ci			   AR_IMR_S2_CABTO |
100562306a36Sopenharmony_ci			   AR_IMR_S2_TSFOOR |
100662306a36Sopenharmony_ci			   AR_IMR_S2_GTT |
100762306a36Sopenharmony_ci			   AR_IMR_S2_CST);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
101062306a36Sopenharmony_ci		if (ints & ATH9K_INT_BB_WATCHDOG)
101162306a36Sopenharmony_ci			ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	ah->imrs2_reg |= mask2;
101562306a36Sopenharmony_ci	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
101862306a36Sopenharmony_ci		if (ints & ATH9K_INT_TIM_TIMER)
101962306a36Sopenharmony_ci			REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
102062306a36Sopenharmony_ci		else
102162306a36Sopenharmony_ci			REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return;
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_set_interrupts);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci#define ATH9K_HW_MAX_DCU       10
102962306a36Sopenharmony_ci#define ATH9K_HW_SLICE_PER_DCU 16
103062306a36Sopenharmony_ci#define ATH9K_HW_BIT_IN_SLICE  16
103162306a36Sopenharmony_civoid ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	int dcu_idx;
103462306a36Sopenharmony_ci	u32 filter;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	for (dcu_idx = 0; dcu_idx < 10; dcu_idx++) {
103762306a36Sopenharmony_ci		filter = SM(set, AR_D_TXBLK_WRITE_COMMAND);
103862306a36Sopenharmony_ci		filter |= SM(dcu_idx, AR_D_TXBLK_WRITE_DCU);
103962306a36Sopenharmony_ci		filter |= SM((destidx / ATH9K_HW_SLICE_PER_DCU),
104062306a36Sopenharmony_ci			     AR_D_TXBLK_WRITE_SLICE);
104162306a36Sopenharmony_ci		filter |= BIT(destidx % ATH9K_HW_BIT_IN_SLICE);
104262306a36Sopenharmony_ci		ath_dbg(ath9k_hw_common(ah), PS,
104362306a36Sopenharmony_ci			"DCU%d staid %d set %d txfilter %08x\n",
104462306a36Sopenharmony_ci			dcu_idx, destidx, set, filter);
104562306a36Sopenharmony_ci		REG_WRITE(ah, AR_D_TXBLK_BASE, filter);
104662306a36Sopenharmony_ci	}
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_set_tx_filter);
1049