]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: mld: add peer schedule support
authorJohannes Berg <johannes.berg@intel.com>
Sun, 10 May 2026 20:48:33 +0000 (23:48 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:09 +0000 (15:17 +0300)
Add support for NAN peer schedule configuration and update.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Co-developed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260510234534.ede42401c3ee.I8e483edd1e917dfa59901b520db595cea28906e3@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/mld/mac80211.c
drivers/net/wireless/intel/iwlwifi/mld/mld.c
drivers/net/wireless/intel/iwlwifi/mld/nan.c
drivers/net/wireless/intel/iwlwifi/mld/nan.h

index d98c6d991a8881b572d05fde6d719268d6a97800..75b4773190967daafb07c63b193e0193714a7d9e 100644 (file)
@@ -76,6 +76,10 @@ enum iwl_mac_conf_subcmd_ids {
         * @NAN_SCHEDULE_CMD: &struct iwl_nan_schedule_cmd
         */
        NAN_SCHEDULE_CMD = 0x13,
+       /**
+        * @NAN_PEER_CMD: &struct iwl_nan_peer_cmd
+        */
+       NAN_PEER_CMD = 0x14,
        /**
         * @NAN_DW_END_NOTIF: &struct iwl_nan_dw_end_notif
         */
@@ -1268,6 +1272,44 @@ struct iwl_nan_schedule_cmd {
        } __packed channels[NUM_PHY_CTX];
 } __packed; /* NAN_SCHEDULE_CMD_API_S_VER_1 */
 
+/**
+ * struct iwl_nan_peer_cmd - NAN peer command
+ * @nmi_sta_id: NAN management station ID
+ * @sequence_id: NAN Availability attribute sequence ID
+ * @committed_dw_info: committed DW info from the NAN Device
+ *     Capability attribute
+ * @max_channel_switch_time: maximum channel switch time
+ *     (in microseconds); 0 means unavailable
+ * @reserved: (reserved)
+ * @per_phy: per-PHY information for this peer, indexed by PHY ID
+ * @per_phy.availability_map: bitmap of which slots this peer
+ *     is available in on this PHY. 0 indicates the this per-PHY entry
+ *     is unused.
+ * @per_phy.channel_entry: the channel description the peer is using,
+ *     used for comparisons in ULW management
+ * @per_phy.link_id: FW link ID, should be a valid id.
+ * @per_phy.map_id: map ID from peer's NAN Availability attributec
+ * @initial_ulw_size: size of the initial ULW blob
+ * @initial_ulw: initial ULW data from the peer
+ */
+struct iwl_nan_peer_cmd {
+       u8 nmi_sta_id;
+       u8 sequence_id;
+       __le16 committed_dw_info;
+       __le16 max_channel_switch_time;
+       __le16 reserved;
+
+       struct {
+               __le32 availability_map;
+               u8 channel_entry[6];
+               u8 link_id;
+               u8 map_id;
+       } __packed per_phy[NUM_PHY_CTX];
+
+       __le32 initial_ulw_size;
+       u8 initial_ulw[];
+} __packed; /* NAN_PEER_SCHEDULE_CMD_API_S_VER_1 */
+
 /**
  * enum iwl_nan_cluster_notif_flags - flags for the cluster notification
  *
index 6b4b2683cd1ee718a4b1587bd605178b04cc94b3..cabf47367fda07cb1d8aa177b8bb3bbf886dc48c 100644 (file)
@@ -2863,4 +2863,5 @@ const struct ieee80211_ops iwl_mld_hw_ops = {
        .start_nan = iwl_mld_start_nan,
        .stop_nan = iwl_mld_stop_nan,
        .nan_change_conf = iwl_mld_nan_change_config,
+       .nan_peer_sched_changed = iwl_mld_mac802111_nan_peer_sched_changed,
 };
index c038a0cde36bdb72fcb407faf798e3e460effb16..dfd4798c103a1341d9bef6c868ea1e74115e0eff 100644 (file)
@@ -237,6 +237,7 @@ static const struct iwl_hcmd_names iwl_mld_mac_conf_names[] = {
        HCMD_NAME(ROC_CMD),
        HCMD_NAME(NAN_CFG_CMD),
        HCMD_NAME(NAN_SCHEDULE_CMD),
+       HCMD_NAME(NAN_PEER_CMD),
        HCMD_NAME(NAN_DW_END_NOTIF),
        HCMD_NAME(NAN_JOINED_CLUSTER_NOTIF),
        HCMD_NAME(MISSED_BEACONS_NOTIF),
index 53d39717deabfd2eaef981ccacc53f018eb81004..ceea66c012054587fe7d466cbb9c61f880dab096 100644 (file)
@@ -664,3 +664,87 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
                        iwl_mld_rm_vif(mld, vif);
        }
 }
+
+int iwl_mld_mac802111_nan_peer_sched_changed(struct ieee80211_hw *hw,
+                                            struct ieee80211_sta *sta)
+{
+       struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+       struct ieee80211_nan_peer_sched *sched = sta->nan_sched;
+       struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(mld_sta->vif);
+       struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
+       struct iwl_mld_nan_link *nan_link;
+       struct iwl_nan_peer_cmd cmd = {
+               .nmi_sta_id = mld_sta->deflink.fw_id,
+               .sequence_id = sched->seq_id,
+               .committed_dw_info = cpu_to_le16(sched->committed_dw),
+               .max_channel_switch_time = cpu_to_le16(sched->max_chan_switch),
+               .initial_ulw_size = cpu_to_le32(sched->ulw_size),
+               .per_phy[0 ... NUM_PHY_CTX - 1] = {
+                       /* unused by FW if availability_map == 0 */
+                       .map_id = CFG80211_NAN_INVALID_MAP_ID,
+                       .link_id = FW_CTXT_ID_INVALID,
+               },
+               /* .initial_ulw directly provided below by data[1]/len[1] */
+       };
+       struct iwl_host_cmd hcmd = {
+               .id = WIDE_ID(MAC_CONF_GROUP, NAN_PEER_CMD),
+               .data[0] = &cmd,
+               .len[0] = sizeof(cmd),
+               .data[1] = sched->init_ulw,
+               .len[1] = sched->ulw_size,
+               .dataflags[1] = IWL_HCMD_DFL_DUP,
+       };
+
+       for (int i = 0; i < ARRAY_SIZE(sched->maps); i++) {
+               if (sched->maps[i].map_id == CFG80211_NAN_INVALID_MAP_ID)
+                       continue;
+
+               BUILD_BUG_ON(ARRAY_SIZE(sched->maps[i].slots) != 32);
+               for (int slot = 0;
+                    slot < ARRAY_SIZE(sched->maps[i].slots);
+                    slot++) {
+                       struct ieee80211_chanctx_conf *ctx;
+                       struct ieee80211_nan_channel *chan;
+                       struct iwl_mld_phy *phy;
+
+                       chan = sched->maps[i].slots[slot];
+                       if (!chan)
+                               continue;
+
+                       ctx = chan->chanctx_conf;
+                       if (!ctx)
+                               continue;
+
+                       phy = iwl_mld_phy_from_mac80211(ctx);
+
+                       for_each_mld_nan_valid_link(mld_vif, nan_link) {
+                               if (nan_link->chanctx == ctx) {
+                                       cmd.per_phy[phy->fw_id].link_id =
+                                               nan_link->fw_id;
+                                       break;
+                               }
+                       }
+
+                       if (WARN_ON(cmd.per_phy[phy->fw_id].link_id ==
+                                   FW_CTXT_ID_INVALID))
+                               continue;
+
+                       /*
+                        * each channel can only appear in one map,
+                        * upper layers enforce that
+                        */
+                       if (WARN_ON(cmd.per_phy[phy->fw_id].map_id != CFG80211_NAN_INVALID_MAP_ID &&
+                                   cmd.per_phy[phy->fw_id].map_id != sched->maps[i].map_id))
+                               continue;
+
+                       cmd.per_phy[phy->fw_id].map_id = sched->maps[i].map_id;
+                       memcpy(cmd.per_phy[phy->fw_id].channel_entry,
+                              chan->channel_entry,
+                              sizeof(cmd.per_phy[phy->fw_id].channel_entry));
+                       cmd.per_phy[phy->fw_id].availability_map |=
+                               cpu_to_le32(BIT(slot));
+               }
+       }
+
+       return iwl_mld_send_cmd(mld, &hcmd);
+}
index 933e16c3c2742de679b89952f6ccb1e8270c3550..80e18c4ddb33cd4cf40071d0a84f388eeeee6f0e 100644 (file)
@@ -50,4 +50,7 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
                                 struct ieee80211_vif *vif,
                                 u64 changes);
 
+int iwl_mld_mac802111_nan_peer_sched_changed(struct ieee80211_hw *hw,
+                                            struct ieee80211_sta *sta);
+
 #endif /* __iwl_mld_nan_h__ */