aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-05-14 14:28:48 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-20 14:46:24 -0400
commitcc65965cbb24d2ca2bb70f26cac9d7243349e7e3 (patch)
treeb46570ebe5a6f73b25dec14a8af06f2180a9859e
parent9d64a3cfaf3edb548b68ef4eedbadbb875eaa10e (diff)
ath9k: Fix PS mode operation to receive buffered broadcast/multicast frames
The previous implementation was moving back to NETWORK SLEEP state immediately after receiving a Beacon frame. This means that we are unlikely to receive all the buffered broadcast/multicast frames that would be sent after DTIM Beacon frames. Fix this by parsing the Beacon frame and remaining awake, if needed, to receive the buffered broadcast/multicast frames. The last buffered frame will trigger the move back into NETWORK SLEEP state. If the last broadcast/multicast frame is not received properly (or if the AP fails to send it), the next Beacon frame will work as a backup trigger for returning into NETWORK SLEEP. A new debug type, PS (debug=0x800 module parameter), is added to make it easier to debug potential power save issues in the future. Currently, this is only used for the Beacon frame and buffered broadcast/multicast receiving. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c119
3 files changed, 114 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 10ffc9442859..34256621d417 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -515,6 +515,7 @@ struct ath_rfkill {
515#define SC_OP_LED_ON BIT(13) 515#define SC_OP_LED_ON BIT(13)
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 519
519struct ath_bus_ops { 520struct ath_bus_ops {
520 void (*read_cachesize)(struct ath_softc *sc, int *csz); 521 void (*read_cachesize)(struct ath_softc *sc, int *csz);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 23298b90b52b..db845cf960c9 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -29,6 +29,7 @@ enum ATH_DEBUG {
29 ATH_DBG_BEACON = 0x00000100, 29 ATH_DBG_BEACON = 0x00000100,
30 ATH_DBG_CONFIG = 0x00000200, 30 ATH_DBG_CONFIG = 0x00000200,
31 ATH_DBG_FATAL = 0x00000400, 31 ATH_DBG_FATAL = 0x00000400,
32 ATH_DBG_PS = 0x00000800,
32 ATH_DBG_ANY = 0xffffffff 33 ATH_DBG_ANY = 0xffffffff
33}; 34};
34 35
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 58bb26c72771..72e9283bcf7b 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -473,6 +473,112 @@ void ath_flushrecv(struct ath_softc *sc)
473 spin_unlock_bh(&sc->rx.rxflushlock); 473 spin_unlock_bh(&sc->rx.rxflushlock);
474} 474}
475 475
476static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
477{
478 /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
479 struct ieee80211_mgmt *mgmt;
480 u8 *pos, *end, id, elen;
481 struct ieee80211_tim_ie *tim;
482
483 mgmt = (struct ieee80211_mgmt *)skb->data;
484 pos = mgmt->u.beacon.variable;
485 end = skb->data + skb->len;
486
487 while (pos + 2 < end) {
488 id = *pos++;
489 elen = *pos++;
490 if (pos + elen > end)
491 break;
492
493 if (id == WLAN_EID_TIM) {
494 if (elen < sizeof(*tim))
495 break;
496 tim = (struct ieee80211_tim_ie *) pos;
497 if (tim->dtim_count != 0)
498 break;
499 return tim->bitmap_ctrl & 0x01;
500 }
501
502 pos += elen;
503 }
504
505 return false;
506}
507
508static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
509{
510 sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
511 if (sc->hw->conf.flags & IEEE80211_CONF_PS)
512 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
513}
514
515static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
516{
517 struct ieee80211_mgmt *mgmt;
518
519 if (skb->len < 24 + 8 + 2 + 2)
520 return;
521
522 mgmt = (struct ieee80211_mgmt *)skb->data;
523 if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
524 return; /* not from our current AP */
525
526 if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
527 /* We are not in PS mode anymore; remain awake */
528 DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
529 "awake\n");
530 sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
531 return;
532 }
533
534 if (ath_beacon_dtim_pending_cab(skb)) {
535 /*
536 * Remain awake waiting for buffered broadcast/multicast
537 * frames.
538 */
539 DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
540 "buffered broadcast/multicast frame(s)\n");
541 sc->sc_flags |= SC_OP_WAIT_FOR_CAB;
542 return;
543 }
544
545 if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) {
546 /*
547 * This can happen if a broadcast frame is dropped or the AP
548 * fails to send a frame indicating that all CAB frames have
549 * been delivered.
550 */
551 DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
552 }
553
554 /* No more broadcast/multicast frames to be received at this point. */
555 ath_rx_ps_back_to_sleep(sc);
556}
557
558static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
559{
560 struct ieee80211_hdr *hdr;
561
562 hdr = (struct ieee80211_hdr *)skb->data;
563
564 /* Process Beacon and CAB receive in PS state */
565 if (ieee80211_is_beacon(hdr->frame_control))
566 ath_rx_ps_beacon(sc, skb);
567 else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) &&
568 (ieee80211_is_data(hdr->frame_control) ||
569 ieee80211_is_action(hdr->frame_control)) &&
570 is_multicast_ether_addr(hdr->addr1) &&
571 !ieee80211_has_moredata(hdr->frame_control)) {
572 DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
573 "sleep\n");
574 /*
575 * No more broadcast/multicast frames to be received at this
576 * point.
577 */
578 ath_rx_ps_back_to_sleep(sc);
579 }
580}
581
476static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, 582static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
477 struct ieee80211_rx_status *rx_status) 583 struct ieee80211_rx_status *rx_status)
478{ 584{
@@ -667,8 +773,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
667 rx_status.flag &= ~RX_FLAG_DECRYPTED; 773 rx_status.flag &= ~RX_FLAG_DECRYPTED;
668 } 774 }
669 775
670 ath_rx_send_to_mac80211(sc, skb, &rx_status);
671
672 /* We will now give hardware our shiny new allocated skb */ 776 /* We will now give hardware our shiny new allocated skb */
673 bf->bf_mpdu = requeue_skb; 777 bf->bf_mpdu = requeue_skb;
674 bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, 778 bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
@@ -680,6 +784,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
680 bf->bf_mpdu = NULL; 784 bf->bf_mpdu = NULL;
681 DPRINTF(sc, ATH_DBG_FATAL, 785 DPRINTF(sc, ATH_DBG_FATAL,
682 "dma_mapping_error() on RX\n"); 786 "dma_mapping_error() on RX\n");
787 ath_rx_send_to_mac80211(sc, skb, &rx_status);
683 break; 788 break;
684 } 789 }
685 bf->bf_dmacontext = bf->bf_buf_addr; 790 bf->bf_dmacontext = bf->bf_buf_addr;
@@ -695,11 +800,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
695 sc->rx.rxotherant = 0; 800 sc->rx.rxotherant = 0;
696 } 801 }
697 802
698 if (ieee80211_is_beacon(fc) && 803 if (unlikely(sc->sc_flags & SC_OP_WAIT_FOR_BEACON))
699 (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { 804 ath_rx_ps(sc, skb);
700 sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; 805
701 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); 806 ath_rx_send_to_mac80211(sc, skb, &rx_status);
702 } 807
703requeue: 808requeue:
704 list_move_tail(&bf->list, &sc->rx.rxbuf); 809 list_move_tail(&bf->list, &sc->rx.rxbuf);
705 ath_rx_buf_link(sc, bf); 810 ath_rx_buf_link(sc, bf);