From: Felix Fietkau Date: Sat, 5 Oct 2024 07:35:49 +0000 (+0200) Subject: mac80211: backport upstream DFS fixes X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=ec61ccc0d3d53a6cd1ac4920e19e78a2a2dbf67c;p=openwrt%2Fstaging%2Fblocktrron.git mac80211: backport upstream DFS fixes Mostly MLO related Signed-off-by: Felix Fietkau --- diff --git a/package/kernel/ath10k-ct/patches/010-api_update.patch b/package/kernel/ath10k-ct/patches/010-api_update.patch index c0d2574748..f70d8eb460 100644 --- a/package/kernel/ath10k-ct/patches/010-api_update.patch +++ b/package/kernel/ath10k-ct/patches/010-api_update.patch @@ -1,5 +1,14 @@ --- a/ath10k-6.9/mac.c +++ b/ath10k-6.9/mac.c +@@ -1675,7 +1675,7 @@ static void ath10k_recalc_radar_detectio + * by indicating that radar was detected. + */ + ath10k_warn(ar, "failed to start CAC: %d\n", ret); +- ieee80211_radar_detected(ar->hw); ++ ieee80211_radar_detected(ar->hw, NULL); + } + } + @@ -6238,7 +6238,7 @@ err: return ret; } @@ -9,3 +18,25 @@ { struct ath10k *ar = hw->priv; u32 opt; +--- a/ath10k-6.9/debug.c ++++ b/ath10k-6.9/debug.c +@@ -3319,7 +3319,7 @@ static ssize_t ath10k_write_simulate_rad + if (!arvif->is_started) + return -EINVAL; + +- ieee80211_radar_detected(ar->hw); ++ ieee80211_radar_detected(ar->hw, NULL); + + return count; + } +--- a/ath10k-6.9/wmi.c ++++ b/ath10k-6.9/wmi.c +@@ -4402,7 +4402,7 @@ static void ath10k_radar_detected(struct + if (ar->dfs_block_radar_events) + ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); + else +- ieee80211_radar_detected(ar->hw); ++ ieee80211_radar_detected(ar->hw, NULL); + } + + static void ath10k_radar_confirmation_work(struct work_struct *work) diff --git a/package/kernel/mac80211/patches/subsys/332-wifi-cfg80211-Set-correct-chandef-when-starting-CAC.patch b/package/kernel/mac80211/patches/subsys/332-wifi-cfg80211-Set-correct-chandef-when-starting-CAC.patch new file mode 100644 index 0000000000..72a3510aac --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/332-wifi-cfg80211-Set-correct-chandef-when-starting-CAC.patch @@ -0,0 +1,64 @@ +From: Issam Hamdi +Date: Fri, 16 Aug 2024 16:24:18 +0200 +Subject: [PATCH] wifi: cfg80211: Set correct chandef when starting CAC + +When starting CAC in a mode other than AP mode, it return a +"WARNING: CPU: 0 PID: 63 at cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]" +caused by the chandef.chan being null at the end of CAC. + +Solution: Ensure the channel definition is set for the different modes +when starting CAC to avoid getting a NULL 'chan' at the end of CAC. + + Call Trace: + ? show_regs.part.0+0x14/0x16 + ? __warn+0x67/0xc0 + ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211] + ? report_bug+0xa7/0x130 + ? exc_overflow+0x30/0x30 + ? handle_bug+0x27/0x50 + ? exc_invalid_op+0x18/0x60 + ? handle_exception+0xf6/0xf6 + ? exc_overflow+0x30/0x30 + ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211] + ? exc_overflow+0x30/0x30 + ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211] + ? regulatory_propagate_dfs_state.cold+0x1b/0x4c [cfg80211] + ? cfg80211_propagate_cac_done_wk+0x1a/0x30 [cfg80211] + ? process_one_work+0x165/0x280 + ? worker_thread+0x120/0x3f0 + ? kthread+0xc2/0xf0 + ? process_one_work+0x280/0x280 + ? kthread_complete_and_exit+0x20/0x20 + ? ret_from_fork+0x19/0x24 + +Reported-by: Kretschmer Mathias +Signed-off-by: Issam Hamdi +Link: https://patch.msgid.link/20240816142418.3381951-1-ih@simonwunderlich.de +[shorten subject, remove OCB, reorder cases to match previous list] +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -10144,7 +10144,20 @@ static int nl80211_start_radar_detection + + err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms); + if (!err) { +- wdev->links[0].ap.chandef = chandef; ++ switch (wdev->iftype) { ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_P2P_GO: ++ wdev->links[0].ap.chandef = chandef; ++ break; ++ case NL80211_IFTYPE_ADHOC: ++ wdev->u.ibss.chandef = chandef; ++ break; ++ case NL80211_IFTYPE_MESH_POINT: ++ wdev->u.mesh.chandef = chandef; ++ break; ++ default: ++ break; ++ } + wdev->cac_started = true; + wdev->cac_start_time = jiffies; + wdev->cac_time_ms = cac_time_ms; diff --git a/package/kernel/mac80211/patches/subsys/333-Revert-wifi-mac80211-move-radar-detect-work-to-sdata.patch b/package/kernel/mac80211/patches/subsys/333-Revert-wifi-mac80211-move-radar-detect-work-to-sdata.patch new file mode 100644 index 0000000000..d12df8f53e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/333-Revert-wifi-mac80211-move-radar-detect-work-to-sdata.patch @@ -0,0 +1,136 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:19 +0530 +Subject: [PATCH] Revert "wifi: mac80211: move radar detect work to sdata" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit ce9e660ef32e ("wifi: mac80211: move radar detect work to sdata"). + +To enable radar detection with MLO, it’s essential to handle it on a +per-link basis. This is because when using MLO, multiple links may already +be active and beaconing. In this scenario, another link should be able to +initiate a radar detection. Also, if underlying links are associated with +different hardware devices but grouped together for MLO, they could +potentially start radar detection simultaneously. Therefore, it makes +sense to manage radar detection settings separately for each link by moving +them back to a per-link data structure. + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-2-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1658,7 +1658,7 @@ static int ieee80211_stop_ap(struct wiph + + if (sdata->wdev.cac_started) { + chandef = link_conf->chanreq.oper; +- wiphy_delayed_work_cancel(wiphy, &sdata->dfs_cac_timer_work); ++ wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_ABORTED, + GFP_KERNEL); +@@ -3482,7 +3482,7 @@ static int ieee80211_start_radar_detecti + if (err) + goto out_unlock; + +- wiphy_delayed_work_queue(wiphy, &sdata->dfs_cac_timer_work, ++ wiphy_delayed_work_queue(wiphy, &sdata->deflink.dfs_cac_timer_work, + msecs_to_jiffies(cac_time_ms)); + + out_unlock: +@@ -3499,7 +3499,7 @@ static void ieee80211_end_cac(struct wip + + list_for_each_entry(sdata, &local->interfaces, list) { + wiphy_delayed_work_cancel(wiphy, +- &sdata->dfs_cac_timer_work); ++ &sdata->deflink.dfs_cac_timer_work); + + if (sdata->wdev.cac_started) { + ieee80211_link_release_channel(&sdata->deflink); +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1069,6 +1069,7 @@ struct ieee80211_link_data { + int ap_power_level; /* in dBm */ + + bool radar_required; ++ struct wiphy_delayed_work dfs_cac_timer_work; + + union { + struct ieee80211_link_data_managed mgd; +@@ -1167,8 +1168,6 @@ struct ieee80211_sub_if_data { + struct ieee80211_link_data deflink; + struct ieee80211_link_data __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + +- struct wiphy_delayed_work dfs_cac_timer_work; +- + /* for ieee80211_set_active_links_async() */ + struct wiphy_work activate_links_work; + u16 desired_active_links; +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -551,7 +551,7 @@ static void ieee80211_do_stop(struct iee + wiphy_work_cancel(local->hw.wiphy, + &sdata->deflink.color_change_finalize_work); + wiphy_delayed_work_cancel(local->hw.wiphy, +- &sdata->dfs_cac_timer_work); ++ &sdata->deflink.dfs_cac_timer_work); + + if (sdata->wdev.cac_started) { + chandef = sdata->vif.bss_conf.chanreq.oper; +@@ -1744,8 +1744,6 @@ static void ieee80211_setup_sdata(struct + wiphy_work_init(&sdata->work, ieee80211_iface_work); + wiphy_work_init(&sdata->activate_links_work, + ieee80211_activate_links_work); +- wiphy_delayed_work_init(&sdata->dfs_cac_timer_work, +- ieee80211_dfs_cac_timer_work); + + switch (type) { + case NL80211_IFTYPE_P2P_GO: +--- a/net/mac80211/link.c ++++ b/net/mac80211/link.c +@@ -45,6 +45,8 @@ void ieee80211_link_init(struct ieee8021 + ieee80211_color_collision_detection_work); + INIT_LIST_HEAD(&link->assigned_chanctx_list); + INIT_LIST_HEAD(&link->reserved_chanctx_list); ++ wiphy_delayed_work_init(&link->dfs_cac_timer_work, ++ ieee80211_dfs_cac_timer_work); + + if (!deflink) { + switch (sdata->vif.type) { +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3031,15 +3031,16 @@ void ieee80211_dynamic_ps_timer(struct t + + void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work) + { +- struct ieee80211_sub_if_data *sdata = +- container_of(work, struct ieee80211_sub_if_data, ++ struct ieee80211_link_data *link = ++ container_of(work, struct ieee80211_link_data, + dfs_cac_timer_work.work); +- struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chanreq.oper; ++ struct cfg80211_chan_def chandef = link->conf->chanreq.oper; ++ struct ieee80211_sub_if_data *sdata = link->sdata; + + lockdep_assert_wiphy(sdata->local->hw.wiphy); + + if (sdata->wdev.cac_started) { +- ieee80211_link_release_channel(&sdata->deflink); ++ ieee80211_link_release_channel(link); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_FINISHED, + GFP_KERNEL); +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -3460,7 +3460,7 @@ void ieee80211_dfs_cac_cancel(struct iee + + list_for_each_entry(sdata, &local->interfaces, list) { + wiphy_delayed_work_cancel(local->hw.wiphy, +- &sdata->dfs_cac_timer_work); ++ &sdata->deflink.dfs_cac_timer_work); + + if (sdata->wdev.cac_started) { + chandef = sdata->vif.bss_conf.chanreq.oper; diff --git a/package/kernel/mac80211/patches/subsys/334-wifi-mac80211-remove-label-usage-in-ieee80211_start_.patch b/package/kernel/mac80211/patches/subsys/334-wifi-mac80211-remove-label-usage-in-ieee80211_start_.patch new file mode 100644 index 0000000000..329b645462 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/334-wifi-mac80211-remove-label-usage-in-ieee80211_start_.patch @@ -0,0 +1,50 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:20 +0530 +Subject: [PATCH] wifi: mac80211: remove label usage in + ieee80211_start_radar_detection() + +After locks rework [1], ieee80211_start_radar_detection() function is no +longer acquiring any lock as such explicitly. Hence, it is not unlocking +anything as well. However, label "out_unlock" is still used which creates +confusion. Also, now there is no need of goto label as such. + +Get rid of the goto logic and use direct return statements. + +[1]: https://lore.kernel.org/all/20230828135928.b1c6efffe9ad.I4aec875e25abc9ef0b5ad1e70b5747fd483fbd3c@changeid/ + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-3-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3468,10 +3468,8 @@ static int ieee80211_start_radar_detecti + + lockdep_assert_wiphy(local->hw.wiphy); + +- if (!list_empty(&local->roc_list) || local->scanning) { +- err = -EBUSY; +- goto out_unlock; +- } ++ if (!list_empty(&local->roc_list) || local->scanning) ++ return -EBUSY; + + /* whatever, but channel contexts should not complain about that one */ + sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; +@@ -3480,13 +3478,12 @@ static int ieee80211_start_radar_detecti + err = ieee80211_link_use_channel(&sdata->deflink, &chanreq, + IEEE80211_CHANCTX_SHARED); + if (err) +- goto out_unlock; ++ return err; + + wiphy_delayed_work_queue(wiphy, &sdata->deflink.dfs_cac_timer_work, + msecs_to_jiffies(cac_time_ms)); + +- out_unlock: +- return err; ++ return 0; + } + + static void ieee80211_end_cac(struct wiphy *wiphy, diff --git a/package/kernel/mac80211/patches/subsys/335-wifi-trace-unlink-rdev_end_cac-trace-event-from-wiph.patch b/package/kernel/mac80211/patches/subsys/335-wifi-trace-unlink-rdev_end_cac-trace-event-from-wiph.patch new file mode 100644 index 0000000000..98bc0c26fd --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/335-wifi-trace-unlink-rdev_end_cac-trace-event-from-wiph.patch @@ -0,0 +1,42 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:21 +0530 +Subject: [PATCH] wifi: trace: unlink rdev_end_cac trace event from + wiphy_netdev_evt class + +rdev_end_cac trace event is linked with wiphy_netdev_evt event class. +There is no option to pass link ID currently to wiphy_netdev_evt class. +A subsequent change would pass link ID to rdev_end_cac event and hence +it can no longer derive the event class from wiphy_netdev_evt. + +Therefore, unlink rdev_end_cac event from wiphy_netdev_evt and define it's +own independent trace event. Link ID would be passed in subsequent change. + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-4-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -805,9 +805,18 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_flus + TP_ARGS(wiphy, netdev) + ); + +-DEFINE_EVENT(wiphy_netdev_evt, rdev_end_cac, +- TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), +- TP_ARGS(wiphy, netdev) ++TRACE_EVENT(rdev_end_cac, ++ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), ++ TP_ARGS(wiphy, netdev), ++ TP_STRUCT__entry( ++ WIPHY_ENTRY ++ NETDEV_ENTRY ++ ), ++ TP_fast_assign( ++ WIPHY_ASSIGN; ++ NETDEV_ASSIGN; ++ ), ++ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) + ); + + DECLARE_EVENT_CLASS(station_add_change, diff --git a/package/kernel/mac80211/patches/subsys/336-wifi-cfg80211-move-DFS-related-members-to-links-in-w.patch b/package/kernel/mac80211/patches/subsys/336-wifi-cfg80211-move-DFS-related-members-to-links-in-w.patch new file mode 100644 index 0000000000..95dac04de5 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/336-wifi-cfg80211-move-DFS-related-members-to-links-in-w.patch @@ -0,0 +1,309 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:22 +0530 +Subject: [PATCH] wifi: cfg80211: move DFS related members to links[] in + wireless_dev + +A few members related to DFS handling are currently under per wireless +device data structure. However, in order to support DFS with MLO, there is +a need to have them on a per-link manner. + +Hence, as a preliminary step, move members cac_started, cac_start_time +and cac_time_ms to be on a per-link basis. + +Since currently, link ID is not known at all places, use default value of +0 for now. + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-5-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/drivers/net/wireless/marvell/mwifiex/11h.c ++++ b/drivers/net/wireless/marvell/mwifiex/11h.c +@@ -117,7 +117,7 @@ void mwifiex_dfs_cac_work_queue(struct w + dfs_cac_work); + + chandef = priv->dfs_chandef; +- if (priv->wdev.cac_started) { ++ if (priv->wdev.links[0].cac_started) { + mwifiex_dbg(priv->adapter, MSG, + "CAC timer finished; No radar detected\n"); + cfg80211_cac_event(priv->netdev, &chandef, +@@ -174,7 +174,7 @@ int mwifiex_stop_radar_detection(struct + */ + void mwifiex_abort_cac(struct mwifiex_private *priv) + { +- if (priv->wdev.cac_started) { ++ if (priv->wdev.links[0].cac_started) { + if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) + mwifiex_dbg(priv->adapter, ERROR, + "failed to stop CAC in FW\n"); +--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c ++++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +@@ -1880,7 +1880,7 @@ mwifiex_cfg80211_del_station(struct wiph + struct mwifiex_sta_node *sta_node; + u8 deauth_mac[ETH_ALEN]; + +- if (!priv->bss_started && priv->wdev.cac_started) { ++ if (!priv->bss_started && priv->wdev.links[0].cac_started) { + mwifiex_dbg(priv->adapter, INFO, "%s: abort CAC!\n", __func__); + mwifiex_abort_cac(priv); + } +@@ -3978,7 +3978,7 @@ mwifiex_cfg80211_channel_switch(struct w + return -EBUSY; + } + +- if (priv->wdev.cac_started) ++ if (priv->wdev.links[0].cac_started) + return -EBUSY; + + if (cfg80211_chandef_identical(¶ms->chandef, +--- a/drivers/net/wireless/quantenna/qtnfmac/event.c ++++ b/drivers/net/wireless/quantenna/qtnfmac/event.c +@@ -520,21 +520,21 @@ static int qtnf_event_handle_radar(struc + cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL); + break; + case QLINK_RADAR_CAC_FINISHED: +- if (!vif->wdev.cac_started) ++ if (!vif->wdev.links[0].cac_started) + break; + + cfg80211_cac_event(vif->netdev, &chandef, + NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); + break; + case QLINK_RADAR_CAC_ABORTED: +- if (!vif->wdev.cac_started) ++ if (!vif->wdev.links[0].cac_started) + break; + + cfg80211_cac_event(vif->netdev, &chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); + break; + case QLINK_RADAR_CAC_STARTED: +- if (vif->wdev.cac_started) ++ if (vif->wdev.links[0].cac_started) + break; + + if (!wiphy_ext_feature_isset(wiphy, +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -6198,9 +6198,6 @@ enum ieee80211_ap_reg_power { + * @address: The address for this device, valid only if @netdev is %NULL + * @is_running: true if this is a non-netdev device that has been started, e.g. + * the P2P Device. +- * @cac_started: true if DFS channel availability check has been started +- * @cac_start_time: timestamp (jiffies) when the dfs state was entered. +- * @cac_time_ms: CAC time in ms + * @ps: powersave mode is enabled + * @ps_timeout: dynamic powersave timeout + * @ap_unexpected_nlportid: (private) netlink port ID of application +@@ -6224,6 +6221,11 @@ enum ieee80211_ap_reg_power { + * unprotected beacon report + * @links: array of %IEEE80211_MLD_MAX_NUM_LINKS elements containing @addr + * @ap and @client for each link ++ * @links[].cac_started: true if DFS channel availability check has been ++ * started ++ * @links[].cac_start_time: timestamp (jiffies) when the dfs state was ++ * entered. ++ * @links[].cac_time_ms: CAC time in ms + * @valid_links: bitmap describing what elements of @links are valid + */ + struct wireless_dev { +@@ -6265,11 +6267,6 @@ struct wireless_dev { + u32 owner_nlportid; + bool nl_owner_dead; + +- /* FIXME: need to rework radar detection for MLO */ +- bool cac_started; +- unsigned long cac_start_time; +- unsigned int cac_time_ms; +- + #ifdef CPTCFG_CFG80211_WEXT + /* wext data */ + struct { +@@ -6336,6 +6333,10 @@ struct wireless_dev { + struct cfg80211_internal_bss *current_bss; + } client; + }; ++ ++ bool cac_started; ++ unsigned long cac_start_time; ++ unsigned int cac_time_ms; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; + u16 valid_links; + }; +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1656,7 +1656,7 @@ static int ieee80211_stop_ap(struct wiph + ieee80211_link_info_change_notify(sdata, link, + BSS_CHANGED_BEACON_ENABLED); + +- if (sdata->wdev.cac_started) { ++ if (sdata->wdev.links[0].cac_started) { + chandef = link_conf->chanreq.oper; + wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work); + cfg80211_cac_event(sdata->dev, &chandef, +@@ -3498,9 +3498,9 @@ static void ieee80211_end_cac(struct wip + wiphy_delayed_work_cancel(wiphy, + &sdata->deflink.dfs_cac_timer_work); + +- if (sdata->wdev.cac_started) { ++ if (sdata->wdev.links[0].cac_started) { + ieee80211_link_release_channel(&sdata->deflink); +- sdata->wdev.cac_started = false; ++ sdata->wdev.links[0].cac_started = false; + } + } + } +@@ -3955,7 +3955,7 @@ __ieee80211_channel_switch(struct wiphy + if (!list_empty(&local->roc_list) || local->scanning) + return -EBUSY; + +- if (sdata->wdev.cac_started) ++ if (sdata->wdev.links[0].cac_started) + return -EBUSY; + + if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS)) +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -553,7 +553,7 @@ static void ieee80211_do_stop(struct iee + wiphy_delayed_work_cancel(local->hw.wiphy, + &sdata->deflink.dfs_cac_timer_work); + +- if (sdata->wdev.cac_started) { ++ if (sdata->wdev.links[0].cac_started) { + chandef = sdata->vif.bss_conf.chanreq.oper; + WARN_ON(local->suspended); + ieee80211_link_release_channel(&sdata->deflink); +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3039,7 +3039,7 @@ void ieee80211_dfs_cac_timer_work(struct + + lockdep_assert_wiphy(sdata->local->hw.wiphy); + +- if (sdata->wdev.cac_started) { ++ if (sdata->wdev.links[0].cac_started) { + ieee80211_link_release_channel(link); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_FINISHED, +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -585,7 +585,7 @@ static bool __ieee80211_can_leave_ch(str + return false; + + list_for_each_entry(sdata_iter, &local->interfaces, list) { +- if (sdata_iter->wdev.cac_started) ++ if (sdata_iter->wdev.links[0].cac_started) + return false; + } + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -3462,7 +3462,7 @@ void ieee80211_dfs_cac_cancel(struct iee + wiphy_delayed_work_cancel(local->hw.wiphy, + &sdata->deflink.dfs_cac_timer_work); + +- if (sdata->wdev.cac_started) { ++ if (sdata->wdev.links[0].cac_started) { + chandef = sdata->vif.bss_conf.chanreq.oper; + ieee80211_link_release_channel(&sdata->deflink); + cfg80211_cac_event(sdata->dev, +--- a/net/wireless/ibss.c ++++ b/net/wireless/ibss.c +@@ -94,7 +94,7 @@ int __cfg80211_join_ibss(struct cfg80211 + + lockdep_assert_held(&rdev->wiphy.mtx); + +- if (wdev->cac_started) ++ if (wdev->links[0].cac_started) + return -EBUSY; + + if (wdev->u.ibss.ssid_len) +--- a/net/wireless/mesh.c ++++ b/net/wireless/mesh.c +@@ -127,7 +127,7 @@ int __cfg80211_join_mesh(struct cfg80211 + if (!rdev->ops->join_mesh) + return -EOPNOTSUPP; + +- if (wdev->cac_started) ++ if (wdev->links[0].cac_started) + return -EBUSY; + + if (!setup->chandef.chan) { +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -1124,13 +1124,14 @@ void cfg80211_cac_event(struct net_devic + + trace_cfg80211_cac_event(netdev, event); + +- if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED)) ++ if (WARN_ON(!wdev->links[0].cac_started && ++ event != NL80211_RADAR_CAC_STARTED)) + return; + + switch (event) { + case NL80211_RADAR_CAC_FINISHED: +- timeout = wdev->cac_start_time + +- msecs_to_jiffies(wdev->cac_time_ms); ++ timeout = wdev->links[0].cac_start_time + ++ msecs_to_jiffies(wdev->links[0].cac_time_ms); + WARN_ON(!time_after_eq(jiffies, timeout)); + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); + memcpy(&rdev->cac_done_chandef, chandef, +@@ -1139,10 +1140,10 @@ void cfg80211_cac_event(struct net_devic + cfg80211_sched_dfs_chan_update(rdev); + fallthrough; + case NL80211_RADAR_CAC_ABORTED: +- wdev->cac_started = false; ++ wdev->links[0].cac_started = false; + break; + case NL80211_RADAR_CAC_STARTED: +- wdev->cac_started = true; ++ wdev->links[0].cac_started = true; + break; + default: + WARN_ON(1); +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -6066,7 +6066,7 @@ static int nl80211_start_ap(struct sk_bu + if (!rdev->ops->start_ap) + return -EOPNOTSUPP; + +- if (wdev->cac_started) ++ if (wdev->links[0].cac_started) + return -EBUSY; + + if (wdev->links[link_id].ap.beacon_interval) +@@ -10122,7 +10122,7 @@ static int nl80211_start_radar_detection + goto unlock; + } + +- if (cfg80211_beaconing_iface_active(wdev) || wdev->cac_started) { ++ if (cfg80211_beaconing_iface_active(wdev) || wdev->links[0].cac_started) { + err = -EBUSY; + goto unlock; + } +@@ -10158,9 +10158,9 @@ static int nl80211_start_radar_detection + default: + break; + } +- wdev->cac_started = true; +- wdev->cac_start_time = jiffies; +- wdev->cac_time_ms = cac_time_ms; ++ wdev->links[0].cac_started = true; ++ wdev->links[0].cac_start_time = jiffies; ++ wdev->links[0].cac_time_ms = cac_time_ms; + } + unlock: + wiphy_unlock(wiphy); +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -4241,7 +4241,7 @@ static void cfg80211_check_and_end_cac(s + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + struct cfg80211_chan_def *chandef; + +- if (!wdev->cac_started) ++ if (!wdev->links[0].cac_started) + continue; + + /* FIXME: radar detection is tied to link 0 for now */ diff --git a/package/kernel/mac80211/patches/subsys/337-wifi-cfg80211-handle-DFS-per-link.patch b/package/kernel/mac80211/patches/subsys/337-wifi-cfg80211-handle-DFS-per-link.patch new file mode 100644 index 0000000000..a4e0333642 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/337-wifi-cfg80211-handle-DFS-per-link.patch @@ -0,0 +1,435 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:23 +0530 +Subject: [PATCH] wifi: cfg80211: handle DFS per link + +Currently, during starting a radar detection, no link id information is +parsed and passed down. In order to support starting radar detection +during Multi Link Operation, it is required to pass link id as well. + +Add changes to first parse and then pass link id in the start radar +detection path. + +Additionally, update notification APIs to allow drivers/mac80211 to +pass the link ID. + +However, everything is handled at link 0 only until all API's are ready to +handle it per link. + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-6-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/drivers/net/wireless/marvell/mwifiex/11h.c ++++ b/drivers/net/wireless/marvell/mwifiex/11h.c +@@ -122,7 +122,7 @@ void mwifiex_dfs_cac_work_queue(struct w + "CAC timer finished; No radar detected\n"); + cfg80211_cac_event(priv->netdev, &chandef, + NL80211_RADAR_CAC_FINISHED, +- GFP_KERNEL); ++ GFP_KERNEL, 0); + } + } + +@@ -182,7 +182,8 @@ void mwifiex_abort_cac(struct mwifiex_pr + "Aborting delayed work for CAC.\n"); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, +- NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); ++ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, ++ 0); + } + } + +@@ -221,7 +222,7 @@ int mwifiex_11h_handle_chanrpt_ready(str + cfg80211_cac_event(priv->netdev, + &priv->dfs_chandef, + NL80211_RADAR_DETECTED, +- GFP_KERNEL); ++ GFP_KERNEL, 0); + } + break; + default: +--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c ++++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +@@ -4145,7 +4145,7 @@ static int + mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, +- u32 cac_time_ms) ++ u32 cac_time_ms, int link_id) + { + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_radar_params radar_params; +--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c ++++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +@@ -837,7 +837,7 @@ static int qtnf_channel_switch(struct wi + static int qtnf_start_radar_detection(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_chan_def *chandef, +- u32 cac_time_ms) ++ u32 cac_time_ms, int link_id) + { + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + int ret; +--- a/drivers/net/wireless/quantenna/qtnfmac/event.c ++++ b/drivers/net/wireless/quantenna/qtnfmac/event.c +@@ -524,14 +524,14 @@ static int qtnf_event_handle_radar(struc + break; + + cfg80211_cac_event(vif->netdev, &chandef, +- NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); ++ NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0); + break; + case QLINK_RADAR_CAC_ABORTED: + if (!vif->wdev.links[0].cac_started) + break; + + cfg80211_cac_event(vif->netdev, &chandef, +- NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); ++ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0); + break; + case QLINK_RADAR_CAC_STARTED: + if (vif->wdev.links[0].cac_started) +@@ -542,7 +542,7 @@ static int qtnf_event_handle_radar(struc + break; + + cfg80211_cac_event(vif->netdev, &chandef, +- NL80211_RADAR_CAC_STARTED, GFP_KERNEL); ++ NL80211_RADAR_CAC_STARTED, GFP_KERNEL, 0); + break; + default: + pr_warn("%s: unhandled radar event %u\n", +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -4841,9 +4841,9 @@ struct cfg80211_ops { + int (*start_radar_detection)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, +- u32 cac_time_ms); ++ u32 cac_time_ms, int link_id); + void (*end_cac)(struct wiphy *wiphy, +- struct net_device *dev); ++ struct net_device *dev, unsigned int link_id); + int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie); + int (*crit_proto_start)(struct wiphy *wiphy, +@@ -8745,6 +8745,7 @@ void cfg80211_sta_opmode_change_notify(s + * @chandef: chandef for the current channel + * @event: type of event + * @gfp: context flags ++ * @link_id: valid link_id for MLO operation or 0 otherwise. + * + * This function is called when a Channel availability check (CAC) is finished + * or aborted. This must be called to notify the completion of a CAC process, +@@ -8752,7 +8753,8 @@ void cfg80211_sta_opmode_change_notify(s + */ + void cfg80211_cac_event(struct net_device *netdev, + const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event, gfp_t gfp); ++ enum nl80211_radar_event event, gfp_t gfp, ++ unsigned int link_id); + + /** + * cfg80211_background_cac_abort - Channel Availability Check offchan abort event +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1661,7 +1661,7 @@ static int ieee80211_stop_ap(struct wiph + wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_ABORTED, +- GFP_KERNEL); ++ GFP_KERNEL, 0); + } + + drv_stop_ap(sdata->local, sdata, link_conf); +@@ -3459,7 +3459,7 @@ static int ieee80211_set_bitrate_mask(st + static int ieee80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, +- u32 cac_time_ms) ++ u32 cac_time_ms, int link_id) + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_chan_req chanreq = { .oper = *chandef }; +@@ -3487,7 +3487,7 @@ static int ieee80211_start_radar_detecti + } + + static void ieee80211_end_cac(struct wiphy *wiphy, +- struct net_device *dev) ++ struct net_device *dev, unsigned int link_id) + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -559,7 +559,7 @@ static void ieee80211_do_stop(struct iee + ieee80211_link_release_channel(&sdata->deflink); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_ABORTED, +- GFP_KERNEL); ++ GFP_KERNEL, 0); + } + + if (sdata->vif.type == NL80211_IFTYPE_AP) { +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3043,7 +3043,7 @@ void ieee80211_dfs_cac_timer_work(struct + ieee80211_link_release_channel(link); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_FINISHED, +- GFP_KERNEL); ++ GFP_KERNEL, 0); + } + } + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -3468,7 +3468,7 @@ void ieee80211_dfs_cac_cancel(struct iee + cfg80211_cac_event(sdata->dev, + &chandef, + NL80211_RADAR_CAC_ABORTED, +- GFP_KERNEL); ++ GFP_KERNEL, 0); + } + } + } +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -1111,18 +1111,19 @@ EXPORT_SYMBOL(__cfg80211_radar_event); + + void cfg80211_cac_event(struct net_device *netdev, + const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event, gfp_t gfp) ++ enum nl80211_radar_event event, gfp_t gfp, ++ unsigned int link_id) + { + struct wireless_dev *wdev = netdev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + unsigned long timeout; + +- /* not yet supported */ +- if (wdev->valid_links) ++ if (WARN_ON(wdev->valid_links && ++ !(wdev->valid_links & BIT(link_id)))) + return; + +- trace_cfg80211_cac_event(netdev, event); ++ trace_cfg80211_cac_event(netdev, event, link_id); + + if (WARN_ON(!wdev->links[0].cac_started && + event != NL80211_RADAR_CAC_STARTED)) +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -10122,7 +10122,20 @@ static int nl80211_start_radar_detection + goto unlock; + } + +- if (cfg80211_beaconing_iface_active(wdev) || wdev->links[0].cac_started) { ++ if (cfg80211_beaconing_iface_active(wdev)) { ++ /* During MLO other link(s) can beacon, only the current link ++ * can not already beacon ++ */ ++ if (wdev->valid_links && ++ !wdev->links[0].ap.beacon_interval) { ++ /* nothing */ ++ } else { ++ err = -EBUSY; ++ goto unlock; ++ } ++ } ++ ++ if (wdev->links[0].cac_started) { + err = -EBUSY; + goto unlock; + } +@@ -10142,7 +10155,8 @@ static int nl80211_start_radar_detection + if (WARN_ON(!cac_time_ms)) + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + +- err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms); ++ err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms, ++ 0); + if (!err) { + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: +@@ -16512,10 +16526,10 @@ nl80211_set_ttlm(struct sk_buff *skb, st + SELECTOR(__sel, NETDEV_UP_NOTMX, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_NO_WIPHY_MTX) \ +- SELECTOR(__sel, NETDEV_UP_NOTMX_NOMLO, \ ++ SELECTOR(__sel, NETDEV_UP_NOTMX_MLO, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_NO_WIPHY_MTX | \ +- NL80211_FLAG_MLO_UNSUPPORTED) \ ++ NL80211_FLAG_MLO_VALID_LINK_ID) \ + SELECTOR(__sel, NETDEV_UP_CLEAR, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_CLEAR_SKB) \ +@@ -17410,7 +17424,7 @@ static const struct genl_small_ops nl802 + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NO_WIPHY_MTX | +- NL80211_FLAG_MLO_UNSUPPORTED), ++ NL80211_FLAG_MLO_VALID_LINK_ID), + }, + { + .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1200,26 +1200,27 @@ static inline int + rdev_start_radar_detection(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_chan_def *chandef, +- u32 cac_time_ms) ++ u32 cac_time_ms, int link_id) + { + int ret = -EOPNOTSUPP; + + trace_rdev_start_radar_detection(&rdev->wiphy, dev, chandef, +- cac_time_ms); ++ cac_time_ms, link_id); + if (rdev->ops->start_radar_detection) + ret = rdev->ops->start_radar_detection(&rdev->wiphy, dev, +- chandef, cac_time_ms); ++ chandef, cac_time_ms, ++ link_id); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; + } + + static inline void + rdev_end_cac(struct cfg80211_registered_device *rdev, +- struct net_device *dev) ++ struct net_device *dev, unsigned int link_id) + { +- trace_rdev_end_cac(&rdev->wiphy, dev); ++ trace_rdev_end_cac(&rdev->wiphy, dev, link_id); + if (rdev->ops->end_cac) +- rdev->ops->end_cac(&rdev->wiphy, dev); ++ rdev->ops->end_cac(&rdev->wiphy, dev, link_id); + trace_rdev_return_void(&rdev->wiphy); + } + +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -4229,6 +4229,8 @@ EXPORT_SYMBOL(regulatory_pre_cac_allowed + static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev) + { + struct wireless_dev *wdev; ++ unsigned int link_id; ++ + /* If we finished CAC or received radar, we should end any + * CAC running on the same channels. + * the check !cfg80211_chandef_dfs_usable contain 2 options: +@@ -4241,16 +4243,17 @@ static void cfg80211_check_and_end_cac(s + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + struct cfg80211_chan_def *chandef; + +- if (!wdev->links[0].cac_started) +- continue; ++ for_each_valid_link(wdev, link_id) { ++ if (!wdev->links[link_id].cac_started) ++ continue; + +- /* FIXME: radar detection is tied to link 0 for now */ +- chandef = wdev_chandef(wdev, 0); +- if (!chandef) +- continue; ++ chandef = wdev_chandef(wdev, link_id); ++ if (!chandef) ++ continue; + +- if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef)) +- rdev_end_cac(rdev, wdev->netdev); ++ if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef)) ++ rdev_end_cac(rdev, wdev->netdev, link_id); ++ } + } + } + +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -806,17 +806,21 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_flus + ); + + TRACE_EVENT(rdev_end_cac, +- TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), +- TP_ARGS(wiphy, netdev), ++ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, ++ unsigned int link_id), ++ TP_ARGS(wiphy, netdev, link_id), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY ++ __field(unsigned int, link_id) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; ++ __entry->link_id = link_id; + ), +- TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) ++ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d", ++ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id) + ); + + DECLARE_EVENT_CLASS(station_add_change, +@@ -2661,24 +2665,26 @@ TRACE_EVENT(rdev_external_auth, + TRACE_EVENT(rdev_start_radar_detection, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_chan_def *chandef, +- u32 cac_time_ms), +- TP_ARGS(wiphy, netdev, chandef, cac_time_ms), ++ u32 cac_time_ms, int link_id), ++ TP_ARGS(wiphy, netdev, chandef, cac_time_ms, link_id), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + CHAN_DEF_ENTRY + __field(u32, cac_time_ms) ++ __field(int, link_id) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + CHAN_DEF_ASSIGN(chandef); + __entry->cac_time_ms = cac_time_ms; ++ __entry->link_id = link_id; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT +- ", cac_time_ms=%u", ++ ", cac_time_ms=%u, link_id=%d", + WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, +- __entry->cac_time_ms) ++ __entry->cac_time_ms, __entry->link_id) + ); + + TRACE_EVENT(rdev_set_mcast_rate, +@@ -3492,18 +3498,21 @@ TRACE_EVENT(cfg80211_radar_event, + ); + + TRACE_EVENT(cfg80211_cac_event, +- TP_PROTO(struct net_device *netdev, enum nl80211_radar_event evt), +- TP_ARGS(netdev, evt), ++ TP_PROTO(struct net_device *netdev, enum nl80211_radar_event evt, ++ unsigned int link_id), ++ TP_ARGS(netdev, evt, link_id), + TP_STRUCT__entry( + NETDEV_ENTRY + __field(enum nl80211_radar_event, evt) ++ __field(unsigned int, link_id) + ), + TP_fast_assign( + NETDEV_ASSIGN; + __entry->evt = evt; ++ __entry->link_id = link_id; + ), +- TP_printk(NETDEV_PR_FMT ", event: %d", +- NETDEV_PR_ARG, __entry->evt) ++ TP_printk(NETDEV_PR_FMT ", event: %d, link_id=%u", ++ NETDEV_PR_ARG, __entry->evt, __entry->link_id) + ); + + DECLARE_EVENT_CLASS(cfg80211_rx_evt, diff --git a/package/kernel/mac80211/patches/subsys/338-wifi-mac80211-handle-DFS-per-link.patch b/package/kernel/mac80211/patches/subsys/338-wifi-mac80211-handle-DFS-per-link.patch new file mode 100644 index 0000000000..388c0575c8 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/338-wifi-mac80211-handle-DFS-per-link.patch @@ -0,0 +1,134 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:24 +0530 +Subject: [PATCH] wifi: mac80211: handle DFS per link + +In order to support DFS with MLO, handle the link ID now passed from +cfg80211, adjust the code to do everything per link and call the +notifications to cfg80211 correctly. + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-7-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3464,6 +3464,7 @@ static int ieee80211_start_radar_detecti + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_chan_req chanreq = { .oper = *chandef }; + struct ieee80211_local *local = sdata->local; ++ struct ieee80211_link_data *link_data; + int err; + + lockdep_assert_wiphy(local->hw.wiphy); +@@ -3471,16 +3472,20 @@ static int ieee80211_start_radar_detecti + if (!list_empty(&local->roc_list) || local->scanning) + return -EBUSY; + ++ link_data = sdata_dereference(sdata->link[link_id], sdata); ++ if (!link_data) ++ return -ENOLINK; ++ + /* whatever, but channel contexts should not complain about that one */ +- sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; +- sdata->deflink.needed_rx_chains = local->rx_chains; ++ link_data->smps_mode = IEEE80211_SMPS_OFF; ++ link_data->needed_rx_chains = local->rx_chains; + +- err = ieee80211_link_use_channel(&sdata->deflink, &chanreq, ++ err = ieee80211_link_use_channel(link_data, &chanreq, + IEEE80211_CHANCTX_SHARED); + if (err) + return err; + +- wiphy_delayed_work_queue(wiphy, &sdata->deflink.dfs_cac_timer_work, ++ wiphy_delayed_work_queue(wiphy, &link_data->dfs_cac_timer_work, + msecs_to_jiffies(cac_time_ms)); + + return 0; +@@ -3491,16 +3496,21 @@ static void ieee80211_end_cac(struct wip + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; ++ struct ieee80211_link_data *link_data; + + lockdep_assert_wiphy(local->hw.wiphy); + + list_for_each_entry(sdata, &local->interfaces, list) { ++ link_data = sdata_dereference(sdata->link[link_id], sdata); ++ if (!link_data) ++ continue; ++ + wiphy_delayed_work_cancel(wiphy, +- &sdata->deflink.dfs_cac_timer_work); ++ &link_data->dfs_cac_timer_work); + +- if (sdata->wdev.links[0].cac_started) { +- ieee80211_link_release_channel(&sdata->deflink); +- sdata->wdev.links[0].cac_started = false; ++ if (sdata->wdev.links[link_id].cac_started) { ++ ieee80211_link_release_channel(link_data); ++ sdata->wdev.links[link_id].cac_started = false; + } + } + } +--- a/net/mac80211/link.c ++++ b/net/mac80211/link.c +@@ -77,6 +77,16 @@ void ieee80211_link_stop(struct ieee8021 + &link->color_change_finalize_work); + wiphy_work_cancel(link->sdata->local->hw.wiphy, + &link->csa.finalize_work); ++ ++ if (link->sdata->wdev.links[link->link_id].cac_started) { ++ wiphy_delayed_work_cancel(link->sdata->local->hw.wiphy, ++ &link->dfs_cac_timer_work); ++ cfg80211_cac_event(link->sdata->dev, ++ &link->conf->chanreq.oper, ++ NL80211_RADAR_CAC_ABORTED, ++ GFP_KERNEL, link->link_id); ++ } ++ + ieee80211_link_release_channel(link); + } + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -3455,20 +3455,30 @@ void ieee80211_dfs_cac_cancel(struct iee + { + struct ieee80211_sub_if_data *sdata; + struct cfg80211_chan_def chandef; ++ struct ieee80211_link_data *link; ++ unsigned int link_id; + + lockdep_assert_wiphy(local->hw.wiphy); + + list_for_each_entry(sdata, &local->interfaces, list) { +- wiphy_delayed_work_cancel(local->hw.wiphy, +- &sdata->deflink.dfs_cac_timer_work); ++ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; ++ link_id++) { ++ link = sdata_dereference(sdata->link[link_id], ++ sdata); ++ if (!link) ++ continue; + +- if (sdata->wdev.links[0].cac_started) { +- chandef = sdata->vif.bss_conf.chanreq.oper; +- ieee80211_link_release_channel(&sdata->deflink); +- cfg80211_cac_event(sdata->dev, +- &chandef, ++ wiphy_delayed_work_cancel(local->hw.wiphy, ++ &link->dfs_cac_timer_work); ++ ++ if (!sdata->wdev.links[link_id].cac_started) ++ continue; ++ ++ chandef = link->conf->chanreq.oper; ++ ieee80211_link_release_channel(link); ++ cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_ABORTED, +- GFP_KERNEL, 0); ++ GFP_KERNEL, link_id); + } + } + } diff --git a/package/kernel/mac80211/patches/subsys/339-wifi-cfg80211-mac80211-use-proper-link-ID-for-DFS.patch b/package/kernel/mac80211/patches/subsys/339-wifi-cfg80211-mac80211-use-proper-link-ID-for-DFS.patch new file mode 100644 index 0000000000..53079b6cf6 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/339-wifi-cfg80211-mac80211-use-proper-link-ID-for-DFS.patch @@ -0,0 +1,168 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:25 +0530 +Subject: [PATCH] wifi: cfg80211/mac80211: use proper link ID for DFS + +Now that all APIs have support to handle DFS per link, use proper link ID +instead of 0. + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-8-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1656,12 +1656,12 @@ static int ieee80211_stop_ap(struct wiph + ieee80211_link_info_change_notify(sdata, link, + BSS_CHANGED_BEACON_ENABLED); + +- if (sdata->wdev.links[0].cac_started) { ++ if (sdata->wdev.links[link_id].cac_started) { + chandef = link_conf->chanreq.oper; + wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_ABORTED, +- GFP_KERNEL, 0); ++ GFP_KERNEL, link_id); + } + + drv_stop_ap(sdata->local, sdata, link_conf); +@@ -3965,7 +3965,7 @@ __ieee80211_channel_switch(struct wiphy + if (!list_empty(&local->roc_list) || local->scanning) + return -EBUSY; + +- if (sdata->wdev.links[0].cac_started) ++ if (sdata->wdev.links[link_id].cac_started) + return -EBUSY; + + if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS)) +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3039,11 +3039,11 @@ void ieee80211_dfs_cac_timer_work(struct + + lockdep_assert_wiphy(sdata->local->hw.wiphy); + +- if (sdata->wdev.links[0].cac_started) { ++ if (sdata->wdev.links[link->link_id].cac_started) { + ieee80211_link_release_channel(link); + cfg80211_cac_event(sdata->dev, &chandef, + NL80211_RADAR_CAC_FINISHED, +- GFP_KERNEL, 0); ++ GFP_KERNEL, link->link_id); + } + } + +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -575,6 +575,7 @@ static bool __ieee80211_can_leave_ch(str + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *sdata_iter; ++ unsigned int link_id; + + lockdep_assert_wiphy(local->hw.wiphy); + +@@ -585,8 +586,9 @@ static bool __ieee80211_can_leave_ch(str + return false; + + list_for_each_entry(sdata_iter, &local->interfaces, list) { +- if (sdata_iter->wdev.links[0].cac_started) +- return false; ++ for_each_valid_link(&sdata_iter->wdev, link_id) ++ if (sdata_iter->wdev.links[link_id].cac_started) ++ return false; + } + + return true; +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -1125,14 +1125,14 @@ void cfg80211_cac_event(struct net_devic + + trace_cfg80211_cac_event(netdev, event, link_id); + +- if (WARN_ON(!wdev->links[0].cac_started && ++ if (WARN_ON(!wdev->links[link_id].cac_started && + event != NL80211_RADAR_CAC_STARTED)) + return; + + switch (event) { + case NL80211_RADAR_CAC_FINISHED: +- timeout = wdev->links[0].cac_start_time + +- msecs_to_jiffies(wdev->links[0].cac_time_ms); ++ timeout = wdev->links[link_id].cac_start_time + ++ msecs_to_jiffies(wdev->links[link_id].cac_time_ms); + WARN_ON(!time_after_eq(jiffies, timeout)); + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); + memcpy(&rdev->cac_done_chandef, chandef, +@@ -1141,10 +1141,10 @@ void cfg80211_cac_event(struct net_devic + cfg80211_sched_dfs_chan_update(rdev); + fallthrough; + case NL80211_RADAR_CAC_ABORTED: +- wdev->links[0].cac_started = false; ++ wdev->links[link_id].cac_started = false; + break; + case NL80211_RADAR_CAC_STARTED: +- wdev->links[0].cac_started = true; ++ wdev->links[link_id].cac_started = true; + break; + default: + WARN_ON(1); +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -6066,7 +6066,7 @@ static int nl80211_start_ap(struct sk_bu + if (!rdev->ops->start_ap) + return -EOPNOTSUPP; + +- if (wdev->links[0].cac_started) ++ if (wdev->links[link_id].cac_started) + return -EBUSY; + + if (wdev->links[link_id].ap.beacon_interval) +@@ -10073,6 +10073,7 @@ static int nl80211_start_radar_detection + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; ++ int link_id = nl80211_link_id(info->attrs); + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_chan_def chandef; + enum nl80211_dfs_regions dfs_region; +@@ -10127,7 +10128,7 @@ static int nl80211_start_radar_detection + * can not already beacon + */ + if (wdev->valid_links && +- !wdev->links[0].ap.beacon_interval) { ++ !wdev->links[link_id].ap.beacon_interval) { + /* nothing */ + } else { + err = -EBUSY; +@@ -10135,7 +10136,7 @@ static int nl80211_start_radar_detection + } + } + +- if (wdev->links[0].cac_started) { ++ if (wdev->links[link_id].cac_started) { + err = -EBUSY; + goto unlock; + } +@@ -10156,7 +10157,7 @@ static int nl80211_start_radar_detection + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + + err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms, +- 0); ++ link_id); + if (!err) { + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: +@@ -10172,9 +10173,9 @@ static int nl80211_start_radar_detection + default: + break; + } +- wdev->links[0].cac_started = true; +- wdev->links[0].cac_start_time = jiffies; +- wdev->links[0].cac_time_ms = cac_time_ms; ++ wdev->links[link_id].cac_started = true; ++ wdev->links[link_id].cac_start_time = jiffies; ++ wdev->links[link_id].cac_time_ms = cac_time_ms; + } + unlock: + wiphy_unlock(wiphy); diff --git a/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-handle-ieee80211_radar_detected-for-ML.patch b/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-handle-ieee80211_radar_detected-for-ML.patch new file mode 100644 index 0000000000..3f64864bd4 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-handle-ieee80211_radar_detected-for-ML.patch @@ -0,0 +1,360 @@ +From: Aditya Kumar Singh +Date: Fri, 6 Sep 2024 12:14:26 +0530 +Subject: [PATCH] wifi: mac80211: handle ieee80211_radar_detected() for MLO + +Currently DFS works under assumption there could be only one channel +context in the hardware. Hence, drivers just calls the function +ieee80211_radar_detected() passing the hardware structure. However, with +MLO, this obviously will not work since number of channel contexts will be +more than one and hence drivers would need to pass the channel information +as well on which the radar is detected. + +Also, when radar is detected in one of the links, other link's CAC should +not be cancelled. + +Hence, in order to support DFS with MLO, do the following changes - + * Add channel context conf pointer as an argument to the function + ieee80211_radar_detected(). During MLO, drivers would have to pass on + which channel context conf radar is detected. Otherwise, drivers could + just pass NULL. + * ieee80211_radar_detected() will iterate over all channel contexts + present and + * if channel context conf is passed, only mark that as radar + detected + * if NULL is passed, then mark all channel contexts as radar + detected + * Then as usual, schedule the radar detected work. + * In the worker, go over all the contexts again and for all such context + which is marked with radar detected, cancel the ongoing CAC by calling + ieee80211_dfs_cac_cancel() and then notify cfg80211 via + cfg80211_radar_event(). + * To cancel the CAC, pass the channel context as well where radar is + detected to ieee80211_dfs_cac_cancel(). This ensures that CAC is + canceled only on the links using the provided context, leaving other + links unaffected. + +This would also help in scenarios where there is split phy 5 GHz radio, +which is capable of DFS channels in both lower and upper band. In this +case, simultaneous radars can be detected. + +Signed-off-by: Aditya Kumar Singh +Link: https://patch.msgid.link/20240906064426.2101315-9-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg +--- + +--- a/drivers/net/wireless/ath/ath10k/debug.c ++++ b/drivers/net/wireless/ath/ath10k/debug.c +@@ -3,7 +3,7 @@ + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -1774,7 +1774,7 @@ static ssize_t ath10k_write_simulate_rad + if (!arvif->is_started) + return -EINVAL; + +- ieee80211_radar_detected(ar->hw); ++ ieee80211_radar_detected(ar->hw, NULL); + + return count; + } +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -1437,7 +1437,7 @@ static void ath10k_recalc_radar_detectio + * by indicating that radar was detected. + */ + ath10k_warn(ar, "failed to start CAC: %d\n", ret); +- ieee80211_radar_detected(ar->hw); ++ ieee80211_radar_detected(ar->hw, NULL); + } + } + +--- a/drivers/net/wireless/ath/ath10k/wmi.c ++++ b/drivers/net/wireless/ath/ath10k/wmi.c +@@ -3990,7 +3990,7 @@ static void ath10k_radar_detected(struct + if (ar->dfs_block_radar_events) + ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); + else +- ieee80211_radar_detected(ar->hw); ++ ieee80211_radar_detected(ar->hw, NULL); + } + + static void ath10k_radar_confirmation_work(struct work_struct *work) +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -8358,7 +8358,7 @@ ath11k_wmi_pdev_dfs_radar_detected_event + if (ar->dfs_block_radar_events) + ath11k_info(ab, "DFS Radar detected, but ignored as requested\n"); + else +- ieee80211_radar_detected(ar->hw); ++ ieee80211_radar_detected(ar->hw, NULL); + + exit: + rcu_read_unlock(); +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -6789,7 +6789,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event + if (ar->dfs_block_radar_events) + ath12k_info(ab, "DFS Radar detected, but ignored as requested\n"); + else +- ieee80211_radar_detected(ath12k_ar_to_hw(ar)); ++ ieee80211_radar_detected(ath12k_ar_to_hw(ar), NULL); + + exit: + rcu_read_unlock(); +--- a/drivers/net/wireless/ath/ath9k/dfs.c ++++ b/drivers/net/wireless/ath/ath9k/dfs.c +@@ -280,7 +280,7 @@ ath9k_dfs_process_radar_pulse(struct ath + if (!pd->add_pulse(pd, pe, NULL)) + return; + DFS_STAT_INC(sc, radar_detected); +- ieee80211_radar_detected(sc->hw); ++ ieee80211_radar_detected(sc->hw, NULL); + } + + /* +--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c ++++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c +@@ -116,7 +116,7 @@ static ssize_t write_file_simulate_radar + { + struct ath_softc *sc = file->private_data; + +- ieee80211_radar_detected(sc->hw); ++ ieee80211_radar_detected(sc->hw, NULL); + + return count; + } +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +@@ -394,7 +394,7 @@ mt7615_mcu_rx_radar_detected(struct mt76 + if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC) + return; + +- ieee80211_radar_detected(mphy->hw); ++ ieee80211_radar_detected(mphy->hw, NULL); + dev->hw_pattern++; + } + +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c +@@ -630,7 +630,7 @@ static void mt76x02_dfs_tasklet(struct t + radar_detected = mt76x02_dfs_check_detection(dev); + if (radar_detected) { + /* sw detector rx radar pattern */ +- ieee80211_radar_detected(dev->mt76.hw); ++ ieee80211_radar_detected(dev->mt76.hw, NULL); + mt76x02_dfs_detector_reset(dev); + + return; +@@ -658,7 +658,7 @@ static void mt76x02_dfs_tasklet(struct t + + /* hw detector rx radar pattern */ + dfs_pd->stats[i].hw_pattern++; +- ieee80211_radar_detected(dev->mt76.hw); ++ ieee80211_radar_detected(dev->mt76.hw, NULL); + mt76x02_dfs_detector_reset(dev); + + return; +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -293,7 +293,7 @@ mt7915_mcu_rx_radar_detected(struct mt79 + &dev->rdd2_chandef, + GFP_ATOMIC); + else +- ieee80211_radar_detected(mphy->hw); ++ ieee80211_radar_detected(mphy->hw, NULL); + dev->hw_pattern++; + } + +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -371,7 +371,7 @@ mt7996_mcu_rx_radar_detected(struct mt79 + &dev->rdd2_chandef, + GFP_ATOMIC); + else +- ieee80211_radar_detected(mphy->hw); ++ ieee80211_radar_detected(mphy->hw, NULL); + dev->hw_pattern++; + } + +--- a/drivers/net/wireless/ti/wl18xx/event.c ++++ b/drivers/net/wireless/ti/wl18xx/event.c +@@ -142,7 +142,7 @@ int wl18xx_process_mailbox_events(struct + wl18xx_radar_type_decode(mbox->radar_type)); + + if (!wl->radar_debug_mode) +- ieee80211_radar_detected(wl->hw); ++ ieee80211_radar_detected(wl->hw, NULL); + } + + if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { +--- a/drivers/net/wireless/virtual/mac80211_hwsim.c ++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c +@@ -1146,7 +1146,7 @@ static int hwsim_write_simulate_radar(vo + { + struct mac80211_hwsim_data *data = dat; + +- ieee80211_radar_detected(data->hw); ++ ieee80211_radar_detected(data->hw, NULL); + + return 0; + } +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6717,8 +6717,11 @@ void ieee80211_cqm_beacon_loss_notify(st + * ieee80211_radar_detected - inform that a radar was detected + * + * @hw: pointer as obtained from ieee80211_alloc_hw() ++ * @chanctx_conf: Channel context on which radar is detected. Mandatory to ++ * pass a valid pointer during MLO. For non-MLO %NULL can be passed + */ +-void ieee80211_radar_detected(struct ieee80211_hw *hw); ++void ieee80211_radar_detected(struct ieee80211_hw *hw, ++ struct ieee80211_chanctx_conf *chanctx_conf); + + /** + * ieee80211_chswitch_done - Complete channel switch process +--- a/net/mac80211/chan.c ++++ b/net/mac80211/chan.c +@@ -681,6 +681,7 @@ ieee80211_alloc_chanctx(struct ieee80211 + ctx->mode = mode; + ctx->conf.radar_enabled = false; + ctx->conf.radio_idx = radio_idx; ++ ctx->radar_detected = false; + _ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false); + + return ctx; +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -895,6 +895,8 @@ struct ieee80211_chanctx { + struct ieee80211_chan_req req; + + struct ieee80211_chanctx_conf conf; ++ ++ bool radar_detected; + }; + + struct mac80211_qos_map { +@@ -2632,7 +2634,8 @@ void ieee80211_recalc_chanctx_min_def(st + bool ieee80211_is_radar_required(struct ieee80211_local *local); + + void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work); +-void ieee80211_dfs_cac_cancel(struct ieee80211_local *local); ++void ieee80211_dfs_cac_cancel(struct ieee80211_local *local, ++ struct ieee80211_chanctx *chanctx); + void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy, + struct wiphy_work *work); + int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/pm.c ++++ b/net/mac80211/pm.c +@@ -32,7 +32,7 @@ int __ieee80211_suspend(struct ieee80211 + + ieee80211_scan_cancel(local); + +- ieee80211_dfs_cac_cancel(local); ++ ieee80211_dfs_cac_cancel(local, NULL); + + ieee80211_roc_purge(local, NULL); + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -3451,11 +3451,16 @@ u64 ieee80211_calculate_rx_timestamp(str + return ts; + } + +-void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) ++/* Cancel CAC for the interfaces under the specified @local. If @ctx is ++ * also provided, only the interfaces using that ctx will be canceled. ++ */ ++void ieee80211_dfs_cac_cancel(struct ieee80211_local *local, ++ struct ieee80211_chanctx *ctx) + { + struct ieee80211_sub_if_data *sdata; + struct cfg80211_chan_def chandef; + struct ieee80211_link_data *link; ++ struct ieee80211_chanctx_conf *chanctx_conf; + unsigned int link_id; + + lockdep_assert_wiphy(local->hw.wiphy); +@@ -3468,6 +3473,11 @@ void ieee80211_dfs_cac_cancel(struct iee + if (!link) + continue; + ++ chanctx_conf = sdata_dereference(link->conf->chanctx_conf, ++ sdata); ++ if (ctx && &ctx->conf != chanctx_conf) ++ continue; ++ + wiphy_delayed_work_cancel(local->hw.wiphy, + &link->dfs_cac_timer_work); + +@@ -3488,9 +3498,8 @@ void ieee80211_dfs_radar_detected_work(s + { + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, radar_detected_work); +- struct cfg80211_chan_def chandef = local->hw.conf.chandef; ++ struct cfg80211_chan_def chandef; + struct ieee80211_chanctx *ctx; +- int num_chanctx = 0; + + lockdep_assert_wiphy(local->hw.wiphy); + +@@ -3498,25 +3507,46 @@ void ieee80211_dfs_radar_detected_work(s + if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) + continue; + +- num_chanctx++; ++ if (!ctx->radar_detected) ++ continue; ++ ++ ctx->radar_detected = false; ++ + chandef = ctx->conf.def; ++ ++ ieee80211_dfs_cac_cancel(local, ctx); ++ cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); + } ++} + +- ieee80211_dfs_cac_cancel(local); ++static void ++ieee80211_radar_mark_chan_ctx_iterator(struct ieee80211_hw *hw, ++ struct ieee80211_chanctx_conf *chanctx_conf, ++ void *data) ++{ ++ struct ieee80211_chanctx *ctx = ++ container_of(chanctx_conf, struct ieee80211_chanctx, ++ conf); + +- if (num_chanctx > 1) +- /* XXX: multi-channel is not supported yet */ +- WARN_ON(1); +- else +- cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); ++ if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) ++ return; ++ ++ if (data && data != chanctx_conf) ++ return; ++ ++ ctx->radar_detected = true; + } + +-void ieee80211_radar_detected(struct ieee80211_hw *hw) ++void ieee80211_radar_detected(struct ieee80211_hw *hw, ++ struct ieee80211_chanctx_conf *chanctx_conf) + { + struct ieee80211_local *local = hw_to_local(hw); + + trace_api_radar_detected(local); + ++ ieee80211_iter_chan_contexts_atomic(hw, ieee80211_radar_mark_chan_ctx_iterator, ++ chanctx_conf); ++ + wiphy_work_queue(hw->wiphy, &local->radar_detected_work); + } + EXPORT_SYMBOL(ieee80211_radar_detected); diff --git a/package/kernel/mt76/patches/100-api_update.patch b/package/kernel/mt76/patches/100-api_update.patch index 8b528f05f7..4cd19f65b2 100644 --- a/package/kernel/mt76/patches/100-api_update.patch +++ b/package/kernel/mt76/patches/100-api_update.patch @@ -9,3 +9,56 @@ head = &wcid->tx_offchannel; else head = &wcid->tx_pending; +--- a/mt7615/mcu.c ++++ b/mt7615/mcu.c +@@ -394,7 +394,7 @@ mt7615_mcu_rx_radar_detected(struct mt76 + if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC) + return; + +- ieee80211_radar_detected(mphy->hw); ++ ieee80211_radar_detected(mphy->hw, NULL); + dev->hw_pattern++; + } + +--- a/mt76x02_dfs.c ++++ b/mt76x02_dfs.c +@@ -630,7 +630,7 @@ static void mt76x02_dfs_tasklet(struct t + radar_detected = mt76x02_dfs_check_detection(dev); + if (radar_detected) { + /* sw detector rx radar pattern */ +- ieee80211_radar_detected(dev->mt76.hw); ++ ieee80211_radar_detected(dev->mt76.hw, NULL); + mt76x02_dfs_detector_reset(dev); + + return; +@@ -658,7 +658,7 @@ static void mt76x02_dfs_tasklet(struct t + + /* hw detector rx radar pattern */ + dfs_pd->stats[i].hw_pattern++; +- ieee80211_radar_detected(dev->mt76.hw); ++ ieee80211_radar_detected(dev->mt76.hw, NULL); + mt76x02_dfs_detector_reset(dev); + + return; +--- a/mt7915/mcu.c ++++ b/mt7915/mcu.c +@@ -297,7 +297,7 @@ mt7915_mcu_rx_radar_detected(struct mt79 + &dev->rdd2_chandef, + GFP_ATOMIC); + else +- ieee80211_radar_detected(mphy->hw); ++ ieee80211_radar_detected(mphy->hw, NULL); + dev->hw_pattern++; + } + +--- a/mt7996/mcu.c ++++ b/mt7996/mcu.c +@@ -383,7 +383,7 @@ mt7996_mcu_rx_radar_detected(struct mt79 + &dev->rdd2_chandef, + GFP_ATOMIC); + else +- ieee80211_radar_detected(mphy->hw); ++ ieee80211_radar_detected(mphy->hw, NULL); + dev->hw_pattern++; + } + diff --git a/package/kernel/mwlwifi/patches/005-mac80211_update.patch b/package/kernel/mwlwifi/patches/005-mac80211_update.patch index 54dc4db783..2ceee4732d 100644 --- a/package/kernel/mwlwifi/patches/005-mac80211_update.patch +++ b/package/kernel/mwlwifi/patches/005-mac80211_update.patch @@ -68,6 +68,15 @@ sta->tdls, sta->tdls_initiator, sta->wme, +@@ -1158,7 +1158,7 @@ static ssize_t mwl_debugfs_dfs_radar_wri + struct mwl_priv *priv = (struct mwl_priv *)file->private_data; + + wiphy_info(priv->hw->wiphy, "simulate radar detected\n"); +- ieee80211_radar_detected(priv->hw); ++ ieee80211_radar_detected(priv->hw, NULL); + + return count; + } --- a/hif/fwcmd.c +++ b/hif/fwcmd.c @@ -633,11 +633,15 @@ einval: @@ -491,3 +500,32 @@ switch (format) { case TX_RATE_FORMAT_LEGACY: +--- a/hif/pcie/pcie.c ++++ b/hif/pcie/pcie.c +@@ -546,7 +546,7 @@ static irqreturn_t pcie_isr_8864(struct + + if (int_status & MACREG_A2HRIC_BIT_RADAR_DETECT) { + wiphy_info(hw->wiphy, "radar detected by firmware\n"); +- ieee80211_radar_detected(hw); ++ ieee80211_radar_detected(hw, NULL); + } + + if (int_status & MACREG_A2HRIC_BIT_CHAN_SWITCH) ieee80211_queue_work(hw, &priv->chnl_switch_handle); +@@ -593,7 +593,7 @@ static irqreturn_t pcie_isr_8997(struct + + if (int_status & MACREG_A2HRIC_BIT_RADAR_DETECT) { + wiphy_info(hw->wiphy, "radar detected by firmware\n"); +- ieee80211_radar_detected(hw); ++ ieee80211_radar_detected(hw, NULL); + } + + if (int_status & MACREG_A2HRIC_BIT_CHAN_SWITCH) +@@ -1071,7 +1071,7 @@ static irqreturn_t pcie_isr_ndp(struct i + + if (int_status & MACREG_A2HRIC_NEWDP_DFS) { + wiphy_info(hw->wiphy, "radar detected by firmware\n"); +- ieee80211_radar_detected(hw); ++ ieee80211_radar_detected(hw, NULL); + } + + if (int_status & MACREG_A2HRIC_NEWDP_CHANNEL_SWITCH)