summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2026-05-10 23:48:31 +0300
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>2026-05-26 15:17:09 +0300
commitcfc84d1710f331e47e09f337b07e0207a5ae9a14 (patch)
treec794db55e5ec027f59ead38f2843c5e42b9058e8 /drivers
parentef9d9c1c1609c425d78bba8457fc710e0f66eedd (diff)
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 <miriam.rachel.korenblit@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Link: https://patch.msgid.link/20260510234534.95fabd44a598.I7cbe877f3b13a44554d95e56b10d930dde4704c9@changeid Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mld.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/nan.c58
3 files changed, 78 insertions, 7 deletions
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 b398c582b867..d98c6d991a88 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
@@ -72,6 +73,10 @@ enum iwl_mac_conf_subcmd_ids {
*/
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
*/
NAN_DW_END_NOTIF = 0xf4,
@@ -1245,6 +1250,25 @@ struct iwl_nan_config_cmd {
} __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
*
* @IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER: indicates that the device has
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
index 9af79297c3b6..c038a0cde36b 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 <linux/rtnetlink.h>
#include <net/mac80211.h>
@@ -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 6ea11b66a545..eba79aca8c06 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);
}
}