xref: /linux/drivers/net/wireless/mediatek/mt76/channel.c (revision 0ad9617c78acbc71373fb341a6f75d4012b01d69)
1 // SPDX-License-Identifier: ISC
2 /*
3  * Copyright (C) 2024 Felix Fietkau <nbd@nbd.name>
4  */
5 #include "mt76.h"
6 
7 static struct mt76_vif_link *
8 mt76_alloc_mlink(struct mt76_dev *dev, struct mt76_vif_data *mvif)
9 {
10 	struct mt76_vif_link *mlink;
11 
12 	mlink = kzalloc(dev->drv->link_data_size, GFP_KERNEL);
13 	if (!mlink)
14 		return NULL;
15 
16 	mlink->mvif = mvif;
17 
18 	return mlink;
19 }
20 
21 static int
22 mt76_phy_update_channel(struct mt76_phy *phy,
23 			struct ieee80211_chanctx_conf *conf)
24 {
25 	phy->radar_enabled = conf->radar_enabled;
26 	phy->main_chandef = conf->def;
27 	phy->chanctx = (struct mt76_chanctx *)conf->drv_priv;
28 
29 	return __mt76_set_channel(phy, &phy->main_chandef, false);
30 }
31 
32 int mt76_add_chanctx(struct ieee80211_hw *hw,
33 		     struct ieee80211_chanctx_conf *conf)
34 {
35 	struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
36 	struct mt76_phy *phy = hw->priv;
37 	struct mt76_dev *dev = phy->dev;
38 	int ret = -EINVAL;
39 
40 	phy = ctx->phy = dev->band_phys[conf->def.chan->band];
41 	if (WARN_ON_ONCE(!phy))
42 		return ret;
43 
44 	if (dev->scan.phy == phy)
45 		mt76_abort_scan(dev);
46 
47 	mutex_lock(&dev->mutex);
48 	if (!phy->chanctx)
49 		ret = mt76_phy_update_channel(phy, conf);
50 	else
51 		ret = 0;
52 	mutex_unlock(&dev->mutex);
53 
54 	return ret;
55 }
56 EXPORT_SYMBOL_GPL(mt76_add_chanctx);
57 
58 void mt76_remove_chanctx(struct ieee80211_hw *hw,
59 			 struct ieee80211_chanctx_conf *conf)
60 {
61 	struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
62 	struct mt76_phy *phy = hw->priv;
63 	struct mt76_dev *dev = phy->dev;
64 
65 	phy = ctx->phy;
66 	if (WARN_ON_ONCE(!phy))
67 		return;
68 
69 	if (dev->scan.phy == phy)
70 		mt76_abort_scan(dev);
71 
72 	mutex_lock(&dev->mutex);
73 	if (phy->chanctx == ctx)
74 		phy->chanctx = NULL;
75 	mutex_unlock(&dev->mutex);
76 }
77 EXPORT_SYMBOL_GPL(mt76_remove_chanctx);
78 
79 void mt76_change_chanctx(struct ieee80211_hw *hw,
80 			 struct ieee80211_chanctx_conf *conf,
81 			 u32 changed)
82 {
83 	struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
84 	struct mt76_phy *phy = ctx->phy;
85 	struct mt76_dev *dev = phy->dev;
86 
87 	if (!(changed & (IEEE80211_CHANCTX_CHANGE_WIDTH |
88 			 IEEE80211_CHANCTX_CHANGE_RADAR)))
89 		return;
90 
91 	cancel_delayed_work_sync(&phy->mac_work);
92 
93 	mutex_lock(&dev->mutex);
94 	mt76_phy_update_channel(phy, conf);
95 	mutex_unlock(&dev->mutex);
96 }
97 EXPORT_SYMBOL_GPL(mt76_change_chanctx);
98 
99 
100 int mt76_assign_vif_chanctx(struct ieee80211_hw *hw,
101 			    struct ieee80211_vif *vif,
102 			    struct ieee80211_bss_conf *link_conf,
103 			    struct ieee80211_chanctx_conf *conf)
104 {
105 	struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
106 	struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
107 	struct mt76_vif_data *mvif = mlink->mvif;
108 	int link_id = link_conf->link_id;
109 	struct mt76_phy *phy = ctx->phy;
110 	struct mt76_dev *dev = phy->dev;
111 	bool mlink_alloc = false;
112 	int ret = 0;
113 
114 	if (dev->scan.vif == vif)
115 		mt76_abort_scan(dev);
116 
117 	mutex_lock(&dev->mutex);
118 
119 	if (vif->type == NL80211_IFTYPE_MONITOR &&
120 	    is_zero_ether_addr(vif->addr))
121 		goto out;
122 
123 	mlink = mt76_vif_conf_link(dev, vif, link_conf);
124 	if (!mlink) {
125 		mlink = mt76_alloc_mlink(dev, mvif);
126 		if (!mlink) {
127 			ret = -ENOMEM;
128 			goto out;
129 		}
130 		mlink_alloc = true;
131 	}
132 
133 	mlink->ctx = conf;
134 	ret = dev->drv->vif_link_add(phy, vif, link_conf, mlink);
135 	if (ret) {
136 		if (mlink_alloc)
137 			kfree(mlink);
138 		goto out;
139 	}
140 
141 	if (link_conf != &vif->bss_conf)
142 		rcu_assign_pointer(mvif->link[link_id], mlink);
143 
144 out:
145 	mutex_unlock(&dev->mutex);
146 
147 	return ret;
148 }
149 EXPORT_SYMBOL_GPL(mt76_assign_vif_chanctx);
150 
151 void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
152 			       struct ieee80211_vif *vif,
153 			       struct ieee80211_bss_conf *link_conf,
154 			       struct ieee80211_chanctx_conf *conf)
155 {
156 	struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
157 	struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
158 	struct mt76_vif_data *mvif = mlink->mvif;
159 	int link_id = link_conf->link_id;
160 	struct mt76_phy *phy = ctx->phy;
161 	struct mt76_dev *dev = phy->dev;
162 
163 	if (dev->scan.vif == vif)
164 		mt76_abort_scan(dev);
165 
166 	mutex_lock(&dev->mutex);
167 
168 	if (vif->type == NL80211_IFTYPE_MONITOR &&
169 	    is_zero_ether_addr(vif->addr))
170 		goto out;
171 
172 	mlink = mt76_vif_conf_link(dev, vif, link_conf);
173 	if (!mlink)
174 		goto out;
175 
176 	if (link_conf != &vif->bss_conf)
177 		rcu_assign_pointer(mvif->link[link_id], NULL);
178 
179 	dev->drv->vif_link_remove(phy, vif, link_conf, mlink);
180 	mlink->ctx = NULL;
181 
182 	if (link_conf != &vif->bss_conf)
183 		kfree_rcu(mlink, rcu_head);
184 
185 out:
186 	mutex_unlock(&dev->mutex);
187 }
188 EXPORT_SYMBOL_GPL(mt76_unassign_vif_chanctx);
189 
190 int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
191 			    struct ieee80211_vif_chanctx_switch *vifs,
192 			    int n_vifs,
193 			    enum ieee80211_chanctx_switch_mode mode)
194 {
195 	struct mt76_chanctx *old_ctx = (struct mt76_chanctx *)vifs->old_ctx->drv_priv;
196 	struct mt76_chanctx *new_ctx = (struct mt76_chanctx *)vifs->new_ctx->drv_priv;
197 	struct ieee80211_chanctx_conf *conf = vifs->new_ctx;
198 	struct mt76_phy *old_phy = old_ctx->phy;
199 	struct mt76_phy *phy = hw->priv;
200 	struct mt76_dev *dev = phy->dev;
201 	struct mt76_vif_link *mlink;
202 	bool update_chan;
203 	int i, ret = 0;
204 
205 	if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
206 		phy = new_ctx->phy = dev->band_phys[conf->def.chan->band];
207 	else
208 		phy = new_ctx->phy;
209 	if (!phy)
210 		return -EINVAL;
211 
212 	update_chan = phy->chanctx != new_ctx;
213 	if (update_chan) {
214 		if (dev->scan.phy == phy)
215 			mt76_abort_scan(dev);
216 
217 		cancel_delayed_work_sync(&phy->mac_work);
218 	}
219 
220 	mutex_lock(&dev->mutex);
221 
222 	if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
223 	    phy != old_phy && old_phy->chanctx == old_ctx)
224 		old_phy->chanctx = NULL;
225 
226 	if (update_chan)
227 		ret = mt76_phy_update_channel(phy, vifs->new_ctx);
228 
229 	if (ret)
230 		goto out;
231 
232 	if (old_phy == phy)
233 		goto skip_link_replace;
234 
235 	for (i = 0; i < n_vifs; i++) {
236 		mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
237 		if (!mlink)
238 			continue;
239 
240 		dev->drv->vif_link_remove(old_phy, vifs[i].vif,
241 					  vifs[i].link_conf, mlink);
242 
243 		ret = dev->drv->vif_link_add(phy, vifs[i].vif,
244 					     vifs[i].link_conf, mlink);
245 		if (ret)
246 			goto out;
247 
248 	}
249 
250 skip_link_replace:
251 	for (i = 0; i < n_vifs; i++) {
252 		mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
253 		if (!mlink)
254 			continue;
255 
256 		mlink->ctx = vifs->new_ctx;
257 	}
258 
259 out:
260 	mutex_unlock(&dev->mutex);
261 
262 	return ret;
263 }
264 EXPORT_SYMBOL_GPL(mt76_switch_vif_chanctx);
265 
266 struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
267 					    struct ieee80211_vif *vif)
268 {
269 	struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
270 	struct mt76_vif_data *mvif = mlink->mvif;
271 	struct mt76_dev *dev = phy->dev;
272 	int i, ret;
273 
274 	for (i = 0; i < ARRAY_SIZE(mvif->link); i++) {
275 		mlink = mt76_dereference(mvif->link[i], dev);
276 		if (!mlink)
277 			continue;
278 
279 		if (mt76_vif_link_phy(mlink) == phy)
280 			return mlink;
281 	}
282 
283 	if (!dev->drv->vif_link_add)
284 		return ERR_PTR(-EINVAL);
285 
286 	mlink = mt76_alloc_mlink(dev, mvif);
287 	if (!mlink)
288 		return ERR_PTR(-ENOMEM);
289 
290 	mlink->offchannel = true;
291 	ret = dev->drv->vif_link_add(phy, vif, &vif->bss_conf, mlink);
292 	if (ret) {
293 		kfree(mlink);
294 		return ERR_PTR(ret);
295 	}
296 
297 	return mlink;
298 }
299 
300 void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
301 			   struct mt76_vif_link *mlink)
302 {
303 	struct mt76_dev *dev = phy->dev;
304 
305 	if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel)
306 		return;
307 
308 	dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
309 	kfree(mlink);
310 }
311 
312 static void mt76_roc_complete(struct mt76_phy *phy)
313 {
314 	struct mt76_vif_link *mlink = phy->roc_link;
315 
316 	if (!phy->roc_vif)
317 		return;
318 
319 	if (mlink)
320 		mlink->mvif->roc_phy = NULL;
321 	if (phy->main_chandef.chan)
322 		mt76_set_channel(phy, &phy->main_chandef, false);
323 	mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
324 	phy->roc_vif = NULL;
325 	phy->roc_link = NULL;
326 	ieee80211_remain_on_channel_expired(phy->hw);
327 }
328 
329 void mt76_roc_complete_work(struct work_struct *work)
330 {
331 	struct mt76_phy *phy = container_of(work, struct mt76_phy, roc_work.work);
332 	struct mt76_dev *dev = phy->dev;
333 
334 	mutex_lock(&dev->mutex);
335 	mt76_roc_complete(phy);
336 	mutex_unlock(&dev->mutex);
337 }
338 
339 void mt76_abort_roc(struct mt76_phy *phy)
340 {
341 	struct mt76_dev *dev = phy->dev;
342 
343 	cancel_delayed_work_sync(&phy->roc_work);
344 
345 	mutex_lock(&dev->mutex);
346 	mt76_roc_complete(phy);
347 	mutex_unlock(&dev->mutex);
348 }
349 
350 int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
351 			   struct ieee80211_channel *chan, int duration,
352 			   enum ieee80211_roc_type type)
353 {
354 	struct cfg80211_chan_def chandef = {};
355 	struct mt76_phy *phy = hw->priv;
356 	struct mt76_dev *dev = phy->dev;
357 	struct mt76_vif_link *mlink;
358 	int ret = 0;
359 
360 	phy = dev->band_phys[chan->band];
361 	if (!phy)
362 		return -EINVAL;
363 
364 	mutex_lock(&dev->mutex);
365 
366 	if (phy->roc_vif || dev->scan.phy == phy) {
367 		ret = -EBUSY;
368 		goto out;
369 	}
370 
371 	mlink = mt76_get_vif_phy_link(phy, vif);
372 	if (IS_ERR(mlink)) {
373 		ret = PTR_ERR(mlink);
374 		goto out;
375 	}
376 
377 	mlink->mvif->roc_phy = phy;
378 	phy->roc_vif = vif;
379 	phy->roc_link = mlink;
380 	cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
381 	mt76_set_channel(phy, &chandef, true);
382 	ieee80211_ready_on_channel(hw);
383 	ieee80211_queue_delayed_work(phy->hw, &phy->roc_work,
384 				     msecs_to_jiffies(duration));
385 
386 out:
387 	mutex_unlock(&dev->mutex);
388 	return ret;
389 }
390 EXPORT_SYMBOL_GPL(mt76_remain_on_channel);
391 
392 int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
393 				  struct ieee80211_vif *vif)
394 {
395 	struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
396 	struct mt76_vif_data *mvif = mlink->mvif;
397 	struct mt76_phy *phy = mvif->roc_phy;
398 
399 	if (!phy)
400 		return 0;
401 
402 	mt76_abort_roc(phy);
403 
404 	return 0;
405 }
406 EXPORT_SYMBOL_GPL(mt76_cancel_remain_on_channel);
407