mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-05 17:03:47 -04:00
wifi: rtw89: acpi: process 6 GHz band policy from DSM
Realtek ACPI DSM func 4, RTW89_ACPI_DSM_FUNC_6G_BP, accepts a configuration via ACPI buffer as below. | index | description | ------------------------- | [0-2] | signature | | [3] | reserved | | [4] | policy mode | | [5] | country count | | [6-] | country list | Through this function, BIOS can indicate to allow/block 6 GHz on some specific countries. Still, driver should follow regd first before taking this configuration into account. Besides, add a bit in debug mask for ACPI. Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://lore.kernel.org/r/20231114091359.50664-2-pkshih@realtek.com
This commit is contained in:
committed by
Kalle Valo
parent
2c4e9acbe3
commit
665ecff7dd
@@ -12,27 +12,74 @@ static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00,
|
||||
0x82, 0xBD, 0xFE, 0x86,
|
||||
0x07, 0x80, 0x3A, 0xA7);
|
||||
|
||||
static int rtw89_acpi_dsm_get(struct rtw89_dev *rtwdev, union acpi_object *obj,
|
||||
u8 *value)
|
||||
static
|
||||
int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj,
|
||||
u8 *value)
|
||||
{
|
||||
switch (obj->type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
*value = (u8)obj->integer.value;
|
||||
break;
|
||||
case ACPI_TYPE_BUFFER:
|
||||
*value = obj->buffer.pointer[0];
|
||||
break;
|
||||
default:
|
||||
rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
|
||||
"acpi dsm return unhandled type: %d\n", obj->type);
|
||||
if (obj->type != ACPI_TYPE_INTEGER) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI,
|
||||
"acpi: expect integer but type: %d\n", obj->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*value = (u8)obj->integer.value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p)
|
||||
{
|
||||
return p->signature[0] == 0x00 &&
|
||||
p->signature[1] == 0xE0 &&
|
||||
p->signature[2] == 0x4C;
|
||||
}
|
||||
|
||||
static
|
||||
int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev,
|
||||
union acpi_object *obj,
|
||||
struct rtw89_acpi_policy_6ghz **policy_6ghz)
|
||||
{
|
||||
const struct rtw89_acpi_policy_6ghz *ptr;
|
||||
u32 expect_len;
|
||||
u32 len;
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI,
|
||||
"acpi: expect buffer but type: %d\n", obj->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = obj->buffer.length;
|
||||
if (len < sizeof(*ptr)) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
|
||||
__func__, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ptr = (typeof(ptr))obj->buffer.pointer;
|
||||
if (!chk_acpi_policy_6ghz_sig(ptr)) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
expect_len = struct_size(ptr, country_list, ptr->country_count);
|
||||
if (len < expect_len) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n",
|
||||
__func__, expect_len, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL);
|
||||
if (!*policy_6ghz)
|
||||
return -ENOMEM;
|
||||
|
||||
rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz,
|
||||
expect_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
|
||||
enum rtw89_acpi_dsm_func func, u8 *value)
|
||||
enum rtw89_acpi_dsm_func func,
|
||||
struct rtw89_acpi_dsm_result *res)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
int ret;
|
||||
@@ -40,12 +87,16 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
|
||||
obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
|
||||
0, func, NULL);
|
||||
if (!obj) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
|
||||
rtw89_debug(rtwdev, RTW89_DBG_ACPI,
|
||||
"acpi dsm fail to evaluate func: %d\n", func);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = rtw89_acpi_dsm_get(rtwdev, obj, value);
|
||||
if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
|
||||
ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
|
||||
&res->u.policy_6ghz);
|
||||
else
|
||||
ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
|
||||
|
||||
ACPI_FREE(obj);
|
||||
return ret;
|
||||
|
||||
@@ -15,7 +15,37 @@ enum rtw89_acpi_dsm_func {
|
||||
RTW89_ACPI_DSM_FUNC_59G_EN = 6,
|
||||
};
|
||||
|
||||
enum rtw89_acpi_policy_mode {
|
||||
RTW89_ACPI_POLICY_BLOCK = 0,
|
||||
RTW89_ACPI_POLICY_ALLOW = 1,
|
||||
};
|
||||
|
||||
struct rtw89_acpi_country_code {
|
||||
/* below are allowed:
|
||||
* * ISO alpha2 country code
|
||||
* * EU for countries in Europe
|
||||
*/
|
||||
char alpha2[2];
|
||||
} __packed;
|
||||
|
||||
struct rtw89_acpi_policy_6ghz {
|
||||
u8 signature[3];
|
||||
u8 rsvd;
|
||||
u8 policy_mode;
|
||||
u8 country_count;
|
||||
struct rtw89_acpi_country_code country_list[] __counted_by(country_count);
|
||||
} __packed;
|
||||
|
||||
struct rtw89_acpi_dsm_result {
|
||||
union {
|
||||
u8 value;
|
||||
/* caller needs to free it after using */
|
||||
struct rtw89_acpi_policy_6ghz *policy_6ghz;
|
||||
} u;
|
||||
};
|
||||
|
||||
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
|
||||
enum rtw89_acpi_dsm_func func, u8 *value);
|
||||
enum rtw89_acpi_dsm_func func,
|
||||
struct rtw89_acpi_dsm_result *res);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@ enum rtw89_debug_mask {
|
||||
RTW89_DBG_WOW = BIT(18),
|
||||
RTW89_DBG_UL_TB = BIT(19),
|
||||
RTW89_DBG_CHAN = BIT(20),
|
||||
RTW89_DBG_ACPI = BIT(21),
|
||||
|
||||
RTW89_DBG_UNEXP = BIT(31),
|
||||
};
|
||||
|
||||
@@ -291,19 +291,22 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
bool regd_allow_unii_4 = chip->support_unii4;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct rtw89_acpi_dsm_result res = {};
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
if (!chip->support_unii4)
|
||||
goto bottom;
|
||||
|
||||
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &val);
|
||||
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &res);
|
||||
if (ret) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_REGD,
|
||||
"acpi: cannot eval unii 4: %d\n", ret);
|
||||
goto bottom;
|
||||
}
|
||||
|
||||
val = res.u.value;
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_REGD,
|
||||
"acpi: eval if allow unii 4: %d\n", val);
|
||||
|
||||
@@ -338,19 +341,22 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
|
||||
bool chip_support_6ghz = chip->support_bands & BIT(NL80211_BAND_6GHZ);
|
||||
bool regd_allow_6ghz = chip_support_6ghz;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct rtw89_acpi_dsm_result res = {};
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
if (!chip_support_6ghz)
|
||||
goto bottom;
|
||||
|
||||
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &val);
|
||||
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &res);
|
||||
if (ret) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_REGD,
|
||||
"acpi: cannot eval 6ghz: %d\n", ret);
|
||||
goto bottom;
|
||||
}
|
||||
|
||||
val = res.u.value;
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_REGD,
|
||||
"acpi: eval if disallow 6ghz: %d\n", val);
|
||||
|
||||
|
||||
@@ -404,16 +404,18 @@ static void rtw89_tas_state_update(struct rtw89_dev *rtwdev)
|
||||
void rtw89_tas_init(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_tas_info *tas = &rtwdev->tas;
|
||||
struct rtw89_acpi_dsm_result res = {};
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &val);
|
||||
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &res);
|
||||
if (ret) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_SAR,
|
||||
"acpi: cannot get TAS: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
val = res.u.value;
|
||||
switch (val) {
|
||||
case 0:
|
||||
tas->enable = false;
|
||||
|
||||
Reference in New Issue
Block a user