ath9k: Fix powersave locking
authorSujith Manoharan <c_manoha@qca.qualcomm.com>
Mon, 4 Jun 2012 14:54:07 +0000 (20:24 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 6 Jun 2012 19:20:32 +0000 (15:20 -0400)
The 'ps_flags' is used/accessed in a variety of contexts
and requires proper locking. Use 'sc_pm_lock' appropriately.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c

index 34d6f26..88f7ad1 100644 (file)
@@ -345,7 +345,7 @@ void ath9k_tasklet(unsigned long data)
        struct ath_softc *sc = (struct ath_softc *)data;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-
+       unsigned long flags;
        u32 status = sc->intrstatus;
        u32 rxmask;
 
@@ -369,6 +369,7 @@ void ath9k_tasklet(unsigned long data)
                goto out;
        }
 
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
                /*
                 * TSF sync does not look correct; remain awake to sync with
@@ -377,6 +378,7 @@ void ath9k_tasklet(unsigned long data)
                ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
                sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
        }
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
@@ -526,8 +528,10 @@ irqreturn_t ath_isr(int irq, void *dev)
                        /* Clear RxAbort bit so that we can
                         * receive frames */
                        ath9k_setpower(sc, ATH9K_PM_AWAKE);
+                       spin_lock(&sc->sc_pm_lock);
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                        sc->ps_flags |= PS_WAIT_FOR_BEACON;
+                       spin_unlock(&sc->sc_pm_lock);
                }
 
 chip_reset:
@@ -682,6 +686,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_tx_control txctl;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       unsigned long flags;
 
        if (sc->ps_enabled) {
                /*
@@ -704,6 +709,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                 * completed and if needed, also for RX of buffered frames.
                 */
                ath9k_ps_wakeup(sc);
+               spin_lock_irqsave(&sc->sc_pm_lock, flags);
                if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                if (ieee80211_is_pspoll(hdr->frame_control)) {
@@ -719,6 +725,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                 * the ps_flags bit is cleared. We are just dropping
                 * the ps_usecount here.
                 */
+               spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
                ath9k_ps_restore(sc);
        }
 
@@ -1479,7 +1486,7 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
        struct ath_vif *avp = (void *)vif->drv_priv;
-
+       unsigned long flags;
        /*
         * Skip iteration if primary station vif's bss info
         * was not changed
@@ -1501,7 +1508,10 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
                 * on the receipt of the first Beacon frame (i.e.,
                 * after time sync with the AP).
                 */
+               spin_lock_irqsave(&sc->sc_pm_lock, flags);
                sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+               spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+
                /* Reset rssi stats */
                sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
index b54e159..fbdcc80 100644 (file)
@@ -587,13 +587,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
 
        /* Process Beacon and CAB receive in PS state */
        if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
-           && mybeacon)
+           && mybeacon) {
                ath_rx_ps_beacon(sc, skb);
-       else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
-                (ieee80211_is_data(hdr->frame_control) ||
-                 ieee80211_is_action(hdr->frame_control)) &&
-                is_multicast_ether_addr(hdr->addr1) &&
-                !ieee80211_has_moredata(hdr->frame_control)) {
+       else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
+                  (ieee80211_is_data(hdr->frame_control) ||
+                   ieee80211_is_action(hdr->frame_control)) &&
+                  is_multicast_ether_addr(hdr->addr1) &&
+                  !ieee80211_has_moredata(hdr->frame_control)) {
                /*
                 * No more broadcast/multicast frames to be received at this
                 * point.
@@ -1229,7 +1229,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                        skb_trim(skb, skb->len - 8);
 
                spin_lock_irqsave(&sc->sc_pm_lock, flags);
-
                if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                     PS_WAIT_FOR_CAB |
                                     PS_WAIT_FOR_PSPOLL_DATA)) ||
index bb74780..f777ddc 100644 (file)
@@ -1994,6 +1994,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
        int q, padpos, padsize;
+       unsigned long flags;
 
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
 
@@ -2012,6 +2013,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                skb_pull(skb, padsize);
        }
 
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
                sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
                ath_dbg(common, PS,
@@ -2021,6 +2023,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                                        PS_WAIT_FOR_PSPOLL_DATA |
                                        PS_WAIT_FOR_TX_ACK));
        }
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        q = skb_get_queue_mapping(skb);
        if (txq == sc->tx.txq_map[q]) {