[ath] [ath_rate] Fix ANI calibration during non-ACTIVE states; start poking at rate control
These are some fun issues I've found with my upstairs wifi link at such a ridiculous low signal level (like, < 5dB.) * Add per-station tx/rx rssi statistics, in potential preparation to use that in the RX rate control. * Call the rate control on each received frame to let it potentially use it as a hint for what rates to potentially use. It's a no-op right now. * Do ANI calibration during scan as well. The ath_newstate() call was disabling the ANI timer and only re-enabling it during transitions to _RUN. This has the unfortunate side-effect that if ANI deafened the NIC because of interference and it disassociated, it wouldn't be reset and the scan would never hear beacons. The ANI configuration is stored at least globally on some HALs and per-channel on others. Because of this a NIC reset wouldn't help; the ANI parameters would simply be programmed back in. Now, I have a feeling I also need to do this during AUTH/ASSOC too and maybe, if I'm feeling clever, I need to reset the ANI parameters on a given channel during a transition through INIT or if the VAP is destroyed/re-created. However for now this gets me out of the immediate weeds with connectivity upstairs (and thus I /can/ commit); I'll keep chipping away at tidying this stuff up in subsequent commits. Tested: * AR9344 (Wasp), 2G STA mode
This commit is contained in:
parent
e786d5adfb
commit
c8d5298b87
@ -196,6 +196,11 @@ ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
|
||||
ath_rate_ctl_start(sc, &an->an_node);
|
||||
}
|
||||
|
||||
void
|
||||
ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
node_reset(struct amrr_node *amn)
|
||||
{
|
||||
|
@ -189,6 +189,12 @@ ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
|
||||
ath_rate_ctl_start(sc, &an->an_node);
|
||||
}
|
||||
|
||||
void
|
||||
ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate)
|
||||
{
|
||||
|
@ -1019,6 +1019,12 @@ ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
|
||||
ath_rate_ctl_reset(sc, &an->an_node);
|
||||
}
|
||||
|
||||
void
|
||||
ath_rate_update_rx_rssi(struct ath_softc *sc, struct ath_node *an, int rssi)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = {
|
||||
NULL, /* IEEE80211_MODE_AUTO */
|
||||
series_11a, /* IEEE80211_MODE_11A */
|
||||
|
@ -3882,6 +3882,10 @@ ath_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
|
||||
/* XXX setup ath_tid */
|
||||
ath_tx_tid_init(sc, an);
|
||||
|
||||
an->an_node_stats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
an->an_node_stats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
an->an_node_stats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
||||
DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: an %p\n", __func__, mac, ":", an);
|
||||
return &an->an_node;
|
||||
}
|
||||
@ -4493,6 +4497,8 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
|
||||
sc->sc_stats.ast_tx_rssi = ts->ts_rssi;
|
||||
ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi,
|
||||
ts->ts_rssi);
|
||||
ATH_RSSI_LPF(ATH_NODE(ni)->an_node_stats.ns_avgtxrssi,
|
||||
ts->ts_rssi);
|
||||
}
|
||||
ATH_TXQ_UNLOCK(txq);
|
||||
|
||||
@ -5435,6 +5441,16 @@ ath_calibrate(void *arg)
|
||||
__func__, sc->sc_curchan->ic_freq);
|
||||
sc->sc_stats.ast_per_calfail++;
|
||||
}
|
||||
/*
|
||||
* XXX TODO: get the NF calibration results from the HAL.
|
||||
* If we failed NF cal then schedule a hard reset to potentially
|
||||
* un-freeze the PHY.
|
||||
*
|
||||
* Note we have to be careful here to not get stuck in an
|
||||
* infinite NIC restart. Ideally we'd not restart if we
|
||||
* failed the first NF cal - that /can/ fail sometimes in
|
||||
* a noisy environment.
|
||||
*/
|
||||
if (shortCal)
|
||||
sc->sc_lastshortcal = ticks;
|
||||
}
|
||||
@ -6090,6 +6106,17 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
|
||||
taskqueue_block(sc->sc_tq);
|
||||
sc->sc_beacons = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For at least STA mode we likely should clear the ANI
|
||||
* and NF calibration state and allow the NIC/HAL to figure
|
||||
* out optimal parameters at runtime. Otherwise if we
|
||||
* disassociate due to interference / deafness it may persist
|
||||
* when we reconnect.
|
||||
*
|
||||
* Note: may need to do this for other states too, not just
|
||||
* _S_INIT.
|
||||
*/
|
||||
#ifdef IEEE80211_SUPPORT_TDMA
|
||||
ath_hal_setcca(ah, AH_TRUE);
|
||||
#endif
|
||||
@ -6119,9 +6146,39 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
|
||||
}
|
||||
ATH_UNLOCK(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note - the ANI/calibration timer isn't re-enabled during
|
||||
* network sleep for now. One unfortunate side-effect is that
|
||||
* the PHY/airtime statistics aren't gathered on the channel
|
||||
* but I haven't yet tested to see if reading those registers
|
||||
* CAN occur during network sleep.
|
||||
*
|
||||
* This should be revisited in a future commit, even if it's
|
||||
* just to split out the airtime polling from ANI/calibration.
|
||||
*/
|
||||
} else if (nstate == IEEE80211_S_SCAN) {
|
||||
/* Quiet time handling - ensure we resync */
|
||||
memset(&avp->quiet_ie, 0, sizeof(avp->quiet_ie));
|
||||
|
||||
/*
|
||||
* If we're in scan mode then startpcureceive() is
|
||||
* hopefully being called with "reset ANI" for this channel;
|
||||
* but once we attempt to reassociate we program in the previous
|
||||
* ANI values and.. not do any calibration until we're running.
|
||||
* This may mean we stay deaf unless we can associate successfully.
|
||||
*
|
||||
* So do kick off the cal timer to get NF/ANI going.
|
||||
*/
|
||||
ATH_LOCK(sc);
|
||||
if (ath_longcalinterval != 0) {
|
||||
/* start periodic recalibration timer */
|
||||
callout_reset(&sc->sc_cal_ch, 1, ath_calibrate, sc);
|
||||
} else {
|
||||
DPRINTF(sc, ATH_DEBUG_CALIBRATE,
|
||||
"%s: calibration disabled\n", __func__);
|
||||
}
|
||||
ATH_UNLOCK(sc);
|
||||
}
|
||||
bad:
|
||||
ieee80211_free_node(ni);
|
||||
|
@ -363,6 +363,11 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
|
||||
ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
|
||||
switch (subtype) {
|
||||
case IEEE80211_FC0_SUBTYPE_BEACON:
|
||||
/*
|
||||
* Always update the per-node beacon RSSI if we're hearing
|
||||
* beacons from that node.
|
||||
*/
|
||||
ATH_RSSI_LPF(ATH_NODE(ni)->an_node_stats.ns_avgbrssi, rssi);
|
||||
|
||||
/*
|
||||
* Only do the following processing if it's for
|
||||
@ -945,6 +950,21 @@ rx_accept:
|
||||
if (ni->ni_flags & IEEE80211_NODE_HT)
|
||||
m->m_flags |= M_AMPDU;
|
||||
|
||||
/*
|
||||
* Inform rate control about the received RSSI.
|
||||
* It can then use this information to potentially drastically
|
||||
* alter the available rate based on the RSSI estimate.
|
||||
*
|
||||
* This is super important when associating to a far away station;
|
||||
* you don't want to waste time trying higher rates at some low
|
||||
* packet exchange rate (like during DHCP) just to establish
|
||||
* that higher MCS rates aren't available.
|
||||
*/
|
||||
ATH_RSSI_LPF(ATH_NODE(ni)->an_node_stats.ns_avgrssi,
|
||||
rs->rs_rssi);
|
||||
ath_rate_update_rx_rssi(sc, ATH_NODE(ni),
|
||||
ATH_RSSI(ATH_NODE(ni)->an_node_stats.ns_avgrssi));
|
||||
|
||||
/*
|
||||
* Sending station is known, dispatch directly.
|
||||
*/
|
||||
@ -973,7 +993,7 @@ rx_accept:
|
||||
*/
|
||||
|
||||
/*
|
||||
* Track rx rssi and do any rx antenna management.
|
||||
* Track legacy station RX rssi and do any rx antenna management.
|
||||
*/
|
||||
ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi);
|
||||
if (sc->sc_diversity) {
|
||||
|
@ -1012,6 +1012,8 @@ ath_edma_tx_processq(struct ath_softc *sc, int dosched)
|
||||
sc->sc_stats.ast_tx_rssi = ts.ts_rssi;
|
||||
ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi,
|
||||
ts.ts_rssi);
|
||||
ATH_RSSI_LPF(ATH_NODE(ni)->an_node_stats.ns_avgtxrssi,
|
||||
ts.ts_rssi);
|
||||
}
|
||||
|
||||
/* Handle frame completion and rate control update */
|
||||
|
@ -156,6 +156,12 @@ void ath_rate_tx_complete(struct ath_softc *, struct ath_node *,
|
||||
const struct ath_rc_series *, const struct ath_tx_status *,
|
||||
int pktlen, int nframes, int nbad);
|
||||
|
||||
/*
|
||||
* Update rate control with a per-packet receive RSSI value.
|
||||
*/
|
||||
void ath_rate_update_rx_rssi(struct ath_softc *, struct ath_node *,
|
||||
int rssi);
|
||||
|
||||
/*
|
||||
* Fetch the global rate control statistics.
|
||||
*/
|
||||
|
@ -204,6 +204,7 @@ struct ath_node {
|
||||
node */
|
||||
int clrdmask; /* has clrdmask been set */
|
||||
uint32_t an_leak_count; /* How many frames to leak during pause */
|
||||
HAL_NODE_STATS an_node_stats; /* HAL node stats for this node */
|
||||
/* variable-length rate control state follows */
|
||||
};
|
||||
#define ATH_NODE(ni) ((struct ath_node *)(ni))
|
||||
|
Loading…
x
Reference in New Issue
Block a user