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