2014-02-11 10:18:20

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/2] ath9k: support only one P2P interface

Preparation for adding P2P powersave and multi-channel support.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/init.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1fc2e5a..72ace06 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -862,13 +862,13 @@ void ath9k_reload_chainmask_settings(struct ath_softc *sc)

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 CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
- BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_AP) },
+ { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },
};

--
1.8.3.4 (Apple Git-47)



2014-02-12 15:44:48

by Sujith Manoharan

[permalink] [raw]
Subject: Re: [PATCH 2/2] ath9k: implement p2p client powersave support

Felix Fietkau wrote:
> It only allocates a very small struct. Doing this in the interface
> add/remove callback means I'd have to handle interface change as well. I
> figured keeping it simple is better than micro-optimizing a single small
> memory allocation.

I think doing this in the interface callbacks would be cleaner since
this won't be required for normal ap/sta operations at all.

Sujith


2014-02-12 15:32:54

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH 2/2] ath9k: implement p2p client powersave support

On 2014-02-12 16:12, Sujith Manoharan wrote:
> Felix Fietkau wrote:
>> + 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);
>> @@ -1067,6 +1070,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
>> {
>> int i = 0;
>>
>> + if (sc->p2p_ps_timer)
>> + ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
>> +
>
> Why do this in the global init/deinit routines ? Wouldn't the
> add/remove interface callbacks be a better place for this (based on
> vif->p2p), since this timer is needed only for p2p interfaces ?
It only allocates a very small struct. Doing this in the interface
add/remove callback means I'd have to handle interface change as well. I
figured keeping it simple is better than micro-optimizing a single small
memory allocation.

>> + if (sc->ps_flags & PS_BEACON_SYNC)
>> + return;
>
> I think sc_pm_lock is required to use sc->ps_flags.
OK, will send v2 later.

- Felix

2014-02-11 10:18:20

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/2] 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 <[email protected]>
---
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(+)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index b5ac32c..65915e1 100644
--- 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 *sc, struct ath_descdma *dd,
#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(struct ieee80211_hw *hw,
/********/

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_softc *sc);
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 */
@@ -731,6 +740,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;

diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 72ace06..3e3f12d 100644
--- 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, struct ath_softc *sc,
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);
@@ -1067,6 +1070,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
{
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++)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5924f72..7634615 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)
sc->gtt_cnt = 0;
ieee80211_wake_queues(sc->hw);

+ ath9k_p2p_ps_timer(sc);
+
return true;
}

@@ -1117,6 +1119,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);

+ avp->vif = vif;
+
an->sc = sc;
an->sta = NULL;
an->vif = vif;
@@ -1161,6 +1165,29 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
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)
{
@@ -1172,6 +1199,13 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,

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;

@@ -1636,6 +1670,70 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
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,
@@ -1710,6 +1808,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
}

+ 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);

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a0ebdd0..ddfb8ff 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)
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)) {
--
1.8.3.4 (Apple Git-47)


2014-02-12 15:13:03

by Sujith Manoharan

[permalink] [raw]
Subject: Re: [PATCH 2/2] ath9k: implement p2p client powersave support

Felix Fietkau wrote:
> + 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);
> @@ -1067,6 +1070,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
> {
> int i = 0;
>
> + if (sc->p2p_ps_timer)
> + ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
> +

Why do this in the global init/deinit routines ? Wouldn't the
add/remove interface callbacks be a better place for this (based on
vif->p2p), since this timer is needed only for p2p interfaces ?

> + if (sc->ps_flags & PS_BEACON_SYNC)
> + return;

I think sc_pm_lock is required to use sc->ps_flags.

Sujith

2014-02-12 15:52:07

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH 2/2] ath9k: implement p2p client powersave support

On 2014-02-12 16:44, Sujith Manoharan wrote:
> Felix Fietkau wrote:
>> It only allocates a very small struct. Doing this in the interface
>> add/remove callback means I'd have to handle interface change as well. I
>> figured keeping it simple is better than micro-optimizing a single small
>> memory allocation.
>
> I think doing this in the interface callbacks would be cleaner since
> this won't be required for normal ap/sta operations at all.
Actually, I just remembered, that I'm also using this timer in my
unfinished multi-channel concurrency patches (for channel switching), so
I don't want to move it to the interface callbacks only to move it back
again later.

- Felix