Skip to content

Commit b2774a9

Browse files
Zong-Zhe YangKalle Valo
authored andcommitted
wifi: rtw89: regd: handle policy of 6 GHz according to BIOS
According to BIOS configuration of Realtek ACPI DSM function 4, RTW89_ACPI_DSM_FUNC_6G_BP, we handle the regd policy of 6 GHz. Policy defines two modes as below. 1. `BLOCK` mode: The countries in configured list are blocked. 2. `ALLOW` mode: _Only_ the countries in configured list are allowed. (i.e. others are all blocked.) Then, when receiving regulatory notification at runtime, if 6 GHz is blocked on the country, 6 GHz channels will be disabled. Signed-off-by: Zong-Zhe Yang <[email protected]> Signed-off-by: Ping-Ke Shih <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 665ecff commit b2774a9

File tree

2 files changed

+160
-2
lines changed

2 files changed

+160
-2
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4327,9 +4327,12 @@ struct rtw89_regd {
43274327
u8 txpwr_regd[RTW89_BAND_NUM];
43284328
};
43294329

4330+
#define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX
4331+
43304332
struct rtw89_regulatory_info {
43314333
const struct rtw89_regd *regd;
43324334
enum rtw89_reg_6ghz_power reg_6ghz_power;
4335+
DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
43334336
};
43344337

43354338
enum rtw89_ifs_clm_application {

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

Lines changed: 157 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,42 @@ static const struct rtw89_regd rtw89_regd_map[] = {
257257
COUNTRY_REGD("PS", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
258258
};
259259

260-
static const struct rtw89_regd *rtw89_regd_find_reg_by_name(char *alpha2)
260+
static const char rtw89_alpha2_list_eu[][3] = {
261+
"AT",
262+
"BE",
263+
"CY",
264+
"CZ",
265+
"DK",
266+
"EE",
267+
"FI",
268+
"FR",
269+
"DE",
270+
"GR",
271+
"HU",
272+
"IS",
273+
"IE",
274+
"IT",
275+
"LV",
276+
"LI",
277+
"LT",
278+
"LU",
279+
"MT",
280+
"MC",
281+
"NL",
282+
"NO",
283+
"PL",
284+
"PT",
285+
"SK",
286+
"SI",
287+
"ES",
288+
"SE",
289+
"CH",
290+
"BG",
291+
"HR",
292+
"RO",
293+
};
294+
295+
static const struct rtw89_regd *rtw89_regd_find_reg_by_name(const char *alpha2)
261296
{
262297
u32 i;
263298

@@ -274,6 +309,24 @@ static bool rtw89_regd_is_ww(const struct rtw89_regd *regd)
274309
return regd == &rtw89_ww_regd;
275310
}
276311

312+
static u8 rtw89_regd_get_index(const struct rtw89_regd *regd)
313+
{
314+
BUILD_BUG_ON(ARRAY_SIZE(rtw89_regd_map) > RTW89_REGD_MAX_COUNTRY_NUM);
315+
316+
if (rtw89_regd_is_ww(regd))
317+
return RTW89_REGD_MAX_COUNTRY_NUM;
318+
319+
return regd - rtw89_regd_map;
320+
}
321+
322+
static u8 rtw89_regd_get_index_by_name(const char *alpha2)
323+
{
324+
const struct rtw89_regd *regd;
325+
326+
regd = rtw89_regd_find_reg_by_name(alpha2);
327+
return rtw89_regd_get_index(regd);
328+
}
329+
277330
#define rtw89_debug_regd(_dev, _regd, _desc, _argv...) \
278331
do { \
279332
typeof(_regd) __r = _regd; \
@@ -335,6 +388,77 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
335388
sband->n_channels -= 3;
336389
}
337390

391+
static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block,
392+
const char *alpha2)
393+
{
394+
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
395+
u8 index;
396+
397+
index = rtw89_regd_get_index_by_name(alpha2);
398+
if (index == RTW89_REGD_MAX_COUNTRY_NUM) {
399+
rtw89_debug(rtwdev, RTW89_DBG_REGD, "%s: unknown alpha2 %c%c\n",
400+
__func__, alpha2[0], alpha2[1]);
401+
return;
402+
}
403+
404+
if (block)
405+
set_bit(index, regulatory->block_6ghz);
406+
else
407+
clear_bit(index, regulatory->block_6ghz);
408+
}
409+
410+
static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev)
411+
{
412+
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
413+
const struct rtw89_acpi_country_code *country;
414+
const struct rtw89_acpi_policy_6ghz *ptr;
415+
struct rtw89_acpi_dsm_result res = {};
416+
bool to_block;
417+
int i, j;
418+
int ret;
419+
420+
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_BP, &res);
421+
if (ret) {
422+
rtw89_debug(rtwdev, RTW89_DBG_REGD,
423+
"acpi: cannot eval policy 6ghz: %d\n", ret);
424+
return;
425+
}
426+
427+
ptr = res.u.policy_6ghz;
428+
429+
switch (ptr->policy_mode) {
430+
case RTW89_ACPI_POLICY_BLOCK:
431+
to_block = true;
432+
break;
433+
case RTW89_ACPI_POLICY_ALLOW:
434+
to_block = false;
435+
/* only below list is allowed; block all first */
436+
bitmap_fill(regulatory->block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
437+
break;
438+
default:
439+
rtw89_debug(rtwdev, RTW89_DBG_REGD,
440+
"%s: unknown policy mode: %d\n", __func__,
441+
ptr->policy_mode);
442+
goto out;
443+
}
444+
445+
for (i = 0; i < ptr->country_count; i++) {
446+
country = &ptr->country_list[i];
447+
if (memcmp("EU", country->alpha2, 2) != 0) {
448+
__rtw89_regd_setup_policy_6ghz(rtwdev, to_block,
449+
country->alpha2);
450+
continue;
451+
}
452+
453+
for (j = 0; j < ARRAY_SIZE(rtw89_alpha2_list_eu); j++)
454+
__rtw89_regd_setup_policy_6ghz(rtwdev, to_block,
455+
rtw89_alpha2_list_eu[j]);
456+
}
457+
458+
out:
459+
kfree(ptr);
460+
}
461+
338462
static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
339463
{
340464
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -375,8 +499,10 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
375499
rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow 6ghz: %d\n",
376500
regd_allow_6ghz);
377501

378-
if (regd_allow_6ghz)
502+
if (regd_allow_6ghz) {
503+
rtw89_regd_setup_policy_6ghz(rtwdev);
379504
return;
505+
}
380506

381507
sband = wiphy->bands[NL80211_BAND_6GHZ];
382508
if (!sband)
@@ -436,6 +562,33 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev,
436562
return 0;
437563
}
438564

565+
static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev,
566+
struct wiphy *wiphy)
567+
{
568+
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
569+
const struct rtw89_regd *regd = regulatory->regd;
570+
struct ieee80211_supported_band *sband;
571+
u8 index;
572+
int i;
573+
574+
index = rtw89_regd_get_index(regd);
575+
if (index == RTW89_REGD_MAX_COUNTRY_NUM)
576+
return;
577+
578+
if (!test_bit(index, regulatory->block_6ghz))
579+
return;
580+
581+
rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n",
582+
regd->alpha2[0], regd->alpha2[1]);
583+
584+
sband = wiphy->bands[NL80211_BAND_6GHZ];
585+
if (!sband)
586+
return;
587+
588+
for (i = 0; i < sband->n_channels; i++)
589+
sband->channels[i].flags |= IEEE80211_CHAN_DISABLED;
590+
}
591+
439592
static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev,
440593
struct wiphy *wiphy,
441594
struct regulatory_request *request)
@@ -450,6 +603,8 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev,
450603
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
451604
else
452605
wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE;
606+
607+
rtw89_regd_apply_policy_6ghz(rtwdev, wiphy);
453608
}
454609

455610
void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request)

0 commit comments

Comments
 (0)