diff options
author | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-05 10:12:53 +0000 |
---|---|---|
committer | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-05 10:12:53 +0000 |
commit | 5c105d9f3fd086aff195d3849dcf847d6b0bd927 (patch) | |
tree | 1229a11f725bfa58aa7c57a76898553bb5f6654a /package/madwifi/patches/389-autochannel.patch | |
download | openwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.tar.gz openwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.zip |
branch Attitude Adjustment
git-svn-id: svn://svn.openwrt.org/openwrt/branches/attitude_adjustment@33625 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/madwifi/patches/389-autochannel.patch')
-rw-r--r-- | package/madwifi/patches/389-autochannel.patch | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/package/madwifi/patches/389-autochannel.patch b/package/madwifi/patches/389-autochannel.patch new file mode 100644 index 000000000..548f09e7d --- /dev/null +++ b/package/madwifi/patches/389-autochannel.patch @@ -0,0 +1,249 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -384,6 +384,7 @@ static u_int32_t ath_get_real_maxtxpower + + static void ath_poll_disable(struct net_device *dev); + static void ath_poll_enable(struct net_device *dev); ++static void ath_fetch_idle_time(struct ath_softc *sc); + + /* calibrate every 30 secs in steady state but check every second at first. */ + static int ath_calinterval = ATH_SHORT_CALINTERVAL; +@@ -2581,6 +2582,7 @@ ath_init(struct net_device *dev) + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ ++ ath_fetch_idle_time(sc); + sc->sc_curchan.channel = ic->ic_curchan->ic_freq; + sc->sc_curchan.channelFlags = ath_chan2flags(ic->ic_curchan); + if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) { +@@ -2914,6 +2916,48 @@ ath_hw_check_atim(struct ath_softc *sc, + return 0; + } + ++#define AR5K_MIBC 0x0040 ++#define AR5K_MIBC_FREEZE (1 << 1) ++#define AR5K_TXFC 0x80ec ++#define AR5K_RXFC 0x80f0 ++#define AR5K_RXCLEAR 0x80f4 ++#define AR5K_CYCLES 0x80f8 ++static void ++ath_fetch_idle_time(struct ath_softc *sc) ++{ ++ struct ieee80211com *ic = &sc->sc_ic; ++ struct ath_hal *ah = sc->sc_ah; ++ u_int32_t cc, rx; ++ u_int32_t time = 0; ++ ++ if (sc->sc_ah->ah_macType < 5212) ++ return; ++ ++ if (!ic->ic_curchan || (ic->ic_curchan == IEEE80211_CHAN_ANYC)) ++ return; ++ ++ OS_REG_WRITE(ah, AR5K_MIBC, AR5K_MIBC_FREEZE); ++ rx = OS_REG_READ(ah, AR5K_RXCLEAR); ++ cc = OS_REG_READ(ah, AR5K_CYCLES); ++ ++ if (!cc) ++ return; ++ ++ if (rx > cc) ++ return; /* should not happen */ ++ ++ if (sc->sc_last_chan) ++ sc->sc_last_chan->ic_idletime = 100 * (cc - rx) / cc; ++ sc->sc_last_chan = ic->ic_curchan; ++ ++ OS_REG_WRITE(ah, AR5K_RXCLEAR, 0); ++ OS_REG_WRITE(ah, AR5K_CYCLES, 0); ++ OS_REG_WRITE(ah, AR5K_TXFC, 0); ++ OS_REG_WRITE(ah, AR5K_RXFC, 0); ++ OS_REG_WRITE(ah, AR5K_MIBC, 0); ++} ++#undef AR5K_RXCLEAR ++#undef AR5K_CYCLES + + /* + * Reset the hardware w/o losing operational state. This is +@@ -2941,6 +2985,7 @@ ath_reset(struct net_device *dev) + * Convert to a HAL channel description with the flags + * constrained to reflect the current operating mode. + */ ++ ath_fetch_idle_time(sc); + c = ic->ic_curchan; + sc->sc_curchan.channel = c->ic_freq; + sc->sc_curchan.channelFlags = ath_chan2flags(c); +@@ -9023,6 +9068,7 @@ ath_chan_set(struct ath_softc *sc, struc + u_int8_t channel_change_required = 0; + struct timeval tv; + ++ + /* + * Convert to a HAL channel description with + * the flags constrained to reflect the current +@@ -9031,6 +9077,14 @@ ath_chan_set(struct ath_softc *sc, struc + memset(&hchan, 0, sizeof(HAL_CHANNEL)); + hchan.channel = chan->ic_freq; + hchan.channelFlags = ath_chan2flags(chan); ++ ++ /* don't do duplicate channel changes, but do ++ * store the available idle time */ ++ ath_fetch_idle_time(sc); ++ if ((sc->sc_curchan.channel == hchan.channel) && ++ (sc->sc_curchan.channelFlags == hchan.channelFlags)) ++ return 0; ++ + KASSERT(hchan.channel != 0, + ("bogus channel %u/0x%x", hchan.channel, hchan.channelFlags)); + do_gettimeofday(&tv); +--- a/ath/if_athvar.h ++++ b/ath/if_athvar.h +@@ -774,6 +774,7 @@ struct ath_softc { + struct ieee80211vap **sc_bslot; /* beacon xmit slots */ + int sc_bnext; /* next slot for beacon xmit */ + ++ struct ieee80211_channel *sc_last_chan; + int sc_beacon_cal; /* use beacon timer for calibration */ + u_int64_t sc_lastcal; /* last time the calibration was performed */ + struct timer_list sc_cal_ch; /* calibration timer */ +--- a/net80211/_ieee80211.h ++++ b/net80211/_ieee80211.h +@@ -148,6 +148,7 @@ struct ieee80211_channel { + int8_t ic_maxpower; /* maximum tx power in dBm */ + int8_t ic_minpower; /* minimum tx power in dBm */ + u_int8_t ic_scanflags; ++ u_int8_t ic_idletime; /* phy idle time in % */ + }; + + #define IEEE80211_CHAN_MAX 255 +--- a/net80211/ieee80211_scan_ap.c ++++ b/net80211/ieee80211_scan_ap.c +@@ -417,6 +417,19 @@ pc_cmp_rssi(struct ap_state *as, struct + + /* This function must be invoked with locks acquired */ + static int ++pc_cmp_idletime(struct ieee80211_channel *a, ++ struct ieee80211_channel *b) ++{ ++ if (!a->ic_idletime || !b->ic_idletime) ++ return 0; ++ ++ /* a is better than b (return < 0) when a has more idle time than b */ ++ return b->ic_idletime - a->ic_idletime; ++} ++ ++ ++/* This function must be invoked with locks acquired */ ++static int + pc_cmp_samechan(struct ieee80211com *ic, struct ieee80211_channel *a, + struct ieee80211_channel *b) + { +@@ -451,6 +464,7 @@ pc_cmp(const void *_a, const void *_b) + + EVALUATE_CRITERION(radar, a, b); + EVALUATE_CRITERION(keepmode, params, a, b); ++ EVALUATE_CRITERION(idletime, a, b); + EVALUATE_CRITERION(sc, ic, a, b); + /* XXX: rssi useless? pick_channel evaluates it anyway */ + EVALUATE_CRITERION(rssi, params->ss->ss_priv, a, b); +@@ -519,16 +533,9 @@ pick_channel(struct ieee80211_scan_state + #endif + + best = NULL; +- best_rssi = 0xff; /* If signal is bigger than 0xff, we'd be melting. */ + + for (i = 0; i < ss_last; i++) { + c = &chans[i]; +- benefit = best_rssi - as->as_maxrssi[c->chan->ic_ieee]; +- sta_assoc = ic->ic_sta_assoc; +- +- /* Don't switch... */ +- if (benefit <= 0) +- continue; + + /* Verify channel is not marked for non-occupancy */ + if (IEEE80211_IS_CHAN_RADAR(c->chan)) +@@ -546,31 +553,8 @@ pick_channel(struct ieee80211_scan_state + break; + } + +- if (sta_assoc != 0) { +- int sl = ic->ic_cn_total - +- ic->ic_chan_nodes[c->chan->ic_ieee]; /* count */ +- if (ic->ic_sc_algorithm == IEEE80211_SC_LOOSE) { +- int sl_max = ic->ic_sc_sldg * benefit; +- sl = 1000 * sl / sta_assoc; /* permil */ +- IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, +- "%s: chan %d, dB gained: %d, " +- "STAs lost: %d permil (max %d)\n", +- __func__, c->chan->ic_ieee, +- benefit, sl, sl_max); +- if (sl > sl_max) +- continue; +- } else if (((ic->ic_sc_algorithm == +- IEEE80211_SC_TIGHT) || +- (ic->ic_sc_algorithm == +- IEEE80211_SC_STRICT)) && +- (sl > 0)) { +- /* Break the loop as the subsequent chans +- * won't be better. */ +- break; +- } +- } + best = c->chan; +- best_rssi = as->as_maxrssi[best->ic_ieee]; ++ break; + } + + if (best != NULL) { +@@ -599,6 +583,9 @@ ap_end(struct ieee80211_scan_state *ss, + ("wrong opmode %u", vap->iv_opmode)); + + ic = vap->iv_ic; ++ ++ /* record stats for the channel that was scanned last */ ++ ic->ic_set_channel(ic); + bestchan = pick_channel(ss, vap, flags); + if (bestchan == NULL) { + if (ss->ss_last > 0) { +--- a/net80211/ieee80211_scan.c ++++ b/net80211/ieee80211_scan.c +@@ -1002,20 +1002,34 @@ ieee80211_scan_add_channels(struct ieee8 + { + struct ieee80211_channel *c, *cg; + u_int modeflags; ++ int has_non_turbo = 0; + int i; + + KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode)); + modeflags = chanflags[mode]; + for (i = 0; i < ic->ic_nchans; i++) { + c = &ic->ic_channels[i]; ++ if (c->ic_flags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)) ++ continue; ++ ++ has_non_turbo = 1; ++ break; ++ } ++ for (i = 0; i < ic->ic_nchans; i++) { ++ c = &ic->ic_channels[i]; + if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee)) + continue; + if (c->ic_scanflags & IEEE80211_NOSCAN_SET) + continue; +- if (modeflags && +- ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) != +- (modeflags & IEEE80211_CHAN_ALLTURBO))) +- continue; ++ if (modeflags) { ++ if ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) != ++ (modeflags & IEEE80211_CHAN_ALLTURBO)) ++ continue; ++ } else if (has_non_turbo) { ++ if ((ss->ss_vap->iv_opmode == IEEE80211_M_HOSTAP) && ++ (c->ic_flags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO))) ++ continue; ++ } + if (mode == IEEE80211_MODE_AUTO) { + /* + * XXX special-case 11b/g channels so we select |