mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
wifi: rtw89: regd/acpi: support 6 GHz VLP policy via ACPI DSM
Process ACPI DSM function 11 to get 6 GHz VLP support by country. If not allowed, return error to block the connection. By default, i.e. ACPI DSM function is not configured, disallow 6 GHz VLP on country US and country CA, because some platform-level certifications are needed in FCC regulation before operating on 6 GHz VLP connection. Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20250709065006.32028-5-pkshih@realtek.com
This commit is contained in:
parent
08fbc2b688
commit
b99d7cd36d
|
|
@ -236,6 +236,50 @@ int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool chk_acpi_policy_6ghz_vlp_sig(const struct rtw89_acpi_policy_6ghz_vlp *p)
|
||||
{
|
||||
return p->signature[0] == 0x52 &&
|
||||
p->signature[1] == 0x54 &&
|
||||
p->signature[2] == 0x4B &&
|
||||
p->signature[3] == 0x0B;
|
||||
}
|
||||
|
||||
static
|
||||
int rtw89_acpi_dsm_get_policy_6ghz_vlp(struct rtw89_dev *rtwdev,
|
||||
union acpi_object *obj,
|
||||
struct rtw89_acpi_policy_6ghz_vlp **policy)
|
||||
{
|
||||
const struct rtw89_acpi_policy_6ghz_vlp *ptr;
|
||||
u32 buf_len;
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI,
|
||||
"acpi: expect buffer but type: %d\n", obj->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf_len = obj->buffer.length;
|
||||
if (buf_len < sizeof(*ptr)) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
|
||||
__func__, buf_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ptr = (typeof(ptr))obj->buffer.pointer;
|
||||
if (!chk_acpi_policy_6ghz_vlp_sig(ptr)) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!*policy)
|
||||
return -ENOMEM;
|
||||
|
||||
rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_vlp: ", *policy,
|
||||
sizeof(*ptr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool chk_acpi_policy_tas_sig(const struct rtw89_acpi_policy_tas *p)
|
||||
{
|
||||
return p->signature[0] == 0x52 &&
|
||||
|
|
@ -345,6 +389,9 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
|
|||
else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP)
|
||||
ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj,
|
||||
&res->u.policy_6ghz_sp);
|
||||
else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP)
|
||||
ret = rtw89_acpi_dsm_get_policy_6ghz_vlp(rtwdev, obj,
|
||||
&res->u.policy_6ghz_vlp);
|
||||
else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN)
|
||||
ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas);
|
||||
else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ enum rtw89_acpi_dsm_func {
|
|||
RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6,
|
||||
RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7,
|
||||
RTW89_ACPI_DSM_FUNC_REG_RULES_EN = 10,
|
||||
RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP = 11,
|
||||
};
|
||||
|
||||
enum rtw89_acpi_conf_unii4 {
|
||||
|
|
@ -68,6 +69,19 @@ struct rtw89_acpi_policy_6ghz_sp {
|
|||
u8 rsvd;
|
||||
} __packed;
|
||||
|
||||
enum rtw89_acpi_conf_6ghz_vlp {
|
||||
RTW89_ACPI_CONF_6GHZ_VLP_US = BIT(0),
|
||||
RTW89_ACPI_CONF_6GHZ_VLP_CA = BIT(1),
|
||||
};
|
||||
|
||||
struct rtw89_acpi_policy_6ghz_vlp {
|
||||
u8 signature[4];
|
||||
u8 revision;
|
||||
u8 override;
|
||||
u8 conf;
|
||||
u8 rsvd;
|
||||
} __packed;
|
||||
|
||||
struct rtw89_acpi_policy_tas {
|
||||
u8 signature[4];
|
||||
u8 revision;
|
||||
|
|
@ -93,6 +107,7 @@ struct rtw89_acpi_dsm_result {
|
|||
/* caller needs to free it after using */
|
||||
struct rtw89_acpi_policy_6ghz *policy_6ghz;
|
||||
struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp;
|
||||
struct rtw89_acpi_policy_6ghz_vlp *policy_6ghz_vlp;
|
||||
struct rtw89_acpi_policy_tas *policy_tas;
|
||||
struct rtw89_acpi_policy_reg_rules *policy_reg_rules;
|
||||
} u;
|
||||
|
|
|
|||
|
|
@ -5386,6 +5386,7 @@ struct rtw89_regulatory_info {
|
|||
DECLARE_BITMAP(block_unii4, RTW89_REGD_MAX_COUNTRY_NUM);
|
||||
DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
|
||||
DECLARE_BITMAP(block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM);
|
||||
DECLARE_BITMAP(block_6ghz_vlp, RTW89_REGD_MAX_COUNTRY_NUM);
|
||||
};
|
||||
|
||||
enum rtw89_ifs_clm_application {
|
||||
|
|
|
|||
|
|
@ -521,6 +521,55 @@ static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev)
|
|||
kfree(ptr);
|
||||
}
|
||||
|
||||
static void rtw89_regd_setup_policy_6ghz_vlp(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
|
||||
const struct rtw89_acpi_policy_6ghz_vlp *ptr = NULL;
|
||||
struct rtw89_acpi_dsm_result res = {};
|
||||
bool enable;
|
||||
u8 index;
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
/* By default, allow 6 GHz VLP on all countries except US and CA. */
|
||||
val = ~(RTW89_ACPI_CONF_6GHZ_VLP_US | RTW89_ACPI_CONF_6GHZ_VLP_CA);
|
||||
|
||||
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP, &res);
|
||||
if (ret) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_REGD,
|
||||
"acpi: cannot eval policy 6ghz-vlp: %d\n", ret);
|
||||
goto bottom;
|
||||
}
|
||||
|
||||
ptr = res.u.policy_6ghz_vlp;
|
||||
|
||||
switch (ptr->override) {
|
||||
default:
|
||||
rtw89_debug(rtwdev, RTW89_DBG_REGD,
|
||||
"%s: unknown override case: %d\n", __func__,
|
||||
ptr->override);
|
||||
fallthrough;
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
val = ptr->conf;
|
||||
break;
|
||||
}
|
||||
|
||||
bottom:
|
||||
index = rtw89_regd_get_index_by_name(rtwdev, "US");
|
||||
enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_US);
|
||||
if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM)
|
||||
set_bit(index, regulatory->block_6ghz_vlp);
|
||||
|
||||
index = rtw89_regd_get_index_by_name(rtwdev, "CA");
|
||||
enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_CA);
|
||||
if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM)
|
||||
set_bit(index, regulatory->block_6ghz_vlp);
|
||||
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
|
||||
{
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
|
|
@ -564,6 +613,7 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
|
|||
if (regd_allow_6ghz) {
|
||||
rtw89_regd_setup_policy_6ghz(rtwdev);
|
||||
rtw89_regd_setup_policy_6ghz_sp(rtwdev);
|
||||
rtw89_regd_setup_policy_6ghz_vlp(rtwdev);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1059,7 +1109,16 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
|
|||
struct rtw89_vif_link *rtwvif_link, bool active,
|
||||
unsigned int *changed)
|
||||
{
|
||||
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
|
||||
const struct rtw89_regd *regd = regulatory->regd;
|
||||
bool blocked[NUM_OF_RTW89_REG_6GHZ_POWER] = {};
|
||||
u8 index = rtw89_regd_get_index(rtwdev, regd);
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
bool dflt = false;
|
||||
|
||||
if (index == RTW89_REGD_MAX_COUNTRY_NUM ||
|
||||
test_bit(index, regulatory->block_6ghz_vlp))
|
||||
blocked[RTW89_REG_6GHZ_POWER_VLP] = true;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
|
|
@ -1078,6 +1137,7 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
|
|||
break;
|
||||
default:
|
||||
rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
|
||||
dflt = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1086,6 +1146,14 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
|
|||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!dflt && blocked[rtwvif_link->reg_6ghz_power]) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_REGD,
|
||||
"%c%c 6 GHz power type-%u is blocked by policy\n",
|
||||
regd->alpha2[0], regd->alpha2[1],
|
||||
rtwvif_link->reg_6ghz_power);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*changed += __rtw89_reg_6ghz_power_recalc(rtwdev);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user