diff options
-rw-r--r-- | include/net/mac80211.h | 6 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 16 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 3 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/iface.c | 6 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 35 |
6 files changed, 43 insertions, 26 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c622450ac012..353488ab94a2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2778,6 +2778,11 @@ struct ieee80211_txq { * @IEEE80211_HW_DISALLOW_PUNCTURING: HW requires disabling puncturing in EHT * and connecting with a lower bandwidth instead * + * @IEEE80211_HW_HANDLES_QUIET_CSA: HW/driver handles quieting for CSA, so + * no need to stop queues. This really should be set by a driver that + * implements MLO, so operation can continue on other links when one + * link is switching. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2836,6 +2841,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_DETECTS_COLOR_COLLISION, IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX, IEEE80211_HW_DISALLOW_PUNCTURING, + IEEE80211_HW_HANDLES_QUIET_CSA, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bc0cc2dff83..3a9d2ceec752 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1607,10 +1607,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, /* abort any running channel switch or color change */ link_conf->csa_active = false; link_conf->color_change_active = false; - if (link->csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - link->csa_block_tx = false; + sdata->csa_blocked_tx = false; } ieee80211_free_next_beacon(link); @@ -3649,7 +3649,7 @@ void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_t struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - sdata->deflink.csa_block_tx = block_tx; + sdata->csa_blocked_tx = block_tx; sdata_info(sdata, "channel switch failed, disconnecting\n"); wiphy_work_queue(local->hw.wiphy, &ifmgd->csa_connection_drop_work); } @@ -3735,10 +3735,10 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) ieee80211_link_info_change_notify(sdata, link_data, changed); - if (link_data->csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - link_data->csa_block_tx = false; + sdata->csa_blocked_tx = false; } err = drv_post_channel_switch(link_data); @@ -4014,12 +4014,14 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, } link_data->csa_chanreq = chanreq; - link_data->csa_block_tx = params->block_tx; link_conf->csa_active = true; - if (link_data->csa_block_tx) + if (params->block_tx && + !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA)) { ieee80211_stop_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_blocked_tx = true; + } cfg80211_ch_switch_started_notify(sdata->dev, &link_data->csa_chanreq.oper, 0, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 74be49191e70..2f68e92a7404 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -4,7 +4,7 @@ * * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018 - 2019, 2021-2023 Intel Corporation + * Copyright (C) 2018 - 2019, 2021-2024 Intel Corporation */ #include <linux/debugfs.h> @@ -498,6 +498,7 @@ static const char *hw_flag_names[] = { FLAG(DETECTS_COLOR_COLLISION), FLAG(MLO_MCAST_MULTI_LINK_TX), FLAG(DISALLOW_PUNCTURING), + FLAG(HANDLES_QUIET_CSA), #undef FLAG }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index da320799fbff..cfd0c03e4bd6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1034,7 +1034,6 @@ struct ieee80211_link_data { struct ieee80211_key __rcu *default_beacon_key; struct wiphy_work csa_finalize_work; - bool csa_block_tx; bool operating_11g_mode; @@ -1093,6 +1092,8 @@ struct ieee80211_sub_if_data { unsigned long state; + bool csa_blocked_tx; + char name[IFNAMSIZ]; struct ieee80211_fragment_cache frags; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b75b83a5142b..395de62d9cb2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -8,7 +8,7 @@ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/slab.h> #include <linux/kernel.h> @@ -544,10 +544,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do sdata->vif.bss_conf.csa_active = false; if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->deflink.u.mgd.csa_waiting_bcn = false; - if (sdata->deflink.csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->deflink.csa_block_tx = false; + sdata->csa_blocked_tx = false; } wiphy_work_cancel(local->hw.wiphy, &sdata->deflink.csa_finalize_work); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c5c757514179..3d5cc3dd9238 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1926,10 +1926,10 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link) WARN_ON(!link->conf->csa_active); - if (link->csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - link->csa_block_tx = false; + sdata->csa_blocked_tx = false; } link->conf->csa_active = false; @@ -1997,11 +1997,12 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_link_data *link) ieee80211_link_unreserve_chanctx(link); - if (link->csa_block_tx) + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_blocked_tx = false; + } - link->csa_block_tx = false; link->conf->csa_active = false; drv_abort_channel_switch(link); @@ -2145,13 +2146,15 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, link->conf->csa_active = true; link->csa_chanreq = csa_ie.chanreq; - link->csa_block_tx = csa_ie.mode; link->u.mgd.csa_ignored_same_chan = false; link->u.mgd.beacon_crc_valid = false; - if (link->csa_block_tx) + if (csa_ie.mode && + !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA)) { ieee80211_stop_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_blocked_tx = true; + } cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chanreq.oper, link->link_id, csa_ie.count, @@ -2179,7 +2182,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, * reset when the disconnection worker runs. */ link->conf->csa_active = true; - link->csa_block_tx = csa_ie.mode; + sdata->csa_blocked_tx = + csa_ie.mode && !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA); wiphy_work_queue(sdata->local->hw.wiphy, &ifmgd->csa_connection_drop_work); @@ -3233,10 +3237,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; sdata->deflink.u.mgd.csa_ignored_same_chan = false; - if (sdata->deflink.csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->deflink.csa_block_tx = false; + sdata->csa_blocked_tx = false; } /* existing TX TSPEC sessions no longer exist */ @@ -3549,9 +3553,12 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) if (!ifmgd->associated) return; - /* in MLO assume we have a link where we can TX the frame */ - tx = ieee80211_vif_is_mld(&sdata->vif) || - !sdata->deflink.csa_block_tx; + /* + * MLO drivers should have HANDLES_QUIET_CSA, so that csa_blocked_tx + * is always false; if they don't then this may try to transmit the + * frame but queues will be stopped. + */ + tx = !sdata->csa_blocked_tx; if (!ifmgd->driver_disconnect) { unsigned int link_id; @@ -3584,10 +3591,10 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) /* the other links will be destroyed */ sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; - if (sdata->deflink.csa_block_tx) { + if (sdata->csa_blocked_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - sdata->deflink.csa_block_tx = false; + sdata->csa_blocked_tx = false; } ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx, |