From: Felix Fietkau Date: Tue, 11 Feb 2014 15:00:51 +0000 (+0000) Subject: ath9k: add p2p client mode support powersave patches X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=cd7fb9a51fcef76259710d1f67e8585d6b17e362;p=openwrt%2Fstaging%2Fdedeckeh.git ath9k: add p2p client mode support powersave patches Signed-off-by: Felix Fietkau SVN-Revision: 39571 --- diff --git a/package/kernel/mac80211/patches/551-ath9k_p2p_ifcomb.patch b/package/kernel/mac80211/patches/551-ath9k_p2p_ifcomb.patch new file mode 100644 index 0000000000..ffffe0cbe8 --- /dev/null +++ b/package/kernel/mac80211/patches/551-ath9k_p2p_ifcomb.patch @@ -0,0 +1,33 @@ +From c997a1da25fe7c717ed099888b8eb35d4e139e70 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 8 Dec 2013 08:52:52 +0100 +Subject: [PATCH] ath9k: support only one P2P interface + +Preparation for adding P2P powersave and multi-channel support. + +Signed-off-by: Felix Fietkau +--- + drivers/net/wireless/ath/ath9k/init.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -863,15 +863,15 @@ void ath9k_reload_chainmask_settings(str + + static const struct ieee80211_iface_limit if_limits[] = { + { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | +- BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_WDS) }, + { .max = 8, .types = + #ifdef CPTCFG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | + #endif +- BIT(NL80211_IFTYPE_AP) | +- BIT(NL80211_IFTYPE_P2P_GO) }, ++ BIT(NL80211_IFTYPE_AP) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | ++ BIT(NL80211_IFTYPE_P2P_GO) }, + }; + + static const struct ieee80211_iface_limit if_dfs_limits[] = { diff --git a/package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch b/package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch new file mode 100644 index 0000000000..feec14a217 --- /dev/null +++ b/package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch @@ -0,0 +1,247 @@ +From 6744d0a7ea037c7d65e13ca906da93009b241d00 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Tue, 11 Feb 2014 11:16:24 +0100 +Subject: [PATCH] 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 +--- + drivers/net/wireless/ath/ath9k/ath9k.h | 12 ++++ + drivers/net/wireless/ath/ath9k/init.c | 6 ++ + drivers/net/wireless/ath/ath9k/main.c | 104 +++++++++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath9k/recv.c | 3 + + 4 files changed, 125 insertions(+) + +--- 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 at + sc->gtt_cnt = 0; + ieee80211_wake_queues(sc->hw); + ++ ath9k_p2p_ps_timer(sc); ++ + return true; + } + +@@ -1126,6 +1128,8 @@ static int ath9k_add_interface(struct ie + if (ath9k_uses_beacons(vif->type)) + ath9k_beacon_assign_slot(sc, vif); + ++ avp->vif = vif; ++ + an->sc = sc; + an->sta = NULL; + an->vif = vif; +@@ -1170,6 +1174,29 @@ static int ath9k_change_interface(struct + return 0; + } + ++static void ++ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) ++{ ++ struct ath_hw *ah = sc->sc_ah; ++ s32 tsf, target_tsf; ++ ++ if (!avp || !avp->noa.has_next_tsf) ++ return; ++ ++ ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer); ++ ++ tsf = ath9k_hw_gettsf32(sc->sc_ah); ++ ++ target_tsf = avp->noa.next_tsf; ++ if (!avp->noa.absent) ++ target_tsf -= ATH_P2P_PS_STOP_TIME; ++ ++ if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) ++ target_tsf = tsf + ATH_P2P_PS_STOP_TIME; ++ ++ ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); ++} ++ + static void ath9k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) + { +@@ -1181,6 +1208,13 @@ static void ath9k_remove_interface(struc + + mutex_lock(&sc->mutex); + ++ spin_lock_bh(&sc->sc_pcu_lock); ++ if (avp == sc->p2p_ps_vif) { ++ sc->p2p_ps_vif = NULL; ++ ath9k_update_p2p_ps_timer(sc, NULL); ++ } ++ spin_unlock_bh(&sc->sc_pcu_lock); ++ + sc->nvifs--; + sc->tx99_vif = NULL; + +@@ -1649,6 +1683,70 @@ static void ath9k_bss_assoc_iter(void *d + ath9k_set_assoc_state(sc, vif); + } + ++void ath9k_p2p_ps_timer(void *priv) ++{ ++ struct ath_softc *sc = priv; ++ struct ath_vif *avp = sc->p2p_ps_vif; ++ struct ieee80211_vif *vif; ++ struct ieee80211_sta *sta; ++ struct ath_node *an; ++ u32 tsf; ++ ++ if (!avp) ++ return; ++ ++ tsf = ath9k_hw_gettsf32(sc->sc_ah); ++ if (!avp->noa.absent) ++ tsf += ATH_P2P_PS_STOP_TIME; ++ ++ if (!avp->noa.has_next_tsf || ++ avp->noa.next_tsf - tsf > BIT(31)) ++ ieee80211_update_p2p_noa(&avp->noa, tsf); ++ ++ ath9k_update_p2p_ps_timer(sc, avp); ++ ++ rcu_read_lock(); ++ ++ vif = avp->vif; ++ sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); ++ if (!sta) ++ goto out; ++ ++ an = (void *) sta->drv_priv; ++ if (an->sleeping == !!avp->noa.absent) ++ goto out; ++ ++ an->sleeping = avp->noa.absent; ++ if (an->sleeping) ++ ath_tx_aggr_sleep(sta, sc, an); ++ else ++ ath_tx_aggr_wakeup(sc, an); ++ ++out: ++ rcu_read_unlock(); ++} ++ ++void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) ++{ ++ struct ath_vif *avp = (void *)vif->drv_priv; ++ u32 tsf; ++ ++ if (!sc->p2p_ps_timer) ++ return; ++ ++ if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) ++ return; ++ ++ sc->p2p_ps_vif = avp; ++ ++ if (sc->ps_flags & PS_BEACON_SYNC) ++ return; ++ ++ tsf = ath9k_hw_gettsf32(sc->sc_ah); ++ ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); ++ ath9k_update_p2p_ps_timer(sc, avp); ++} ++ + static void ath9k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, +@@ -1723,6 +1821,12 @@ static void ath9k_bss_info_changed(struc + } + } + ++ if (changed & BSS_CHANGED_P2P_PS) { ++ spin_lock_bh(&sc->sc_pcu_lock); ++ ath9k_update_p2p_ps(sc, vif); ++ spin_unlock_bh(&sc->sc_pcu_lock); ++ } ++ + if (changed & CHECK_ANI) + ath_check_ani(sc); + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -115,6 +115,9 @@ int ath_descdma_setup(struct ath_softc * + #define ATH_TXFIFO_DEPTH 8 + #define ATH_TX_ERROR 0x01 + ++/* Stop tx traffic 1ms before the GO goes away */ ++#define ATH_P2P_PS_STOP_TIME 1000 ++ + #define IEEE80211_SEQ_SEQ_SHIFT 4 + #define IEEE80211_SEQ_MAX 4096 + #define IEEE80211_WEP_IVLEN 3 +@@ -363,11 +366,15 @@ void ath9k_release_buffered_frames(struc + /********/ + + struct ath_vif { ++ struct ieee80211_vif *vif; + struct ath_node mcast_node; + int av_bslot; + bool primary_sta_vif; + __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ + struct ath_buf *av_bcbuf; ++ ++ /* P2P Client */ ++ struct ieee80211_noa_data noa; + }; + + struct ath9k_vif_iter_data { +@@ -472,6 +479,8 @@ int ath_update_survey_stats(struct ath_s + void ath_update_survey_nf(struct ath_softc *sc, int channel); + void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); + void ath_ps_full_sleep(unsigned long data); ++void ath9k_p2p_ps_timer(void *priv); ++void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); + + /**********/ + /* BTCOEX */ +@@ -741,6 +750,9 @@ struct ath_softc { + struct completion paprd_complete; + wait_queue_head_t tx_wait; + ++ struct ath_gen_timer *p2p_ps_timer; ++ struct ath_vif *p2p_ps_vif; ++ + unsigned long sc_flags; + unsigned long driver_data; + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -797,6 +797,9 @@ static int ath9k_init_softc(u16 devid, s + if (ret) + goto err_btcoex; + ++ sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, ++ NULL, sc, AR_FIRST_NDP_TIMER); ++ + ath9k_cmn_init_crypto(sc->sc_ah); + ath9k_init_misc(sc); + ath_fill_led_pin(sc); +@@ -1081,6 +1084,9 @@ static void ath9k_deinit_softc(struct at + { + int i = 0; + ++ if (sc->p2p_ps_timer) ++ ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer); ++ + ath9k_deinit_btcoex(sc); + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) +--- 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_ + ath_dbg(common, PS, + "Reconfigure beacon timers based on synchronized timestamp\n"); + ath9k_set_beacon(sc); ++ ++ if (sc->p2p_ps_vif) ++ ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); + } + + if (ath_beacon_dtim_pending_cab(skb)) {