]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: iwlwifi: mld: support NPCA capability for UHR devices
authorJohannes Berg <johannes.berg@intel.com>
Wed, 13 May 2026 05:43:53 +0000 (08:43 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:11 +0000 (15:17 +0300)
UHR devices have NPCA capability, so implement the necessary
configuration and set the capability bit.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Link: https://patch.msgid.link/20260513084215.8c88bf84af91.If59ceaa49c2431e08941bcba3b2e75bb93aaad63@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/mld/link.c
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
drivers/net/wireless/intel/iwlwifi/mld/phy.c

index dde6cfd9d286f9134ea3210260a633266470fee1..fa2fc6a92e6036e4b66136c4154649955ad4a78a 100644 (file)
@@ -549,12 +549,14 @@ enum iwl_link_ctx_protection_flags {
  *      radar pulses).
  * @LINK_FLG_NDP_FEEDBACK_ENABLED: mark support for NDP feedback and change
  *     of threshold
+ * @LINK_FLG_NPCA: NPCA enabled
  */
 enum iwl_link_ctx_flags {
        LINK_FLG_BSS_COLOR_DIS          = BIT(0),
        LINK_FLG_MU_EDCA_CW             = BIT(1),
        LINK_FLG_RU_2MHZ_BLOCK          = BIT(2),
        LINK_FLG_NDP_FEEDBACK_ENABLED   = BIT(3),
+       LINK_FLG_NPCA                   = BIT(4),
 }; /* LINK_CONTEXT_FLAG_E_VER_1 */
 
 /**
@@ -591,7 +593,7 @@ enum iwl_npca_flags {
  * @initial_qsrc: Indicates the value that is used to initialize the
  *     EDCAF QSRC[AC] variables
  * @min_dur_threshold: minimum PPDU time to switch to the non-primary
- *     NPCA channel (usec)
+ *     NPCA channel (spec representation)
  * @flags: NPCA flags, see &enum iwl_npca_flags
  * @reserved: reserved for alignment purposes
  */
index 38ff6f944adde12536ef35fe33bb101963b09a18..4e8222ffe732b74bbce2d9e5bfe5f6e4cff586c5 100644 (file)
@@ -695,6 +695,9 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = {
                        .has_uhr = true,
                        .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
                                   IEEE80211_UHR_PHY_CAP_ELR_TX,
+                       .mac.mac_cap = {
+                               [0] = IEEE80211_UHR_MAC_CAP0_NPCA_SUPP,
+                       },
                },
        },
        {
index 805f2e2eac3893c8d21bb6a5764fae2f39838923..9ef39b03e67ff091f08c5a974927b3e520d7d273 100644 (file)
@@ -374,6 +374,21 @@ iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link,
        if (WARN_ON(changes & LINK_CONTEXT_MODIFY_EHT_PARAMS))
                changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
 
+       if (link->uhr_support && link->npca.enabled) {
+               flags |= LINK_FLG_NPCA;
+               if (link->npca.moplen)
+                       cmd.npca_params.flags |= IWL_NPCA_FLAG_MAC_HDR_BASED;
+               cmd.npca_params.dis_subch_bmap =
+                       cpu_to_le16(link->chanreq.oper.npca_punctured);
+               cmd.npca_params.initial_qsrc = link->npca.init_qsrc;
+               cmd.npca_params.min_dur_threshold = link->npca.min_dur_thresh;
+               /* spec/mac80211 have these in units of 4 usec */
+               cmd.npca_params.switch_delay =
+                       4 * link->npca.switch_delay;
+               cmd.npca_params.switch_back_delay =
+                       4 * link->npca.switch_back_delay;
+       }
+
 send_cmd:
        cmd.modify_mask = cpu_to_le32(changes);
        cmd.flags = cpu_to_le32(flags);
index 41bc47e4e00c4764b1b76c073f26187056bcf5be..1f2843af39c15021e99cdd13a3308f5cac4a96d4 100644 (file)
@@ -981,6 +981,30 @@ void iwl_mld_remove_chanctx(struct ieee80211_hw *hw,
        mld->used_phy_ids &= ~BIT(phy->fw_id);
 }
 
+static void
+iwl_mld_update_link_npca_puncturing(struct ieee80211_hw *hw,
+                                   struct ieee80211_chanctx_conf *ctx)
+{
+       struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
+       struct ieee80211_vif *vif;
+
+       for_each_active_interface(vif, hw) {
+               struct ieee80211_bss_conf *link;
+               int link_id;
+
+               for_each_vif_active_link(vif, link, link_id) {
+                       if (rcu_access_pointer(link->chanctx_conf) != ctx)
+                               continue;
+
+                       if (!link->npca.enabled)
+                               continue;
+
+                       iwl_mld_change_link_in_fw(mld, link,
+                                                 LINK_CONTEXT_MODIFY_UHR_PARAMS);
+               }
+       }
+}
+
 static
 void iwl_mld_change_chanctx(struct ieee80211_hw *hw,
                            struct ieee80211_chanctx_conf *ctx, u32 changed)
@@ -996,9 +1020,19 @@ void iwl_mld_change_chanctx(struct ieee80211_hw *hw,
                          IEEE80211_CHANCTX_CHANGE_CHANNEL)))
                return;
 
+       /* NPCA puncturing is in link API for FW */
+       if (changed & IEEE80211_CHANCTX_CHANGE_NPCA_PUNCT) {
+               iwl_mld_update_link_npca_puncturing(hw, ctx);
+               changed &= ~IEEE80211_CHANCTX_CHANGE_NPCA_PUNCT;
+       }
+
        /* Check if a FW update is required */
 
-       if (changed & IEEE80211_CHANCTX_CHANGE_AP)
+       if (!changed)
+               return;
+
+       if (changed & IEEE80211_CHANCTX_CHANGE_AP ||
+           changed & IEEE80211_CHANCTX_CHANGE_NPCA)
                goto update;
 
        if (chandef->chan == phy->chandef.chan &&
@@ -1255,6 +1289,9 @@ u32 iwl_mld_link_changed_mapping(struct iwl_mld *mld,
                link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
        }
 
+       if (changes & BSS_CHANGED_NPCA)
+               link_changes |= LINK_CONTEXT_MODIFY_UHR_PARAMS;
+
        return link_changes;
 }
 
index 1d93fb9e4dbf3a695d397aca681077cfb962ff11..59bf088ead840a9caa947ca89666cc488e15569f 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #include <net/mac80211.h>
 
@@ -99,9 +99,9 @@ iwl_mld_nl80211_width_to_fw(enum nl80211_chan_width width)
 /* Maps the driver specific control channel position (relative to the center
  * freq) definitions to the fw values
  */
-u8 iwl_mld_get_fw_ctrl_pos(const struct cfg80211_chan_def *chandef)
+static u8 _iwl_mld_get_fw_ctrl_pos(u32 control, u32 cf1)
 {
-       int offs = chandef->chan->center_freq - chandef->center_freq1;
+       int offs = control - cf1;
        int abs_offs = abs(offs);
        u8 ret;
 
@@ -127,6 +127,12 @@ u8 iwl_mld_get_fw_ctrl_pos(const struct cfg80211_chan_def *chandef)
        return ret;
 }
 
+u8 iwl_mld_get_fw_ctrl_pos(const struct cfg80211_chan_def *chandef)
+{
+       return _iwl_mld_get_fw_ctrl_pos(chandef->chan->center_freq,
+                                       chandef->center_freq1);
+}
+
 int iwl_mld_phy_fw_action(struct iwl_mld *mld,
                          struct ieee80211_chanctx_conf *ctx, u32 action)
 {
@@ -150,6 +156,18 @@ int iwl_mld_phy_fw_action(struct iwl_mld *mld,
                cmd.sbb_ctrl_channel_loc = iwl_mld_get_fw_ctrl_pos(&ctx->ap);
        }
 
+       /*
+        * Set NPCA channel if NPCA is used; if not used, just set it to an
+        * arbitrary channel on the other side to help firmware.
+        */
+       if (chandef->npca_chan)
+               cmd.secondary_ctrl_chnl_loc =
+                       _iwl_mld_get_fw_ctrl_pos(chandef->npca_chan->center_freq,
+                                                chandef->center_freq1);
+       else
+               cmd.secondary_ctrl_chnl_loc =
+                       cmd.ci.ctrl_pos ^ IWL_PHY_CTRL_POS_ABOVE;
+
        ret = iwl_mld_send_cmd_pdu(mld, PHY_CONTEXT_CMD, &cmd);
        if (ret)
                IWL_ERR(mld, "Failed to send PHY_CONTEXT_CMD ret = %d\n", ret);