Skip to content

Commit 8233462

Browse files
committed
wifi: mt76: add chanctx functions for multi-channel phy support
This adds an implementation for the chanctx functions, which can be used by multi-channel capable drivers. Preparation for adding MLO support. Link: https://patch.msgid.link/[email protected] Signed-off-by: Felix Fietkau <[email protected]>
1 parent cbf5e61 commit 8233462

File tree

5 files changed

+342
-15
lines changed

5 files changed

+342
-15
lines changed

drivers/net/wireless/mediatek/mt76/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ obj-$(CONFIG_MT792x_USB) += mt792x-usb.o
1010

1111
mt76-y := \
1212
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
13-
tx.o agg-rx.o mcu.o wed.o scan.o
13+
tx.o agg-rx.o mcu.o wed.o scan.o channel.o
1414

1515
mt76-$(CONFIG_PCI) += pci.o
1616
mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
// SPDX-License-Identifier: ISC
2+
/*
3+
* Copyright (C) 2024 Felix Fietkau <[email protected]>
4+
*/
5+
#include "mt76.h"
6+
7+
static int
8+
mt76_phy_update_channel(struct mt76_phy *phy,
9+
struct ieee80211_chanctx_conf *conf)
10+
{
11+
phy->radar_enabled = conf->radar_enabled;
12+
phy->main_chandef = conf->def;
13+
phy->chanctx = (struct mt76_chanctx *)conf->drv_priv;
14+
15+
return __mt76_set_channel(phy, &phy->main_chandef, false);
16+
}
17+
18+
int mt76_add_chanctx(struct ieee80211_hw *hw,
19+
struct ieee80211_chanctx_conf *conf)
20+
{
21+
struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
22+
struct mt76_phy *phy = hw->priv;
23+
struct mt76_dev *dev = phy->dev;
24+
int ret = -EINVAL;
25+
26+
phy = ctx->phy = dev->band_phys[conf->def.chan->band];
27+
if (WARN_ON_ONCE(!phy))
28+
return ret;
29+
30+
if (dev->scan.phy == phy)
31+
mt76_abort_scan(dev);
32+
33+
mutex_lock(&dev->mutex);
34+
if (!phy->chanctx)
35+
ret = mt76_phy_update_channel(phy, conf);
36+
else
37+
ret = 0;
38+
mutex_unlock(&dev->mutex);
39+
40+
return ret;
41+
}
42+
EXPORT_SYMBOL_GPL(mt76_add_chanctx);
43+
44+
void mt76_remove_chanctx(struct ieee80211_hw *hw,
45+
struct ieee80211_chanctx_conf *conf)
46+
{
47+
struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
48+
struct mt76_phy *phy = hw->priv;
49+
struct mt76_dev *dev = phy->dev;
50+
51+
phy = ctx->phy;
52+
if (WARN_ON_ONCE(!phy))
53+
return;
54+
55+
if (dev->scan.phy == phy)
56+
mt76_abort_scan(dev);
57+
58+
mutex_lock(&dev->mutex);
59+
if (phy->chanctx == ctx)
60+
phy->chanctx = NULL;
61+
mutex_unlock(&dev->mutex);
62+
}
63+
EXPORT_SYMBOL_GPL(mt76_remove_chanctx);
64+
65+
void mt76_change_chanctx(struct ieee80211_hw *hw,
66+
struct ieee80211_chanctx_conf *conf,
67+
u32 changed)
68+
{
69+
struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
70+
struct mt76_phy *phy = ctx->phy;
71+
struct mt76_dev *dev = phy->dev;
72+
73+
if (!(changed & (IEEE80211_CHANCTX_CHANGE_WIDTH |
74+
IEEE80211_CHANCTX_CHANGE_RADAR)))
75+
return;
76+
77+
cancel_delayed_work_sync(&phy->mac_work);
78+
79+
mutex_lock(&dev->mutex);
80+
mt76_phy_update_channel(phy, conf);
81+
mutex_unlock(&dev->mutex);
82+
}
83+
EXPORT_SYMBOL_GPL(mt76_change_chanctx);
84+
85+
86+
int mt76_assign_vif_chanctx(struct ieee80211_hw *hw,
87+
struct ieee80211_vif *vif,
88+
struct ieee80211_bss_conf *link_conf,
89+
struct ieee80211_chanctx_conf *conf)
90+
{
91+
struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
92+
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
93+
struct mt76_vif_data *mvif = mlink->mvif;
94+
int link_id = link_conf->link_id;
95+
struct mt76_phy *phy = ctx->phy;
96+
struct mt76_dev *dev = phy->dev;
97+
bool mlink_alloc = false;
98+
int ret = 0;
99+
100+
if (dev->scan.vif == vif)
101+
mt76_abort_scan(dev);
102+
103+
mutex_lock(&dev->mutex);
104+
105+
if (vif->type == NL80211_IFTYPE_MONITOR &&
106+
is_zero_ether_addr(vif->addr))
107+
goto out;
108+
109+
mlink = mt76_vif_conf_link(dev, vif, link_conf);
110+
if (!mlink) {
111+
mlink = kzalloc(dev->drv->link_data_size, GFP_KERNEL);
112+
if (!mlink) {
113+
ret = -ENOMEM;
114+
goto out;
115+
}
116+
mlink_alloc = true;
117+
}
118+
119+
mlink->ctx = conf;
120+
ret = dev->drv->vif_link_add(phy, vif, link_conf, mlink);
121+
if (ret) {
122+
if (mlink_alloc)
123+
kfree(mlink);
124+
goto out;
125+
}
126+
127+
if (link_conf != &vif->bss_conf)
128+
rcu_assign_pointer(mvif->link[link_id], mlink);
129+
130+
out:
131+
mutex_unlock(&dev->mutex);
132+
133+
return ret;
134+
}
135+
EXPORT_SYMBOL_GPL(mt76_assign_vif_chanctx);
136+
137+
void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
138+
struct ieee80211_vif *vif,
139+
struct ieee80211_bss_conf *link_conf,
140+
struct ieee80211_chanctx_conf *conf)
141+
{
142+
struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
143+
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
144+
struct mt76_vif_data *mvif = mlink->mvif;
145+
int link_id = link_conf->link_id;
146+
struct mt76_phy *phy = ctx->phy;
147+
struct mt76_dev *dev = phy->dev;
148+
149+
if (dev->scan.vif == vif)
150+
mt76_abort_scan(dev);
151+
152+
mutex_lock(&dev->mutex);
153+
154+
if (vif->type == NL80211_IFTYPE_MONITOR &&
155+
is_zero_ether_addr(vif->addr))
156+
goto out;
157+
158+
mlink = mt76_vif_conf_link(dev, vif, link_conf);
159+
if (!mlink)
160+
goto out;
161+
162+
if (link_conf != &vif->bss_conf)
163+
rcu_assign_pointer(mvif->link[link_id], NULL);
164+
165+
dev->drv->vif_link_remove(phy, vif, link_conf, mlink);
166+
mlink->ctx = NULL;
167+
168+
if (link_conf != &vif->bss_conf)
169+
kfree_rcu(mlink, rcu_head);
170+
171+
out:
172+
mutex_unlock(&dev->mutex);
173+
}
174+
EXPORT_SYMBOL_GPL(mt76_unassign_vif_chanctx);
175+
176+
int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
177+
struct ieee80211_vif_chanctx_switch *vifs,
178+
int n_vifs,
179+
enum ieee80211_chanctx_switch_mode mode)
180+
{
181+
struct mt76_chanctx *old_ctx = (struct mt76_chanctx *)vifs->old_ctx->drv_priv;
182+
struct mt76_chanctx *new_ctx = (struct mt76_chanctx *)vifs->new_ctx->drv_priv;
183+
struct ieee80211_chanctx_conf *conf = vifs->new_ctx;
184+
struct mt76_phy *old_phy = old_ctx->phy;
185+
struct mt76_phy *phy = hw->priv;
186+
struct mt76_dev *dev = phy->dev;
187+
struct mt76_vif_link *mlink;
188+
bool update_chan;
189+
int i, ret = 0;
190+
191+
if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
192+
phy = new_ctx->phy = dev->band_phys[conf->def.chan->band];
193+
else
194+
phy = new_ctx->phy;
195+
if (!phy)
196+
return -EINVAL;
197+
198+
update_chan = phy->chanctx != new_ctx;
199+
if (update_chan) {
200+
if (dev->scan.phy == phy)
201+
mt76_abort_scan(dev);
202+
203+
cancel_delayed_work_sync(&phy->mac_work);
204+
}
205+
206+
mutex_lock(&dev->mutex);
207+
208+
if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
209+
phy != old_phy && old_phy->chanctx == old_ctx)
210+
old_phy->chanctx = NULL;
211+
212+
if (update_chan)
213+
ret = mt76_phy_update_channel(phy, vifs->new_ctx);
214+
215+
if (ret)
216+
goto out;
217+
218+
if (old_phy == phy)
219+
goto skip_link_replace;
220+
221+
for (i = 0; i < n_vifs; i++) {
222+
mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
223+
if (!mlink)
224+
continue;
225+
226+
dev->drv->vif_link_remove(old_phy, vifs[i].vif,
227+
vifs[i].link_conf, mlink);
228+
229+
ret = dev->drv->vif_link_add(phy, vifs[i].vif,
230+
vifs[i].link_conf, mlink);
231+
if (ret)
232+
goto out;
233+
234+
}
235+
236+
skip_link_replace:
237+
for (i = 0; i < n_vifs; i++) {
238+
mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
239+
if (!mlink)
240+
continue;
241+
242+
mlink->ctx = vifs->new_ctx;
243+
}
244+
245+
out:
246+
mutex_unlock(&dev->mutex);
247+
248+
return ret;
249+
}
250+
EXPORT_SYMBOL_GPL(mt76_switch_vif_chanctx);

drivers/net/wireless/mediatek/mt76/mac80211.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
414414
cfg80211_chandef_create(&phy->chandef, &sband->channels[0],
415415
NL80211_CHAN_HT20);
416416
phy->chan_state = &msband->chan[0];
417+
phy->dev->band_phys[band] = phy;
417418
return;
418419
}
419420

@@ -959,16 +960,13 @@ void mt76_update_survey(struct mt76_phy *phy)
959960
}
960961
EXPORT_SYMBOL_GPL(mt76_update_survey);
961962

962-
int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
963-
bool offchannel)
963+
int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
964+
bool offchannel)
964965
{
965966
struct mt76_dev *dev = phy->dev;
966967
int timeout = HZ / 5;
967968
int ret;
968969

969-
cancel_delayed_work_sync(&phy->mac_work);
970-
971-
mutex_lock(&dev->mutex);
972970
set_bit(MT76_RESET, &phy->state);
973971

974972
mt76_worker_disable(&dev->tx_worker);
@@ -995,6 +993,19 @@ int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
995993
mt76_worker_enable(&dev->tx_worker);
996994
mt76_worker_schedule(&dev->tx_worker);
997995

996+
return ret;
997+
}
998+
999+
int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
1000+
bool offchannel)
1001+
{
1002+
struct mt76_dev *dev = phy->dev;
1003+
int ret;
1004+
1005+
cancel_delayed_work_sync(&phy->mac_work);
1006+
1007+
mutex_lock(&dev->mutex);
1008+
ret = __mt76_set_channel(phy, chandef, offchannel);
9981009
mutex_unlock(&dev->mutex);
9991010

10001011
return ret;
@@ -1006,6 +1017,8 @@ int mt76_update_channel(struct mt76_phy *phy)
10061017
struct cfg80211_chan_def *chandef = &hw->conf.chandef;
10071018
bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
10081019

1020+
phy->radar_enabled = hw->conf.radar_enabled;
1021+
10091022
return mt76_set_channel(phy, chandef, offchannel);
10101023
}
10111024
EXPORT_SYMBOL_GPL(mt76_update_channel);
@@ -1919,7 +1932,7 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
19191932
test_bit(MT76_SCANNING, &phy->state))
19201933
return MT_DFS_STATE_DISABLED;
19211934

1922-
if (!hw->conf.radar_enabled) {
1935+
if (!phy->radar_enabled) {
19231936
if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
19241937
(phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
19251938
return MT_DFS_STATE_ACTIVE;
@@ -1933,3 +1946,13 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
19331946
return MT_DFS_STATE_ACTIVE;
19341947
}
19351948
EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1949+
1950+
void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
1951+
{
1952+
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
1953+
struct mt76_vif_data *mvif = mlink->mvif;
1954+
1955+
rcu_assign_pointer(mvif->link[0], NULL);
1956+
mt76_abort_scan(dev);
1957+
}
1958+
EXPORT_SYMBOL_GPL(mt76_vif_cleanup);

0 commit comments

Comments
 (0)