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