/* * Copyright (c) 2008-2011 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* * This function will modify certain transmit queue properties depending on * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max
*/ staticvoid ath9k_beaconq_config(struct ath_softc *sc)
{ struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi, qi_be; struct ath_txq *txq;
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) { /* Always burst out beacon and CAB traffic. */
qi.tqi_aifs = 1;
qi.tqi_cwmin = 0;
qi.tqi_cwmax = 0;
} else { /* Adhoc mode; important thing is to use 2x cwmin. */
txq = sc->tx.txq_map[IEEE80211_AC_BE];
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs; if (ah->slottime == 20)
qi.tqi_cwmin = 2*qi_be.tqi_cwmin; else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
qi.tqi_cwmax = qi_be.tqi_cwmax;
}
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
ath_err(common, "Unable to update h/w beacon queue parameters\n");
} else {
ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
}
}
/* * Associates the beacon frame buffer with a transmit descriptor. Will set * up rate codes, and channel flags. Beacons are always sent out at the * lowest rate, and are not retried.
*/ staticvoid ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, struct ath_buf *bf, int rateidx)
{ struct sk_buff *skb = bf->bf_mpdu; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_tx_info info; struct ieee80211_supported_band *sband;
u8 chainmask = ah->txchainmask;
u8 i, rate = 0;
/* * if the CABQ traffic from previous DTIM is pending and the current * beacon is also a DTIM. * 1) if there is only one vif let the cab traffic continue. * 2) if there are more than one vif and we are using staggered * beacons, then drain the cabq by dropping all the frames in * the cabq so that the current vifs cab traffic can be scheduled.
*/
spin_lock_bh(&cabq->axq_lock);
cabq_depth = cabq->axq_depth;
spin_unlock_bh(&cabq->axq_lock);
if (skb && cabq_depth) { if (sc->cur_chan->nvifs > 1) {
ath_dbg(common, BEACON, "Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq);
}
}
/* tsf_adjust is added to the TSF value. We send out the * beacon late, so need to adjust the TSF starting point to be * later in time (i.e. the theoretical first beacon has a TSF * of 0 after correction).
*/
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(tsfadjust);
ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
(signedlonglong)tsfadjust, avp->av_bslot);
}
}
if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
ath_dbg(common, RESET, "reset work is pending, skip beaconing now\n"); return;
}
/* * Check if the previous beacon has gone out. If * not don't try to post another, skip this period * and wait for the next. Missed beacons indicate * a problem and should not occur. If we miss too * many consecutive beacons reset the device.
*/ if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
sc->beacon.bmisscnt++;
ath9k_hw_check_nav(ah);
/* * If the previous beacon has not been transmitted * and a MAC/BB hang has been identified, return * here because a chip reset would have been * initiated.
*/ if (!ath_hw_check(sc)) return;
/* EDMA devices check that in the tx completion function. */ if (!edma) { if (ath9k_is_chanctx_enabled()) {
ath_chanctx_beacon_sent_ev(sc,
ATH_CHANCTX_EVENT_BEACON_SENT);
}
if (ath9k_csa_is_finished(sc, vif)) return;
}
if (!vif || !vif->bss_conf.enable_beacon) return;
if (ath9k_is_chanctx_enabled()) {
ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
}
bf = ath9k_beacon_generate(sc->hw, vif);
if (sc->beacon.bmisscnt != 0) {
ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
sc->beacon.bmisscnt);
sc->beacon.bmisscnt = 0;
}
/* * Handle slot time change when a non-ERP station joins/leaves * an 11g network. The 802.11 layer notifies us via callback, * we mark updateslot, then wait one beacon before effecting * the change. This gives associated stations at least one * beacon interval to note the state change. * * NB: The slot time change state machine is clocked according * to whether we are bursting or staggering beacons. We * recognize the request to update and record the current * slot then don't transition until that slot is reached * again. If we miss a beacon for that slot then we'll be * slow to transition but we'll be sure at least one beacon * interval has passed. When bursting slot is always left * set to ATH_BCBUF so this check is a noop.
*/ if (sc->beacon.updateslot == UPDATE) {
sc->beacon.updateslot = COMMIT;
sc->beacon.slotupdate = slot;
} elseif (sc->beacon.updateslot == COMMIT &&
sc->beacon.slotupdate == slot) {
ah->slottime = sc->beacon.slottime;
ath9k_hw_init_global_settings(ah);
sc->beacon.updateslot = OK;
}
if (bf) {
ath9k_reset_beacon_status(sc);
ath_dbg(common, BEACON, "Transmitting beacon for slot: %d\n", slot);
/* NB: cabq traffic should already be queued and primed */
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
if (!edma)
ath9k_hw_txstart(ah, sc->beacon.beaconq);
}
}
/* * Both nexttbtt and intval have to be in usecs.
*/ staticvoid ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
u32 intval)
{ struct ath_hw *ah = sc->sc_ah;
/* * For multi-bss ap support beacons are either staggered evenly over N slots or * burst together. For the former arrange for the SWBA to be delivered for each * slot. Slots that are not occupied will generate nothing.
*/ staticvoid ath9k_beacon_config_ap(struct ath_softc *sc, struct ath_beacon_config *conf)
{ struct ath_hw *ah = sc->sc_ah;
/* * Set the global 'beacon has been configured' flag for the * joiner case in IBSS mode.
*/ if (!conf->ibss_creator && conf->enable_beacon)
set_bit(ATH_OP_BEACONS, &common->op_flags);
}
/* * 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;
/* Update the beacon configuration. */
ath9k_cache_beacon_config(sc, ctx, main_vif);
/* * Configure the HW beacon registers only when we have a valid * beacon interval.
*/ if (cur_conf->beacon_interval) { /* Special case to sync the TSF when joining an existing IBSS. * This is only done if no AP interface is active. * Note that mac80211 always resets the TSF when creating a new * IBSS interface.
*/ if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
!enabled && beacons && !main_vif->cfg.ibss_creator) {
spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
skip_beacon = true;
}
/* * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode * here, it is done in ath9k_beacon_config_adhoc().
*/ if (beacons && !skip_beacon) {
set_bit(ATH_OP_BEACONS, &common->op_flags);
ath9k_set_beacon(sc);
} else {
clear_bit(ATH_OP_BEACONS, &common->op_flags);
ath9k_beacon_stop(sc);
}
} else {
clear_bit(ATH_OP_BEACONS, &common->op_flags);
ath9k_beacon_stop(sc);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.