Skip to content

Commit e7196b3

Browse files
Zong-Zhe YangPing-Ke Shih
authored andcommitted
wifi: rtw89: regd: support loading regd table from fw element
Regd table is a table that we use to describe how to map Realtek RF TX power settings on different countries. Originally, a common regd table for all chips is implemented in driver. However, in order to work on all chips, the common regd table might have some trade-off. So now, there are also an individual regd table for some chips. And, we support loading it from FW element. Signed-off-by: Zong-Zhe Yang <[email protected]> Signed-off-by: Ping-Ke Shih <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 076652f commit e7196b3

File tree

4 files changed

+166
-22
lines changed

4 files changed

+166
-22
lines changed

drivers/net/wireless/realtek/rtw89/core.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct rtw89_h2c_rf_tssi;
2222
struct rtw89_fw_txpwr_track_cfg;
2323
struct rtw89_phy_rfk_log_fmt;
2424
struct rtw89_debugfs;
25+
struct rtw89_regd_data;
2526

2627
extern const struct ieee80211_ops rtw89_ops;
2728

@@ -718,6 +719,7 @@ enum rtw89_ofdma_type {
718719
RTW89_OFDMA_NUM,
719720
};
720721

722+
/* neither insert new in the middle, nor change any given definition */
721723
enum rtw89_regulation_type {
722724
RTW89_WW = 0,
723725
RTW89_ETSI = 1,
@@ -4539,6 +4541,7 @@ struct rtw89_fw_elm_info {
45394541
struct rtw89_phy_table *rf_nctl;
45404542
struct rtw89_fw_txpwr_track_cfg *txpwr_trk;
45414543
struct rtw89_phy_rfk_log_fmt *rfk_log_fmt;
4544+
const struct rtw89_regd_data *regd;
45424545
};
45434546

45444547
enum rtw89_fw_mss_dev_type {
@@ -5153,11 +5156,22 @@ struct rtw89_regd {
51535156
u8 txpwr_regd[RTW89_BAND_NUM];
51545157
};
51555158

5159+
struct rtw89_regd_data {
5160+
unsigned int nr;
5161+
struct rtw89_regd map[] __counted_by(nr);
5162+
};
5163+
5164+
struct rtw89_regd_ctrl {
5165+
unsigned int nr;
5166+
const struct rtw89_regd *map;
5167+
};
5168+
51565169
#define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX
51575170
#define RTW89_5GHZ_UNII4_CHANNEL_NUM 3
51585171
#define RTW89_5GHZ_UNII4_START_INDEX 25
51595172

51605173
struct rtw89_regulatory_info {
5174+
struct rtw89_regd_ctrl ctrl;
51615175
const struct rtw89_regd *regd;
51625176
enum rtw89_reg_6ghz_power reg_6ghz_power;
51635177
struct rtw89_reg_6ghz_tpe reg_6ghz_tpe;

drivers/net/wireless/realtek/rtw89/fw.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,89 @@ int rtw89_build_rfk_log_fmt_from_elm(struct rtw89_dev *rtwdev,
10561056
return 0;
10571057
}
10581058

1059+
static bool rtw89_regd_entcpy(struct rtw89_regd *regd, const void *cursor,
1060+
u8 cursor_size)
1061+
{
1062+
/* fill default values if needed for backward compatibility */
1063+
struct rtw89_fw_regd_entry entry = {
1064+
.rule_2ghz = RTW89_NA,
1065+
.rule_5ghz = RTW89_NA,
1066+
.rule_6ghz = RTW89_NA,
1067+
};
1068+
u8 valid_size = min_t(u8, sizeof(entry), cursor_size);
1069+
1070+
memcpy(&entry, cursor, valid_size);
1071+
memset(regd, 0, sizeof(*regd));
1072+
1073+
regd->alpha2[0] = entry.alpha2_0;
1074+
regd->alpha2[1] = entry.alpha2_1;
1075+
regd->alpha2[2] = '\0';
1076+
1077+
/* also need to consider forward compatibility */
1078+
regd->txpwr_regd[RTW89_BAND_2G] = entry.rule_2ghz < RTW89_REGD_NUM ?
1079+
entry.rule_2ghz : RTW89_NA;
1080+
regd->txpwr_regd[RTW89_BAND_5G] = entry.rule_5ghz < RTW89_REGD_NUM ?
1081+
entry.rule_5ghz : RTW89_NA;
1082+
regd->txpwr_regd[RTW89_BAND_6G] = entry.rule_6ghz < RTW89_REGD_NUM ?
1083+
entry.rule_6ghz : RTW89_NA;
1084+
1085+
return true;
1086+
}
1087+
1088+
#define rtw89_for_each_in_regd_element(regd, element) \
1089+
for (const void *cursor = (element)->content, \
1090+
*end = (element)->content + \
1091+
le32_to_cpu((element)->num_ents) * (element)->ent_sz; \
1092+
cursor < end; cursor += (element)->ent_sz) \
1093+
if (rtw89_regd_entcpy(regd, cursor, (element)->ent_sz))
1094+
1095+
static
1096+
int rtw89_recognize_regd_from_elm(struct rtw89_dev *rtwdev,
1097+
const struct rtw89_fw_element_hdr *elm,
1098+
const union rtw89_fw_element_arg arg)
1099+
{
1100+
const struct __rtw89_fw_regd_element *regd_elm = &elm->u.regd;
1101+
struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
1102+
u32 num_ents = le32_to_cpu(regd_elm->num_ents);
1103+
struct rtw89_regd_data *p;
1104+
struct rtw89_regd regd;
1105+
u32 i = 0;
1106+
1107+
if (num_ents > RTW89_REGD_MAX_COUNTRY_NUM) {
1108+
rtw89_warn(rtwdev,
1109+
"regd element ents (%d) are over max num (%d)\n",
1110+
num_ents, RTW89_REGD_MAX_COUNTRY_NUM);
1111+
rtw89_warn(rtwdev,
1112+
"regd element ignore and take another/common\n");
1113+
return 1;
1114+
}
1115+
1116+
if (elm_info->regd) {
1117+
rtw89_debug(rtwdev, RTW89_DBG_REGD,
1118+
"regd element take the latter\n");
1119+
devm_kfree(rtwdev->dev, elm_info->regd);
1120+
elm_info->regd = NULL;
1121+
}
1122+
1123+
p = devm_kzalloc(rtwdev->dev, struct_size(p, map, num_ents), GFP_KERNEL);
1124+
if (!p)
1125+
return -ENOMEM;
1126+
1127+
p->nr = num_ents;
1128+
rtw89_for_each_in_regd_element(&regd, regd_elm)
1129+
p->map[i++] = regd;
1130+
1131+
if (i != num_ents) {
1132+
rtw89_err(rtwdev, "regd element has %d invalid ents\n",
1133+
num_ents - i);
1134+
devm_kfree(rtwdev->dev, p);
1135+
return -EINVAL;
1136+
}
1137+
1138+
elm_info->regd = p;
1139+
return 0;
1140+
}
1141+
10591142
static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
10601143
[RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm,
10611144
{ .fw_type = RTW89_FW_BBMCU0 }, NULL},
@@ -1114,6 +1197,9 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
11141197
[RTW89_FW_ELEMENT_ID_RFKLOG_FMT] = {
11151198
rtw89_build_rfk_log_fmt_from_elm, {}, NULL,
11161199
},
1200+
[RTW89_FW_ELEMENT_ID_REGD] = {
1201+
rtw89_recognize_regd_from_elm, {}, "REGD",
1202+
},
11171203
};
11181204

11191205
int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)

drivers/net/wireless/realtek/rtw89/fw.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3882,6 +3882,7 @@ enum rtw89_fw_element_id {
38823882
RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT_RU = 17,
38833883
RTW89_FW_ELEMENT_ID_TXPWR_TRK = 18,
38843884
RTW89_FW_ELEMENT_ID_RFKLOG_FMT = 19,
3885+
RTW89_FW_ELEMENT_ID_REGD = 20,
38853886

38863887
RTW89_FW_ELEMENT_ID_NUM,
38873888
};
@@ -3925,6 +3926,15 @@ struct __rtw89_fw_txpwr_element {
39253926
u8 content[];
39263927
} __packed;
39273928

3929+
struct __rtw89_fw_regd_element {
3930+
u8 rsvd0;
3931+
u8 rsvd1;
3932+
u8 rsvd2;
3933+
u8 ent_sz;
3934+
__le32 num_ents;
3935+
u8 content[];
3936+
} __packed;
3937+
39283938
enum rtw89_fw_txpwr_trk_type {
39293939
__RTW89_FW_TXPWR_TRK_TYPE_6GHZ_START = 0,
39303940
RTW89_FW_TXPWR_TRK_TYPE_6GB_N = 0,
@@ -4016,6 +4026,7 @@ struct rtw89_fw_element_hdr {
40164026
__le16 offset[];
40174027
} __packed rfk_log_fmt;
40184028
struct __rtw89_fw_txpwr_element txpwr;
4029+
struct __rtw89_fw_regd_element regd;
40194030
} __packed u;
40204031
} __packed;
40214032

@@ -4874,6 +4885,17 @@ int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
48744885
return 0;
48754886
}
48764887

4888+
/* Must consider compatibility; don't insert new in the mid.
4889+
* Fill each field's default value in rtw89_regd_entcpy().
4890+
*/
4891+
struct rtw89_fw_regd_entry {
4892+
u8 alpha2_0;
4893+
u8 alpha2_1;
4894+
u8 rule_2ghz;
4895+
u8 rule_5ghz;
4896+
u8 rule_6ghz;
4897+
} __packed;
4898+
48774899
/* must consider compatibility; don't insert new in the mid */
48784900
struct rtw89_fw_txpwr_byrate_entry {
48794901
u8 band;

drivers/net/wireless/realtek/rtw89/regd.c

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
#include "ps.h"
88
#include "util.h"
99

10-
#define COUNTRY_REGD(_alpha2, _txpwr_regd...) \
11-
{.alpha2 = (_alpha2), \
12-
.txpwr_regd = {_txpwr_regd}, \
10+
#define COUNTRY_REGD(_alpha2, _rule_2ghz, _rule_5ghz, _rule_6ghz) \
11+
{ \
12+
.alpha2 = _alpha2, \
13+
.txpwr_regd[RTW89_BAND_2G] = _rule_2ghz, \
14+
.txpwr_regd[RTW89_BAND_5G] = _rule_5ghz, \
15+
.txpwr_regd[RTW89_BAND_6G] = _rule_6ghz, \
1316
}
1417

1518
static const struct rtw89_regd rtw89_ww_regd =
@@ -295,13 +298,16 @@ static const char rtw89_alpha2_list_eu[][3] = {
295298
"RO",
296299
};
297300

298-
static const struct rtw89_regd *rtw89_regd_find_reg_by_name(const char *alpha2)
301+
static const struct rtw89_regd *rtw89_regd_find_reg_by_name(struct rtw89_dev *rtwdev,
302+
const char *alpha2)
299303
{
304+
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
305+
const struct rtw89_regd_ctrl *regd_ctrl = &regulatory->ctrl;
300306
u32 i;
301307

302-
for (i = 0; i < ARRAY_SIZE(rtw89_regd_map); i++) {
303-
if (!memcmp(rtw89_regd_map[i].alpha2, alpha2, 2))
304-
return &rtw89_regd_map[i];
308+
for (i = 0; i < regd_ctrl->nr; i++) {
309+
if (!memcmp(regd_ctrl->map[i].alpha2, alpha2, 2))
310+
return &regd_ctrl->map[i];
305311
}
306312

307313
return &rtw89_ww_regd;
@@ -312,22 +318,25 @@ static bool rtw89_regd_is_ww(const struct rtw89_regd *regd)
312318
return regd == &rtw89_ww_regd;
313319
}
314320

315-
static u8 rtw89_regd_get_index(const struct rtw89_regd *regd)
321+
static u8 rtw89_regd_get_index(struct rtw89_dev *rtwdev, const struct rtw89_regd *regd)
316322
{
323+
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
324+
const struct rtw89_regd_ctrl *regd_ctrl = &regulatory->ctrl;
325+
317326
BUILD_BUG_ON(ARRAY_SIZE(rtw89_regd_map) > RTW89_REGD_MAX_COUNTRY_NUM);
318327

319328
if (rtw89_regd_is_ww(regd))
320329
return RTW89_REGD_MAX_COUNTRY_NUM;
321330

322-
return regd - rtw89_regd_map;
331+
return regd - regd_ctrl->map;
323332
}
324333

325-
static u8 rtw89_regd_get_index_by_name(const char *alpha2)
334+
static u8 rtw89_regd_get_index_by_name(struct rtw89_dev *rtwdev, const char *alpha2)
326335
{
327336
const struct rtw89_regd *regd;
328337

329-
regd = rtw89_regd_find_reg_by_name(alpha2);
330-
return rtw89_regd_get_index(regd);
338+
regd = rtw89_regd_find_reg_by_name(rtwdev, alpha2);
339+
return rtw89_regd_get_index(rtwdev, regd);
331340
}
332341

333342
#define rtw89_debug_regd(_dev, _regd, _desc, _argv...) \
@@ -345,6 +354,7 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
345354
struct wiphy *wiphy)
346355
{
347356
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
357+
const struct rtw89_regd_ctrl *regd_ctrl = &regulatory->ctrl;
348358
const struct rtw89_chip_info *chip = rtwdev->chip;
349359
struct ieee80211_supported_band *sband;
350360
struct rtw89_acpi_dsm_result res = {};
@@ -382,8 +392,8 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
382392
"acpi: eval if allow unii-4: 0x%x\n", val);
383393

384394
bottom:
385-
for (i = 0; i < ARRAY_SIZE(rtw89_regd_map); i++) {
386-
const struct rtw89_regd *regd = &rtw89_regd_map[i];
395+
for (i = 0; i < regd_ctrl->nr; i++) {
396+
const struct rtw89_regd *regd = &regd_ctrl->map[i];
387397

388398
switch (regd->txpwr_regd[RTW89_BAND_5G]) {
389399
case RTW89_FCC:
@@ -406,7 +416,7 @@ static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block,
406416
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
407417
u8 index;
408418

409-
index = rtw89_regd_get_index_by_name(alpha2);
419+
index = rtw89_regd_get_index_by_name(rtwdev, alpha2);
410420
if (index == RTW89_REGD_MAX_COUNTRY_NUM) {
411421
rtw89_debug(rtwdev, RTW89_DBG_REGD, "%s: unknown alpha2 %c%c\n",
412422
__func__, alpha2[0], alpha2[1]);
@@ -474,6 +484,7 @@ static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev)
474484
static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev)
475485
{
476486
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
487+
const struct rtw89_regd_ctrl *regd_ctrl = &regulatory->ctrl;
477488
const struct rtw89_acpi_policy_6ghz_sp *ptr;
478489
struct rtw89_acpi_dsm_result res = {};
479490
bool enable_by_us;
@@ -505,8 +516,8 @@ static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev)
505516

506517
enable_by_us = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_US);
507518

508-
for (i = 0; i < ARRAY_SIZE(rtw89_regd_map); i++) {
509-
const struct rtw89_regd *tmp = &rtw89_regd_map[i];
519+
for (i = 0; i < regd_ctrl->nr; i++) {
520+
const struct rtw89_regd *tmp = &regd_ctrl->map[i];
510521

511522
if (enable_by_us && memcmp(tmp->alpha2, "US", 2) == 0)
512523
clear_bit(i, regulatory->block_6ghz_sp);
@@ -573,8 +584,19 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
573584

574585
int rtw89_regd_setup(struct rtw89_dev *rtwdev)
575586
{
587+
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
588+
struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
589+
const struct rtw89_regd_data *regd_data = elm_info->regd;
576590
struct wiphy *wiphy = rtwdev->hw->wiphy;
577591

592+
if (regd_data) {
593+
regulatory->ctrl.nr = regd_data->nr;
594+
regulatory->ctrl.map = regd_data->map;
595+
} else {
596+
regulatory->ctrl.nr = ARRAY_SIZE(rtw89_regd_map);
597+
regulatory->ctrl.map = rtw89_regd_map;
598+
}
599+
578600
if (!wiphy)
579601
return -EINVAL;
580602

@@ -599,7 +621,7 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev,
599621
if (!wiphy)
600622
return -EINVAL;
601623

602-
chip_regd = rtw89_regd_find_reg_by_name(rtwdev->efuse.country_code);
624+
chip_regd = rtw89_regd_find_reg_by_name(rtwdev, rtwdev->efuse.country_code);
603625
if (!rtw89_regd_is_ww(chip_regd)) {
604626
rtwdev->regulatory.regd = chip_regd;
605627
/* Ignore country ie if there is a country domain programmed in chip */
@@ -637,7 +659,7 @@ static void rtw89_regd_apply_policy_unii4(struct rtw89_dev *rtwdev,
637659
if (!chip->support_unii4)
638660
return;
639661

640-
index = rtw89_regd_get_index(regd);
662+
index = rtw89_regd_get_index(rtwdev, regd);
641663
if (index != RTW89_REGD_MAX_COUNTRY_NUM &&
642664
!test_bit(index, regulatory->block_unii4))
643665
return;
@@ -655,7 +677,7 @@ static bool regd_is_6ghz_blocked(struct rtw89_dev *rtwdev)
655677
const struct rtw89_regd *regd = regulatory->regd;
656678
u8 index;
657679

658-
index = rtw89_regd_get_index(regd);
680+
index = rtw89_regd_get_index(rtwdev, regd);
659681
if (index != RTW89_REGD_MAX_COUNTRY_NUM &&
660682
!test_bit(index, regulatory->block_6ghz))
661683
return false;
@@ -700,7 +722,7 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev,
700722
struct wiphy *wiphy,
701723
struct regulatory_request *request)
702724
{
703-
rtwdev->regulatory.regd = rtw89_regd_find_reg_by_name(request->alpha2);
725+
rtwdev->regulatory.regd = rtw89_regd_find_reg_by_name(rtwdev, request->alpha2);
704726
/* This notification might be set from the system of distros,
705727
* and it does not expect the regulatory will be modified by
706728
* connecting to an AP (i.e. country ie).
@@ -925,7 +947,7 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev)
925947
sel = RTW89_REG_6GHZ_POWER_DFLT;
926948

927949
if (sel == RTW89_REG_6GHZ_POWER_STD) {
928-
index = rtw89_regd_get_index(regd);
950+
index = rtw89_regd_get_index(rtwdev, regd);
929951
if (index == RTW89_REGD_MAX_COUNTRY_NUM ||
930952
test_bit(index, regulatory->block_6ghz_sp)) {
931953
rtw89_debug(rtwdev, RTW89_DBG_REGD,

0 commit comments

Comments
 (0)