From: Johannes Berg Date: Sun, 10 May 2026 20:48:31 +0000 (+0300) Subject: wifi: iwlwifi: add NAN schedule command support X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=cfc84d1710f331e47e09f337b07e0207a5ae9a14;p=thirdparty%2Flinux.git wifi: iwlwifi: add NAN schedule command support Add the NAN schedule command API definition and implementation of the schedule updates. Co-developed-by: Miri Korenblit Signed-off-by: Johannes Berg Link: https://patch.msgid.link/20260510234534.95fabd44a598.I7cbe877f3b13a44554d95e56b10d930dde4704c9@changeid Signed-off-by: Miri Korenblit --- diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index b398c582b8670..d98c6d991a888 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -8,6 +8,7 @@ #define __iwl_fw_api_mac_cfg_h__ #include "mac.h" +#include "phy-ctxt.h" /** * enum iwl_mac_conf_subcmd_ids - mac configuration command IDs @@ -71,6 +72,10 @@ enum iwl_mac_conf_subcmd_ids { * @NAN_CFG_CMD: &struct iwl_nan_config_cmd */ NAN_CFG_CMD = 0x12, + /** + * @NAN_SCHEDULE_CMD: &struct iwl_nan_schedule_cmd + */ + NAN_SCHEDULE_CMD = 0x13, /** * @NAN_DW_END_NOTIF: &struct iwl_nan_dw_end_notif */ @@ -1244,6 +1249,25 @@ struct iwl_nan_config_cmd { u8 beacon_data[]; } __packed; /* NAN_CONFIG_CMD_API_S_VER_1 */ +/** + * struct iwl_nan_schedule_cmd - NAN schedule command + * @channels: per channel information + * @channels.availability_map: bitmap of slots this channel is advertising + * availability on, will be ULW'ed out if no link/inactive link is + * referenced by the link ID below + * @channels.channel_entry: NAN channel entry descriptor + * @channels.link_id: FW link ID, or %0xFF for unset + * @channels.reserved: (reserved) + */ +struct iwl_nan_schedule_cmd { + struct { + __le32 availability_map; + u8 channel_entry[6]; + u8 link_id; + u8 reserved; + } __packed channels[NUM_PHY_CTX]; +} __packed; /* NAN_SCHEDULE_CMD_API_S_VER_1 */ + /** * enum iwl_nan_cluster_notif_flags - flags for the cluster notification * diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index 9af79297c3b6a..c038a0cde36bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -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 #include @@ -236,6 +236,7 @@ static const struct iwl_hcmd_names iwl_mld_mac_conf_names[] = { HCMD_NAME(STA_REMOVE_CMD), HCMD_NAME(ROC_CMD), HCMD_NAME(NAN_CFG_CMD), + HCMD_NAME(NAN_SCHEDULE_CMD), HCMD_NAME(NAN_DW_END_NOTIF), HCMD_NAME(NAN_JOINED_CLUSTER_NOTIF), HCMD_NAME(MISSED_BEACONS_NOTIF), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index 6ea11b66a5453..eba79aca8c062 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -401,8 +401,14 @@ iwl_mld_nan_link_add(struct iwl_mld *mld, u8 fw_id; int ret; + lockdep_assert_wiphy(mld->wiphy); + ret = iwl_mld_allocate_link_fw_id(mld, &fw_id, ERR_PTR(-ENODEV)); - if (ret < 0) + /* + * We should always have enough links. The schedule contains up to 3, + * and the BSS vif cannot do EMLSR - so can only have 1. + */ + if (WARN_ON(ret < 0)) return NULL; nan_link = &mld_vif->nan.links[fw_id]; @@ -504,19 +510,21 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld, struct ieee80211_vif *vif, u64 changes) { + struct iwl_nan_schedule_cmd cmd = {}; struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); bool previously_empty_schedule = !iwl_mld_nan_have_links(mld_vif); struct ieee80211_nan_sched_cfg *sched_cfg = &vif->cfg.nan_sched; struct iwl_mld_nan_link *links[ARRAY_SIZE(sched_cfg->channels)] = {}; + struct ieee80211_nan_channel **slots = sched_cfg->schedule; bool link_used[ARRAY_SIZE(mld_vif->nan.links)] = {}; struct iwl_mld_nan_link *nan_link; bool empty_schedule = true; - int ret; + int ret, i; if (!(changes & BSS_CHANGED_NAN_LOCAL_SCHED)) return; - for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { + for (i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { if (!sched_cfg->channels[i].chanreq.oper.chan) continue; empty_schedule = false; @@ -539,8 +547,12 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld, return; } + /* this currently just uses the same index */ + BUILD_BUG_ON(ARRAY_SIZE(sched_cfg->channels) != + ARRAY_SIZE(cmd.channels)); + /* find links we can keep (same chanctx/PHY) */ - for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { + for (i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { struct ieee80211_chanctx_conf *chanctx; struct iwl_mld_nan_link *link; @@ -556,7 +568,7 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld, } /* add/reassign links for new channels */ - for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { + for (i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { struct ieee80211_chanctx_conf *chanctx; /* already have an existing active link */ @@ -581,6 +593,39 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld, } } + /* fill the command */ + for (i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) { + cmd.channels[i].link_id = FW_CTXT_ID_INVALID; + + if (!sched_cfg->channels[i].chanreq.oper.chan) + continue; + + memcpy(cmd.channels[i].channel_entry, + sched_cfg->channels[i].channel_entry, 6); + cmd.channels[i].link_id = + links[i] ? links[i]->fw_id : FW_CTXT_ID_INVALID; + } + + for (i = 0; i < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; i++) { + int chan_idx; + + if (!slots[i]) + continue; + + chan_idx = slots[i] - sched_cfg->channels; + if (WARN_ON_ONCE(chan_idx < 0 || + chan_idx >= ARRAY_SIZE(cmd.channels))) + continue; + + cmd.channels[chan_idx].availability_map |= cpu_to_le32(BIT(i)); + } + + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(MAC_CONF_GROUP, NAN_SCHEDULE_CMD), + &cmd); + if (ret) + IWL_ERR(mld, "NAN: failed to update schedule (%d)\n", ret); + /* delete unused links */ for_each_mld_nan_valid_link(mld_vif, nan_link) { if (!link_used[nan_link->fw_id]) { @@ -595,7 +640,8 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld, WARN_ON_ONCE(!mld_vif->nan.mac_added); /* mac80211 should reconfigure same state */ - if (!WARN_ON_ONCE(mld->fw_status.in_hw_restart)) + if (!WARN_ON_ONCE(mld->fw_status.in_hw_restart && + !iwl_mld_error_before_recovery(mld))) iwl_mld_rm_vif(mld, vif); } }