ath9k: Use atomic reference count for interrupt ops
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>
Fri, 5 Aug 2011 13:29:41 +0000 (18:59 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 9 Aug 2011 19:52:06 +0000 (15:52 -0400)
Let us enable/disable interrupts based on reference count.
By doing this we can ensure that interrupts are never be
enabled in the middle of tasklet processing. Instead of
addressing corner cases like "ath9k: avoid enabling interrupts
while processing rx", this approach handles it in generic manner.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c

index 64dd4e34c86f9f0a24bf802452f27c890012975f..c03949eb37c893ea102879484d486ac7a4ea9be0 100644 (file)
@@ -567,7 +567,6 @@ struct ath_ant_comb {
 #define PS_WAIT_FOR_PSPOLL_DATA   BIT(2)
 #define PS_WAIT_FOR_TX_ACK        BIT(3)
 #define PS_BEACON_SYNC            BIT(4)
-#define PS_TSFOOR_SYNC            BIT(5)
 
 struct ath_rate_table;
 
index f1d66abc367fda6cef1d1384de2c39e70b15c0fd..086c9c816bf78b0e0210869936c3feed40772ee1 100644 (file)
@@ -649,14 +649,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
        ath9k_hw_set_sta_beacon_timers(ah, &bs);
        ah->imask |= ATH9K_INT_BMISS;
 
-       /*
-        * If the beacon config is called beacause of TSFOOR,
-        * Interrupts will be enabled back at the end of ath9k_tasklet
-        */
-       if (!(sc->ps_flags & PS_TSFOOR_SYNC)) {
-               ath9k_hw_set_interrupts(ah, ah->imask);
-               ath9k_hw_enable_interrupts(ah);
-       }
+       ath9k_hw_set_interrupts(ah, ah->imask);
+       ath9k_hw_enable_interrupts(ah);
 }
 
 static void ath_beacon_config_adhoc(struct ath_softc *sc,
@@ -690,14 +684,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
        ath9k_hw_disable_interrupts(ah);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
-       /*
-        * If the beacon config is called beacause of TSFOOR,
-        * Interrupts will be enabled back at the end of ath9k_tasklet
-        */
-       if (!(sc->ps_flags & PS_TSFOOR_SYNC)) {
-               ath9k_hw_set_interrupts(ah, ah->imask);
-               ath9k_hw_enable_interrupts(ah);
-       }
+
+       ath9k_hw_set_interrupts(ah, ah->imask);
+       ath9k_hw_enable_interrupts(ah);
 }
 
 static bool ath9k_allow_beacon_config(struct ath_softc *sc,
index 138722130b6c81a16310439682fd06c800961a69..4fbcced2828cf7a454e3aa01012d14091312485c 100644 (file)
@@ -709,6 +709,7 @@ struct ath_hw {
        u32 txdesc_interrupt_mask;
        u32 txeol_interrupt_mask;
        u32 txurn_interrupt_mask;
+       atomic_t intr_ref_cnt;
        bool chip_fullsleep;
        u32 atim_window;
 
index d99f188dfcfcba3289da148e39a3ecb060ea243d..db38a58e752d4a001ffd9b22a909b6f3c55669cd 100644 (file)
@@ -566,6 +566,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        ah->reg_ops.read = ath9k_ioread32;
        ah->reg_ops.write = ath9k_iowrite32;
        ah->reg_ops.rmw = ath9k_reg_rmw;
+       atomic_set(&ah->intr_ref_cnt, -1);
        sc->sc_ah = ah;
 
        if (!pdata) {
index c3af61e38bd524ba22d1d1935fef5520df83555e..0f90e1521ffeb61865ed8ee1ce473aea5c255349 100644 (file)
@@ -800,6 +800,11 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
 
+       if (!(ah->imask & ATH9K_INT_GLOBAL))
+               atomic_set(&ah->intr_ref_cnt, -1);
+       else
+               atomic_dec(&ah->intr_ref_cnt);
+
        ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n");
        REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
        (void) REG_READ(ah, AR_IER);
@@ -821,6 +826,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
        if (!(ah->imask & ATH9K_INT_GLOBAL))
                return;
 
+       if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+               ath_dbg(common, ATH_DBG_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;
 
@@ -852,7 +864,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 
        ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
 
-       /* TODO: global int Ref count */
        mask = ints & ATH9K_INT_COMMON;
        mask2 = 0;
 
index 3050d83673b2e05b8155fd58fe0c01ffa2cba6a7..1e7fe8c0e11915352f02319bee55fb36e83748cb 100644 (file)
@@ -707,8 +707,7 @@ void ath9k_tasklet(unsigned long data)
                 */
                ath_dbg(common, ATH_DBG_PS,
                        "TSFOOR - Sync with next Beacon\n");
-               sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC |
-                               PS_TSFOOR_SYNC;
+               sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
        }
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
@@ -887,6 +886,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
        ath9k_ps_wakeup(sc);
        spin_lock_bh(&sc->sc_pcu_lock);
+       atomic_set(&ah->intr_ref_cnt, -1);
 
        ath9k_hw_configpcipowersave(ah, 0, 0);
 
index a551a942027b601cafab1911197b66e6db6a9fed..5b4f05366f87c7eb216ff6cbf4b1aa156f2c4c95 100644 (file)
@@ -601,7 +601,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
                ath_dbg(common, ATH_DBG_PS,
                        "Reconfigure Beacon timers based on timestamp from the AP\n");
                ath_set_beacon(sc);
-               sc->ps_flags &= ~PS_TSFOOR_SYNC;
        }
 
        if (ath_beacon_dtim_pending_cab(skb)) {