Skip to content

Commit e04e4b6

Browse files
jonasjelonekkvalo
authored andcommitted
wifi: ath9k: fix per-packet TX-power cap for TPC
Fix incorrect usage of plain rate_idx as index into the max (power) per rate lookup table. For transmit power control (TPC), the ath9k driver maintains internal tables (in struct ath_hw) to store the max allowed power level per rate. They are used to limit a given TX-power according to regulatory and user limits in the TX-path per packet. The tables are filled in a predefined order, starting with values for CCK + OFDM rates and followed by the values for MCS rates. Thus, the maximum power levels for MCS do not start at index 0 in the table but are shifted by a fixed value. The TX-power limiting in ath_get_rate_txpower currently does not apply this shift, thus retrieves the incorrect maximum power level for a given rate. In particular for MCS rates, the maximum power levels for CCK/OFDM rates were used, e.g. maximum power for OFDM 0 was used for MCS 0. If STBC is used, the power is mostly limited to 0 because the STBC table is zeroed for legacy CCK/OFDM rates. Encountered this during testing of our work-in-progress TPC per packet for ath9k. This only has an effect when TPC is enabled in ath9k (tpc_enabled in struct ath_hw) which defaults to false. In this case it has a significant impact on the used TX-power, throughput + RSSI. Otherwise the affected code is just skipped and TX-power is limited with the hardware registers only. This patch fixes this table lookup. Tested on OpenWrt (kernel 5.15.98, but backported ath9k driver) with small desk setup using ath9k chips AR9280 and AR9580. Cap of TX-power is working properly for all rates now, throughput and RSSI as expected, equal to as if TPC was disabled. Compile-tested with latest 6.3 kernel + allyesconfig. Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com> Acked-by: Toke Høiland-Jørgensen <toke@toke.dk> Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com> Link: https://lore.kernel.org/r/20230330132159.758088-1-jelonek.jonas@gmail.com
1 parent 41e02bf commit e04e4b6

1 file changed

Lines changed: 24 additions & 6 deletions

File tree

  • drivers/net/wireless/ath/ath9k

drivers/net/wireless/ath/ath9k/xmit.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
3535
#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
3636

37+
/* Shifts in ar5008_phy.c and ar9003_phy.c are equal for all revisions */
38+
#define ATH9K_PWRTBL_11NA_OFDM_SHIFT 0
39+
#define ATH9K_PWRTBL_11NG_OFDM_SHIFT 4
40+
#define ATH9K_PWRTBL_11NA_HT_SHIFT 8
41+
#define ATH9K_PWRTBL_11NG_HT_SHIFT 12
42+
3743

3844
static u16 bits_per_symbol[][2] = {
3945
/* 20MHz 40MHz */
@@ -1169,13 +1175,14 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
11691175
}
11701176

11711177
static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
1172-
u8 rateidx, bool is_40, bool is_cck)
1178+
u8 rateidx, bool is_40, bool is_cck, bool is_mcs)
11731179
{
11741180
u8 max_power;
11751181
struct sk_buff *skb;
11761182
struct ath_frame_info *fi;
11771183
struct ieee80211_tx_info *info;
11781184
struct ath_hw *ah = sc->sc_ah;
1185+
bool is_2ghz, is_5ghz, use_stbc;
11791186

11801187
if (sc->tx99_state || !ah->tpc_enabled)
11811188
return MAX_RATE_POWER;
@@ -1184,6 +1191,19 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
11841191
fi = get_frame_info(skb);
11851192
info = IEEE80211_SKB_CB(skb);
11861193

1194+
is_2ghz = info->band == NL80211_BAND_2GHZ;
1195+
is_5ghz = info->band == NL80211_BAND_5GHZ;
1196+
use_stbc = is_mcs && rateidx < 8 && (info->flags &
1197+
IEEE80211_TX_CTL_STBC);
1198+
1199+
if (is_mcs)
1200+
rateidx += is_5ghz ? ATH9K_PWRTBL_11NA_HT_SHIFT
1201+
: ATH9K_PWRTBL_11NG_HT_SHIFT;
1202+
else if (is_2ghz && !is_cck)
1203+
rateidx += ATH9K_PWRTBL_11NG_OFDM_SHIFT;
1204+
else
1205+
rateidx += ATH9K_PWRTBL_11NA_OFDM_SHIFT;
1206+
11871207
if (!AR_SREV_9300_20_OR_LATER(ah)) {
11881208
int txpower = fi->tx_power;
11891209

@@ -1193,10 +1213,8 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
11931213
u16 eeprom_rev = ah->eep_ops->get_eeprom_rev(ah);
11941214

11951215
if (eeprom_rev >= AR5416_EEP_MINOR_VER_2) {
1196-
bool is_2ghz;
11971216
struct modal_eep_header *pmodal;
11981217

1199-
is_2ghz = info->band == NL80211_BAND_2GHZ;
12001218
pmodal = &eep->modalHeader[is_2ghz];
12011219
power_ht40delta = pmodal->ht40PowerIncForPdadc;
12021220
} else {
@@ -1229,7 +1247,7 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
12291247
if (!max_power && !AR_SREV_9280_20_OR_LATER(ah))
12301248
max_power = 1;
12311249
} else if (!bf->bf_state.bfs_paprd) {
1232-
if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC))
1250+
if (use_stbc)
12331251
max_power = min_t(u8, ah->tx_power_stbc[rateidx],
12341252
fi->tx_power);
12351253
else
@@ -1319,7 +1337,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
13191337
}
13201338

13211339
info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
1322-
is_40, false);
1340+
is_40, false, true);
13231341
continue;
13241342
}
13251343

@@ -1350,7 +1368,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
13501368

13511369
is_cck = IS_CCK_RATE(info->rates[i].Rate);
13521370
info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false,
1353-
is_cck);
1371+
is_cck, false);
13541372
}
13551373

13561374
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */

0 commit comments

Comments
 (0)