1 From: Aditya Kumar Singh <quic_adisi@quicinc.com>
2 Date: Fri, 6 Sep 2024 12:14:26 +0530
3 Subject: [PATCH] wifi: mac80211: handle ieee80211_radar_detected() for MLO
5 Currently DFS works under assumption there could be only one channel
6 context in the hardware. Hence, drivers just calls the function
7 ieee80211_radar_detected() passing the hardware structure. However, with
8 MLO, this obviously will not work since number of channel contexts will be
9 more than one and hence drivers would need to pass the channel information
10 as well on which the radar is detected.
12 Also, when radar is detected in one of the links, other link's CAC should
15 Hence, in order to support DFS with MLO, do the following changes -
16 * Add channel context conf pointer as an argument to the function
17 ieee80211_radar_detected(). During MLO, drivers would have to pass on
18 which channel context conf radar is detected. Otherwise, drivers could
20 * ieee80211_radar_detected() will iterate over all channel contexts
22 * if channel context conf is passed, only mark that as radar
24 * if NULL is passed, then mark all channel contexts as radar
26 * Then as usual, schedule the radar detected work.
27 * In the worker, go over all the contexts again and for all such context
28 which is marked with radar detected, cancel the ongoing CAC by calling
29 ieee80211_dfs_cac_cancel() and then notify cfg80211 via
30 cfg80211_radar_event().
31 * To cancel the CAC, pass the channel context as well where radar is
32 detected to ieee80211_dfs_cac_cancel(). This ensures that CAC is
33 canceled only on the links using the provided context, leaving other
36 This would also help in scenarios where there is split phy 5 GHz radio,
37 which is capable of DFS channels in both lower and upper band. In this
38 case, simultaneous radars can be detected.
40 Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
41 Link: https://patch.msgid.link/20240906064426.2101315-9-quic_adisi@quicinc.com
42 Signed-off-by: Johannes Berg <johannes.berg@intel.com>
45 --- a/drivers/net/wireless/ath/ath10k/debug.c
46 +++ b/drivers/net/wireless/ath/ath10k/debug.c
48 * Copyright (c) 2005-2011 Atheros Communications Inc.
49 * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
50 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
51 - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
52 + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
55 #include <linux/module.h>
56 @@ -1774,7 +1774,7 @@ static ssize_t ath10k_write_simulate_rad
57 if (!arvif->is_started)
60 - ieee80211_radar_detected(ar->hw);
61 + ieee80211_radar_detected(ar->hw, NULL);
65 --- a/drivers/net/wireless/ath/ath10k/mac.c
66 +++ b/drivers/net/wireless/ath/ath10k/mac.c
67 @@ -1437,7 +1437,7 @@ static void ath10k_recalc_radar_detectio
68 * by indicating that radar was detected.
70 ath10k_warn(ar, "failed to start CAC: %d\n", ret);
71 - ieee80211_radar_detected(ar->hw);
72 + ieee80211_radar_detected(ar->hw, NULL);
76 --- a/drivers/net/wireless/ath/ath10k/wmi.c
77 +++ b/drivers/net/wireless/ath/ath10k/wmi.c
78 @@ -3990,7 +3990,7 @@ static void ath10k_radar_detected(struct
79 if (ar->dfs_block_radar_events)
80 ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
82 - ieee80211_radar_detected(ar->hw);
83 + ieee80211_radar_detected(ar->hw, NULL);
86 static void ath10k_radar_confirmation_work(struct work_struct *work)
87 --- a/drivers/net/wireless/ath/ath11k/wmi.c
88 +++ b/drivers/net/wireless/ath/ath11k/wmi.c
89 @@ -8358,7 +8358,7 @@ ath11k_wmi_pdev_dfs_radar_detected_event
90 if (ar->dfs_block_radar_events)
91 ath11k_info(ab, "DFS Radar detected, but ignored as requested\n");
93 - ieee80211_radar_detected(ar->hw);
94 + ieee80211_radar_detected(ar->hw, NULL);
98 --- a/drivers/net/wireless/ath/ath12k/wmi.c
99 +++ b/drivers/net/wireless/ath/ath12k/wmi.c
100 @@ -6789,7 +6789,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event
101 if (ar->dfs_block_radar_events)
102 ath12k_info(ab, "DFS Radar detected, but ignored as requested\n");
104 - ieee80211_radar_detected(ath12k_ar_to_hw(ar));
105 + ieee80211_radar_detected(ath12k_ar_to_hw(ar), NULL);
109 --- a/drivers/net/wireless/ath/ath9k/dfs.c
110 +++ b/drivers/net/wireless/ath/ath9k/dfs.c
111 @@ -280,7 +280,7 @@ ath9k_dfs_process_radar_pulse(struct ath
112 if (!pd->add_pulse(pd, pe, NULL))
114 DFS_STAT_INC(sc, radar_detected);
115 - ieee80211_radar_detected(sc->hw);
116 + ieee80211_radar_detected(sc->hw, NULL);
120 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
121 +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
122 @@ -116,7 +116,7 @@ static ssize_t write_file_simulate_radar
124 struct ath_softc *sc = file->private_data;
126 - ieee80211_radar_detected(sc->hw);
127 + ieee80211_radar_detected(sc->hw, NULL);
131 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
132 +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
133 @@ -394,7 +394,7 @@ mt7615_mcu_rx_radar_detected(struct mt76
134 if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC)
137 - ieee80211_radar_detected(mphy->hw);
138 + ieee80211_radar_detected(mphy->hw, NULL);
142 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
143 +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
144 @@ -630,7 +630,7 @@ static void mt76x02_dfs_tasklet(struct t
145 radar_detected = mt76x02_dfs_check_detection(dev);
146 if (radar_detected) {
147 /* sw detector rx radar pattern */
148 - ieee80211_radar_detected(dev->mt76.hw);
149 + ieee80211_radar_detected(dev->mt76.hw, NULL);
150 mt76x02_dfs_detector_reset(dev);
153 @@ -658,7 +658,7 @@ static void mt76x02_dfs_tasklet(struct t
155 /* hw detector rx radar pattern */
156 dfs_pd->stats[i].hw_pattern++;
157 - ieee80211_radar_detected(dev->mt76.hw);
158 + ieee80211_radar_detected(dev->mt76.hw, NULL);
159 mt76x02_dfs_detector_reset(dev);
162 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
163 +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
164 @@ -293,7 +293,7 @@ mt7915_mcu_rx_radar_detected(struct mt79
168 - ieee80211_radar_detected(mphy->hw);
169 + ieee80211_radar_detected(mphy->hw, NULL);
173 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
174 +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
175 @@ -371,7 +371,7 @@ mt7996_mcu_rx_radar_detected(struct mt79
179 - ieee80211_radar_detected(mphy->hw);
180 + ieee80211_radar_detected(mphy->hw, NULL);
184 --- a/drivers/net/wireless/ti/wl18xx/event.c
185 +++ b/drivers/net/wireless/ti/wl18xx/event.c
186 @@ -142,7 +142,7 @@ int wl18xx_process_mailbox_events(struct
187 wl18xx_radar_type_decode(mbox->radar_type));
189 if (!wl->radar_debug_mode)
190 - ieee80211_radar_detected(wl->hw);
191 + ieee80211_radar_detected(wl->hw, NULL);
194 if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
195 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c
196 +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
197 @@ -1146,7 +1146,7 @@ static int hwsim_write_simulate_radar(vo
199 struct mac80211_hwsim_data *data = dat;
201 - ieee80211_radar_detected(data->hw);
202 + ieee80211_radar_detected(data->hw, NULL);
206 --- a/include/net/mac80211.h
207 +++ b/include/net/mac80211.h
208 @@ -6717,8 +6717,11 @@ void ieee80211_cqm_beacon_loss_notify(st
209 * ieee80211_radar_detected - inform that a radar was detected
211 * @hw: pointer as obtained from ieee80211_alloc_hw()
212 + * @chanctx_conf: Channel context on which radar is detected. Mandatory to
213 + * pass a valid pointer during MLO. For non-MLO %NULL can be passed
215 -void ieee80211_radar_detected(struct ieee80211_hw *hw);
216 +void ieee80211_radar_detected(struct ieee80211_hw *hw,
217 + struct ieee80211_chanctx_conf *chanctx_conf);
220 * ieee80211_chswitch_done - Complete channel switch process
221 --- a/net/mac80211/chan.c
222 +++ b/net/mac80211/chan.c
223 @@ -681,6 +681,7 @@ ieee80211_alloc_chanctx(struct ieee80211
225 ctx->conf.radar_enabled = false;
226 ctx->conf.radio_idx = radio_idx;
227 + ctx->radar_detected = false;
228 _ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
231 --- a/net/mac80211/ieee80211_i.h
232 +++ b/net/mac80211/ieee80211_i.h
233 @@ -895,6 +895,8 @@ struct ieee80211_chanctx {
234 struct ieee80211_chan_req req;
236 struct ieee80211_chanctx_conf conf;
238 + bool radar_detected;
241 struct mac80211_qos_map {
242 @@ -2632,7 +2634,8 @@ void ieee80211_recalc_chanctx_min_def(st
243 bool ieee80211_is_radar_required(struct ieee80211_local *local);
245 void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work);
246 -void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
247 +void ieee80211_dfs_cac_cancel(struct ieee80211_local *local,
248 + struct ieee80211_chanctx *chanctx);
249 void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
250 struct wiphy_work *work);
251 int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
252 --- a/net/mac80211/pm.c
253 +++ b/net/mac80211/pm.c
254 @@ -32,7 +32,7 @@ int __ieee80211_suspend(struct ieee80211
256 ieee80211_scan_cancel(local);
258 - ieee80211_dfs_cac_cancel(local);
259 + ieee80211_dfs_cac_cancel(local, NULL);
261 ieee80211_roc_purge(local, NULL);
263 --- a/net/mac80211/util.c
264 +++ b/net/mac80211/util.c
265 @@ -3451,11 +3451,16 @@ u64 ieee80211_calculate_rx_timestamp(str
269 -void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
270 +/* Cancel CAC for the interfaces under the specified @local. If @ctx is
271 + * also provided, only the interfaces using that ctx will be canceled.
273 +void ieee80211_dfs_cac_cancel(struct ieee80211_local *local,
274 + struct ieee80211_chanctx *ctx)
276 struct ieee80211_sub_if_data *sdata;
277 struct cfg80211_chan_def chandef;
278 struct ieee80211_link_data *link;
279 + struct ieee80211_chanctx_conf *chanctx_conf;
280 unsigned int link_id;
282 lockdep_assert_wiphy(local->hw.wiphy);
283 @@ -3468,6 +3473,11 @@ void ieee80211_dfs_cac_cancel(struct iee
287 + chanctx_conf = sdata_dereference(link->conf->chanctx_conf,
289 + if (ctx && &ctx->conf != chanctx_conf)
292 wiphy_delayed_work_cancel(local->hw.wiphy,
293 &link->dfs_cac_timer_work);
295 @@ -3488,9 +3498,8 @@ void ieee80211_dfs_radar_detected_work(s
297 struct ieee80211_local *local =
298 container_of(work, struct ieee80211_local, radar_detected_work);
299 - struct cfg80211_chan_def chandef = local->hw.conf.chandef;
300 + struct cfg80211_chan_def chandef;
301 struct ieee80211_chanctx *ctx;
302 - int num_chanctx = 0;
304 lockdep_assert_wiphy(local->hw.wiphy);
306 @@ -3498,25 +3507,46 @@ void ieee80211_dfs_radar_detected_work(s
307 if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
311 + if (!ctx->radar_detected)
314 + ctx->radar_detected = false;
316 chandef = ctx->conf.def;
318 + ieee80211_dfs_cac_cancel(local, ctx);
319 + cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
323 - ieee80211_dfs_cac_cancel(local);
325 +ieee80211_radar_mark_chan_ctx_iterator(struct ieee80211_hw *hw,
326 + struct ieee80211_chanctx_conf *chanctx_conf,
329 + struct ieee80211_chanctx *ctx =
330 + container_of(chanctx_conf, struct ieee80211_chanctx,
333 - if (num_chanctx > 1)
334 - /* XXX: multi-channel is not supported yet */
337 - cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
338 + if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
341 + if (data && data != chanctx_conf)
344 + ctx->radar_detected = true;
347 -void ieee80211_radar_detected(struct ieee80211_hw *hw)
348 +void ieee80211_radar_detected(struct ieee80211_hw *hw,
349 + struct ieee80211_chanctx_conf *chanctx_conf)
351 struct ieee80211_local *local = hw_to_local(hw);
353 trace_api_radar_detected(local);
355 + ieee80211_iter_chan_contexts_atomic(hw, ieee80211_radar_mark_chan_ctx_iterator,
358 wiphy_work_queue(hw->wiphy, &local->radar_detected_work);
360 EXPORT_SYMBOL(ieee80211_radar_detected);