From patchwork Wed Feb 16 17:33:24 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rajkumar Manoharan X-Patchwork-Id: 567851 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p1GHXn9v022017 for ; Wed, 16 Feb 2011 17:33:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753545Ab1BPRdr (ORCPT ); Wed, 16 Feb 2011 12:33:47 -0500 Received: from mail.atheros.com ([12.19.149.2]:32380 "EHLO mail.atheros.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752627Ab1BPRdq (ORCPT ); Wed, 16 Feb 2011 12:33:46 -0500 Received: from mail.atheros.com ([10.10.20.105]) by sidewinder.atheros.com for ; Wed, 16 Feb 2011 09:33:25 -0800 Received: from mail.atheros.com (10.12.4.12) by SC1EXHC-01.global.atheros.com (10.10.20.111) with Microsoft SMTP Server (TLS) id 8.2.213.0; Wed, 16 Feb 2011 09:33:44 -0800 Received: by mail.atheros.com (sSMTP sendmail emulation); Wed, 16 Feb 2011 23:03:24 +0530 From: Rajkumar Manoharan To: CC: Rajkumar Manoharan Subject: [RFC/RFT] ath9k: configure opmode sepecific beacon timers dynamically Date: Wed, 16 Feb 2011 23:03:24 +0530 Message-ID: <1297877604-8084-1-git-send-email-rmanoharan@atheros.com> X-Mailer: git-send-email 1.7.4 MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Wed, 16 Feb 2011 17:33:50 +0000 (UTC) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ba436cd..6d1e865 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -372,11 +372,14 @@ struct ath_vif { #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) struct ath_beacon_config { + struct ieee80211_vif *vif; + enum nl80211_iftype opmode; int beacon_interval; u16 listen_interval; u16 dtim_period; u16 bmiss_timeout; u8 dtim_count; + bool update; }; struct ath_beacon { @@ -400,11 +403,15 @@ struct ath_beacon { }; void ath_beacon_tasklet(unsigned long data); -void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath_beacon_config(struct ath_softc *sc); int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); int ath_beaconq_config(struct ath_softc *sc); void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); +void ath_fill_beacon_conf(struct ath_beacon_config *cur_conf, + struct ieee80211_vif *vif); +void ath9k_update_vif_beacon(struct ieee80211_hw *hw, + struct ath_beacon_config *beacon_conf); /*******/ /* ANI */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index a4bdfdb..6420b0d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -694,45 +694,12 @@ 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) +void ath_beacon_config(struct ath_softc *sc) { struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - enum nl80211_iftype iftype; - /* 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; - } - - cur_conf->listen_interval = 1; - cur_conf->dtim_count = 1; - cur_conf->bmiss_timeout = - ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; - - /* - * It looks like mac80211 may end up using beacon interval of zero in - * some cases (at least for mesh point). Avoid getting into an - * infinite loop by using a bit safer value instead. To be safe, - * do sanity check on beacon interval for all operating modes. - */ - if (cur_conf->beacon_interval == 0) - cur_conf->beacon_interval = 100; - - /* - * We don't parse dtim period from mac80211 during the driver - * initialization as it breaks association with hidden-ssid - * AP and it causes latency in roaming - */ - if (cur_conf->dtim_period == 0) - cur_conf->dtim_period = 1; - - switch (iftype) { + switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: ath_beacon_config_ap(sc, cur_conf); break; @@ -750,6 +717,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) } sc->sc_flags |= SC_OP_BEACONS; + cur_conf->update = false; } void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) @@ -759,22 +727,22 @@ 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; @@ -784,3 +752,77 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) } ath9k_ps_restore(sc); } + + +static void ath9k_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_beacon_config *beacon_conf = data; + + /* Get matching vif with opmode */ + if (beacon_conf->opmode != vif->type) + return; + + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + if (bss_conf->enable_beacon) + ath_fill_beacon_conf(beacon_conf, vif); + break; + case NL80211_IFTYPE_STATION: + if (bss_conf->assoc) + ath_fill_beacon_conf(beacon_conf, vif); + break; + default: + break; + } +} + +void ath9k_update_vif_beacon(struct ieee80211_hw *hw, + struct ath_beacon_config *beacon_conf) +{ + struct ath_softc *sc = hw->priv; + + ieee80211_iterate_active_interfaces_atomic(hw, ath9k_beacon_iter, + beacon_conf); + if (beacon_conf->update) { + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) + sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | PS_BEACON_SYNC); + else + sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; + } else + beacon_conf->vif = NULL; +} + +void ath_fill_beacon_conf(struct ath_beacon_config *cur_conf, + struct ieee80211_vif *vif) +{ + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + 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 = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + + /* + * It looks like mac80211 may end up using beacon interval of zero in + * some cases (at least for mesh point). Avoid getting into an + * infinite loop by using a bit safer value instead. To be safe, + * do sanity check on beacon interval for all operating modes. + */ + if (cur_conf->beacon_interval == 0) + cur_conf->beacon_interval = 100; + + /* + * We don't parse dtim period from mac80211 during the driver + * initialization as it breaks association with hidden-ssid + * AP and it causes latency in roaming + */ + if (cur_conf->dtim_period == 0) + cur_conf->dtim_period = 1; + + cur_conf->vif = vif; + cur_conf->update = true; +} diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4f568b8..fd14cca 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -226,6 +226,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, cancel_delayed_work_sync(&sc->hw_pll_work); ath9k_ps_wakeup(sc); + ath9k_set_beaconing_status(sc, false); spin_lock_bh(&sc->sc_pcu_lock); @@ -279,15 +280,15 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); - ath9k_hw_set_interrupts(ah, ah->imask); if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); + ath_beacon_config(sc); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); ath_start_ani(common); } + ath9k_hw_set_interrupts(ah, ah->imask); ps_restore: ieee80211_wake_queues(hw); @@ -812,6 +813,45 @@ chip_reset: #undef SCHED_INTR } +static bool ath9k_is_primary_vif(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ + int ret = false, slot; + struct ath_vif *avp; + + if (sc->sc_ah->opmode != vif->type) + goto out; + + if (!(sc->sc_flags & SC_OP_BEACONS)) { + ret = true; + goto out; + } else if ((sc->sc_flags & SC_OP_BEACONS) && + (sc->cur_beacon_conf.vif && + (sc->cur_beacon_conf.vif != vif))) + goto out; + + switch (sc->sc_ah->opmode) { + case NL80211_IFTYPE_AP: + /* Do not allow if an AP vif is beaconing */ + 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) + goto out; + } + } + ret = true; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + ret = true; + default: + break; + } +out: + return ret; +} + static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -825,19 +865,23 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, common->curbssid); - /* New association, store aid */ - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(ah); + if (ath9k_is_primary_vif(sc, vif)) { + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->ps_flags |= PS_BEACON_SYNC; + + ath_fill_beacon_conf(&sc->cur_beacon_conf, vif); - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC; + /* Configure the beacon */ + ath_beacon_config(sc); - /* Configure the beacon */ - ath_beacon_config(sc, vif); + /* New association, store aid */ + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(ah); + } /* Reset rssi stats */ sc->last_rssi = ATH_RSSI_DUMMY_MARKER; @@ -847,10 +891,24 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_start_ani(common); } else { ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); - common->curaid = 0; - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); + if (ath9k_is_primary_vif(sc, vif)) { + ath9k_update_vif_beacon(hw, &sc->cur_beacon_conf); + if (sc->cur_beacon_conf.vif) { + /* Set BSSID */ + memcpy(common->curbssid, + sc->cur_beacon_conf.vif->bss_conf.bssid, + ETH_ALEN); + /* New association, store aid */ + common->curaid = + sc->cur_beacon_conf.vif->bss_conf.aid; + ath9k_hw_write_associd(ah); + } else { + common->curaid = 0; + /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); + } + } } } @@ -883,7 +941,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) goto out; } if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_beacon_config(sc); /* restart beacons */ /* Re-Enable interrupts */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -986,7 +1044,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->config.txpowlimit, &sc->curtxpow); if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_beacon_config(sc); /* restart beacons */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -1294,7 +1352,8 @@ static void ath9k_reclaim_beacon(struct ath_softc *sc, ath9k_set_beaconing_status(sc, false); ath_beacon_return(sc, avp); ath9k_set_beaconing_status(sc, true); - sc->sc_flags &= ~SC_OP_BEACONS; + if (sc->cur_beacon_conf.vif == vif) + sc->sc_flags &= ~SC_OP_BEACONS; } static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) @@ -1402,11 +1461,12 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(ah, ah->imask); ath9k_ps_restore(sc); + sc->cur_beacon_conf.opmode = ah->opmode; /* Set up ANI */ if ((iter_data.naps + iter_data.nadhocs) > 0) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); - } else { + } else if (!sc->cur_beacon_conf.vif) { sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); } @@ -1431,9 +1491,10 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, ath9k_set_beaconing_status(sc, false); error = ath_beacon_alloc(sc, vif); if (!error) - ath_beacon_config(sc, vif); + ath_beacon_config(sc); ath9k_set_beaconing_status(sc, true); } + ath9k_update_vif_beacon(hw, &sc->cur_beacon_conf); } @@ -1556,6 +1617,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_reclaim_beacon(sc, vif); ath9k_calculate_summary_state(hw, NULL); + ath9k_update_vif_beacon(hw, &sc->cur_beacon_conf); mutex_unlock(&sc->mutex); } @@ -1886,20 +1948,28 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); if (changed & BSS_CHANGED_BSSID) { - /* Set BSSID */ - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); - common->curaid = 0; - ath9k_hw_write_associd(ah); - /* Set aggregation protection mode parameters */ - sc->config.ath_aggr_prot = 0; + if (!common->curaid || (sc->cur_beacon_conf.vif && + !memcmp(sc->cur_beacon_conf.vif->bss_conf.bssid, + bss_conf->bssid, ETH_ALEN))) { + /* Set BSSID */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); + ath9k_hw_write_associd(ah); - ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", - common->curbssid, common->curaid); + /* Set aggregation protection mode parameters */ + sc->config.ath_aggr_prot = 0; + ath_dbg(common, ATH_DBG_CONFIG, + "BSSID: %pM aid: 0x%x\n", + common->curbssid, common->curaid); + } else { + common->curaid = 0; + memset(common->curbssid, 0, ETH_ALEN); + } /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; + if (sc->cur_beacon_conf.vif == vif) + sc->sc_flags &= ~SC_OP_BEACONS ; } /* Enable transmission of beacons (AP, IBSS, MESH) */ @@ -1908,7 +1978,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_set_beaconing_status(sc, false); error = ath_beacon_alloc(sc, vif); if (!error) - ath_beacon_config(sc, vif); + ath_beacon_config(sc); ath9k_set_beaconing_status(sc, true); } @@ -1933,7 +2003,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, /* Disable transmission of beacons */ if ((changed & BSS_CHANGED_BEACON_ENABLED) && - !bss_conf->enable_beacon) { + !bss_conf->enable_beacon && + ath9k_is_primary_vif(sc, vif)) { ath9k_set_beaconing_status(sc, false); avp->is_bslot_active = false; ath9k_set_beaconing_status(sc, true); @@ -1950,11 +2021,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_set_beaconing_status(sc, false); error = ath_beacon_alloc(sc, vif); if (!error) - ath_beacon_config(sc, vif); + ath_beacon_config(sc); ath9k_set_beaconing_status(sc, true); - } else { - ath_beacon_config(sc, vif); - } + } else if (ath9k_is_primary_vif(sc, vif)) + ath_beacon_config(sc); } if (changed & BSS_CHANGED_ERP_PREAMBLE) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index daf171d..a42b0c3 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -576,7 +576,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, ATH_DBG_PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); - ath_beacon_config(sc, NULL); + ath_beacon_config(sc); } if (ath_beacon_dtim_pending_cab(skb)) {