From: Johannes Berg Date: Sun, 10 May 2026 20:48:33 +0000 (+0300) Subject: wifi: iwlwifi: mld: add peer schedule support X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ddb509acccb70dd3a60f6353db95e52296f06c63;p=thirdparty%2Flinux.git wifi: iwlwifi: mld: add peer schedule support Add support for NAN peer schedule configuration and update. Signed-off-by: Johannes Berg Co-developed-by: Miri Korenblit Link: https://patch.msgid.link/20260510234534.ede42401c3ee.I8e483edd1e917dfa59901b520db595cea28906e3@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 d98c6d991a88..75b477319096 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -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 * diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 6b4b2683cd1e..cabf47367fda 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -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, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index c038a0cde36b..dfd4798c103a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -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), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index 53d39717deab..ceea66c01205 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -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); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h index 933e16c3c274..80e18c4ddb33 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h @@ -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__ */