]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: advertise UHR capabilities for such devices
authorJohannes Berg <johannes.berg@intel.com>
Tue, 12 May 2026 05:22:58 +0000 (08:22 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:10 +0000 (15:17 +0300)
Advertise UHR capabilities for devices supporting UHR
(i.e. devices with some, but not all, PE RFs.)

For correct support it's also needed to plumb through
the regulatory flags the firmware might have/enforce.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Link: https://patch.msgid.link/20260512082114.ef9ebeb41889.I85b67f4973752bcf62416dabb943b9ddf1e63f16@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-utils.h
drivers/net/wireless/intel/iwlwifi/pcie/drv.c

index 2c29054ce7b848c653eec77bcfe1e675ee41eaf8..c02478b73057990288b31cec783193de1697a7c5 100644 (file)
@@ -4,7 +4,28 @@
  */
 #include "iwl-config.h"
 
-/* currently iwl_rf_wh/iwl_rf_wh_160mhz are just defines for the FM ones */
+#define IWL_PE_NVM_VERSION             0x0a1d
+
+#define IWL_DEVICE_PE                                                  \
+       .ht_params = {                                                  \
+               .stbc = true,                                           \
+               .ldpc = true,                                           \
+               .ht40_bands = BIT(NL80211_BAND_2GHZ) |                  \
+                             BIT(NL80211_BAND_5GHZ),                   \
+       },                                                              \
+       .led_mode = IWL_LED_RF_STATE,                                   \
+       .non_shared_ant = ANT_B,                                        \
+       .vht_mu_mimo_supported = true,                                  \
+       .uhb_supported = true,                                          \
+       .eht_supported = true,                                          \
+       .uhr_supported = true,                                          \
+       .num_rbds = IWL_NUM_RBDS_EHT,                                   \
+       .nvm_ver = IWL_PE_NVM_VERSION,                                  \
+       .nvm_type = IWL_NVM_EXT
+
+const struct iwl_rf_cfg iwl_rf_pe = {
+       IWL_DEVICE_PE,
+};
 
 const char iwl_killer_bn1850w2_name[] =
        "Killer(R) Wi-Fi 8 BN1850w2 320MHz Wireless Network Adapter (BN201.D2W)";
index 5f40cd15e27f777ec1ec7fc2ad5170b829e2124f..da6d3686e7dd0d080d3ab0b2537e82945defb3c6 100644 (file)
@@ -416,6 +416,7 @@ struct iwl_mac_cfg {
  * @nvm_type: see &enum iwl_nvm_type
  * @uhb_supported: ultra high band channels supported
  * @eht_supported: EHT supported
+ * @uhr_supported: UHR supported
  * @num_rbds: number of receive buffer descriptors to use
  *     (only used for multi-queue capable devices)
  *
@@ -449,7 +450,8 @@ struct iwl_rf_cfg {
            lp_xtal_workaround:1,
            vht_mu_mimo_supported:1,
            uhb_supported:1,
-           eht_supported:1;
+           eht_supported:1,
+           uhr_supported:1;
        u8 valid_tx_ant;
        u8 valid_rx_ant;
        u8 non_shared_ant;
@@ -744,7 +746,8 @@ extern const struct iwl_rf_cfg iwl_rf_fm_160mhz;
 #define iwl_rf_wh iwl_rf_fm
 #define iwl_rf_wh_160mhz iwl_rf_fm_160mhz
 extern const struct iwl_rf_cfg iwl_rf_wh_non_eht;
-#define iwl_rf_pe iwl_rf_fm
+extern const struct iwl_rf_cfg iwl_rf_pe;
+#define iwl_rf_pe_no_uhr iwl_rf_fm
 #endif /* CONFIG_IWLMLD */
 
 #endif /* __IWL_CONFIG_H__ */
index 455d6e8c70285925e2ff7c226b5f614a278b8bd4..38ff6f944adde12536ef35fe33bb101963b09a18 100644 (file)
@@ -205,28 +205,30 @@ enum iwl_reg_capa_flags_v2 {
 }; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_2 */
 
 /**
- * enum iwl_reg_capa_flags_v4 - global flags applied for the whole regulatory
+ * enum iwl_reg_capa_flags_v5 - global flags applied for the whole regulatory
  * domain.
- * @REG_CAPA_V4_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed
+ * @REG_CAPA_V5_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed
  *     for this regulatory domain (valid only in 5Ghz).
- * @REG_CAPA_V4_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed
+ * @REG_CAPA_V5_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed
  *     for this regulatory domain (valid only in 5Ghz).
- * @REG_CAPA_V4_MCS_12_ALLOWED: 11ac with MCS 12 is allowed.
- * @REG_CAPA_V4_MCS_13_ALLOWED: 11ac with MCS 13 is allowed.
- * @REG_CAPA_V4_11BE_DISABLED: 11be is forbidden for this regulatory domain.
- * @REG_CAPA_V4_11AX_DISABLED: 11ax is forbidden for this regulatory domain.
- * @REG_CAPA_V4_320MHZ_ALLOWED: 11be channel with a width of 320Mhz is allowed
+ * @REG_CAPA_V5_MCS_12_ALLOWED: 11ac with MCS 12 is allowed.
+ * @REG_CAPA_V5_MCS_13_ALLOWED: 11ac with MCS 13 is allowed.
+ * @REG_CAPA_V5_11BE_DISABLED: 11be is forbidden for this regulatory domain.
+ * @REG_CAPA_V5_11AX_DISABLED: 11ax is forbidden for this regulatory domain.
+ * @REG_CAPA_V5_320MHZ_ALLOWED: 11be channel with a width of 320Mhz is allowed
  *     for this regulatory domain (valid only in 5GHz).
+ * @REG_CAPA_V5_11BN_DISABLED: UHR is not allowed for this regulatory domain
  */
-enum iwl_reg_capa_flags_v4 {
-       REG_CAPA_V4_160MHZ_ALLOWED              = BIT(3),
-       REG_CAPA_V4_80MHZ_ALLOWED               = BIT(4),
-       REG_CAPA_V4_MCS_12_ALLOWED              = BIT(5),
-       REG_CAPA_V4_MCS_13_ALLOWED              = BIT(6),
-       REG_CAPA_V4_11BE_DISABLED               = BIT(8),
-       REG_CAPA_V4_11AX_DISABLED               = BIT(13),
-       REG_CAPA_V4_320MHZ_ALLOWED              = BIT(16),
-}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4 */
+enum iwl_reg_capa_flags_v5 {
+       REG_CAPA_V5_160MHZ_ALLOWED              = BIT(3),
+       REG_CAPA_V5_80MHZ_ALLOWED               = BIT(4),
+       REG_CAPA_V5_MCS_12_ALLOWED              = BIT(5),
+       REG_CAPA_V5_MCS_13_ALLOWED              = BIT(6),
+       REG_CAPA_V5_11BE_DISABLED               = BIT(8),
+       REG_CAPA_V5_11AX_DISABLED               = BIT(13),
+       REG_CAPA_V5_320MHZ_ALLOWED              = BIT(16),
+       REG_CAPA_V5_11BN_DISABLED               = BIT(17),
+}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4, 5 */
 
 /*
 * API v2 for reg_capa_flags is relevant from version 6 and onwards of the
@@ -545,7 +547,7 @@ static const u8 iwl_vendor_caps[] = {
        0x00
 };
 
-static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = {
+static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = {
        {
                .types_mask = BIT(NL80211_IFTYPE_STATION) |
                              BIT(NL80211_IFTYPE_P2P_CLIENT),
@@ -689,6 +691,11 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = {
                         */
                        .eht_ppe_thres = {0xc1, 0x0e, 0xe0 }
                },
+               .uhr_cap = {
+                       .has_uhr = true,
+                       .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+                                  IEEE80211_UHR_PHY_CAP_ELR_TX,
+               },
        },
        {
                .types_mask = BIT(NL80211_IFTYPE_AP) |
@@ -787,6 +794,11 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = {
                         */
                        .eht_ppe_thres = {0xc1, 0x0e, 0xe0 }
                },
+               .uhr_cap = {
+                       .has_uhr = true,
+                       .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+                                  IEEE80211_UHR_PHY_CAP_ELR_TX,
+               },
        },
 };
 
@@ -854,6 +866,9 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
            fips_enabled)
                iftype_data->eht_cap.has_eht = false;
 
+       if (!data->sku_cap_11bn_enable || !iftype_data->eht_cap.has_eht)
+               iftype_data->uhr_cap.has_uhr = false;
+
        /* Advertise an A-MPDU exponent extension based on
         * operating band
         */
@@ -1022,9 +1037,9 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,
        struct ieee80211_sband_iftype_data *iftype_data;
        int i;
 
-       BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_he_eht_capa));
-       BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_he_eht_capa));
-       BUILD_BUG_ON(sizeof(data->iftd.uhb) != sizeof(iwl_he_eht_capa));
+       BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_iftype_cap));
+       BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_iftype_cap));
+       BUILD_BUG_ON(sizeof(data->iftd.uhb) != sizeof(iwl_iftype_cap));
 
        switch (sband->band) {
        case NL80211_BAND_2GHZ:
@@ -1041,10 +1056,10 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,
                return;
        }
 
-       memcpy(iftype_data, iwl_he_eht_capa, sizeof(iwl_he_eht_capa));
+       memcpy(iftype_data, iwl_iftype_cap, sizeof(iwl_iftype_cap));
 
        _ieee80211_set_sband_iftype_data(sband, iftype_data,
-                                        ARRAY_SIZE(iwl_he_eht_capa));
+                                        ARRAY_SIZE(iwl_iftype_cap));
 
        for (i = 0; i < sband->n_iftype_data; i++)
                iwl_nvm_fixup_sband_iftd(trans, data, sband, &iftype_data[i],
@@ -1652,6 +1667,9 @@ u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan,
        if (reg_capa.disable_11be)
                flags |= NL80211_RRF_NO_EHT;
 
+       if (reg_capa.disable_11bn)
+               flags |= NL80211_RRF_NO_UHR;
+
        return flags;
 }
 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_nvm_get_regdom_bw_flags);
@@ -1662,11 +1680,13 @@ static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver)
 
        if (resp_ver >= REG_CAPA_V4_RESP_VER) {
                reg_capa.allow_40mhz = true;
-               reg_capa.allow_80mhz = flags & REG_CAPA_V4_80MHZ_ALLOWED;
-               reg_capa.allow_160mhz = flags & REG_CAPA_V4_160MHZ_ALLOWED;
-               reg_capa.allow_320mhz = flags & REG_CAPA_V4_320MHZ_ALLOWED;
-               reg_capa.disable_11ax = flags & REG_CAPA_V4_11AX_DISABLED;
-               reg_capa.disable_11be = flags & REG_CAPA_V4_11BE_DISABLED;
+               reg_capa.allow_80mhz = flags & REG_CAPA_V5_80MHZ_ALLOWED;
+               reg_capa.allow_160mhz = flags & REG_CAPA_V5_160MHZ_ALLOWED;
+               reg_capa.allow_320mhz = flags & REG_CAPA_V5_320MHZ_ALLOWED;
+               reg_capa.disable_11ax = flags & REG_CAPA_V5_11AX_DISABLED;
+               reg_capa.disable_11be = flags & REG_CAPA_V5_11BE_DISABLED;
+               /* can check: was reserved and irrelevant for pre-UHR devices */
+               reg_capa.disable_11bn = flags & REG_CAPA_V5_11BN_DISABLED;
        } else if (resp_ver >= REG_CAPA_V2_RESP_VER) {
                reg_capa.allow_40mhz = flags & REG_CAPA_V2_40MHZ_ALLOWED;
                reg_capa.allow_80mhz = flags & REG_CAPA_V2_80MHZ_ALLOWED;
@@ -2121,6 +2141,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
                !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED);
        if (trans->cfg->eht_supported)
                nvm->sku_cap_11be_enable = true;
+       nvm->sku_cap_11bn_enable = trans->cfg->uhr_supported;
 
        /* Initialize PHY sku data */
        nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains);
index 12f28bb0e859dade88fac4d7eb7ab58a9ed2067c..e676d7c2d6cc06c2401dacaa836fd015cd6808ea 100644 (file)
@@ -35,6 +35,7 @@ enum iwl_nvm_sbands_flags {
  *     for this regulatory domain (valid only in 6 Ghz).
  * @disable_11ax: 11ax is forbidden for this regulatory domain.
  * @disable_11be: 11be is forbidden for this regulatory domain.
+ * @disable_11bn: UHR/11bn is not allowed for this regulatory domain
  */
 struct iwl_reg_capa {
        bool allow_40mhz;
@@ -43,6 +44,7 @@ struct iwl_reg_capa {
        bool allow_320mhz;
        bool disable_11ax;
        bool disable_11be;
+       bool disable_11bn;
 };
 
 /**
index e0c31f328a6c2188c12014faae9c3820c785326c..52d35b73ed74ff51b902360ab65ee21a182ed395 100644 (file)
@@ -32,6 +32,7 @@ struct iwl_nvm_data {
        bool sku_cap_ipan_enable;
        bool sku_cap_mimo_disabled;
        bool sku_cap_11be_enable;
+       bool sku_cap_11bn_enable;
 
        u16 radio_cfg_type;
        u8 radio_cfg_step;
index dc99e7ac47261e647fac3ba1fb5babe5e5e31121..78482db732c12da09ef75acb39b24aa16c1f579c 100644 (file)
@@ -1069,7 +1069,7 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = {
 
 /* PE RF */
        IWL_DEV_INFO(iwl_rf_pe, iwl_bn201_name, RF_TYPE(PE)),
-       IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE),
+       IWL_DEV_INFO(iwl_rf_pe_no_uhr, iwl_be223_name, RF_TYPE(PE),
                     SUBDEV_MASKED(0x0524, 0xFFF)),
        IWL_DEV_INFO(iwl_rf_pe, iwl_bn203_name, RF_TYPE(PE),
                     SUBDEV_MASKED(0x0324, 0xFFF)),