xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/roc.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2024 - 2025 Intel Corporation
4  */
5 #include <net/cfg80211.h>
6 #include <net/mac80211.h>
7 
8 #include "mld.h"
9 #include "roc.h"
10 #include "hcmd.h"
11 #include "iface.h"
12 #include "sta.h"
13 #include "mlo.h"
14 
15 #include "fw/api/context.h"
16 #include "fw/api/time-event.h"
17 
18 #define AUX_ROC_MAX_DELAY MSEC_TO_TU(200)
19 
20 static void
iwl_mld_vif_iter_emlsr_block_roc(void * data,u8 * mac,struct ieee80211_vif * vif)21 iwl_mld_vif_iter_emlsr_block_roc(void *data, u8 *mac, struct ieee80211_vif *vif)
22 {
23 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
24 	int *result = data;
25 	int ret;
26 
27 	ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif,
28 				       IWL_MLD_EMLSR_BLOCKED_ROC,
29 				       iwl_mld_get_primary_link(vif));
30 	if (ret)
31 		*result = ret;
32 }
33 
34 struct iwl_mld_roc_iter_data {
35 	enum iwl_roc_activity activity;
36 	struct ieee80211_vif *vif;
37 	bool found;
38 };
39 
iwl_mld_find_roc_vif_iter(void * data,u8 * mac,struct ieee80211_vif * vif)40 static void iwl_mld_find_roc_vif_iter(void *data, u8 *mac,
41 				      struct ieee80211_vif *vif)
42 {
43 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
44 	struct iwl_mld_roc_iter_data *roc_data = data;
45 
46 	if (mld_vif->roc_activity != roc_data->activity)
47 		return;
48 
49 	/* The FW supports one ROC of each type simultaneously */
50 	if (WARN_ON(roc_data->found)) {
51 		roc_data->vif = NULL;
52 		return;
53 	}
54 
55 	roc_data->found = true;
56 	roc_data->vif = vif;
57 }
58 
59 static struct ieee80211_vif *
iwl_mld_find_roc_vif(struct iwl_mld * mld,enum iwl_roc_activity activity)60 iwl_mld_find_roc_vif(struct iwl_mld *mld, enum iwl_roc_activity activity)
61 {
62 	struct iwl_mld_roc_iter_data roc_data = {
63 		.activity = activity,
64 		.found = false,
65 	};
66 
67 	ieee80211_iterate_active_interfaces_mtx(mld->hw,
68 						IEEE80211_IFACE_ITER_NORMAL,
69 						iwl_mld_find_roc_vif_iter,
70 						&roc_data);
71 
72 	return roc_data.vif;
73 }
74 
iwl_mld_start_roc(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_channel * channel,int duration,enum ieee80211_roc_type type)75 int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
76 		      struct ieee80211_channel *channel, int duration,
77 		      enum ieee80211_roc_type type)
78 {
79 	struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
80 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
81 	struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta;
82 	struct iwl_roc_req cmd = {
83 		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
84 	};
85 	u8 ver = iwl_fw_lookup_cmd_ver(mld->fw,
86 				       WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0);
87 	u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd);
88 	enum iwl_roc_activity activity;
89 	int ret = 0;
90 
91 	lockdep_assert_wiphy(mld->wiphy);
92 
93 	if (vif->type != NL80211_IFTYPE_P2P_DEVICE &&
94 	    vif->type != NL80211_IFTYPE_STATION) {
95 		IWL_ERR(mld, "NOT SUPPORTED: ROC on vif->type %d\n",
96 			vif->type);
97 
98 		return -EOPNOTSUPP;
99 	}
100 
101 	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
102 		switch (type) {
103 		case IEEE80211_ROC_TYPE_NORMAL:
104 			activity = ROC_ACTIVITY_P2P_DISC;
105 			break;
106 		case IEEE80211_ROC_TYPE_MGMT_TX:
107 			activity = ROC_ACTIVITY_P2P_NEG;
108 			break;
109 		default:
110 			WARN_ONCE(1, "Got an invalid P2P ROC type\n");
111 			return -EINVAL;
112 		}
113 	} else {
114 		activity = ROC_ACTIVITY_HOTSPOT;
115 	}
116 
117 	/* The FW supports one ROC of each type simultaneously */
118 	if (WARN_ON(iwl_mld_find_roc_vif(mld, activity)))
119 		return -EBUSY;
120 
121 	ieee80211_iterate_active_interfaces_mtx(mld->hw,
122 						IEEE80211_IFACE_ITER_NORMAL,
123 						iwl_mld_vif_iter_emlsr_block_roc,
124 						&ret);
125 	if (ret)
126 		return ret;
127 
128 	ret = iwl_mld_add_aux_sta(mld, aux_sta);
129 	if (ret)
130 		return ret;
131 
132 	cmd.activity = cpu_to_le32(activity);
133 	cmd.sta_id = cpu_to_le32(aux_sta->sta_id);
134 	cmd.channel_info.channel = cpu_to_le32(channel->hw_value);
135 	cmd.channel_info.band = iwl_mld_nl80211_band_to_fw(channel->band);
136 	cmd.channel_info.width = IWL_PHY_CHANNEL_MODE20;
137 	cmd.max_delay = cpu_to_le32(AUX_ROC_MAX_DELAY);
138 	cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
139 
140 	memcpy(cmd.node_addr, vif->addr, ETH_ALEN);
141 
142 	ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD),
143 				   &cmd, cmd_len);
144 	if (ret) {
145 		IWL_ERR(mld, "Couldn't send the ROC_CMD\n");
146 		return ret;
147 	}
148 
149 	mld_vif->roc_activity = activity;
150 
151 	return 0;
152 }
153 
154 static void
iwl_mld_vif_iter_emlsr_unblock_roc(void * data,u8 * mac,struct ieee80211_vif * vif)155 iwl_mld_vif_iter_emlsr_unblock_roc(void *data, u8 *mac,
156 				   struct ieee80211_vif *vif)
157 {
158 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
159 
160 	iwl_mld_unblock_emlsr(mld_vif->mld, vif, IWL_MLD_EMLSR_BLOCKED_ROC);
161 }
162 
iwl_mld_destroy_roc(struct iwl_mld * mld,struct ieee80211_vif * vif,struct iwl_mld_vif * mld_vif)163 static void iwl_mld_destroy_roc(struct iwl_mld *mld,
164 				struct ieee80211_vif *vif,
165 				struct iwl_mld_vif *mld_vif)
166 {
167 	mld_vif->roc_activity = ROC_NUM_ACTIVITIES;
168 
169 	ieee80211_iterate_active_interfaces_mtx(mld->hw,
170 						IEEE80211_IFACE_ITER_NORMAL,
171 						iwl_mld_vif_iter_emlsr_unblock_roc,
172 						NULL);
173 
174 	/* wait until every tx has seen that roc_activity has been reset */
175 	synchronize_net();
176 	/* from here, no new tx will be added
177 	 * we can flush the Tx on the queues
178 	 */
179 
180 	iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id);
181 
182 	iwl_mld_remove_aux_sta(mld, vif);
183 }
184 
iwl_mld_cancel_roc(struct ieee80211_hw * hw,struct ieee80211_vif * vif)185 int iwl_mld_cancel_roc(struct ieee80211_hw *hw,
186 		       struct ieee80211_vif *vif)
187 {
188 	struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
189 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
190 	struct iwl_roc_req cmd = {
191 		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
192 	};
193 	u8 ver = iwl_fw_lookup_cmd_ver(mld->fw,
194 				       WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0);
195 	u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd);
196 	int ret;
197 
198 	lockdep_assert_wiphy(mld->wiphy);
199 
200 	if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE &&
201 		    vif->type != NL80211_IFTYPE_STATION))
202 		return -EOPNOTSUPP;
203 
204 	/* No roc activity running it's probably already done */
205 	if (mld_vif->roc_activity == ROC_NUM_ACTIVITIES)
206 		return 0;
207 
208 	cmd.activity = cpu_to_le32(mld_vif->roc_activity);
209 
210 	ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD),
211 				   &cmd, cmd_len);
212 	if (ret)
213 		IWL_ERR(mld, "Couldn't send the command to cancel the ROC\n");
214 
215 	/* We may have raced with the firmware expiring the ROC instance at
216 	 * this very moment. In that case, we can have a notification in the
217 	 * async processing queue. However, none can arrive _after_ this as
218 	 * ROC_CMD was sent synchronously, i.e. we waited for a response and
219 	 * the firmware cannot refer to this ROC after the response. Thus,
220 	 * if we just cancel the notification (if there's one) we'll be at a
221 	 * clean state for any possible next ROC.
222 	 */
223 	iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_ROC,
224 					       mld_vif->roc_activity);
225 
226 	iwl_mld_destroy_roc(mld, vif, mld_vif);
227 
228 	return 0;
229 }
230 
iwl_mld_handle_roc_notif(struct iwl_mld * mld,struct iwl_rx_packet * pkt)231 void iwl_mld_handle_roc_notif(struct iwl_mld *mld,
232 			      struct iwl_rx_packet *pkt)
233 {
234 	const struct iwl_roc_notif *notif = (void *)pkt->data;
235 	u32 activity = le32_to_cpu(notif->activity);
236 	struct iwl_mld_vif *mld_vif;
237 	struct ieee80211_vif *vif;
238 
239 	vif = iwl_mld_find_roc_vif(mld, activity);
240 	if (WARN_ON(!vif))
241 		return;
242 
243 	mld_vif = iwl_mld_vif_from_mac80211(vif);
244 	/* It is possible that the ROC was canceled
245 	 * but the notification was already fired.
246 	 */
247 	if (mld_vif->roc_activity != activity)
248 		return;
249 
250 	if (le32_to_cpu(notif->success) &&
251 	    le32_to_cpu(notif->started)) {
252 		/* We had a successful start */
253 		ieee80211_ready_on_channel(mld->hw);
254 	} else {
255 		/* ROC was not successful, tell the firmware to remove it */
256 		if (le32_to_cpu(notif->started))
257 			iwl_mld_cancel_roc(mld->hw, vif);
258 		else
259 			iwl_mld_destroy_roc(mld, vif, mld_vif);
260 		/* we need to let know mac80211 about end OR
261 		 * an unsuccessful start
262 		 */
263 		ieee80211_remain_on_channel_expired(mld->hw);
264 	}
265 }
266