wifi: rtw89: regd: extend policy of UNII-4 for IC regulatory
authorZong-Zhe Yang <kevin_yang@realtek.com>
Fri, 12 Apr 2024 11:57:27 +0000 (19:57 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Thu, 18 Apr 2024 01:10:04 +0000 (09:10 +0800)
Originally, we have an ACPI function to determine whether to enable UNII-4.
Since IC (Industry Canada) has allowed UNII-4, the ACPI result is extended
to be two bits as below.
  * BIT(0): determine if rtw89_regd::FCC enable UNII-4
  * BIT(1): determine if rtw89_regd::IC enable UNII-4

Besides, to take old platforms into account, we enable UNII-4 on IC if and
only if BIOS configuration enable it.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://msgid.link/20240412115729.8316-7-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/acpi.h
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/regd.c

index fe85b40cf07698c54f80fb5994bd28a9859cb2bf..5182797e68b6d40e4fd27364f802c0a7b0a9111f 100644 (file)
@@ -12,7 +12,12 @@ enum rtw89_acpi_dsm_func {
        RTW89_ACPI_DSM_FUNC_6G_DIS = 3,
        RTW89_ACPI_DSM_FUNC_6G_BP = 4,
        RTW89_ACPI_DSM_FUNC_TAS_EN = 5,
-       RTW89_ACPI_DSM_FUNC_59G_EN = 6,
+       RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6,
+};
+
+enum rtw89_acpi_conf_unii4 {
+       RTW89_ACPI_CONF_UNII4_FCC = BIT(0),
+       RTW89_ACPI_CONF_UNII4_IC = BIT(1),
 };
 
 enum rtw89_acpi_policy_mode {
index 52588f04155a3652907f16b6dde98b0220e1dd4b..a02c26b51fa645532a58477a3107219efdf905f9 100644 (file)
@@ -82,6 +82,9 @@ static struct ieee80211_channel rtw89_channels_5ghz[] = {
        RTW89_DEF_CHAN_5G(5885, 177),
 };
 
+static_assert(RTW89_5GHZ_UNII4_START_INDEX + RTW89_5GHZ_UNII4_CHANNEL_NUM ==
+             ARRAY_SIZE(rtw89_channels_5ghz));
+
 static struct ieee80211_channel rtw89_channels_6ghz[] = {
        RTW89_DEF_CHAN_6G(5955, 1),
        RTW89_DEF_CHAN_6G(5975, 5),
index 2cc8785f3205d7a543934fd6856b3c1b5d47602e..7cd6b31797133a5cf48337e744d5be2369aab65e 100644 (file)
@@ -4752,10 +4752,13 @@ struct rtw89_regd {
 };
 
 #define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX
+#define RTW89_5GHZ_UNII4_CHANNEL_NUM 3
+#define RTW89_5GHZ_UNII4_START_INDEX 25
 
 struct rtw89_regulatory_info {
        const struct rtw89_regd *regd;
        enum rtw89_reg_6ghz_power reg_6ghz_power;
+       DECLARE_BITMAP(block_unii4, RTW89_REGD_MAX_COUNTRY_NUM);
        DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
 };
 
index 85a7f902ccf9fb570511cc00294095a360ae5eda..47384615e18c1465fa6e139b090edc140182f78a 100644 (file)
@@ -341,51 +341,60 @@ do { \
 static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
                                   struct wiphy *wiphy)
 {
+       struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
        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 = {};
+       bool enable_by_fcc;
+       bool enable_by_ic;
        int ret;
        u8 val;
+       int i;
 
-       if (!chip->support_unii4)
-               goto bottom;
+       sband = wiphy->bands[NL80211_BAND_5GHZ];
+       if (!sband)
+               return;
 
-       ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &res);
+       if (!chip->support_unii4) {
+               sband->n_channels -= RTW89_5GHZ_UNII4_CHANNEL_NUM;
+               return;
+       }
+
+       bitmap_fill(regulatory->block_unii4, RTW89_REGD_MAX_COUNTRY_NUM);
+
+       ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_UNII4_SUP, &res);
        if (ret) {
                rtw89_debug(rtwdev, RTW89_DBG_REGD,
                            "acpi: cannot eval unii 4: %d\n", ret);
+               enable_by_fcc = true;
+               enable_by_ic = false;
                goto bottom;
        }
 
        val = res.u.value;
+       enable_by_fcc = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_FCC);
+       enable_by_ic = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_IC);
 
        rtw89_debug(rtwdev, RTW89_DBG_REGD,
-                   "acpi: eval if allow unii 4: %d\n", val);
-
-       switch (val) {
-       case 0:
-               regd_allow_unii_4 = false;
-               break;
-       case 1:
-               regd_allow_unii_4 = true;
-               break;
-       default:
-               break;
-       }
+                   "acpi: eval if allow unii-4: 0x%x\n", val);
 
 bottom:
-       rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow unii 4: %d\n",
-                   regd_allow_unii_4);
-
-       if (regd_allow_unii_4)
-               return;
-
-       sband = wiphy->bands[NL80211_BAND_5GHZ];
-       if (!sband)
-               return;
+       for (i = 0; i < ARRAY_SIZE(rtw89_regd_map); i++) {
+               const struct rtw89_regd *regd = &rtw89_regd_map[i];
 
-       sband->n_channels -= 3;
+               switch (regd->txpwr_regd[RTW89_BAND_5G]) {
+               case RTW89_FCC:
+                       if (enable_by_fcc)
+                               clear_bit(i, regulatory->block_unii4);
+                       break;
+               case RTW89_IC:
+                       if (enable_by_ic)
+                               clear_bit(i, regulatory->block_unii4);
+                       break;
+               default:
+                       break;
+               }
+       }
 }
 
 static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block,
@@ -562,6 +571,35 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev,
        return 0;
 }
 
+static void rtw89_regd_apply_policy_unii4(struct rtw89_dev *rtwdev,
+                                         struct wiphy *wiphy)
+{
+       struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+       const struct rtw89_chip_info *chip = rtwdev->chip;
+       const struct rtw89_regd *regd = regulatory->regd;
+       struct ieee80211_supported_band *sband;
+       u8 index;
+       int i;
+
+       sband = wiphy->bands[NL80211_BAND_5GHZ];
+       if (!sband)
+               return;
+
+       if (!chip->support_unii4)
+               return;
+
+       index = rtw89_regd_get_index(regd);
+       if (index != RTW89_REGD_MAX_COUNTRY_NUM &&
+           !test_bit(index, regulatory->block_unii4))
+               return;
+
+       rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c unii-4 is blocked by policy\n",
+                   regd->alpha2[0], regd->alpha2[1]);
+
+       for (i = RTW89_5GHZ_UNII4_START_INDEX; i < sband->n_channels; i++)
+               sband->channels[i].flags |= IEEE80211_CHAN_DISABLED;
+}
+
 static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev,
                                         struct wiphy *wiphy)
 {
@@ -602,6 +640,7 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev,
        else
                wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE;
 
+       rtw89_regd_apply_policy_unii4(rtwdev, wiphy);
        rtw89_regd_apply_policy_6ghz(rtwdev, wiphy);
 }