Commit 07c15a3f authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville

ath9k: Fix powersave locking

The 'ps_flags' is used/accessed in a variety of contexts
and requires proper locking. Use 'sc_pm_lock' appropriately.
Signed-off-by: default avatarSujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b74713d0
...@@ -345,7 +345,7 @@ void ath9k_tasklet(unsigned long data) ...@@ -345,7 +345,7 @@ void ath9k_tasklet(unsigned long data)
struct ath_softc *sc = (struct ath_softc *)data; struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
unsigned long flags;
u32 status = sc->intrstatus; u32 status = sc->intrstatus;
u32 rxmask; u32 rxmask;
...@@ -369,6 +369,7 @@ void ath9k_tasklet(unsigned long data) ...@@ -369,6 +369,7 @@ void ath9k_tasklet(unsigned long data)
goto out; goto out;
} }
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
/* /*
* TSF sync does not look correct; remain awake to sync with * TSF sync does not look correct; remain awake to sync with
...@@ -377,6 +378,7 @@ void ath9k_tasklet(unsigned long data) ...@@ -377,6 +378,7 @@ void ath9k_tasklet(unsigned long data)
ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n"); ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; 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) if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
...@@ -526,8 +528,10 @@ irqreturn_t ath_isr(int irq, void *dev) ...@@ -526,8 +528,10 @@ irqreturn_t ath_isr(int irq, void *dev)
/* Clear RxAbort bit so that we can /* Clear RxAbort bit so that we can
* receive frames */ * receive frames */
ath9k_setpower(sc, ATH9K_PM_AWAKE); ath9k_setpower(sc, ATH9K_PM_AWAKE);
spin_lock(&sc->sc_pm_lock);
ath9k_hw_setrxabort(sc->sc_ah, 0); ath9k_hw_setrxabort(sc->sc_ah, 0);
sc->ps_flags |= PS_WAIT_FOR_BEACON; sc->ps_flags |= PS_WAIT_FOR_BEACON;
spin_unlock(&sc->sc_pm_lock);
} }
chip_reset: chip_reset:
...@@ -682,6 +686,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -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_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_tx_control txctl; struct ath_tx_control txctl;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
unsigned long flags;
if (sc->ps_enabled) { if (sc->ps_enabled) {
/* /*
...@@ -704,6 +709,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -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. * completed and if needed, also for RX of buffered frames.
*/ */
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
ath9k_hw_setrxabort(sc->sc_ah, 0); ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) { if (ieee80211_is_pspoll(hdr->frame_control)) {
...@@ -719,6 +725,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -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_flags bit is cleared. We are just dropping
* the ps_usecount here. * the ps_usecount here.
*/ */
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
} }
...@@ -1479,7 +1486,7 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ...@@ -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 ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
struct ath_vif *avp = (void *)vif->drv_priv; struct ath_vif *avp = (void *)vif->drv_priv;
unsigned long flags;
/* /*
* Skip iteration if primary station vif's bss info * Skip iteration if primary station vif's bss info
* was not changed * was not changed
...@@ -1501,7 +1508,10 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ...@@ -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., * on the receipt of the first Beacon frame (i.e.,
* after time sync with the AP). * after time sync with the AP).
*/ */
spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
/* Reset rssi stats */ /* Reset rssi stats */
sc->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
......
...@@ -587,13 +587,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) ...@@ -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 */ /* Process Beacon and CAB receive in PS state */
if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc)) if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
&& mybeacon) && mybeacon) {
ath_rx_ps_beacon(sc, skb); ath_rx_ps_beacon(sc, skb);
else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && } else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
(ieee80211_is_data(hdr->frame_control) || (ieee80211_is_data(hdr->frame_control) ||
ieee80211_is_action(hdr->frame_control)) && ieee80211_is_action(hdr->frame_control)) &&
is_multicast_ether_addr(hdr->addr1) && is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_moredata(hdr->frame_control)) { !ieee80211_has_moredata(hdr->frame_control)) {
/* /*
* No more broadcast/multicast frames to be received at this * No more broadcast/multicast frames to be received at this
* point. * point.
...@@ -1229,7 +1229,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ...@@ -1229,7 +1229,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
skb_trim(skb, skb->len - 8); skb_trim(skb, skb->len - 8);
spin_lock_irqsave(&sc->sc_pm_lock, flags); spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB | PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) || PS_WAIT_FOR_PSPOLL_DATA)) ||
......
...@@ -1994,6 +1994,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ...@@ -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 ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
int q, padpos, padsize; int q, padpos, padsize;
unsigned long flags;
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); 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, ...@@ -2012,6 +2013,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
skb_pull(skb, padsize); skb_pull(skb, padsize);
} }
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
ath_dbg(common, PS, ath_dbg(common, PS,
...@@ -2021,6 +2023,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ...@@ -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_PSPOLL_DATA |
PS_WAIT_FOR_TX_ACK)); PS_WAIT_FOR_TX_ACK));
} }
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
q = skb_get_queue_mapping(skb); q = skb_get_queue_mapping(skb);
if (txq == sc->tx.txq_map[q]) { if (txq == sc->tx.txq_map[q]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment