summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/beacon.c
diff options
context:
space:
mode:
authorRajkumar Manoharan2011-04-04 19:26:19 +0200
committerJohn W. Linville2011-04-07 21:49:40 +0200
commit99e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4 (patch)
tree35f19c1d608a4abff349f68529f8e8ce817837cc /drivers/net/wireless/ath/ath9k/beacon.c
parentath9k: Handle BSSID/AID for multiple interfaces (diff)
downloadkernel-qcow2-linux-99e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4.tar.gz
kernel-qcow2-linux-99e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4.tar.xz
kernel-qcow2-linux-99e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4.zip
ath9k: configure beacons based on hw opmode
Current ath9k code does not handle beacon timers on opmode specific. One such example is that a STA beacon config overwrites already configured AP vif's beacon timers during scan. On multi station vif case, configure beacon timers beased on primary vif selected. This also helps while moving back to single STA vif from multi STA vifs, where the power save is enabled and hw has to be reconfigured with proper beacon and bssid/aid. Otherwise connection poll will be triggered so frequently due to beacon loss. Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/beacon.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c99
1 files changed, 75 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index dfd1b98a086b..eccb0ec87adb 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -663,22 +663,63 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
ath9k_hw_set_interrupts(ah, ah->imask);
}
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+static bool ath9k_allow_beacon_config(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
{
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- enum nl80211_iftype iftype;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_vif *avp = (void *)vif->drv_priv;
- /* Setup the beacon configuration parameters */
- if (vif) {
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
- iftype = vif->type;
- cur_conf->beacon_interval = bss_conf->beacon_int;
- cur_conf->dtim_period = bss_conf->dtim_period;
- } else {
- iftype = sc->sc_ah->opmode;
+ /*
+ * Can not have different beacon interval on multiple
+ * AP interface case
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (sc->nbcnvifs > 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 false;
+ }
+ /*
+ * Can not configure station vif's beacon config
+ * while on AP opmode
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (vif->type != NL80211_IFTYPE_AP)) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "STA vif's beacon not allowed on AP mode\n");
+ return false;
+ }
+ /*
+ * Do not allow beacon config if HW was already configured
+ * with another STA vif
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+ (vif->type == NL80211_IFTYPE_STATION) &&
+ (sc->sc_flags & SC_OP_BEACONS) &&
+ !avp->primary_sta_vif) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Beacon already configured for a station interface\n");
+ return false;
}
+ return true;
+}
+
+void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ if (!ath9k_allow_beacon_config(sc, vif))
+ return;
+
+ /* Setup the beacon configuration parameters */
+ cur_conf->beacon_interval = bss_conf->beacon_int;
+ cur_conf->dtim_period = bss_conf->dtim_period;
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
@@ -701,6 +742,15 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
if (cur_conf->dtim_period == 0)
cur_conf->dtim_period = 1;
+ ath_set_beacon(sc);
+ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+}
+
+void ath_set_beacon(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+
switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP:
ath_beacon_config_ap(sc, cur_conf);
@@ -728,22 +778,23 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
int slot;
bool found = false;
- ath9k_ps_wakeup(sc);
- if (status) {
- for (slot = 0; slot < ATH_BCBUF; slot++) {
- if (sc->beacon.bslot[slot]) {
- avp = (void *)sc->beacon.bslot[slot]->drv_priv;
- if (avp->is_bslot_active) {
- found = true;
- break;
- }
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (sc->beacon.bslot[slot]) {
+ avp = (void *)sc->beacon.bslot[slot]->drv_priv;
+ if (avp->is_bslot_active) {
+ found = true;
+ break;
}
}
- if (found) {
- /* Re-enable beaconing */
- ah->imask |= ATH9K_INT_SWBA;
- ath9k_hw_set_interrupts(ah, ah->imask);
- }
+ }
+ if (!found)
+ return;
+
+ ath9k_ps_wakeup(sc);
+ if (status) {
+ /* Re-enable beaconing */
+ ah->imask |= ATH9K_INT_SWBA;
+ ath9k_hw_set_interrupts(ah, ah->imask);
} else {
/* Disable SWBA interrupt */
ah->imask &= ~ATH9K_INT_SWBA;