diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 30 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 10 |
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 | ||
520 | struct ath_bus_ops { | 522 | struct 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 |