Skip to content

Commit

Permalink
ath9k_htc: Properly adjust timers in multi-vif scenario
Browse files Browse the repository at this point in the history
AR_LAST_TSTP holds the timestamp of the last RX beacon. In the
multi-vif scenario, this registers is updated only for the first
vif that that is connected to an AP.

This commit properly adjust the hardware timers for the first vif
using the values from this register.
  • Loading branch information
dorugucea91 committed May 1, 2017
1 parent 88d1387 commit ff34a84
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 12 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/ath/ath9k/beacon.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ static void ath9k_beacon_config_sta(struct ath_hw *ah,
{
struct ath9k_beacon_state bs;

if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)
if (ath9k_cmn_beacon_config_sta(ah, conf, &bs, 0) == -EPERM)
return;

ath9k_hw_disable_interrupts(ah);
Expand Down
24 changes: 20 additions & 4 deletions drivers/net/wireless/ath/ath9k/common-beacon.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@ static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf,
*/
int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
struct ath_beacon_config *conf,
struct ath9k_beacon_state *bs)
struct ath9k_beacon_state *bs,
int use_tsf_register)
{
struct ath_common *common = ath9k_hw_common(ah);
int dtim_intval;
u64 tsf;
u32 last_tstp;

/* No need to configure beacon if we are not associated */
if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
Expand All @@ -90,14 +92,28 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
* TSF and calculate dtim state for the result.
*/
tsf = ath9k_hw_gettsf64(ah);
conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval);
last_tstp = REG_READ(ah, AR_LAST_TSTP);
printk(KERN_INFO "%s: TSF of last RX beacon: %u\n", __func__, last_tstp);

if (last_tstp != ah->saved_last_tstp && use_tsf_register) {
printk(KERN_INFO "%s: Using last_tstp\n", __func__);
ah->saved_last_tstp = last_tstp;
conf->nexttbtt = ath9k_get_next_tbtt(ah, last_tstp, conf->intval);
} else {
printk(KERN_INFO "%s: Using ath9k_hw_gettsf64\n", __func__);
conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval);
}

bs->bs_intval = TU_TO_USEC(conf->intval);
bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval;
bs->bs_nexttbtt = conf->nexttbtt;
bs->bs_nextdtim = conf->nexttbtt;
if (conf->dtim_period > 1)
bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval);
if (conf->dtim_period > 1) {
if (!use_tsf_register)
bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval);
else
bs->bs_nextdtim = ath9k_get_next_tbtt(ah, last_tstp, dtim_intval);
}

/*
* Calculate the number of consecutive beacons to miss* before taking
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath/ath9k/common-beacon.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ struct ath_beacon_config;

int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
struct ath_beacon_config *conf,
struct ath9k_beacon_state *bs);
struct ath9k_beacon_state *bs,
int use_tsf_register);
void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah,
struct ath_beacon_config *conf);
void ath9k_cmn_beacon_config_ap(struct ath_hw *ah,
Expand Down
24 changes: 20 additions & 4 deletions drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,32 @@ static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv,
}

static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
struct ath_beacon_config *bss_conf)
struct ath_beacon_config *bss_conf,
struct ieee80211_vif *vif)
{
struct ath9k_beacon_state bs;
enum ath9k_int imask = 0;
__be32 htc_imask = 0;
int ret __attribute__ ((unused));
u8 cmd_rsp;
int use_tsf_register = 0;
printk(KERN_INFO "%s\n", __func__);

if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM)
if (!vif)
printk(KERN_INFO "vif is NULL\n");

if (vif) {
if (vif->addr[ETH_ALEN - 1] == 0x39) {
printk(KERN_INFO "39 interface\n");
use_tsf_register = 1;
}
else if (vif->addr[ETH_ALEN - 1] == 0x40)
printk(KERN_INFO "40 interface\n");
else
printk(KERN_INFO "Unknown interface: %x\n", priv->csa_vif->addr[ETH_ALEN - 1]);
}

if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs, use_tsf_register) == -EPERM)
return;

WMI_CMD(WMI_DISABLE_INTR_CMDID);
Expand Down Expand Up @@ -471,7 +487,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,

switch (vif->type) {
case NL80211_IFTYPE_STATION:
ath9k_htc_beacon_config_sta(priv, cur_conf);
ath9k_htc_beacon_config_sta(priv, cur_conf, vif);
avp->beacon_configured = true;
break;
case NL80211_IFTYPE_ADHOC:
Expand All @@ -494,7 +510,7 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)

switch (priv->ah->opmode) {
case NL80211_IFTYPE_STATION:
ath9k_htc_beacon_config_sta(priv, cur_conf);
ath9k_htc_beacon_config_sta(priv, cur_conf, NULL);
break;
case NL80211_IFTYPE_ADHOC:
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath/ath9k/hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -2324,11 +2324,12 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
if (ah->saved_next_dtim) {
difference = ah->saved_next_dtim - SLEEP_SLOP - tsf;

/* estimate a delta time of ~10m between receiving a
/* estimate a delta time of ~10ms between receiving a
* beacon and arming the timer
* TODO: does AR9271 have any register holding the TSF
* of the last received beacon?
*/

if (difference > 10000) {
ah->saved_next_dtim -= 10000;
ah->saved_next_tbtt -= 10000;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/ath/ath9k/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ struct ath_hw {
u8 tx_power_stbc[Ar5416RateSize];

/* Power Save for the multiple-interface scenario */
u32 saved_next_dtim, saved_next_tbtt;
u32 saved_next_dtim, saved_next_tbtt, saved_last_tstp;
};

struct ath_bus_ops {
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath9k/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
printk(KERN_INFO "!!! %s\n", __func__);
ah->saved_next_dtim = 0;
ah->saved_next_tbtt = 0;
ah->saved_last_tstp = 0;
common = ath9k_hw_common(ah);
ath9k_set_hw_capab(sc, hw);

Expand Down
4 changes: 4 additions & 0 deletions net/mac80211/status.c
Original file line number Diff line number Diff line change
Expand Up @@ -862,11 +862,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
printk(KERN_INFO "%s: ACK'ed NULL function for sdata1: %s\n", __func__, sta->sdata->name);
local->ps_sdata1->u.mgd.flags |=
IEEE80211_STA_NULLFUNC_ACKED;
local->ps_sdata2->u.mgd.flags |=
IEEE80211_STA_NULLFUNC_ACKED;
}
else if (local->ps_sdata2 && !strcmp(local->ps_sdata2->name, sta->sdata->name)) {
printk(KERN_INFO "%s: ACK'ed NULL function for sdata2: %s\n", __func__, sta->sdata->name);
local->ps_sdata2->u.mgd.flags |=
IEEE80211_STA_NULLFUNC_ACKED;
local->ps_sdata1->u.mgd.flags |=
IEEE80211_STA_NULLFUNC_ACKED;
}
else
printk(KERN_INFO "!!! %s: something is wrong\n", __func__);
Expand Down

1 comment on commit ff34a84

@psyborg55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

according to your commit message: "this registers is updated only for the first
vif that that is connected to an AP" i assume you run STA+AP combination

would you mind testing your changes with more AP interfaces. find the details in the pr: torvalds/linux#574

Please sign in to comment.