wifi: iwlwifi: mld: support NPCA capability for UHR devices

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>
This commit is contained in:
Johannes Berg
2026-05-13 08:43:53 +03:00
committed by Miri Korenblit
parent ba3b38d38a
commit 7f7a450ed8
5 changed files with 80 additions and 5 deletions

View 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
*/

View 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,
},
},
},
{

View 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);

View 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;
}

View 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);