ath9k_htc: Configure beacon timers in AP mode
Handle multi-interface situations by checking if AP interfaces are already present. Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
a236254c35
commit
a5fae37d11
@@ -352,10 +352,8 @@ struct ath_led {
|
|||||||
|
|
||||||
struct htc_beacon_config {
|
struct htc_beacon_config {
|
||||||
u16 beacon_interval;
|
u16 beacon_interval;
|
||||||
u16 listen_interval;
|
|
||||||
u16 dtim_period;
|
u16 dtim_period;
|
||||||
u16 bmiss_timeout;
|
u16 bmiss_timeout;
|
||||||
u8 dtim_count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath_btcoex {
|
struct ath_btcoex {
|
||||||
@@ -380,6 +378,7 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
|
|||||||
#define OP_BT_PRIORITY_DETECTED BIT(6)
|
#define OP_BT_PRIORITY_DETECTED BIT(6)
|
||||||
#define OP_BT_SCAN BIT(7)
|
#define OP_BT_SCAN BIT(7)
|
||||||
#define OP_ANI_RUNNING BIT(8)
|
#define OP_ANI_RUNNING BIT(8)
|
||||||
|
#define OP_TSF_RESET BIT(9)
|
||||||
|
|
||||||
struct ath9k_htc_priv {
|
struct ath9k_htc_priv {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@@ -138,6 +138,51 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
|
|||||||
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
|
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
|
||||||
|
struct htc_beacon_config *bss_conf)
|
||||||
|
{
|
||||||
|
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||||
|
enum ath9k_int imask = 0;
|
||||||
|
u32 nexttbtt, intval, tsftu;
|
||||||
|
__be32 htc_imask = 0;
|
||||||
|
int ret;
|
||||||
|
u8 cmd_rsp;
|
||||||
|
u64 tsf;
|
||||||
|
|
||||||
|
intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||||
|
intval /= ATH9K_HTC_MAX_BCN_VIF;
|
||||||
|
nexttbtt = intval;
|
||||||
|
|
||||||
|
if (priv->op_flags & OP_TSF_RESET) {
|
||||||
|
intval |= ATH9K_BEACON_RESET_TSF;
|
||||||
|
priv->op_flags &= ~OP_TSF_RESET;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Pull nexttbtt forward to reflect the current TSF.
|
||||||
|
*/
|
||||||
|
tsf = ath9k_hw_gettsf64(priv->ah);
|
||||||
|
tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
|
||||||
|
do {
|
||||||
|
nexttbtt += intval;
|
||||||
|
} while (nexttbtt < tsftu);
|
||||||
|
}
|
||||||
|
|
||||||
|
intval |= ATH9K_BEACON_ENA;
|
||||||
|
|
||||||
|
if (priv->op_flags & OP_ENABLE_BEACON)
|
||||||
|
imask |= ATH9K_INT_SWBA;
|
||||||
|
|
||||||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
"AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n",
|
||||||
|
bss_conf->beacon_interval, nexttbtt, imask);
|
||||||
|
|
||||||
|
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||||
|
ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
|
||||||
|
priv->bmiss_cnt = 0;
|
||||||
|
htc_imask = cpu_to_be32(imask);
|
||||||
|
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
|
||||||
|
}
|
||||||
|
|
||||||
static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
|
static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
|
||||||
struct htc_beacon_config *bss_conf)
|
struct htc_beacon_config *bss_conf)
|
||||||
{
|
{
|
||||||
@@ -260,13 +305,36 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
|
|||||||
struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
|
struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
|
||||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changing the beacon interval when multiple AP interfaces
|
||||||
|
* are configured will affect beacon transmission of all
|
||||||
|
* of them.
|
||||||
|
*/
|
||||||
|
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
|
||||||
|
(priv->num_ap_vif > 1) &&
|
||||||
|
(vif->type == NL80211_IFTYPE_AP) &&
|
||||||
|
(cur_conf->beacon_interval != bss_conf->beacon_int)) {
|
||||||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
"Changing beacon interval of multiple AP interfaces !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the HW is operating in AP mode, any new station interfaces that
|
||||||
|
* are added cannot change the beacon parameters.
|
||||||
|
*/
|
||||||
|
if (priv->num_ap_vif &&
|
||||||
|
(vif->type != NL80211_IFTYPE_AP)) {
|
||||||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
"HW in AP mode, cannot set STA beacon parameters\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cur_conf->beacon_interval = bss_conf->beacon_int;
|
cur_conf->beacon_interval = bss_conf->beacon_int;
|
||||||
if (cur_conf->beacon_interval == 0)
|
if (cur_conf->beacon_interval == 0)
|
||||||
cur_conf->beacon_interval = 100;
|
cur_conf->beacon_interval = 100;
|
||||||
|
|
||||||
cur_conf->dtim_period = bss_conf->dtim_period;
|
cur_conf->dtim_period = bss_conf->dtim_period;
|
||||||
cur_conf->listen_interval = 1;
|
|
||||||
cur_conf->dtim_count = 1;
|
|
||||||
cur_conf->bmiss_timeout =
|
cur_conf->bmiss_timeout =
|
||||||
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
|
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
|
||||||
|
|
||||||
@@ -277,6 +345,9 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
|
|||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
|
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
|
||||||
break;
|
break;
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
ath9k_htc_beacon_config_ap(priv, cur_conf);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ath_dbg(common, ATH_DBG_CONFIG,
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
"Unsupported beaconing mode\n");
|
"Unsupported beaconing mode\n");
|
||||||
@@ -296,6 +367,9 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
|
|||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
|
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
|
||||||
break;
|
break;
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
ath9k_htc_beacon_config_ap(priv, cur_conf);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ath_dbg(common, ATH_DBG_CONFIG,
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
"Unsupported beaconing mode\n");
|
"Unsupported beaconing mode\n");
|
||||||
|
@@ -110,6 +110,9 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|||||||
struct ath9k_htc_priv *priv = data;
|
struct ath9k_htc_priv *priv = data;
|
||||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||||
|
|
||||||
|
if ((vif->type == NL80211_IFTYPE_AP) && bss_conf->enable_beacon)
|
||||||
|
priv->reconfig_beacon = true;
|
||||||
|
|
||||||
if (bss_conf->assoc) {
|
if (bss_conf->assoc) {
|
||||||
priv->rearm_ani = true;
|
priv->rearm_ani = true;
|
||||||
priv->reconfig_beacon = true;
|
priv->reconfig_beacon = true;
|
||||||
@@ -288,6 +291,11 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
htc_start(priv->htc);
|
htc_start(priv->htc);
|
||||||
|
|
||||||
|
if (!(priv->op_flags & OP_SCANNING) &&
|
||||||
|
!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
|
||||||
|
ath9k_htc_vif_reconfig(priv);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
ath9k_htc_ps_restore(priv);
|
ath9k_htc_ps_restore(priv);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1620,19 +1628,42 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
|
|||||||
common->curbssid, common->curaid);
|
common->curbssid, common->curaid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((changed & BSS_CHANGED_BEACON_INT) ||
|
if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
|
||||||
(changed & BSS_CHANGED_BEACON) ||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
((changed & BSS_CHANGED_BEACON_ENABLED) &&
|
"Beacon enabled for BSS: %pM\n", bss_conf->bssid);
|
||||||
bss_conf->enable_beacon)) {
|
|
||||||
priv->op_flags |= OP_ENABLE_BEACON;
|
priv->op_flags |= OP_ENABLE_BEACON;
|
||||||
ath9k_htc_beacon_config(priv, vif);
|
ath9k_htc_beacon_config(priv, vif);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
|
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
|
||||||
!bss_conf->enable_beacon) {
|
/*
|
||||||
|
* Disable SWBA interrupt only if there are no
|
||||||
|
* AP/IBSS interfaces.
|
||||||
|
*/
|
||||||
|
if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) {
|
||||||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
"Beacon disabled for BSS: %pM\n",
|
||||||
|
bss_conf->bssid);
|
||||||
priv->op_flags &= ~OP_ENABLE_BEACON;
|
priv->op_flags &= ~OP_ENABLE_BEACON;
|
||||||
ath9k_htc_beacon_config(priv, vif);
|
ath9k_htc_beacon_config(priv, vif);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||||
|
/*
|
||||||
|
* Reset the HW TSF for the first AP interface.
|
||||||
|
*/
|
||||||
|
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
|
||||||
|
(priv->nvifs == 1) &&
|
||||||
|
(priv->num_ap_vif == 1) &&
|
||||||
|
(vif->type == NL80211_IFTYPE_AP)) {
|
||||||
|
priv->op_flags |= OP_TSF_RESET;
|
||||||
|
}
|
||||||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
"Beacon interval changed for BSS: %pM\n",
|
||||||
|
bss_conf->bssid);
|
||||||
|
ath9k_htc_beacon_config(priv, vif);
|
||||||
|
}
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||||
if (bss_conf->use_short_slot)
|
if (bss_conf->use_short_slot)
|
||||||
|
@@ -123,12 +123,8 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
|
|||||||
void ath9k_swba_tasklet(unsigned long data)
|
void ath9k_swba_tasklet(unsigned long data)
|
||||||
{
|
{
|
||||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
|
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
|
||||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
|
||||||
|
|
||||||
ath_dbg(common, ATH_DBG_WMI, "SWBA Event received\n");
|
|
||||||
|
|
||||||
ath9k_htc_swba(priv, priv->wmi->beacon_pending);
|
ath9k_htc_swba(priv, priv->wmi->beacon_pending);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath9k_fatal_work(struct work_struct *work)
|
void ath9k_fatal_work(struct work_struct *work)
|
||||||
|
Reference in New Issue
Block a user