ath9k: fix stopping tx dma on reset
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / mac.c
index 180170d..58aaf9a 100644 (file)
@@ -143,6 +143,34 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
 }
 EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
 
+void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
+{
+       int i, q;
+
+       REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
+
+       REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
+       REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+       REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
+
+       for (q = 0; q < AR_NUM_QCU; q++) {
+               for (i = 0; i < 1000; i++) {
+                       if (i)
+                               udelay(5);
+
+                       if (!ath9k_hw_numtxpending(ah, q))
+                               break;
+               }
+       }
+
+       REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
+       REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+       REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
+
+       REG_WRITE(ah, AR_Q_TXD, 0);
+}
+EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
+
 bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
 {
 #define ATH9K_TX_STOP_DMA_TIMEOUT      4000    /* usec */
@@ -690,17 +718,23 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
                rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
 
        if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
+               /*
+                * Treat these errors as mutually exclusive to avoid spurious
+                * extra error reports from the hardware. If a CRC error is
+                * reported, then decryption and MIC errors are irrelevant,
+                * the frame is going to be dropped either way
+                */
                if (ads.ds_rxstatus8 & AR_CRCErr)
                        rs->rs_status |= ATH9K_RXERR_CRC;
-               if (ads.ds_rxstatus8 & AR_PHYErr) {
+               else if (ads.ds_rxstatus8 & AR_PHYErr) {
                        rs->rs_status |= ATH9K_RXERR_PHY;
                        phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
                        rs->rs_phyerr = phyerr;
-               }
-               if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+               } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
-               if (ads.ds_rxstatus8 & AR_MichaelErr)
+               else if (ads.ds_rxstatus8 & AR_MichaelErr)
                        rs->rs_status |= ATH9K_RXERR_MIC;
+
                if (ads.ds_rxstatus8 & AR_KeyMiss)
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
        }