Skip to content

Commit a8f424c

Browse files
committed
wifi: mt76: add multi-radio remain_on_channel functions
This allows a driver using the generic channel context functions to temporarily switch to another channel for off-channel rx/tx. Link: https://patch.msgid.link/[email protected] Signed-off-by: Felix Fietkau <[email protected]>
1 parent e411b81 commit a8f424c

File tree

4 files changed

+112
-1
lines changed

4 files changed

+112
-1
lines changed

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

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,99 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
308308
dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
309309
kfree(mlink);
310310
}
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);

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
431431

432432
INIT_LIST_HEAD(&phy->tx_list);
433433
spin_lock_init(&phy->tx_lock);
434+
INIT_DELAYED_WORK(&phy->roc_work, mt76_roc_complete_work);
434435

435436
if ((void *)phy != hw->priv)
436437
return 0;
@@ -1999,5 +2000,7 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
19992000

20002001
rcu_assign_pointer(mvif->link[0], NULL);
20012002
mt76_abort_scan(dev);
2003+
if (mvif->roc_phy)
2004+
mt76_abort_roc(mvif->roc_phy);
20022005
}
20032006
EXPORT_SYMBOL_GPL(mt76_vif_cleanup);

drivers/net/wireless/mediatek/mt76/mt76.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ struct mt76_vif_link {
787787
struct mt76_vif_data {
788788
struct mt76_vif_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
789789

790+
struct mt76_phy *roc_phy;
790791
u16 valid_links;
791792
u8 deflink_id;
792793
};
@@ -809,6 +810,10 @@ struct mt76_phy {
809810
bool offchannel;
810811
bool radar_enabled;
811812

813+
struct delayed_work roc_work;
814+
struct ieee80211_vif *roc_vif;
815+
struct mt76_vif_link *roc_link;
816+
812817
struct mt76_chanctx *chanctx;
813818

814819
struct mt76_channel_state *chan_state;
@@ -1521,6 +1526,11 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
15211526
struct ieee80211_vif_chanctx_switch *vifs,
15221527
int n_vifs,
15231528
enum ieee80211_chanctx_switch_mode mode);
1529+
int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1530+
struct ieee80211_channel *chan, int duration,
1531+
enum ieee80211_roc_type type);
1532+
int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
1533+
struct ieee80211_vif *vif);
15241534
int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15251535
void *data, int len);
15261536
int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -1572,6 +1582,8 @@ int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
15721582
bool offchannel);
15731583
void mt76_scan_work(struct work_struct *work);
15741584
void mt76_abort_scan(struct mt76_dev *dev);
1585+
void mt76_roc_complete_work(struct work_struct *work);
1586+
void mt76_abort_roc(struct mt76_phy *phy);
15751587
struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
15761588
struct ieee80211_vif *vif);
15771589
void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
134134

135135
mutex_lock(&dev->mutex);
136136

137-
if (dev->scan.req) {
137+
if (dev->scan.req || phy->roc_vif) {
138138
ret = -EBUSY;
139139
goto out;
140140
}

0 commit comments

Comments
 (0)