Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtw88: correct power limit selection

If phy rate is decreased, sub bandwidth may be chosen by RA.
We consider possible power limits and apply the min one;
otherwise, the tx power index may be larger than spec.

And we cross-reference power limits of vht and ht with
20/40M bandwidth in 5G to avoid values are not assigned.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>

authored by

Zong-Zhe Yang and committed by
Kalle Valo
93f68a86 adf3c676

+131 -8
+24
drivers/net/wireless/realtek/rtw88/main.c
··· 198 198 { 199 199 struct ieee80211_channel *channel = chandef->chan; 200 200 enum nl80211_chan_width width = chandef->width; 201 + u8 *cch_by_bw = chan_params->cch_by_bw; 201 202 u32 primary_freq, center_freq; 202 203 u8 center_chan; 203 204 u8 bandwidth = RTW_CHANNEL_WIDTH_20; 204 205 u8 primary_chan_idx = 0; 206 + u8 i; 205 207 206 208 center_chan = channel->hw_value; 207 209 primary_freq = channel->center_freq; 208 210 center_freq = chandef->center_freq1; 211 + 212 + /* assign the center channel used while 20M bw is selected */ 213 + cch_by_bw[RTW_CHANNEL_WIDTH_20] = channel->hw_value; 209 214 210 215 switch (width) { 211 216 case NL80211_CHAN_WIDTH_20_NOHT: ··· 238 233 primary_chan_idx = 3; 239 234 center_chan -= 6; 240 235 } 236 + /* assign the center channel used 237 + * while 40M bw is selected 238 + */ 239 + cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_chan + 4; 241 240 } else { 242 241 if (center_freq - primary_freq == 10) { 243 242 primary_chan_idx = 2; ··· 250 241 primary_chan_idx = 4; 251 242 center_chan += 6; 252 243 } 244 + /* assign the center channel used 245 + * while 40M bw is selected 246 + */ 247 + cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_chan - 4; 253 248 } 254 249 break; 255 250 default: ··· 264 251 chan_params->center_chan = center_chan; 265 252 chan_params->bandwidth = bandwidth; 266 253 chan_params->primary_chan_idx = primary_chan_idx; 254 + 255 + /* assign the center channel used while current bw is selected */ 256 + cch_by_bw[bandwidth] = center_chan; 257 + 258 + for (i = bandwidth + 1; i <= RTW_MAX_CHANNEL_WIDTH; i++) 259 + cch_by_bw[i] = 0; 267 260 } 268 261 269 262 void rtw_set_channel(struct rtw_dev *rtwdev) ··· 279 260 struct rtw_chip_info *chip = rtwdev->chip; 280 261 struct rtw_channel_params ch_param; 281 262 u8 center_chan, bandwidth, primary_chan_idx; 263 + u8 i; 282 264 283 265 rtw_get_channel_params(&hw->conf.chandef, &ch_param); 284 266 if (WARN(ch_param.center_chan == 0, "Invalid channel\n")) ··· 292 272 hal->current_band_width = bandwidth; 293 273 hal->current_channel = center_chan; 294 274 hal->current_band_type = center_chan > 14 ? RTW_BAND_5G : RTW_BAND_2G; 275 + 276 + for (i = RTW_CHANNEL_WIDTH_20; i <= RTW_MAX_CHANNEL_WIDTH; i++) 277 + hal->cch_by_bw[i] = ch_param.cch_by_bw[i]; 278 + 295 279 chip->ops->set_channel(rtwdev, center_chan, bandwidth, primary_chan_idx); 296 280 297 281 rtw_phy_set_tx_power_level(rtwdev, center_chan);
+13
drivers/net/wireless/realtek/rtw88/main.h
··· 62 62 RTW_BAND_MAX, 63 63 }; 64 64 65 + /* now, support upto 80M bw */ 66 + #define RTW_MAX_CHANNEL_WIDTH RTW_CHANNEL_WIDTH_80 67 + 65 68 enum rtw_bandwidth { 66 69 RTW_CHANNEL_WIDTH_20 = 0, 67 70 RTW_CHANNEL_WIDTH_40 = 1, ··· 416 413 u8 center_chan; 417 414 u8 bandwidth; 418 415 u8 primary_chan_idx; 416 + /* center channel by different available bandwidth, 417 + * val of (bw > current bandwidth) is invalid 418 + */ 419 + u8 cch_by_bw[RTW_MAX_CHANNEL_WIDTH + 1]; 419 420 }; 420 421 421 422 struct rtw_hw_reg { ··· 991 984 u8 current_channel; 992 985 u8 current_band_width; 993 986 u8 current_band_type; 987 + 988 + /* center channel for different available bandwidth, 989 + * val of (bw > current_band_width) is invalid 990 + */ 991 + u8 cch_by_bw[RTW_MAX_CHANNEL_WIDTH + 1]; 992 + 994 993 u8 sec_ch_offset; 995 994 u8 rf_type; 996 995 u8 rf_path_num;
+94 -8
drivers/net/wireless/realtek/rtw88/phy.c
··· 1198 1198 } 1199 1199 } 1200 1200 1201 + /* cross-reference 5G power limits if values are not assigned */ 1202 + static void 1203 + rtw_xref_5g_txpwr_lmt(struct rtw_dev *rtwdev, u8 regd, 1204 + u8 bw, u8 ch_idx, u8 rs_ht, u8 rs_vht) 1205 + { 1206 + struct rtw_hal *hal = &rtwdev->hal; 1207 + s8 lmt_ht = hal->tx_pwr_limit_5g[regd][bw][rs_ht][ch_idx]; 1208 + s8 lmt_vht = hal->tx_pwr_limit_5g[regd][bw][rs_vht][ch_idx]; 1209 + 1210 + if (lmt_ht == lmt_vht) 1211 + return; 1212 + 1213 + if (lmt_ht == RTW_MAX_POWER_INDEX) 1214 + hal->tx_pwr_limit_5g[regd][bw][rs_ht][ch_idx] = lmt_vht; 1215 + 1216 + else if (lmt_vht == RTW_MAX_POWER_INDEX) 1217 + hal->tx_pwr_limit_5g[regd][bw][rs_vht][ch_idx] = lmt_ht; 1218 + } 1219 + 1220 + /* cross-reference power limits for ht and vht */ 1221 + static void 1222 + rtw_xref_txpwr_lmt_by_rs(struct rtw_dev *rtwdev, u8 regd, u8 bw, u8 ch_idx) 1223 + { 1224 + u8 rs_idx, rs_ht, rs_vht; 1225 + u8 rs_cmp[2][2] = {{RTW_RATE_SECTION_HT_1S, RTW_RATE_SECTION_VHT_1S}, 1226 + {RTW_RATE_SECTION_HT_2S, RTW_RATE_SECTION_VHT_2S} }; 1227 + 1228 + for (rs_idx = 0; rs_idx < 2; rs_idx++) { 1229 + rs_ht = rs_cmp[rs_idx][0]; 1230 + rs_vht = rs_cmp[rs_idx][1]; 1231 + 1232 + rtw_xref_5g_txpwr_lmt(rtwdev, regd, bw, ch_idx, rs_ht, rs_vht); 1233 + } 1234 + } 1235 + 1236 + /* cross-reference power limits for 5G channels */ 1237 + static void 1238 + rtw_xref_5g_txpwr_lmt_by_ch(struct rtw_dev *rtwdev, u8 regd, u8 bw) 1239 + { 1240 + u8 ch_idx; 1241 + 1242 + for (ch_idx = 0; ch_idx < RTW_MAX_CHANNEL_NUM_5G; ch_idx++) 1243 + rtw_xref_txpwr_lmt_by_rs(rtwdev, regd, bw, ch_idx); 1244 + } 1245 + 1246 + /* cross-reference power limits for 20/40M bandwidth */ 1247 + static void 1248 + rtw_xref_txpwr_lmt_by_bw(struct rtw_dev *rtwdev, u8 regd) 1249 + { 1250 + u8 bw; 1251 + 1252 + for (bw = RTW_CHANNEL_WIDTH_20; bw <= RTW_CHANNEL_WIDTH_40; bw++) 1253 + rtw_xref_5g_txpwr_lmt_by_ch(rtwdev, regd, bw); 1254 + } 1255 + 1256 + /* cross-reference power limits */ 1257 + static void rtw_xref_txpwr_lmt(struct rtw_dev *rtwdev) 1258 + { 1259 + u8 regd; 1260 + 1261 + for (regd = 0; regd < RTW_REGD_MAX; regd++) 1262 + rtw_xref_txpwr_lmt_by_bw(rtwdev, regd); 1263 + } 1264 + 1201 1265 void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev, 1202 1266 const struct rtw_table *tbl) 1203 1267 { ··· 1274 1210 rtw_phy_set_tx_power_limit(rtwdev, p->regd, p->band, 1275 1211 p->bw, p->rs, p->ch, p->txpwr_lmt); 1276 1212 } 1213 + 1214 + rtw_xref_txpwr_lmt(rtwdev); 1277 1215 } 1278 1216 1279 1217 void rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl, ··· 1545 1479 u8 rate, u8 channel, u8 regd) 1546 1480 { 1547 1481 struct rtw_hal *hal = &rtwdev->hal; 1548 - s8 power_limit; 1482 + u8 *cch_by_bw = hal->cch_by_bw; 1483 + s8 power_limit = RTW_MAX_POWER_INDEX; 1549 1484 u8 rs; 1550 1485 int ch_idx; 1486 + u8 cur_bw, cur_ch; 1487 + s8 cur_lmt; 1551 1488 1552 1489 if (regd > RTW_REGD_WW) 1553 1490 return RTW_MAX_POWER_INDEX; ··· 1570 1501 else 1571 1502 goto err; 1572 1503 1573 - ch_idx = rtw_channel_to_idx(band, channel); 1574 - if (ch_idx < 0) 1575 - goto err; 1504 + /* only 20M BW with cck and ofdm */ 1505 + if (rs == RTW_RATE_SECTION_CCK || rs == RTW_RATE_SECTION_OFDM) 1506 + bw = RTW_CHANNEL_WIDTH_20; 1576 1507 1577 - if (channel <= RTW_MAX_CHANNEL_NUM_2G) 1578 - power_limit = hal->tx_pwr_limit_2g[regd][bw][rs][ch_idx]; 1579 - else 1580 - power_limit = hal->tx_pwr_limit_5g[regd][bw][rs][ch_idx]; 1508 + /* only 20/40M BW with ht */ 1509 + if (rs == RTW_RATE_SECTION_HT_1S || rs == RTW_RATE_SECTION_HT_2S) 1510 + bw = min_t(u8, bw, RTW_CHANNEL_WIDTH_40); 1511 + 1512 + /* select min power limit among [20M BW ~ current BW] */ 1513 + for (cur_bw = RTW_CHANNEL_WIDTH_20; cur_bw <= bw; cur_bw++) { 1514 + cur_ch = cch_by_bw[cur_bw]; 1515 + 1516 + ch_idx = rtw_channel_to_idx(band, cur_ch); 1517 + if (ch_idx < 0) 1518 + goto err; 1519 + 1520 + cur_lmt = cur_ch <= RTW_MAX_CHANNEL_NUM_2G ? 1521 + hal->tx_pwr_limit_2g[regd][cur_bw][rs][ch_idx] : 1522 + hal->tx_pwr_limit_5g[regd][cur_bw][rs][ch_idx]; 1523 + 1524 + power_limit = min_t(s8, cur_lmt, power_limit); 1525 + } 1581 1526 1582 1527 return power_limit; 1583 1528 ··· 1775 1692 void rtw_phy_tx_power_limit_config(struct rtw_hal *hal) 1776 1693 { 1777 1694 u8 regd, bw, rs; 1695 + 1696 + /* default at channel 1 */ 1697 + hal->cch_by_bw[RTW_CHANNEL_WIDTH_20] = 1; 1778 1698 1779 1699 for (regd = 0; regd < RTW_REGD_MAX; regd++) 1780 1700 for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)