Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/mediatek/mt76/channel.c
105379 views
1
// SPDX-License-Identifier: BSD-3-Clause-Clear
2
/*
3
* Copyright (C) 2024 Felix Fietkau <[email protected]>
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 (mlink != (struct mt76_vif_link *)vif->drv_priv)
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 (mlink != (struct mt76_vif_link *)vif->drv_priv)
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
rcu_assign_pointer(mvif->offchannel_link, mlink);
297
298
return mlink;
299
}
300
301
void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
302
struct mt76_vif_link *mlink)
303
{
304
struct mt76_dev *dev = phy->dev;
305
struct mt76_vif_data *mvif;
306
307
if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel)
308
return;
309
310
mvif = mlink->mvif;
311
312
rcu_assign_pointer(mvif->offchannel_link, NULL);
313
dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
314
kfree(mlink);
315
}
316
317
void mt76_roc_complete(struct mt76_phy *phy)
318
{
319
struct mt76_vif_link *mlink = phy->roc_link;
320
struct mt76_dev *dev = phy->dev;
321
322
if (!phy->roc_vif)
323
return;
324
325
if (mlink)
326
mlink->mvif->roc_phy = NULL;
327
if (phy->main_chandef.chan &&
328
!test_bit(MT76_MCU_RESET, &dev->phy.state))
329
mt76_set_channel(phy, &phy->main_chandef, false);
330
mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
331
phy->roc_vif = NULL;
332
phy->roc_link = NULL;
333
if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
334
ieee80211_remain_on_channel_expired(phy->hw);
335
}
336
337
void mt76_roc_complete_work(struct work_struct *work)
338
{
339
struct mt76_phy *phy = container_of(work, struct mt76_phy, roc_work.work);
340
struct mt76_dev *dev = phy->dev;
341
342
mutex_lock(&dev->mutex);
343
mt76_roc_complete(phy);
344
mutex_unlock(&dev->mutex);
345
}
346
347
void mt76_abort_roc(struct mt76_phy *phy)
348
{
349
struct mt76_dev *dev = phy->dev;
350
351
cancel_delayed_work_sync(&phy->roc_work);
352
353
mutex_lock(&dev->mutex);
354
mt76_roc_complete(phy);
355
mutex_unlock(&dev->mutex);
356
}
357
EXPORT_SYMBOL_GPL(mt76_abort_roc);
358
359
int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
360
struct ieee80211_channel *chan, int duration,
361
enum ieee80211_roc_type type)
362
{
363
struct cfg80211_chan_def chandef = {};
364
struct mt76_phy *phy = hw->priv;
365
struct mt76_dev *dev = phy->dev;
366
struct mt76_vif_link *mlink;
367
int ret = 0;
368
369
phy = dev->band_phys[chan->band];
370
if (!phy)
371
return -EINVAL;
372
373
mutex_lock(&dev->mutex);
374
375
if (phy->roc_vif || dev->scan.phy == phy ||
376
test_bit(MT76_MCU_RESET, &dev->phy.state)) {
377
ret = -EBUSY;
378
goto out;
379
}
380
381
mlink = mt76_get_vif_phy_link(phy, vif);
382
if (IS_ERR(mlink)) {
383
ret = PTR_ERR(mlink);
384
goto out;
385
}
386
387
mlink->mvif->roc_phy = phy;
388
phy->roc_vif = vif;
389
phy->roc_link = mlink;
390
cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
391
mt76_set_channel(phy, &chandef, true);
392
ieee80211_ready_on_channel(hw);
393
ieee80211_queue_delayed_work(phy->hw, &phy->roc_work,
394
msecs_to_jiffies(duration));
395
396
out:
397
mutex_unlock(&dev->mutex);
398
return ret;
399
}
400
EXPORT_SYMBOL_GPL(mt76_remain_on_channel);
401
402
int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
403
struct ieee80211_vif *vif)
404
{
405
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
406
struct mt76_vif_data *mvif = mlink->mvif;
407
struct mt76_phy *phy = mvif->roc_phy;
408
409
if (!phy)
410
return 0;
411
412
mt76_abort_roc(phy);
413
414
return 0;
415
}
416
EXPORT_SYMBOL_GPL(mt76_cancel_remain_on_channel);
417
418