Skip to content

Commit 88ca310

Browse files
Zong-Zhe YangPing-Ke Shih
authored andcommitted
wifi: rtw89: sar: add skeleton for SAR configuration via ACPI
To support SAR configuration in BIOS via ACPI, add related subbnad/band converting/handling function and define SW format to store result after parsing. Then, register a new SAR source, i.e. ACPI, into SAR flow and implement its query function. Besides, tweak priority of common SAR to be the highest. And, ACPI SAR can just be configured once when no other sources is already working. For now, evaluating SAR via ACPI returns -ENOENT, i.e. ACPI SAR doesn't really work yet. The evaluating flow will be implemented in the following. Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20250326020643.14487-5-pkshih@realtek.com
1 parent 1e262fc commit 88ca310

File tree

7 files changed

+269
-13
lines changed

7 files changed

+269
-13
lines changed

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

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,82 @@ int rtw89_acpi_evaluate_rtag(struct rtw89_dev *rtwdev,
195195
ACPI_FREE(obj);
196196
return ret;
197197
}
198+
199+
enum rtw89_acpi_sar_subband rtw89_acpi_sar_get_subband(struct rtw89_dev *rtwdev,
200+
u32 center_freq)
201+
{
202+
switch (center_freq) {
203+
default:
204+
rtw89_debug(rtwdev, RTW89_DBG_ACPI,
205+
"center freq %u to ACPI SAR subband is unhandled\n",
206+
center_freq);
207+
fallthrough;
208+
case 2412 ... 2484:
209+
return RTW89_ACPI_SAR_2GHZ_SUBBAND;
210+
case 5180 ... 5240:
211+
return RTW89_ACPI_SAR_5GHZ_SUBBAND_1;
212+
case 5250 ... 5320:
213+
return RTW89_ACPI_SAR_5GHZ_SUBBAND_2;
214+
case 5500 ... 5720:
215+
return RTW89_ACPI_SAR_5GHZ_SUBBAND_2E;
216+
case 5745 ... 5885:
217+
return RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4;
218+
case 5955 ... 6155:
219+
return RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L;
220+
case 6175 ... 6415:
221+
return RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H;
222+
case 6435 ... 6515:
223+
return RTW89_ACPI_SAR_6GHZ_SUBBAND_6;
224+
case 6535 ... 6695:
225+
return RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L;
226+
case 6715 ... 6855:
227+
return RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H;
228+
229+
/* freq 6875 (ch 185, 20MHz) spans RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H
230+
* and RTW89_ACPI_SAR_6GHZ_SUBBAND_8, so directly describe it with
231+
* struct rtw89_6ghz_span.
232+
*/
233+
234+
case 6895 ... 7115:
235+
return RTW89_ACPI_SAR_6GHZ_SUBBAND_8;
236+
}
237+
}
238+
239+
enum rtw89_band rtw89_acpi_sar_subband_to_band(struct rtw89_dev *rtwdev,
240+
enum rtw89_acpi_sar_subband subband)
241+
{
242+
switch (subband) {
243+
default:
244+
rtw89_debug(rtwdev, RTW89_DBG_ACPI,
245+
"ACPI SAR subband %u to band is unhandled\n", subband);
246+
fallthrough;
247+
case RTW89_ACPI_SAR_2GHZ_SUBBAND:
248+
return RTW89_BAND_2G;
249+
case RTW89_ACPI_SAR_5GHZ_SUBBAND_1:
250+
return RTW89_BAND_5G;
251+
case RTW89_ACPI_SAR_5GHZ_SUBBAND_2:
252+
return RTW89_BAND_5G;
253+
case RTW89_ACPI_SAR_5GHZ_SUBBAND_2E:
254+
return RTW89_BAND_5G;
255+
case RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4:
256+
return RTW89_BAND_5G;
257+
case RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L:
258+
return RTW89_BAND_6G;
259+
case RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H:
260+
return RTW89_BAND_6G;
261+
case RTW89_ACPI_SAR_6GHZ_SUBBAND_6:
262+
return RTW89_BAND_6G;
263+
case RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L:
264+
return RTW89_BAND_6G;
265+
case RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H:
266+
return RTW89_BAND_6G;
267+
case RTW89_ACPI_SAR_6GHZ_SUBBAND_8:
268+
return RTW89_BAND_6G;
269+
}
270+
}
271+
272+
int rtw89_acpi_evaluate_sar(struct rtw89_dev *rtwdev,
273+
struct rtw89_sar_cfg_acpi *cfg)
274+
{
275+
return -ENOENT;
276+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,17 @@ struct rtw89_acpi_rtag_result {
7070
u8 ant_gain_table[RTW89_ANT_GAIN_CHAIN_NUM][RTW89_ANT_GAIN_SUBBAND_NR];
7171
} __packed;
7272

73+
enum rtw89_acpi_sar_subband rtw89_acpi_sar_get_subband(struct rtw89_dev *rtwdev,
74+
u32 center_freq);
75+
enum rtw89_band rtw89_acpi_sar_subband_to_band(struct rtw89_dev *rtwdev,
76+
enum rtw89_acpi_sar_subband subband);
77+
7378
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
7479
enum rtw89_acpi_dsm_func func,
7580
struct rtw89_acpi_dsm_result *res);
7681
int rtw89_acpi_evaluate_rtag(struct rtw89_dev *rtwdev,
7782
struct rtw89_acpi_rtag_result *res);
83+
int rtw89_acpi_evaluate_sar(struct rtw89_dev *rtwdev,
84+
struct rtw89_sar_cfg_acpi *cfg);
7885

7986
#endif

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
211211
[RTW89_6GHZ_SPAN_IDX(center_freq)] = { \
212212
.sar_subband_low = RTW89_SAR_6GHZ_ ## subband_l, \
213213
.sar_subband_high = RTW89_SAR_6GHZ_ ## subband_h, \
214+
.acpi_sar_subband_low = RTW89_ACPI_SAR_6GHZ_ ## subband_l, \
215+
.acpi_sar_subband_high = RTW89_ACPI_SAR_6GHZ_ ## subband_h, \
214216
.ant_gain_subband_low = RTW89_ANT_GAIN_6GHZ_ ## subband_l, \
215217
.ant_gain_subband_high = RTW89_ANT_GAIN_6GHZ_ ## subband_h, \
216218
}
@@ -4919,7 +4921,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
49194921

49204922
rtw89_ser_init(rtwdev);
49214923
rtw89_entity_init(rtwdev);
4922-
rtw89_tas_init(rtwdev);
4924+
rtw89_sar_init(rtwdev);
49234925
rtw89_phy_ant_gain_init(rtwdev);
49244926

49254927
return 0;

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4606,6 +4606,7 @@ struct rtw89_cam_info {
46064606
enum rtw89_sar_sources {
46074607
RTW89_SAR_SOURCE_NONE,
46084608
RTW89_SAR_SOURCE_COMMON,
4609+
RTW89_SAR_SOURCE_ACPI,
46094610

46104611
RTW89_SAR_SOURCE_NR,
46114612
};
@@ -4630,6 +4631,45 @@ struct rtw89_sar_cfg_common {
46304631
s32 cfg[RTW89_SAR_SUBBAND_NR];
46314632
};
46324633

4634+
enum rtw89_acpi_sar_subband {
4635+
RTW89_ACPI_SAR_2GHZ_SUBBAND,
4636+
RTW89_ACPI_SAR_5GHZ_SUBBAND_1, /* U-NII-1 */
4637+
RTW89_ACPI_SAR_5GHZ_SUBBAND_2, /* U-NII-2 */
4638+
RTW89_ACPI_SAR_5GHZ_SUBBAND_2E, /* U-NII-2-Extended */
4639+
RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4, /* U-NII-3 and U-NII-4 */
4640+
RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L, /* U-NII-5 lower part */
4641+
RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H, /* U-NII-5 higher part */
4642+
RTW89_ACPI_SAR_6GHZ_SUBBAND_6, /* U-NII-6 */
4643+
RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L, /* U-NII-7 lower part */
4644+
RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H, /* U-NII-7 higher part */
4645+
RTW89_ACPI_SAR_6GHZ_SUBBAND_8, /* U-NII-8 */
4646+
4647+
NUM_OF_RTW89_ACPI_SAR_SUBBAND,
4648+
};
4649+
4650+
#define TXPWR_FACTOR_OF_RTW89_ACPI_SAR 3 /* unit: 0.125 dBm */
4651+
#define MAX_VAL_OF_RTW89_ACPI_SAR S16_MAX
4652+
#define MIN_VAL_OF_RTW89_ACPI_SAR S16_MIN
4653+
#define MAX_NUM_OF_RTW89_ACPI_SAR_TBL 6
4654+
#define NUM_OF_RTW89_ACPI_SAR_RF_PATH (RF_PATH_B + 1)
4655+
4656+
struct rtw89_sar_entry_from_acpi {
4657+
s16 v[NUM_OF_RTW89_ACPI_SAR_SUBBAND][NUM_OF_RTW89_ACPI_SAR_RF_PATH];
4658+
};
4659+
4660+
struct rtw89_sar_table_from_acpi {
4661+
/* If this table is active, must fill all fields according to either
4662+
* configuration in BIOS or some default values for SAR to work well.
4663+
*/
4664+
struct rtw89_sar_entry_from_acpi entries[RTW89_REGD_NUM];
4665+
};
4666+
4667+
struct rtw89_sar_cfg_acpi {
4668+
u8 downgrade_2tx;
4669+
unsigned int valid_num;
4670+
struct rtw89_sar_table_from_acpi tables[MAX_NUM_OF_RTW89_ACPI_SAR_TBL];
4671+
};
4672+
46334673
struct rtw89_sar_info {
46344674
/* used to decide how to access SAR cfg union */
46354675
enum rtw89_sar_sources src;
@@ -4639,6 +4679,7 @@ struct rtw89_sar_info {
46394679
*/
46404680
union {
46414681
struct rtw89_sar_cfg_common cfg_common;
4682+
struct rtw89_sar_cfg_acpi cfg_acpi;
46424683
};
46434684
};
46444685

@@ -4674,11 +4715,14 @@ struct rtw89_ant_gain_info {
46744715
struct rtw89_6ghz_span {
46754716
enum rtw89_sar_subband sar_subband_low;
46764717
enum rtw89_sar_subband sar_subband_high;
4718+
enum rtw89_acpi_sar_subband acpi_sar_subband_low;
4719+
enum rtw89_acpi_sar_subband acpi_sar_subband_high;
46774720
enum rtw89_ant_gain_subband ant_gain_subband_low;
46784721
enum rtw89_ant_gain_subband ant_gain_subband_high;
46794722
};
46804723

46814724
#define RTW89_SAR_SPAN_VALID(span) ((span)->sar_subband_high)
4725+
#define RTW89_ACPI_SAR_SPAN_VALID(span) ((span)->acpi_sar_subband_high)
46824726
#define RTW89_ANT_GAIN_SPAN_VALID(span) ((span)->ant_gain_subband_high)
46834727

46844728
enum rtw89_tas_state {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,6 +2266,7 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
22662266
u8 reg6 = regulatory->reg_6ghz_power;
22672267
struct rtw89_sar_parm sar_parm = {
22682268
.center_freq = freq,
2269+
.ntx = ntx,
22692270
};
22702271
s8 lmt = 0, sar, offset;
22712272
s8 cstr;
@@ -2529,6 +2530,7 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
25292530
u8 reg6 = regulatory->reg_6ghz_power;
25302531
struct rtw89_sar_parm sar_parm = {
25312532
.center_freq = freq,
2533+
.ntx = ntx,
25322534
};
25332535
s8 lmt_ru = 0, sar, offset;
25342536
s8 cstr;

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

Lines changed: 132 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,65 @@ static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev,
9292
return 0;
9393
}
9494

95+
static
96+
s32 rtw89_sar_cfg_acpi_get_min(const struct rtw89_sar_entry_from_acpi *ent,
97+
enum rtw89_rf_path path,
98+
enum rtw89_acpi_sar_subband subband_low,
99+
enum rtw89_acpi_sar_subband subband_high)
100+
{
101+
return min(ent->v[subband_low][path], ent->v[subband_high][path]);
102+
}
103+
104+
static int rtw89_query_sar_config_acpi(struct rtw89_dev *rtwdev,
105+
const struct rtw89_sar_parm *sar_parm,
106+
s32 *cfg)
107+
{
108+
const struct rtw89_sar_cfg_acpi *rtwsar = &rtwdev->sar.cfg_acpi;
109+
const struct rtw89_sar_table_from_acpi *tbl = rtwsar->tables;
110+
enum rtw89_acpi_sar_subband subband_l, subband_h;
111+
const struct rtw89_sar_entry_from_acpi *ent;
112+
u32 center_freq = sar_parm->center_freq;
113+
const struct rtw89_6ghz_span *span;
114+
enum rtw89_regulation_type regd;
115+
enum rtw89_band band;
116+
s32 cfg_a, cfg_b;
117+
118+
span = rtw89_get_6ghz_span(rtwdev, center_freq);
119+
120+
if (span && RTW89_ACPI_SAR_SPAN_VALID(span)) {
121+
subband_l = span->acpi_sar_subband_low;
122+
subband_h = span->acpi_sar_subband_high;
123+
} else {
124+
subband_l = rtw89_acpi_sar_get_subband(rtwdev, center_freq);
125+
subband_h = subband_l;
126+
}
127+
128+
band = rtw89_acpi_sar_subband_to_band(rtwdev, subband_l);
129+
regd = rtw89_regd_get(rtwdev, band);
130+
ent = &tbl->entries[regd];
131+
132+
cfg_a = rtw89_sar_cfg_acpi_get_min(ent, RF_PATH_A, subband_l, subband_h);
133+
cfg_b = rtw89_sar_cfg_acpi_get_min(ent, RF_PATH_B, subband_l, subband_h);
134+
*cfg = min(cfg_a, cfg_b);
135+
136+
if (sar_parm->ntx == RTW89_2TX)
137+
*cfg -= rtwsar->downgrade_2tx;
138+
139+
return 0;
140+
}
141+
95142
static const
96143
struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = {
97144
[RTW89_SAR_SOURCE_COMMON] = {
98145
.descr_sar_source = "RTW89_SAR_SOURCE_COMMON",
99146
.txpwr_factor_sar = 2,
100147
.query_sar_config = rtw89_query_sar_config_common,
101148
},
149+
[RTW89_SAR_SOURCE_ACPI] = {
150+
.descr_sar_source = "RTW89_SAR_SOURCE_ACPI",
151+
.txpwr_factor_sar = TXPWR_FACTOR_OF_RTW89_ACPI_SAR,
152+
.query_sar_config = rtw89_query_sar_config_acpi,
153+
},
102154
};
103155

104156
#define rtw89_sar_set_src(_dev, _src, _cfg_name, _cfg_data) \
@@ -288,16 +340,7 @@ int rtw89_print_tas(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
288340
static int rtw89_apply_sar_common(struct rtw89_dev *rtwdev,
289341
const struct rtw89_sar_cfg_common *sar)
290342
{
291-
enum rtw89_sar_sources src;
292-
293-
lockdep_assert_wiphy(rtwdev->hw->wiphy);
294-
295-
src = rtwdev->sar.src;
296-
if (src != RTW89_SAR_SOURCE_NONE && src != RTW89_SAR_SOURCE_COMMON) {
297-
rtw89_warn(rtwdev, "SAR source: %d is in use", src);
298-
return -EBUSY;
299-
}
300-
343+
/* let common SAR have the highest priority; always apply it */
301344
rtw89_sar_set_src(rtwdev, RTW89_SAR_SOURCE_COMMON, cfg_common, sar);
302345
rtw89_core_set_chip_txpwr(rtwdev);
303346
rtw89_tas_reset(rtwdev, false);
@@ -365,6 +408,78 @@ int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
365408
return rtw89_apply_sar_common(rtwdev, &sar_common);
366409
}
367410

411+
static void rtw89_apply_sar_acpi(struct rtw89_dev *rtwdev,
412+
const struct rtw89_sar_cfg_acpi *sar)
413+
{
414+
const struct rtw89_sar_table_from_acpi *tbl;
415+
const struct rtw89_sar_entry_from_acpi *ent;
416+
enum rtw89_sar_sources src;
417+
unsigned int i, j, k;
418+
419+
src = rtwdev->sar.src;
420+
if (src != RTW89_SAR_SOURCE_NONE) {
421+
rtw89_warn(rtwdev, "SAR source: %d is in use", src);
422+
return;
423+
}
424+
425+
rtw89_debug(rtwdev, RTW89_DBG_SAR,
426+
"SAR-ACPI downgrade 2TX: %u (unit: 1/%lu dBm)\n",
427+
sar->downgrade_2tx, BIT(TXPWR_FACTOR_OF_RTW89_ACPI_SAR));
428+
429+
for (i = 0; i < sar->valid_num; i++) {
430+
tbl = &sar->tables[i];
431+
432+
for (j = 0; j < RTW89_REGD_NUM; j++) {
433+
ent = &tbl->entries[j];
434+
435+
rtw89_debug(rtwdev, RTW89_DBG_SAR,
436+
"SAR-ACPI-[%u] REGD-%s (unit: 1/%lu dBm)\n",
437+
i, rtw89_regd_get_string(j),
438+
BIT(TXPWR_FACTOR_OF_RTW89_ACPI_SAR));
439+
440+
for (k = 0; k < NUM_OF_RTW89_ACPI_SAR_SUBBAND; k++)
441+
rtw89_debug(rtwdev, RTW89_DBG_SAR,
442+
"On subband %u, { %d, %d }\n", k,
443+
ent->v[k][RF_PATH_A], ent->v[k][RF_PATH_B]);
444+
}
445+
}
446+
447+
rtw89_sar_set_src(rtwdev, RTW89_SAR_SOURCE_ACPI, cfg_acpi, sar);
448+
449+
/* SAR via ACPI is only configured in the early initial phase, so
450+
* it does not seem necessary to reset txpwr related things here.
451+
*/
452+
}
453+
454+
static void rtw89_set_sar_from_acpi(struct rtw89_dev *rtwdev)
455+
{
456+
struct rtw89_sar_cfg_acpi *cfg;
457+
int ret;
458+
459+
lockdep_assert_wiphy(rtwdev->hw->wiphy);
460+
461+
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
462+
if (!cfg)
463+
return;
464+
465+
ret = rtw89_acpi_evaluate_sar(rtwdev, cfg);
466+
if (ret) {
467+
rtw89_debug(rtwdev, RTW89_DBG_SAR,
468+
"evaluating ACPI SAR returns %d\n", ret);
469+
goto out;
470+
}
471+
472+
if (unlikely(!cfg->valid_num)) {
473+
rtw89_debug(rtwdev, RTW89_DBG_SAR, "no valid SAR table from ACPI\n");
474+
goto out;
475+
}
476+
477+
rtw89_apply_sar_acpi(rtwdev, cfg);
478+
479+
out:
480+
kfree(cfg);
481+
}
482+
368483
static bool rtw89_tas_query_sar_config(struct rtw89_dev *rtwdev, s32 *cfg)
369484
{
370485
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
@@ -524,7 +639,7 @@ static void rtw89_tas_rolling_average(struct rtw89_dev *rtwdev)
524639
rtw89_tas_state_update(rtwdev, state);
525640
}
526641

527-
void rtw89_tas_init(struct rtw89_dev *rtwdev)
642+
static void rtw89_tas_init(struct rtw89_dev *rtwdev)
528643
{
529644
const struct rtw89_chip_info *chip = rtwdev->chip;
530645
struct rtw89_tas_info *tas = &rtwdev->tas;
@@ -671,3 +786,9 @@ void rtw89_tas_chanctx_cb(struct rtw89_dev *rtwdev,
671786
}
672787
}
673788
EXPORT_SYMBOL(rtw89_tas_chanctx_cb);
789+
790+
void rtw89_sar_init(struct rtw89_dev *rtwdev)
791+
{
792+
rtw89_set_sar_from_acpi(rtwdev);
793+
rtw89_tas_init(rtwdev);
794+
}

0 commit comments

Comments
 (0)