mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
wifi: mt76: mt7925: support deferred NAN schedule update and cluster events
Send the is_deferred flag in the availability control TLV so FW
applies a deferred schedule change at the next DW boundary, and report
the NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE and STARTED_CLUSTER events to
mac80211 via ieee80211_nan_sched_update_done() and
ieee80211_nan_cluster_joined().
Both events arrive on the BH-disabled MCU RX path, where notifying
mac80211 inline is wrong: ieee80211_nan_sched_update_done() needs the
wiphy mutex and may sleep, and ieee80211_nan_cluster_joined() would
fire during NAN_START before mac80211 sets sdata->u.nan.started and
before the supplicant subscribes to NL80211_MCGRP_NAN, so the
self-anchor cluster-join is lost and a solo anchor master can never
publish a service.
Deliver both events from a shared nan_deferred_work selected by a
pending bitmap instead. The bitmap spinlock is taken with
spin_lock_bh() on the RX side, the work re-checks nan_vif under the
wiphy mutex, and the stop path clears the bitmap. STARTED_CLUSTER
signals new_cluster=true, and JOINED_CLUSTER is corrected to
new_cluster=false.
Fixes: a5487a682406 ("wifi: mt76: mt7925: add NAN MCU helpers")
Co-developed-by: Sean Wang <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
Co-developed-by: Stella Liu <[email protected]>
Signed-off-by: Stella Liu <[email protected]>
Signed-off-by: Jacobs Wu <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
@@ -270,6 +270,8 @@ int mt7925_register_device(struct mt792x_dev *dev)
|
|||||||
|
|
||||||
INIT_WORK(&dev->reset_work, mt7925_mac_reset_work);
|
INIT_WORK(&dev->reset_work, mt7925_mac_reset_work);
|
||||||
INIT_WORK(&dev->init_work, mt7925_init_work);
|
INIT_WORK(&dev->init_work, mt7925_init_work);
|
||||||
|
INIT_WORK(&dev->nan_deferred_work, mt7925_nan_deferred_work);
|
||||||
|
spin_lock_init(&dev->nan_deferred_lock);
|
||||||
|
|
||||||
INIT_WORK(&dev->phy.roc_work, mt7925_roc_work);
|
INIT_WORK(&dev->phy.roc_work, mt7925_roc_work);
|
||||||
timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0);
|
timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0);
|
||||||
|
|||||||
@@ -2613,6 +2613,13 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,
|
|||||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||||
int err, ret;
|
int err, ret;
|
||||||
|
|
||||||
|
/* Drop a deferred event queued just before stop so a stale cluster_id
|
||||||
|
* cannot leak into a restart; the work re-checks liveness anyway.
|
||||||
|
*/
|
||||||
|
spin_lock_bh(&dev->nan_deferred_lock);
|
||||||
|
dev->nan_deferred_pending = 0;
|
||||||
|
spin_unlock_bh(&dev->nan_deferred_lock);
|
||||||
|
|
||||||
mt792x_mutex_acquire(dev);
|
mt792x_mutex_acquire(dev);
|
||||||
|
|
||||||
err = mt7925_nan_disable(vif, dev);
|
err = mt7925_nan_disable(vif, dev);
|
||||||
|
|||||||
@@ -361,6 +361,7 @@ void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac,
|
|||||||
void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
|
void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
|
||||||
struct ieee80211_vif *vif);
|
struct ieee80211_vif *vif);
|
||||||
void mt7925_set_ipv6_ns_work(struct work_struct *work);
|
void mt7925_set_ipv6_ns_work(struct work_struct *work);
|
||||||
|
void mt7925_nan_deferred_work(struct work_struct *work);
|
||||||
|
|
||||||
int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
|
int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
|
||||||
bool enable);
|
bool enable);
|
||||||
|
|||||||
+82
-3
@@ -454,9 +454,27 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
|
|||||||
dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n",
|
dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n",
|
||||||
de_evt->event_type, de_evt->cluster_id);
|
de_evt->event_type, de_evt->cluster_id);
|
||||||
|
|
||||||
if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER)
|
if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER &&
|
||||||
|
de_evt->event_type != NAN_EVENT_ID_STARTED_CLUSTER)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* STARTED_CLUSTER fires during NAN_START, before nan.started is set and
|
||||||
|
* before the supplicant subscribes - defer past NAN_START via the work
|
||||||
|
* so ieee80211_nan_cluster_joined() actually reaches userspace.
|
||||||
|
*/
|
||||||
|
if (de_evt->event_type == NAN_EVENT_ID_STARTED_CLUSTER) {
|
||||||
|
dev_dbg(dev->mt76.dev,
|
||||||
|
"nan: deferring STARTED_CLUSTER cluster=%pM\n",
|
||||||
|
cluster_id);
|
||||||
|
spin_lock_bh(&dev->nan_deferred_lock);
|
||||||
|
memcpy(dev->nan_started_cluster_id, cluster_id, ETH_ALEN);
|
||||||
|
set_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER,
|
||||||
|
&dev->nan_deferred_pending);
|
||||||
|
spin_unlock_bh(&dev->nan_deferred_lock);
|
||||||
|
ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) {
|
if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) {
|
||||||
dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n");
|
dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n");
|
||||||
return;
|
return;
|
||||||
@@ -468,7 +486,43 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
|
|||||||
dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n",
|
dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n",
|
||||||
de_evt->own_nmi, de_evt->master_nmi);
|
de_evt->own_nmi, de_evt->master_nmi);
|
||||||
|
|
||||||
ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL);
|
/* joined an existing cluster, not a self-anchored new one */
|
||||||
|
ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, false, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Runs the deferred NAN MCU events in process context; takes wiphy_lock
|
||||||
|
* before nan_vif, which the NAN stop path frees under that mutex.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mt7925_nan_deferred_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct mt792x_dev *dev = container_of(work, struct mt792x_dev,
|
||||||
|
nan_deferred_work);
|
||||||
|
struct ieee80211_vif *vif;
|
||||||
|
unsigned long pending;
|
||||||
|
u8 cluster_id[ETH_ALEN];
|
||||||
|
|
||||||
|
spin_lock_bh(&dev->nan_deferred_lock);
|
||||||
|
pending = dev->nan_deferred_pending;
|
||||||
|
dev->nan_deferred_pending = 0;
|
||||||
|
memcpy(cluster_id, dev->nan_started_cluster_id, ETH_ALEN);
|
||||||
|
spin_unlock_bh(&dev->nan_deferred_lock);
|
||||||
|
|
||||||
|
if (!pending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wiphy_lock(dev->mt76.hw->wiphy);
|
||||||
|
vif = dev->nan_vif;
|
||||||
|
if (!vif || !ieee80211_vif_nan_started(vif))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (test_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER, &pending))
|
||||||
|
ieee80211_nan_cluster_joined(vif, cluster_id, true, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (test_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &pending))
|
||||||
|
ieee80211_nan_sched_update_done(vif);
|
||||||
|
out:
|
||||||
|
wiphy_unlock(dev->mt76.hw->wiphy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -517,6 +571,27 @@ mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv)
|
|||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mt7925_nan_handle_sched_update_done(struct mt792x_dev *dev, struct tlv *tlv)
|
||||||
|
{
|
||||||
|
struct ieee80211_vif *vif;
|
||||||
|
|
||||||
|
if (!dev || !tlv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vif = dev->nan_vif;
|
||||||
|
if (!vif || !ieee80211_vif_nan_started(vif))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Runs in the BH-disabled MCU-event RX path; the mac80211 helper needs
|
||||||
|
* the wiphy mutex and may sleep, so hand it to the work instead.
|
||||||
|
*/
|
||||||
|
spin_lock_bh(&dev->nan_deferred_lock);
|
||||||
|
set_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &dev->nan_deferred_pending);
|
||||||
|
spin_unlock_bh(&dev->nan_deferred_lock);
|
||||||
|
ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
|
||||||
|
}
|
||||||
|
|
||||||
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
|
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct tlv *tlv;
|
struct tlv *tlv;
|
||||||
@@ -548,6 +623,9 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
|
|||||||
case NAN_UNI_EVENT_ID_ULW_UPDATE:
|
case NAN_UNI_EVENT_ID_ULW_UPDATE:
|
||||||
mt7925_nan_handle_ulw_update(dev, tlv);
|
mt7925_nan_handle_ulw_update(dev, tlv);
|
||||||
break;
|
break;
|
||||||
|
case NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE:
|
||||||
|
mt7925_nan_handle_sched_update_done(dev, tlv);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -585,6 +663,7 @@ static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb,
|
|||||||
avail_ctrl_tlv->avail_ctrl =
|
avail_ctrl_tlv->avail_ctrl =
|
||||||
cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED);
|
cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED);
|
||||||
avail_ctrl_tlv->seq_id = seq_id;
|
avail_ctrl_tlv->seq_id = seq_id;
|
||||||
|
avail_ctrl_tlv->is_deferred = sched->deferred ? 1 : 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -710,7 +789,7 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
|
mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), false);
|
||||||
out:
|
out:
|
||||||
mt792x_mutex_release(dev);
|
mt792x_mutex_release(dev);
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-1
@@ -97,15 +97,25 @@ enum nan_uni_cmd_tag {
|
|||||||
enum nan_uni_event_tag {
|
enum nan_uni_event_tag {
|
||||||
NAN_UNI_EVENT_ID_DE_EVENT_IND = 19,
|
NAN_UNI_EVENT_ID_DE_EVENT_IND = 19,
|
||||||
NAN_UNI_EVENT_ID_ULW_UPDATE = 39,
|
NAN_UNI_EVENT_ID_ULW_UPDATE = 39,
|
||||||
|
NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE = 43,
|
||||||
NAN_UNI_EVENT_REPORT_DW_START = 59,
|
NAN_UNI_EVENT_REPORT_DW_START = 59,
|
||||||
NAN_UNI_EVENT_REPORT_DW_END = 60,
|
NAN_UNI_EVENT_REPORT_DW_END = 60,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum nan_disc_event_type {
|
enum nan_disc_event_type {
|
||||||
NAN_EVENT_ID_DISC_MAC_ADDR = 0,
|
NAN_EVENT_ID_DISC_MAC_ADDR = 0,
|
||||||
|
NAN_EVENT_ID_STARTED_CLUSTER = 1,
|
||||||
NAN_EVENT_ID_JOINED_CLUSTER = 2,
|
NAN_EVENT_ID_JOINED_CLUSTER = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* bit indices into mt792x_dev->nan_deferred_pending, set from the atomic
|
||||||
|
* MCU-event RX path and consumed by mt7925_nan_deferred_work()
|
||||||
|
*/
|
||||||
|
enum mt7925_nan_deferred_event {
|
||||||
|
MT7925_NAN_DEFERRED_STARTED_CLUSTER,
|
||||||
|
MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE,
|
||||||
|
};
|
||||||
|
|
||||||
/* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */
|
/* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */
|
||||||
enum nan_supported_bands {
|
enum nan_supported_bands {
|
||||||
NAN_SUPPORTED_BAND_ID_2P4G = 2,
|
NAN_SUPPORTED_BAND_ID_2P4G = 2,
|
||||||
@@ -345,7 +355,7 @@ struct mt7925_nan_avail_ctrl_tlv {
|
|||||||
__le16 len;
|
__le16 len;
|
||||||
__le16 avail_ctrl;
|
__le16 avail_ctrl;
|
||||||
u8 seq_id;
|
u8 seq_id;
|
||||||
u8 reserved[1];
|
u8 is_deferred;
|
||||||
} __packed __aligned(4);
|
} __packed __aligned(4);
|
||||||
|
|
||||||
struct mt7925_nan_ch_timeline {
|
struct mt7925_nan_ch_timeline {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)
|
|||||||
cancel_delayed_work_sync(&pm->ps_work);
|
cancel_delayed_work_sync(&pm->ps_work);
|
||||||
cancel_delayed_work_sync(&dev->mlo_pm_work);
|
cancel_delayed_work_sync(&dev->mlo_pm_work);
|
||||||
cancel_work_sync(&pm->wake_work);
|
cancel_work_sync(&pm->wake_work);
|
||||||
|
cancel_work_sync(&dev->nan_deferred_work);
|
||||||
|
|
||||||
mt7925_tx_token_put(dev);
|
mt7925_tx_token_put(dev);
|
||||||
__mt792x_mcu_drv_pmctrl(dev);
|
__mt792x_mcu_drv_pmctrl(dev);
|
||||||
|
|||||||
+14
-1
@@ -348,6 +348,19 @@ failed:
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
|
static void mt7925u_disconnect(struct usb_interface *usb_intf)
|
||||||
|
{
|
||||||
|
struct mt792x_dev *dev = usb_get_intfdata(usb_intf);
|
||||||
|
|
||||||
|
/* mt792xu_disconnect() ends in mt76_free_device(), so the work has to
|
||||||
|
* go before it rather than after mt76_unregister_device() as on PCI.
|
||||||
|
*/
|
||||||
|
if (dev)
|
||||||
|
cancel_work_sync(&dev->nan_deferred_work);
|
||||||
|
|
||||||
|
mt792xu_disconnect(usb_intf);
|
||||||
|
}
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(usb, mt7925u_device_table);
|
MODULE_DEVICE_TABLE(usb, mt7925u_device_table);
|
||||||
MODULE_FIRMWARE(MT7925_FIRMWARE_WM);
|
MODULE_FIRMWARE(MT7925_FIRMWARE_WM);
|
||||||
MODULE_FIRMWARE(MT7925_ROM_PATCH);
|
MODULE_FIRMWARE(MT7925_ROM_PATCH);
|
||||||
@@ -356,7 +369,7 @@ static struct usb_driver mt7925u_driver = {
|
|||||||
.name = KBUILD_MODNAME,
|
.name = KBUILD_MODNAME,
|
||||||
.id_table = mt7925u_device_table,
|
.id_table = mt7925u_device_table,
|
||||||
.probe = mt7925u_probe,
|
.probe = mt7925u_probe,
|
||||||
.disconnect = mt792xu_disconnect,
|
.disconnect = mt7925u_disconnect,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.suspend = mt7925u_suspend,
|
.suspend = mt7925u_suspend,
|
||||||
.resume = mt7925u_resume,
|
.resume = mt7925u_resume,
|
||||||
|
|||||||
@@ -342,6 +342,14 @@ struct mt792x_dev {
|
|||||||
struct ieee80211_vif *nan_vif;
|
struct ieee80211_vif *nan_vif;
|
||||||
const struct ieee80211_iface_combination *iface_combinations;
|
const struct ieee80211_iface_combination *iface_combinations;
|
||||||
int n_iface_combinations;
|
int n_iface_combinations;
|
||||||
|
/* deferred NAN MCU events run out of the atomic RX path on one shared
|
||||||
|
* work; see mt7925_nan_deferred_work() and enum mt7925_nan_deferred_event
|
||||||
|
*/
|
||||||
|
struct work_struct nan_deferred_work;
|
||||||
|
/* protects @nan_deferred_pending */
|
||||||
|
spinlock_t nan_deferred_lock;
|
||||||
|
unsigned long nan_deferred_pending;
|
||||||
|
u8 nan_started_cluster_id[ETH_ALEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct mt792x_bss_conf *
|
static inline struct mt792x_bss_conf *
|
||||||
|
|||||||
Reference in New Issue
Block a user