aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2014-04-05 18:37:03 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-04-22 15:06:28 -0400
commitd463af4a1c344beb26937b9ba79d129faad6b1d9 (patch)
treed26925635d3d445cb97ae4ae66d9c4f1f772f46e
parent95ae4812461bb9018c4845761eec1262026d97a7 (diff)
ath9k: implement p2p client powersave support
Use generic TSF timers to trigger powersave state changes based information from the P2P NoA attribute. Opportunistic Powersave is not handled, because the driver does not support powersave at the moment. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c106
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c3
4 files changed, 127 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 44d74495c4de..05935f638525 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -114,6 +114,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
114#define ATH_TXFIFO_DEPTH 8 114#define ATH_TXFIFO_DEPTH 8
115#define ATH_TX_ERROR 0x01 115#define ATH_TX_ERROR 0x01
116 116
117/* Stop tx traffic 1ms before the GO goes away */
118#define ATH_P2P_PS_STOP_TIME 1000
119
117#define IEEE80211_SEQ_SEQ_SHIFT 4 120#define IEEE80211_SEQ_SEQ_SHIFT 4
118#define IEEE80211_SEQ_MAX 4096 121#define IEEE80211_SEQ_MAX 4096
119#define IEEE80211_WEP_IVLEN 3 122#define IEEE80211_WEP_IVLEN 3
@@ -367,11 +370,15 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
367/********/ 370/********/
368 371
369struct ath_vif { 372struct ath_vif {
373 struct ieee80211_vif *vif;
370 struct ath_node mcast_node; 374 struct ath_node mcast_node;
371 int av_bslot; 375 int av_bslot;
372 bool primary_sta_vif; 376 bool primary_sta_vif;
373 __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ 377 __le64 tsf_adjust; /* TSF adjustment for staggered beacons */
374 struct ath_buf *av_bcbuf; 378 struct ath_buf *av_bcbuf;
379
380 /* P2P Client */
381 struct ieee80211_noa_data noa;
375}; 382};
376 383
377struct ath9k_vif_iter_data { 384struct ath9k_vif_iter_data {
@@ -464,6 +471,8 @@ int ath_update_survey_stats(struct ath_softc *sc);
464void ath_update_survey_nf(struct ath_softc *sc, int channel); 471void ath_update_survey_nf(struct ath_softc *sc, int channel);
465void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); 472void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
466void ath_ps_full_sleep(unsigned long data); 473void ath_ps_full_sleep(unsigned long data);
474void ath9k_p2p_ps_timer(void *priv);
475void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
467 476
468/**********/ 477/**********/
469/* BTCOEX */ 478/* BTCOEX */
@@ -714,6 +723,9 @@ struct ath_softc {
714 struct completion paprd_complete; 723 struct completion paprd_complete;
715 wait_queue_head_t tx_wait; 724 wait_queue_head_t tx_wait;
716 725
726 struct ath_gen_timer *p2p_ps_timer;
727 struct ath_vif *p2p_ps_vif;
728
717 unsigned long driver_data; 729 unsigned long driver_data;
718 730
719 u8 gtt_cnt; 731 u8 gtt_cnt;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index bab6c5af62c5..21e174cfc909 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -589,6 +589,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
589 if (ret) 589 if (ret)
590 goto err_btcoex; 590 goto err_btcoex;
591 591
592 sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
593 NULL, sc, AR_FIRST_NDP_TIMER);
594
592 ath9k_cmn_init_crypto(sc->sc_ah); 595 ath9k_cmn_init_crypto(sc->sc_ah);
593 ath9k_init_misc(sc); 596 ath9k_init_misc(sc);
594 ath_fill_led_pin(sc); 597 ath_fill_led_pin(sc);
@@ -852,6 +855,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
852{ 855{
853 int i = 0; 856 int i = 0;
854 857
858 if (sc->p2p_ps_timer)
859 ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
860
855 ath9k_deinit_btcoex(sc); 861 ath9k_deinit_btcoex(sc);
856 862
857 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) 863 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d69853b848ce..22c9e5471f9c 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -261,6 +261,8 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
261 sc->gtt_cnt = 0; 261 sc->gtt_cnt = 0;
262 ieee80211_wake_queues(sc->hw); 262 ieee80211_wake_queues(sc->hw);
263 263
264 ath9k_p2p_ps_timer(sc);
265
264 return true; 266 return true;
265} 267}
266 268
@@ -1119,6 +1121,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
1119 if (ath9k_uses_beacons(vif->type)) 1121 if (ath9k_uses_beacons(vif->type))
1120 ath9k_beacon_assign_slot(sc, vif); 1122 ath9k_beacon_assign_slot(sc, vif);
1121 1123
1124 avp->vif = vif;
1125
1122 an->sc = sc; 1126 an->sc = sc;
1123 an->sta = NULL; 1127 an->sta = NULL;
1124 an->vif = vif; 1128 an->vif = vif;
@@ -1163,6 +1167,29 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
1163 return 0; 1167 return 0;
1164} 1168}
1165 1169
1170static void
1171ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
1172{
1173 struct ath_hw *ah = sc->sc_ah;
1174 s32 tsf, target_tsf;
1175
1176 if (!avp || !avp->noa.has_next_tsf)
1177 return;
1178
1179 ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
1180
1181 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1182
1183 target_tsf = avp->noa.next_tsf;
1184 if (!avp->noa.absent)
1185 target_tsf -= ATH_P2P_PS_STOP_TIME;
1186
1187 if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
1188 target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
1189
1190 ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
1191}
1192
1166static void ath9k_remove_interface(struct ieee80211_hw *hw, 1193static void ath9k_remove_interface(struct ieee80211_hw *hw,
1167 struct ieee80211_vif *vif) 1194 struct ieee80211_vif *vif)
1168{ 1195{
@@ -1174,6 +1201,13 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
1174 1201
1175 mutex_lock(&sc->mutex); 1202 mutex_lock(&sc->mutex);
1176 1203
1204 spin_lock_bh(&sc->sc_pcu_lock);
1205 if (avp == sc->p2p_ps_vif) {
1206 sc->p2p_ps_vif = NULL;
1207 ath9k_update_p2p_ps_timer(sc, NULL);
1208 }
1209 spin_unlock_bh(&sc->sc_pcu_lock);
1210
1177 sc->nvifs--; 1211 sc->nvifs--;
1178 sc->tx99_vif = NULL; 1212 sc->tx99_vif = NULL;
1179 1213
@@ -1636,6 +1670,72 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
1636 ath9k_set_assoc_state(sc, vif); 1670 ath9k_set_assoc_state(sc, vif);
1637} 1671}
1638 1672
1673void ath9k_p2p_ps_timer(void *priv)
1674{
1675 struct ath_softc *sc = priv;
1676 struct ath_vif *avp = sc->p2p_ps_vif;
1677 struct ieee80211_vif *vif;
1678 struct ieee80211_sta *sta;
1679 struct ath_node *an;
1680 u32 tsf;
1681
1682 if (!avp)
1683 return;
1684
1685 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1686 if (!avp->noa.absent)
1687 tsf += ATH_P2P_PS_STOP_TIME;
1688
1689 if (!avp->noa.has_next_tsf ||
1690 avp->noa.next_tsf - tsf > BIT(31))
1691 ieee80211_update_p2p_noa(&avp->noa, tsf);
1692
1693 ath9k_update_p2p_ps_timer(sc, avp);
1694
1695 rcu_read_lock();
1696
1697 vif = avp->vif;
1698 sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
1699 if (!sta)
1700 goto out;
1701
1702 an = (void *) sta->drv_priv;
1703 if (an->sleeping == !!avp->noa.absent)
1704 goto out;
1705
1706 an->sleeping = avp->noa.absent;
1707 if (an->sleeping)
1708 ath_tx_aggr_sleep(sta, sc, an);
1709 else
1710 ath_tx_aggr_wakeup(sc, an);
1711
1712out:
1713 rcu_read_unlock();
1714}
1715
1716void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
1717{
1718 struct ath_vif *avp = (void *)vif->drv_priv;
1719 unsigned long flags;
1720 u32 tsf;
1721
1722 if (!sc->p2p_ps_timer)
1723 return;
1724
1725 if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
1726 return;
1727
1728 sc->p2p_ps_vif = avp;
1729
1730 spin_lock_irqsave(&sc->sc_pm_lock, flags);
1731 if (!(sc->ps_flags & PS_BEACON_SYNC)) {
1732 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1733 ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
1734 ath9k_update_p2p_ps_timer(sc, avp);
1735 }
1736 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1737}
1738
1639static void ath9k_bss_info_changed(struct ieee80211_hw *hw, 1739static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1640 struct ieee80211_vif *vif, 1740 struct ieee80211_vif *vif,
1641 struct ieee80211_bss_conf *bss_conf, 1741 struct ieee80211_bss_conf *bss_conf,
@@ -1710,6 +1810,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1710 } 1810 }
1711 } 1811 }
1712 1812
1813 if (changed & BSS_CHANGED_P2P_PS) {
1814 spin_lock_bh(&sc->sc_pcu_lock);
1815 ath9k_update_p2p_ps(sc, vif);
1816 spin_unlock_bh(&sc->sc_pcu_lock);
1817 }
1818
1713 if (changed & CHECK_ANI) 1819 if (changed & CHECK_ANI)
1714 ath_check_ani(sc); 1820 ath_check_ani(sc);
1715 1821
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 6c9accdb52e4..a01efd3e741e 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -539,6 +539,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
539 ath_dbg(common, PS, 539 ath_dbg(common, PS,
540 "Reconfigure beacon timers based on synchronized timestamp\n"); 540 "Reconfigure beacon timers based on synchronized timestamp\n");
541 ath9k_set_beacon(sc); 541 ath9k_set_beacon(sc);
542
543 if (sc->p2p_ps_vif)
544 ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
542 } 545 }
543 546
544 if (ath_beacon_dtim_pending_cab(skb)) { 547 if (ath_beacon_dtim_pending_cab(skb)) {