aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-05-19 10:01:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-20 14:46:32 -0400
commit9a23f9ca50943c1b4535d22b3acda3c31b4ad072 (patch)
treec8e4e3398279f6ac461e5ebfdb2d22d974e5f6c3 /drivers
parentcce4c77b87ce7e71a0f244a3dfb6ac1c3a1bc67e (diff)
ath9k: Wake up for TX in mac80211 timeout=0 sleep mode
When using timeout=0 (PS-Poll) with mac80211, the driver will need to wake up for TX requests and remain awake until the TX has been completed (ACK received or timeout) or until the buffer frame(s) have been received (in case the TX is for a PS-Poll frame). Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
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