aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c10
4 files changed, 58 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index bd2363f075cf..0d4ac43f6d91 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -516,6 +516,8 @@ struct ath_rfkill {
516#define SC_OP_SCANNING BIT(14) 516#define SC_OP_SCANNING BIT(14)
517#define SC_OP_TSF_RESET BIT(15) 517#define SC_OP_TSF_RESET BIT(15)
518#define SC_OP_WAIT_FOR_CAB BIT(16) 518#define SC_OP_WAIT_FOR_CAB BIT(16)
519#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
520#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
519 521
520struct ath_bus_ops { 522struct ath_bus_ops {
521 void (*read_cachesize)(struct ath_softc *sc, int *csz); 523 void (*read_cachesize)(struct ath_softc *sc, int *csz);
@@ -678,7 +680,9 @@ static inline void ath9k_ps_restore(struct ath_softc *sc)
678{ 680{
679 if (atomic_dec_and_test(&sc->ps_usecount)) 681 if (atomic_dec_and_test(&sc->ps_usecount))
680 if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && 682 if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
681 !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) 683 !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
684 SC_OP_WAIT_FOR_PSPOLL_DATA |
685 SC_OP_WAIT_FOR_TX_ACK)))
682 ath9k_hw_setpower(sc->sc_ah, 686 ath9k_hw_setpower(sc->sc_ah,
683 sc->sc_ah->restore_mode); 687 sc->sc_ah->restore_mode);
684} 688}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index c161b75cded6..7c3a98b1957d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2070,6 +2070,31 @@ static int ath9k_tx(struct ieee80211_hw *hw,
2070 goto exit; 2070 goto exit;
2071 } 2071 }
2072 2072
2073 if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
2074 /*
2075 * We are using PS-Poll and mac80211 can request TX while in
2076 * power save mode. Need to wake up hardware for the TX to be
2077 * completed and if needed, also for RX of buffered frames.
2078 */
2079 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
2080 ath9k_ps_wakeup(sc);
2081 ath9k_hw_setrxabort(sc->sc_ah, 0);
2082 if (ieee80211_is_pspoll(hdr->frame_control)) {
2083 DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a "
2084 "buffered frame\n");
2085 sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA;
2086 } else {
2087 DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n");
2088 sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK;
2089 }
2090 /*
2091 * The actual restore operation will happen only after
2092 * the sc_flags bit is cleared. We are just dropping
2093 * the ps_usecount here.
2094 */
2095 ath9k_ps_restore(sc);
2096 }
2097
2073 memset(&txctl, 0, sizeof(struct ath_tx_control)); 2098 memset(&txctl, 0, sizeof(struct ath_tx_control));
2074 2099
2075 /* 2100 /*
@@ -2307,7 +2332,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
2307 if (!(ah->caps.hw_caps & 2332 if (!(ah->caps.hw_caps &
2308 ATH9K_HW_CAP_AUTOSLEEP)) { 2333 ATH9K_HW_CAP_AUTOSLEEP)) {
2309 ath9k_hw_setrxabort(sc->sc_ah, 0); 2334 ath9k_hw_setrxabort(sc->sc_ah, 0);
2310 sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; 2335 sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON |
2336 SC_OP_WAIT_FOR_CAB |
2337 SC_OP_WAIT_FOR_PSPOLL_DATA |
2338 SC_OP_WAIT_FOR_TX_ACK);
2311 if (sc->imask & ATH9K_INT_TIM_TIMER) { 2339 if (sc->imask & ATH9K_INT_TIM_TIMER) {
2312 sc->imask &= ~ATH9K_INT_TIM_TIMER; 2340 sc->imask &= ~ATH9K_INT_TIM_TIMER;
2313 ath9k_hw_set_interrupts(sc->sc_ah, 2341 ath9k_hw_set_interrupts(sc->sc_ah,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 5567517aa641..5e046b58ad93 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -560,7 +560,8 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
560 hdr = (struct ieee80211_hdr *)skb->data; 560 hdr = (struct ieee80211_hdr *)skb->data;
561 561
562 /* Process Beacon and CAB receive in PS state */ 562 /* Process Beacon and CAB receive in PS state */
563 if (ieee80211_is_beacon(hdr->frame_control)) 563 if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) &&
564 ieee80211_is_beacon(hdr->frame_control))
564 ath_rx_ps_beacon(sc, skb); 565 ath_rx_ps_beacon(sc, skb);
565 else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && 566 else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) &&
566 (ieee80211_is_data(hdr->frame_control) || 567 (ieee80211_is_data(hdr->frame_control) ||
@@ -574,6 +575,16 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
574 * point. 575 * point.
575 */ 576 */
576 ath_rx_ps_back_to_sleep(sc); 577 ath_rx_ps_back_to_sleep(sc);
578 } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
579 !is_multicast_ether_addr(hdr->addr1) &&
580 !ieee80211_has_morefrags(hdr->frame_control)) {
581 sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
582 DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
583 "received PS-Poll data (0x%x)\n",
584 sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
585 SC_OP_WAIT_FOR_CAB |
586 SC_OP_WAIT_FOR_PSPOLL_DATA |
587 SC_OP_WAIT_FOR_TX_ACK));
577 } 588 }
578} 589}
579 590
@@ -798,7 +809,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
798 sc->rx.rxotherant = 0; 809 sc->rx.rxotherant = 0;
799 } 810 }
800 811
801 if (unlikely(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) 812 if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
813 SC_OP_WAIT_FOR_PSPOLL_DATA)))
802 ath_rx_ps(sc, skb); 814 ath_rx_ps(sc, skb);
803 815
804 ath_rx_send_to_mac80211(sc, skb, &rx_status); 816 ath_rx_send_to_mac80211(sc, skb, &rx_status);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 3f2bd79f945e..a8def4fa449c 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1790,6 +1790,16 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
1790 skb_pull(skb, padsize); 1790 skb_pull(skb, padsize);
1791 } 1791 }
1792 1792
1793 if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
1794 sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
1795 DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
1796 "received TX status (0x%x)\n",
1797 sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
1798 SC_OP_WAIT_FOR_CAB |
1799 SC_OP_WAIT_FOR_PSPOLL_DATA |
1800 SC_OP_WAIT_FOR_TX_ACK));
1801 }
1802
1793 if (frame_type == ATH9K_NOT_INTERNAL) 1803 if (frame_type == ATH9K_NOT_INTERNAL)
1794 ieee80211_tx_status(hw, skb); 1804 ieee80211_tx_status(hw, skb);
1795 else 1805 else