diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/mac.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.c | 159 |
1 files changed, 66 insertions, 93 deletions
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index b6b523a..2d628f9 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -16,11 +16,12 @@ #include "hw.h" #include "hw-ops.h" +#include <linux/export.h> static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) { - ath_dbg(ath9k_hw_common(ah), ATH_DBG_INTERRUPT, + ath_dbg(ath9k_hw_common(ah), INTERRUPT, "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", ah->txok_interrupt_mask, ah->txerr_interrupt_mask, ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, @@ -56,24 +57,11 @@ EXPORT_SYMBOL(ath9k_hw_puttxbuf); void ath9k_hw_txstart(struct ath_hw *ah, u32 q) { - ath_dbg(ath9k_hw_common(ah), ATH_DBG_QUEUE, - "Enable TXE on queue: %u\n", q); + ath_dbg(ath9k_hw_common(ah), QUEUE, "Enable TXE on queue: %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); } EXPORT_SYMBOL(ath9k_hw_txstart); -void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; -} -EXPORT_SYMBOL(ath9k_hw_cleartxdesc); - u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) { u32 npend; @@ -197,13 +185,6 @@ bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q) } EXPORT_SYMBOL(ath9k_hw_stop_dma_queue); -void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) -{ - *txqs &= ah->intr_txqs; - ah->intr_txqs &= ~(*txqs); -} -EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs); - bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo) { @@ -213,12 +194,12 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, ATH_DBG_QUEUE, + ath_dbg(common, QUEUE, "Set TXQ properties, inactive queue: %u\n", q); return false; } - ath_dbg(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); + ath_dbg(common, QUEUE, "Set queue properties for: %u\n", q); qi->tqi_ver = qinfo->tqi_ver; qi->tqi_subtype = qinfo->tqi_subtype; @@ -277,7 +258,7 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, ATH_DBG_QUEUE, + ath_dbg(common, QUEUE, "Get TXQ properties, inactive queue: %u\n", q); return false; } @@ -322,21 +303,14 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, q = ATH9K_NUM_TX_QUEUES - 3; break; case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) - if (ah->txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == ATH9K_NUM_TX_QUEUES) { - ath_err(common, "No available TX queue\n"); - return -1; - } + q = qinfo->tqi_subtype; break; default: ath_err(common, "Invalid TX queue type: %u\n", type); return -1; } - ath_dbg(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); + ath_dbg(common, QUEUE, "Setup TX queue: %u\n", q); qi = &ah->txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { @@ -345,26 +319,22 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, } memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); qi->tqi_type = type; - if (qinfo == NULL) { - qi->tqi_qflags = - TXQ_FLAG_TXOKINT_ENABLE - | TXQ_FLAG_TXERRINT_ENABLE - | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; - qi->tqi_aifs = INIT_AIFS; - qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; - qi->tqi_cwmax = INIT_CWMAX; - qi->tqi_shretry = INIT_SH_RETRY; - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_physCompBuf = 0; - } else { - qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; - (void) ath9k_hw_set_txq_props(ah, q, qinfo); - } + qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; + (void) ath9k_hw_set_txq_props(ah, q, qinfo); return q; } EXPORT_SYMBOL(ath9k_hw_setuptxqueue); +static void ath9k_hw_clear_queue_interrupts(struct ath_hw *ah, u32 q) +{ + ah->txok_interrupt_mask &= ~(1 << q); + ah->txerr_interrupt_mask &= ~(1 << q); + ah->txdesc_interrupt_mask &= ~(1 << q); + ah->txeol_interrupt_mask &= ~(1 << q); + ah->txurn_interrupt_mask &= ~(1 << q); +} + bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { struct ath_common *common = ath9k_hw_common(ah); @@ -372,19 +342,14 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, ATH_DBG_QUEUE, - "Release TXQ, inactive queue: %u\n", q); + ath_dbg(common, QUEUE, "Release TXQ, inactive queue: %u\n", q); return false; } - ath_dbg(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); + ath_dbg(common, QUEUE, "Release TX queue: %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ah->txok_interrupt_mask &= ~(1 << q); - ah->txerr_interrupt_mask &= ~(1 << q); - ah->txdesc_interrupt_mask &= ~(1 << q); - ah->txeol_interrupt_mask &= ~(1 << q); - ah->txurn_interrupt_mask &= ~(1 << q); + ath9k_hw_clear_queue_interrupts(ah, q); ath9k_hw_set_txq_interrupts(ah, qi); return true; @@ -400,12 +365,11 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, ATH_DBG_QUEUE, - "Reset TXQ, inactive queue: %u\n", q); + ath_dbg(common, QUEUE, "Reset TXQ, inactive queue: %u\n", q); return true; } - ath_dbg(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); + ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { if (chan && IS_CHAN_B(chan)) @@ -537,26 +501,17 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) if (AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN); - if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) + ath9k_hw_clear_queue_interrupts(ah, q); + if (qi->tqi_qflags & TXQ_FLAG_TXINT_ENABLE) { ah->txok_interrupt_mask |= 1 << q; - else - ah->txok_interrupt_mask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) ah->txerr_interrupt_mask |= 1 << q; - else - ah->txerr_interrupt_mask &= ~(1 << q); + } if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) ah->txdesc_interrupt_mask |= 1 << q; - else - ah->txdesc_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) ah->txeol_interrupt_mask |= 1 << q; - else - ah->txeol_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) ah->txurn_interrupt_mask |= 1 << q; - else - ah->txurn_interrupt_mask &= ~(1 << q); ath9k_hw_set_txq_interrupts(ah, qi); return true; @@ -564,7 +519,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) EXPORT_SYMBOL(ath9k_hw_resettxqueue); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - struct ath_rx_status *rs, u64 tsf) + struct ath_rx_status *rs) { struct ar5416_desc ads; struct ar5416_desc *adsp = AR5416DESC(ds); @@ -609,7 +564,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, else rs->rs_keyix = ATH9K_RXKEYIX_INVALID; - rs->rs_rate = RXSTATUS_RATE(ah, (&ads)); + rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate); rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; @@ -645,10 +600,11 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; - else if (ads.ds_rxstatus8 & AR_KeyMiss) - rs->rs_status |= ATH9K_RXERR_DECRYPT; } + if (ads.ds_rxstatus8 & AR_KeyMiss) + rs->rs_status |= ATH9K_RXERR_KEYMISS; + return 0; } EXPORT_SYMBOL(ath9k_hw_rxprocdesc); @@ -771,7 +727,10 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah) qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; - /* NB: don't enable any interrupts */ + + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE; + return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } EXPORT_SYMBOL(ath9k_hw_beaconq_setup); @@ -784,7 +743,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) return true; host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); - if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS)) + + if (((host_isr & AR_INTR_MAC_IRQ) || + (host_isr & AR_INTR_ASYNC_MASK_MCI)) && + (host_isr != AR_INTR_SPURIOUS)) return true; host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); @@ -800,7 +762,12 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n"); + if (!(ah->imask & ATH9K_INT_GLOBAL)) + atomic_set(&ah->intr_ref_cnt, -1); + else + atomic_dec(&ah->intr_ref_cnt); + + ath_dbg(common, INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { @@ -817,32 +784,42 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); u32 sync_default = AR_INTR_SYNC_DEFAULT; + u32 async_mask; if (!(ah->imask & ATH9K_INT_GLOBAL)) return; + if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { + ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", + atomic_read(&ah->intr_ref_cnt)); + return; + } + if (AR_SREV_9340(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; - ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); + async_mask = AR_INTR_MAC_IRQ; + + if (ah->imask & ATH9K_INT_MCI) + async_mask |= AR_INTR_ASYNC_MASK_MCI; + + ath_dbg(common, INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, - AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask); + REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask); REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); } - ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); } EXPORT_SYMBOL(ath9k_hw_enable_interrupts); -void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) +void ath9k_hw_set_interrupts(struct ath_hw *ah) { - enum ath9k_int omask = ah->imask; + enum ath9k_int ints = ah->imask; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); @@ -850,9 +827,8 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) if (!(ints & ATH9K_INT_GLOBAL)) ath9k_hw_disable_interrupts(ah); - ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); + ath_dbg(common, INTERRUPT, "New interrupt mask 0x%x\n", ints); - /* TODO: global int Ref count */ mask = ints & ATH9K_INT_COMMON; mask2 = 0; @@ -914,7 +890,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) mask2 |= AR_IMR_S2_CST; } - ath_dbg(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); + ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | @@ -929,9 +905,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); } - if (ints & ATH9K_INT_GLOBAL) - ath9k_hw_enable_interrupts(ah); - return; } EXPORT_SYMBOL(ath9k_hw_set_interrupts); |