aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2009-03-25 01:26:44 +0000
committerFelix Fietkau <nbd@openwrt.org>2009-03-25 01:26:44 +0000
commit47e127477beb4ade5ef26b67ee7a73f831bee1fc (patch)
treee86155fbe48eeb9589b81fafbc42438d296fb4fd
parent4f42b6112e4091c489500879377130a58988c05b (diff)
downloadupstream-47e127477beb4ade5ef26b67ee7a73f831bee1fc.tar.gz
upstream-47e127477beb4ade5ef26b67ee7a73f831bee1fc.tar.bz2
upstream-47e127477beb4ade5ef26b67ee7a73f831bee1fc.zip
madwifi: rework tx power handling, don't clamp user-configured tx power limit based on current channel properties
SVN-Revision: 15031
-rw-r--r--package/madwifi/patches/414-txpower.patch243
1 files changed, 243 insertions, 0 deletions
diff --git a/package/madwifi/patches/414-txpower.patch b/package/madwifi/patches/414-txpower.patch
new file mode 100644
index 0000000000..3e7e315d11
--- /dev/null
+++ b/package/madwifi/patches/414-txpower.patch
@@ -0,0 +1,243 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -270,6 +270,7 @@ ieee80211_ifattach(struct ieee80211com *
+ ("invalid number of channels specified: %u", ic->ic_nchans));
+ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
+ ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO;
++ ic->ic_max_txpower = IEEE80211_TXPOWER_MIN;
+
+ for (i = 0; i < ic->ic_nchans; i++) {
+ c = &ic->ic_channels[i];
+@@ -277,6 +278,7 @@ ieee80211_ifattach(struct ieee80211com *
+ KASSERT(c->ic_ieee < IEEE80211_CHAN_MAX,
+ ("channel with bogus ieee number %u", c->ic_ieee));
+ setbit(ic->ic_chan_avail, c->ic_ieee);
++ ic->ic_max_txpower = max(ic->ic_max_txpower, (u16) c->ic_maxpower * 2);
+
+ if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT)
+ c->ic_scanflags |= IEEE80211_NOSCAN_SET;
+@@ -346,8 +348,6 @@ ieee80211_ifattach(struct ieee80211com *
+ TAILQ_INIT(&ic->ic_vaps);
+
+ ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
+- ic->ic_txpowlimit = IEEE80211_TXPOWER_MIN;
+- ic->ic_newtxpowlimit = IEEE80211_TXPOWER_MAX;
+
+ init_timer(&ic->ic_dfs_excl_timer);
+ ic->ic_dfs_excl_timer.function =
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -1125,7 +1125,7 @@ ieee80211_alloc_node(struct ieee80211vap
+
+ ni->ni_chan = IEEE80211_CHAN_ANYC;
+ ni->ni_authmode = IEEE80211_AUTH_OPEN;
+- ni->ni_txpower = ic->ic_txpowlimit;
++ ni->ni_txpower = IEEE80211_TXPOWER_MAX;
+
+ ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey,
+ IEEE80211_KEYIX_NONE);
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -343,8 +343,9 @@ struct ieee80211com {
+ u_int16_t ic_holdover; /* PM hold over duration */
+ u_int16_t ic_bmissthreshold; /* beacon miss threshold (# beacons) */
+ unsigned long ic_bmiss_guard; /* when to cease ignoring bmiss (jiffies) */
+- u_int16_t ic_txpowlimit; /* global tx power limit (in 0.5 dBm) */
+- u_int16_t ic_newtxpowlimit; /* tx power limit to change to (in 0.5 dBm) */
++ u_int16_t ic_txpowlimit; /* configured global tx power limit (in 0.5 dBm) */
++ u_int16_t ic_max_txpower; /* global hardware tx power limit */
++ u_int16_t ic_cur_txpower; /* current tx power */
+ u_int16_t ic_uapsdmaxtriggers; /* max triggers that could arrive */
+ u_int8_t ic_coverageclass; /* coverage class */
+ u_int8_t ic_protmode_rssi; /* rssi threshold for protection mode */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -920,17 +920,23 @@ ieee80211_ioctl_giwrange(struct net_devi
+ u_int8_t reported[IEEE80211_CHAN_BYTES]; /* XXX stack usage? */
+ int i, r;
+ int step = 0;
++ u_int16_t power;
+
+ data->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
++ power = ic->ic_max_txpower;
++ if (ic->ic_bsschan && (ic->ic_bsschan != IEEE80211_CHAN_ANYC))
++ power = min(power, ic->ic_bsschan->ic_maxpower);
++
+ /* txpower (128 values, but will print out only IW_MAX_TXPOWER) */
+- range->num_txpower = (ic->ic_txpowlimit >= 8) ? IW_MAX_TXPOWER : ic->ic_txpowlimit;
+- step = ic->ic_txpowlimit / (2 * (IW_MAX_TXPOWER - 1));
++ power /= 2; /* Unit: 0.5 dBm */
++ range->num_txpower = (power >= 8) ? IW_MAX_TXPOWER : power;
++ step = power / (IW_MAX_TXPOWER - 1);
+
+ range->txpower[0] = 0;
+ for (i = 1; i < IW_MAX_TXPOWER; i++)
+- range->txpower[i] = (ic->ic_txpowlimit/2)
++ range->txpower[i] = power
+ - (IW_MAX_TXPOWER - i - 1) * step;
+
+ range->txpower_capa = IW_TXPOW_DBM;
+@@ -1382,10 +1388,8 @@ ieee80211_ioctl_siwtxpow(struct net_devi
+ disabled = (fixed && vap->iv_bss->ni_txpower == 0);
+ if (rrq->disabled) {
+ if (!disabled) {
+- if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
+- return -EOPNOTSUPP;
+ ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+- vap->iv_bss->ni_txpower = 0;
++ ic->ic_txpowlimit = 0;
+ goto done;
+ }
+ return 0;
+@@ -1396,30 +1400,12 @@ ieee80211_ioctl_siwtxpow(struct net_devi
+ return -EOPNOTSUPP;
+ if (rrq->flags != IW_TXPOW_DBM)
+ return -EINVAL;
+- if (ic->ic_bsschan != IEEE80211_CHAN_ANYC) {
+- if ((ic->ic_bsschan->ic_maxregpower >= rrq->value) &&
+- (ic->ic_txpowlimit/2 >= rrq->value)) {
+- vap->iv_bss->ni_txpower = 2 * rrq->value;
+- ic->ic_newtxpowlimit = 2 * rrq->value;
+- ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+- } else
+- return -EINVAL;
+- } else {
+- /*
+- * No channel set yet
+- */
+- if (ic->ic_txpowlimit/2 >= rrq->value) {
+- vap->iv_bss->ni_txpower = 2 * rrq->value;
+- ic->ic_newtxpowlimit = 2 * rrq->value;
+- ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+- }
+- else
+- return -EINVAL;
+- }
++ ic->ic_txpowlimit = 2 * rrq->value;
++ ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+ } else {
+ if (!fixed) /* no change */
+ return 0;
+- ic->ic_newtxpowlimit = IEEE80211_TXPOWER_MAX;
++ ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
+ ic->ic_flags &= ~IEEE80211_F_TXPOW_FIXED;
+ }
+ done:
+@@ -1588,9 +1574,22 @@ ieee80211_ioctl_giwtxpow(struct net_devi
+ {
+ struct ieee80211vap *vap = dev->priv;
+ struct ieee80211com *ic = vap->iv_ic;
+-
+- rrq->value = vap->iv_bss->ni_txpower / 2;
+- rrq->fixed = (ic->ic_flags & IEEE80211_F_TXPOW_FIXED) != 0;
++ unsigned int power = ic->ic_txpowlimit;
++ struct ieee80211_channel *c;
++ u_int16_t txp = ic->ic_max_txpower;
++
++ if (ic->ic_bsschan && (ic->ic_bsschan != IEEE80211_CHAN_ANYC))
++ txp = min(txp, ic->ic_bsschan->ic_maxpower);
++ } else if (ic->ic_cur_txpower > 0) {
++ txp = min(txp, ic->ic_cur_txpower);
++ }
++ if (ic->ic_flags & IEEE80211_F_TXPOW_FIXED) {
++ txp = min(txp, ic->ic_txpowlimit);
++ rrq->fixed = 1;
++ } else {
++ rrq->fixed = 0;
++ }
++ rrq->value = txp / 2;
+ rrq->disabled = (rrq->fixed && rrq->value == 0);
+ rrq->flags = IW_TXPOW_DBM;
+ return 0;
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -380,7 +380,6 @@ static unsigned int ath_dump_hal_map(str
+ static u_int32_t ath_get_clamped_maxtxpower(struct ath_softc *sc);
+ static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc,
+ u_int32_t new_clamped_maxtxpower);
+-static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc);
+
+ static void ath_poll_disable(struct net_device *dev);
+ static void ath_poll_enable(struct net_device *dev);
+@@ -3159,7 +3158,7 @@ ath_tx_startraw(struct net_device *dev,
+ try0 = ph->try0;
+ rt = sc->sc_currates;
+ txrate = dot11_to_ratecode(sc, rt, ph->rate0);
+- power = ph->power > 60 ? 60 : ph->power;
++ power = ph->power > 63 ? 63 : ph->power;
+ hdrlen = ieee80211_anyhdrsize(wh);
+ pktlen = skb->len + IEEE80211_CRC_LEN;
+
+@@ -8381,7 +8380,7 @@ ath_tx_start(struct net_device *dev, str
+ pktlen, /* packet length */
+ hdrlen, /* header length */
+ atype, /* Atheros packet type */
+- MIN(ni->ni_txpower, 60), /* txpower */
++ MIN(ni->ni_txpower, 63), /* txpower */
+ txrate, try0, /* series 0 rate/tries */
+ keyix, /* key cache index */
+ antenna, /* antenna mode */
+@@ -10364,59 +10363,16 @@ ath_get_clamped_maxtxpower(struct ath_so
+
+ /* XXX: this function needs some locking to avoid being called
+ * twice/interrupted */
+-/* 1. Save the currently specified maximum txpower (as clamped by madwifi)
+- * 2. Determine the real maximum txpower the card can support by
+- * setting a value that exceeds the maximum range (by one) and
+- * finding out what it limits us to.
+- * 3. Restore the saved maxtxpower value we had previously specified */
+-static u_int32_t
+-ath_get_real_maxtxpower(struct ath_softc *sc)
+-{
+- u_int32_t saved_clamped_maxtxpower;
+- u_int32_t real_maxtxpower;
+-
+- saved_clamped_maxtxpower = ath_get_clamped_maxtxpower(sc);
+- real_maxtxpower =
+- ath_set_clamped_maxtxpower(sc, IEEE80211_TXPOWER_MAX + 1);
+- ath_set_clamped_maxtxpower(sc, saved_clamped_maxtxpower);
+- return real_maxtxpower;
+-}
+-
+-
+-/* XXX: this function needs some locking to avoid being called
+- * twice/interrupted */
+ static void
+ ath_update_txpow(struct ath_softc *sc)
+ {
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = NULL;
+ struct ath_hal *ah = sc->sc_ah;
+- u_int32_t prev_clamped_maxtxpower = 0;
+- u_int32_t new_clamped_maxtxpower = 0;
+
+ /* Determine the previous value of maxtxpower */
+- prev_clamped_maxtxpower = ath_get_clamped_maxtxpower(sc);
+- /* Determine the real maximum txpower the card can support */
+- ic->ic_txpowlimit = ath_get_real_maxtxpower(sc);
+- /* Grab the new maxtxpower setting (which may have changed) */
+- new_clamped_maxtxpower = ic->ic_newtxpowlimit;
+- /* Make sure the change is within limits, clamp it otherwise */
+- if (ic->ic_newtxpowlimit > ic->ic_txpowlimit)
+- new_clamped_maxtxpower = ic->ic_txpowlimit;
+- /* Search for the VAP that needs a txpow change, if any */
+- TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+- if (!tpc || ic->ic_newtxpowlimit != vap->iv_bss->ni_txpower) {
+- vap->iv_bss->ni_txpower = new_clamped_maxtxpower;
+- ieee80211_iterate_nodes(&vap->iv_ic->ic_sta,
+- set_node_txpower,
+- &new_clamped_maxtxpower);
+- }
+- }
+-
+- /* Store the assigned (clamped) maximum txpower and update the HAL */
+- sc->sc_curtxpow = new_clamped_maxtxpower;
+- if (new_clamped_maxtxpower != prev_clamped_maxtxpower)
+- ath_hal_settxpowlimit(ah, new_clamped_maxtxpower);
++ ath_set_clamped_maxtxpower(sc, ic->ic_txpowlimit);
++ ic->ic_cur_txpower = ath_get_clamped_maxtxpower(sc);
+ }
+
+ #ifdef ATH_SUPERG_XR