aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c2
-rw-r--r--sys/dev/rtwn/rtl8188e/r88e_chan.c34
-rw-r--r--sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c2
-rw-r--r--sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c2
-rw-r--r--sys/dev/rtwn/rtl8192c/r92c.h1
-rw-r--r--sys/dev/rtwn/rtl8192c/r92c_chan.c31
-rw-r--r--sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c2
-rw-r--r--sys/dev/rtwn/rtl8192e/r92e.h1
-rw-r--r--sys/dev/rtwn/rtl8192e/r92e_chan.c48
-rw-r--r--sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c2
10 files changed, 107 insertions, 18 deletions
diff --git a/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c b/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c
index e4c0027c39a5..d8c0a98e43a3 100644
--- a/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c
+++ b/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c
@@ -191,7 +191,7 @@ r88ee_attach(struct rtwn_pci_softc *pc)
sc->sc_init_antsel = rtwn_nop_softc;
sc->sc_post_init = r88ee_post_init;
sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc;
- sc->sc_set_tx_power = rtwn_nop_int_softc_vap;
+ sc->sc_set_tx_power = r92c_set_tx_power;
sc->mac_prog = &rtl8188e_mac[0];
sc->mac_size = nitems(rtl8188e_mac);
diff --git a/sys/dev/rtwn/rtl8188e/r88e_chan.c b/sys/dev/rtwn/rtl8188e/r88e_chan.c
index 51474bc1b819..f91862720639 100644
--- a/sys/dev/rtwn/rtl8188e/r88e_chan.c
+++ b/sys/dev/rtwn/rtl8188e/r88e_chan.c
@@ -84,6 +84,7 @@ void
r88e_get_txpower(struct rtwn_softc *sc, int chain,
struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT])
{
+ const struct ieee80211com *ic = &sc->sc_ic;
struct r92c_softc *rs = sc->sc_priv;
const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr;
uint8_t cckpow, ofdmpow, bw20pow, htpow = 0;
@@ -96,15 +97,36 @@ r88e_get_txpower(struct rtwn_softc *sc, int chain,
return;
}
- /* XXX net80211 regulatory */
+ /*
+ * Treat the entries in 1/2 dBm resolution where 0 = 0dBm.
+ * Apply the adjustments afterwards; assume that the vendor
+ * driver is applying offsets to make up for the actual
+ * target power in dBm.
+ */
max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1);
KASSERT(max_mcs <= RTWN_RIDX_LEGACY_HT_COUNT, ("increase ridx limit\n"));
/* Compute per-CCK rate Tx power. */
- cckpow = rt->cck_tx_pwr[group];
for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) {
- power[ridx] = (ridx == RTWN_RIDX_CCK2) ? cckpow - 9 : cckpow;
+ /*
+ * Note: the regulatory limit is applied to cckpow before
+ * it's subtracted for CCK2.
+ */
+ cckpow = rt->cck_tx_pwr[group];
+ if (cckpow > ic->ic_txpowlimit)
+ cckpow = ic->ic_txpowlimit;
+
+ /*
+ * If it's CCK2 then we subtract the 9 (4.5dB?) offset
+ * and make sure we aren't going to underflow.
+ */
+ if (ridx == RTWN_RIDX_CCK2 && cckpow < 9)
+ cckpow = 0;
+ else if (ridx == RTWN_RIDX_CCK2)
+ cckpow = cckpow - 9;
+
+ power[ridx] = cckpow;
}
if (group < 5)
@@ -112,14 +134,18 @@ r88e_get_txpower(struct rtwn_softc *sc, int chain,
/* Compute per-OFDM rate Tx power. */
ofdmpow = htpow + rt->ofdm_tx_pwr_diff;
+ if (ofdmpow > ic->ic_txpowlimit)
+ ofdmpow = ic->ic_txpowlimit;
for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
power[ridx] = ofdmpow;
bw20pow = htpow + rt->bw20_tx_pwr_diff;
+ if (bw20pow > ic->ic_txpowlimit)
+ bw20pow = ic->ic_txpowlimit;
for (ridx = RTWN_RIDX_HT_MCS(0); ridx <= max_mcs; ridx++)
power[ridx] = bw20pow;
- /* Apply max limit. */
+ /* Apply max limit */
for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) {
if (power[ridx] > R92C_MAX_TX_PWR)
power[ridx] = R92C_MAX_TX_PWR;
diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
index 400c0a148f35..752761415bce 100644
--- a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
+++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
@@ -184,7 +184,7 @@ r88eu_attach(struct rtwn_usb_softc *uc)
sc->sc_init_antsel = rtwn_nop_softc;
sc->sc_post_init = r88eu_post_init;
sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc;
- sc->sc_set_tx_power = rtwn_nop_int_softc_vap;
+ sc->sc_set_tx_power = r92c_set_tx_power;
sc->mac_prog = &rtl8188e_mac[0];
sc->mac_size = nitems(rtl8188e_mac);
diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c
index e992f1c50f26..ddb9fa9ae8c1 100644
--- a/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c
+++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c
@@ -221,7 +221,7 @@ r92ce_attach(struct rtwn_pci_softc *pc)
sc->sc_init_antsel = rtwn_nop_softc;
sc->sc_post_init = r92ce_post_init;
sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc;
- sc->sc_set_tx_power = rtwn_nop_int_softc_vap;
+ sc->sc_set_tx_power = r92c_set_tx_power;
sc->mac_prog = &rtl8192ce_mac[0];
sc->mac_size = nitems(rtl8192ce_mac);
diff --git a/sys/dev/rtwn/rtl8192c/r92c.h b/sys/dev/rtwn/rtl8192c/r92c.h
index 759a946dac3c..c602f314825a 100644
--- a/sys/dev/rtwn/rtl8192c/r92c.h
+++ b/sys/dev/rtwn/rtl8192c/r92c.h
@@ -59,6 +59,7 @@ void r92c_get_txpower(struct rtwn_softc *, int,
struct ieee80211_channel *, uint8_t[RTWN_RIDX_COUNT]);
void r92c_write_txpower(struct rtwn_softc *, int,
uint8_t power[RTWN_RIDX_COUNT]);
+int r92c_set_tx_power(struct rtwn_softc *, struct ieee80211vap *);
void r92c_set_bw20(struct rtwn_softc *, uint8_t);
void r92c_set_chan(struct rtwn_softc *, struct ieee80211_channel *);
void r92c_set_gain(struct rtwn_softc *, uint8_t);
diff --git a/sys/dev/rtwn/rtl8192c/r92c_chan.c b/sys/dev/rtwn/rtl8192c/r92c_chan.c
index 5404ad4a81bf..f93159a3c94e 100644
--- a/sys/dev/rtwn/rtl8192c/r92c_chan.c
+++ b/sys/dev/rtwn/rtl8192c/r92c_chan.c
@@ -131,6 +131,7 @@ void
r92c_get_txpower(struct rtwn_softc *sc, int chain,
struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT])
{
+ const struct ieee80211com *ic = &sc->sc_ic;
struct r92c_softc *rs = sc->sc_priv;
struct rtwn_r92c_txpwr *rt = rs->rs_txpwr;
const struct rtwn_r92c_txagc *base = rs->rs_txagc;
@@ -144,7 +145,12 @@ r92c_get_txpower(struct rtwn_softc *sc, int chain,
return;
}
- /* XXX net80211 regulatory */
+ /*
+ * Treat the entries in 1/2 dBm resolution where 0 = 0dBm.
+ * Apply the adjustments afterwards; assume that the vendor
+ * driver is applying offsets to make up for the actual
+ * target power in dBm.
+ */
max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1);
KASSERT(max_mcs <= RTWN_RIDX_LEGACY_HT_COUNT, ("increase ridx limit\n"));
@@ -199,6 +205,10 @@ r92c_get_txpower(struct rtwn_softc *sc, int chain,
for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) {
if (power[ridx] > R92C_MAX_TX_PWR)
power[ridx] = R92C_MAX_TX_PWR;
+ /* Apply net80211 limits */
+ if (power[ridx] > ic->ic_txpowlimit)
+ power[ridx] = ic->ic_txpowlimit;
+
}
}
@@ -281,6 +291,25 @@ r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c)
}
}
+/*
+ * Only reconfigure the transmit power if there's a valid BSS node and
+ * channel. Otherwise just let the next call to r92c_set_chan()
+ * configure the transmit power.
+ */
+int
+r92c_set_tx_power(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+ if (vap->iv_bss == NULL)
+ return (EINVAL);
+ if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
+ return (EINVAL);
+
+ /* Set it for the current channel */
+ r92c_set_txpower(sc, vap->iv_bss->ni_chan);
+
+ return (0);
+}
+
static void
r92c_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo)
{
diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
index 6482c933eec2..8e9c4987a359 100644
--- a/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
+++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
@@ -213,7 +213,7 @@ r92cu_attach(struct rtwn_usb_softc *uc)
sc->sc_init_antsel = r92c_init_antsel;
sc->sc_post_init = r92cu_post_init;
sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc;
- sc->sc_set_tx_power = rtwn_nop_int_softc_vap;
+ sc->sc_set_tx_power = r92c_set_tx_power;
sc->mac_prog = &rtl8192cu_mac[0];
sc->mac_size = nitems(rtl8192cu_mac);
diff --git a/sys/dev/rtwn/rtl8192e/r92e.h b/sys/dev/rtwn/rtl8192e/r92e.h
index 331750c48726..280cc1464ac6 100644
--- a/sys/dev/rtwn/rtl8192e/r92e.h
+++ b/sys/dev/rtwn/rtl8192e/r92e.h
@@ -46,6 +46,7 @@ void r92e_detach_private(struct rtwn_softc *);
/* r92e_chan.c */
void r92e_set_chan(struct rtwn_softc *, struct ieee80211_channel *);
+int r92e_set_tx_power(struct rtwn_softc *sc, struct ieee80211vap *vap);
/* r92e_fw.c */
#ifndef RTWN_WITHOUT_UCODE
diff --git a/sys/dev/rtwn/rtl8192e/r92e_chan.c b/sys/dev/rtwn/rtl8192e/r92e_chan.c
index 4c761f61809d..4c7121a80c89 100644
--- a/sys/dev/rtwn/rtl8192e/r92e_chan.c
+++ b/sys/dev/rtwn/rtl8192e/r92e_chan.c
@@ -90,6 +90,7 @@ static void
r92e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c,
uint8_t power[RTWN_RIDX_COUNT])
{
+ const struct ieee80211com *ic = &sc->sc_ic;
struct r92e_softc *rs = sc->sc_priv;
int i, ridx, group, max_mcs;
@@ -103,19 +104,32 @@ r92e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c,
max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1);
/* XXX regulatory */
- /* XXX net80211 regulatory */
- for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
+ for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) {
power[ridx] = rs->cck_tx_pwr[chain][group];
- for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++)
+ if (power[ridx] > ic->ic_txpowlimit)
+ power[ridx] = ic->ic_txpowlimit;
+ }
+ for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) {
power[ridx] = rs->ht40_tx_pwr_2g[chain][group];
+ if (power[ridx] > ic->ic_txpowlimit)
+ power[ridx] = ic->ic_txpowlimit;
+ }
+
+ for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) {
+ /* Ensure we don't underflow if the power delta is -ve */
+ int8_t pwr;
- for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
- power[ridx] += rs->ofdm_tx_pwr_diff_2g[chain][0];
+ pwr = power[ridx] + rs->ofdm_tx_pwr_diff_2g[chain][0];
+ if (pwr < 0)
+ pwr = 0;
+
+ power[ridx] = pwr;
+ }
for (i = 0; i < sc->ntxchains; i++) {
uint8_t min_mcs;
- uint8_t pwr_diff;
+ int8_t pwr_diff, pwr;
if (IEEE80211_IS_CHAN_HT40(c))
pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i];
@@ -123,8 +137,13 @@ r92e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c,
pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i];
min_mcs = RTWN_RIDX_HT_MCS(i * 8);
- for (ridx = min_mcs; ridx <= max_mcs; ridx++)
- power[ridx] += pwr_diff;
+ for (ridx = min_mcs; ridx <= max_mcs; ridx++) {
+ /* Ensure we don't underflow */
+ pwr = power[ridx] + pwr_diff;
+ if (pwr < 0)
+ pwr = 0;
+ power[ridx] = pwr;
+ }
}
/* Apply max limit. */
@@ -151,6 +170,19 @@ r92e_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c)
}
}
+int
+r92e_set_tx_power(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+
+ if (vap->iv_bss == NULL)
+ return (EINVAL);
+ if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
+ return (EINVAL);
+
+ r92e_set_txpower(sc, vap->iv_bss->ni_chan);
+ return (0);
+}
+
static void
r92e_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo)
{
diff --git a/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c b/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c
index c134ba22a430..35ff5cb65853 100644
--- a/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c
+++ b/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c
@@ -164,7 +164,7 @@ r92eu_attach(struct rtwn_usb_softc *uc)
sc->sc_init_antsel = rtwn_nop_softc;
sc->sc_post_init = r92eu_post_init;
sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc;
- sc->sc_set_tx_power = rtwn_nop_int_softc_vap;
+ sc->sc_set_tx_power = r92e_set_tx_power;
sc->mac_prog = &rtl8192eu_mac[0];
sc->mac_size = nitems(rtl8192eu_mac);