Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <quic_adisi@quicinc.com>
Link: https://patch.msgid.link/20240906064426.2101315-9-quic_adisi@quicinc.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Aditya Kumar Singh and committed by
Johannes Berg
bca8bc03 0b779823

+67 -30
+2 -2
drivers/net/wireless/ath/ath10k/debug.c
··· 3 3 * Copyright (c) 2005-2011 Atheros Communications Inc. 4 4 * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. 5 5 * Copyright (c) 2018, The Linux Foundation. All rights reserved. 6 - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 6 + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. 7 7 */ 8 8 9 9 #include <linux/module.h> ··· 1774 1774 if (!arvif->is_started) 1775 1775 return -EINVAL; 1776 1776 1777 - ieee80211_radar_detected(ar->hw); 1777 + ieee80211_radar_detected(ar->hw, NULL); 1778 1778 1779 1779 return count; 1780 1780 }
+1 -1
drivers/net/wireless/ath/ath10k/mac.c
··· 1437 1437 * by indicating that radar was detected. 1438 1438 */ 1439 1439 ath10k_warn(ar, "failed to start CAC: %d\n", ret); 1440 - ieee80211_radar_detected(ar->hw); 1440 + ieee80211_radar_detected(ar->hw, NULL); 1441 1441 } 1442 1442 } 1443 1443
+1 -1
drivers/net/wireless/ath/ath10k/wmi.c
··· 3990 3990 if (ar->dfs_block_radar_events) 3991 3991 ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); 3992 3992 else 3993 - ieee80211_radar_detected(ar->hw); 3993 + ieee80211_radar_detected(ar->hw, NULL); 3994 3994 } 3995 3995 3996 3996 static void ath10k_radar_confirmation_work(struct work_struct *work)
+1 -1
drivers/net/wireless/ath/ath11k/wmi.c
··· 8358 8358 if (ar->dfs_block_radar_events) 8359 8359 ath11k_info(ab, "DFS Radar detected, but ignored as requested\n"); 8360 8360 else 8361 - ieee80211_radar_detected(ar->hw); 8361 + ieee80211_radar_detected(ar->hw, NULL); 8362 8362 8363 8363 exit: 8364 8364 rcu_read_unlock();
+1 -1
drivers/net/wireless/ath/ath12k/wmi.c
··· 6789 6789 if (ar->dfs_block_radar_events) 6790 6790 ath12k_info(ab, "DFS Radar detected, but ignored as requested\n"); 6791 6791 else 6792 - ieee80211_radar_detected(ath12k_ar_to_hw(ar)); 6792 + ieee80211_radar_detected(ath12k_ar_to_hw(ar), NULL); 6793 6793 6794 6794 exit: 6795 6795 rcu_read_unlock();
+1 -1
drivers/net/wireless/ath/ath9k/dfs.c
··· 280 280 if (!pd->add_pulse(pd, pe, NULL)) 281 281 return; 282 282 DFS_STAT_INC(sc, radar_detected); 283 - ieee80211_radar_detected(sc->hw); 283 + ieee80211_radar_detected(sc->hw, NULL); 284 284 } 285 285 286 286 /*
+1 -1
drivers/net/wireless/ath/ath9k/dfs_debug.c
··· 116 116 { 117 117 struct ath_softc *sc = file->private_data; 118 118 119 - ieee80211_radar_detected(sc->hw); 119 + ieee80211_radar_detected(sc->hw, NULL); 120 120 121 121 return count; 122 122 }
+1 -1
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
··· 394 394 if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC) 395 395 return; 396 396 397 - ieee80211_radar_detected(mphy->hw); 397 + ieee80211_radar_detected(mphy->hw, NULL); 398 398 dev->hw_pattern++; 399 399 } 400 400
+2 -2
drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
··· 630 630 radar_detected = mt76x02_dfs_check_detection(dev); 631 631 if (radar_detected) { 632 632 /* sw detector rx radar pattern */ 633 - ieee80211_radar_detected(dev->mt76.hw); 633 + ieee80211_radar_detected(dev->mt76.hw, NULL); 634 634 mt76x02_dfs_detector_reset(dev); 635 635 636 636 return; ··· 658 658 659 659 /* hw detector rx radar pattern */ 660 660 dfs_pd->stats[i].hw_pattern++; 661 - ieee80211_radar_detected(dev->mt76.hw); 661 + ieee80211_radar_detected(dev->mt76.hw, NULL); 662 662 mt76x02_dfs_detector_reset(dev); 663 663 664 664 return;
+1 -1
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
··· 293 293 &dev->rdd2_chandef, 294 294 GFP_ATOMIC); 295 295 else 296 - ieee80211_radar_detected(mphy->hw); 296 + ieee80211_radar_detected(mphy->hw, NULL); 297 297 dev->hw_pattern++; 298 298 } 299 299
+1 -1
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
··· 371 371 &dev->rdd2_chandef, 372 372 GFP_ATOMIC); 373 373 else 374 - ieee80211_radar_detected(mphy->hw); 374 + ieee80211_radar_detected(mphy->hw, NULL); 375 375 dev->hw_pattern++; 376 376 } 377 377
+1 -1
drivers/net/wireless/ti/wl18xx/event.c
··· 142 142 wl18xx_radar_type_decode(mbox->radar_type)); 143 143 144 144 if (!wl->radar_debug_mode) 145 - ieee80211_radar_detected(wl->hw); 145 + ieee80211_radar_detected(wl->hw, NULL); 146 146 } 147 147 148 148 if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+1 -1
drivers/net/wireless/virtual/mac80211_hwsim.c
··· 1146 1146 { 1147 1147 struct mac80211_hwsim_data *data = dat; 1148 1148 1149 - ieee80211_radar_detected(data->hw); 1149 + ieee80211_radar_detected(data->hw, NULL); 1150 1150 1151 1151 return 0; 1152 1152 }
+4 -1
include/net/mac80211.h
··· 6748 6748 * ieee80211_radar_detected - inform that a radar was detected 6749 6749 * 6750 6750 * @hw: pointer as obtained from ieee80211_alloc_hw() 6751 + * @chanctx_conf: Channel context on which radar is detected. Mandatory to 6752 + * pass a valid pointer during MLO. For non-MLO %NULL can be passed 6751 6753 */ 6752 - void ieee80211_radar_detected(struct ieee80211_hw *hw); 6754 + void ieee80211_radar_detected(struct ieee80211_hw *hw, 6755 + struct ieee80211_chanctx_conf *chanctx_conf); 6753 6756 6754 6757 /** 6755 6758 * ieee80211_chswitch_done - Complete channel switch process
+1
net/mac80211/chan.c
··· 683 683 ctx->mode = mode; 684 684 ctx->conf.radar_enabled = false; 685 685 ctx->conf.radio_idx = radio_idx; 686 + ctx->radar_detected = false; 686 687 _ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false); 687 688 688 689 return ctx;
+4 -1
net/mac80211/ieee80211_i.h
··· 893 893 struct ieee80211_chan_req req; 894 894 895 895 struct ieee80211_chanctx_conf conf; 896 + 897 + bool radar_detected; 896 898 }; 897 899 898 900 struct mac80211_qos_map { ··· 2651 2649 bool ieee80211_is_radar_required(struct ieee80211_local *local); 2652 2650 2653 2651 void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work); 2654 - void ieee80211_dfs_cac_cancel(struct ieee80211_local *local); 2652 + void ieee80211_dfs_cac_cancel(struct ieee80211_local *local, 2653 + struct ieee80211_chanctx *chanctx); 2655 2654 void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy, 2656 2655 struct wiphy_work *work); 2657 2656 int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+1 -1
net/mac80211/pm.c
··· 32 32 33 33 ieee80211_scan_cancel(local); 34 34 35 - ieee80211_dfs_cac_cancel(local); 35 + ieee80211_dfs_cac_cancel(local, NULL); 36 36 37 37 ieee80211_roc_purge(local, NULL); 38 38
+42 -12
net/mac80211/util.c
··· 3467 3467 return ts; 3468 3468 } 3469 3469 3470 - void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) 3470 + /* Cancel CAC for the interfaces under the specified @local. If @ctx is 3471 + * also provided, only the interfaces using that ctx will be canceled. 3472 + */ 3473 + void ieee80211_dfs_cac_cancel(struct ieee80211_local *local, 3474 + struct ieee80211_chanctx *ctx) 3471 3475 { 3472 3476 struct ieee80211_sub_if_data *sdata; 3473 3477 struct cfg80211_chan_def chandef; 3474 3478 struct ieee80211_link_data *link; 3479 + struct ieee80211_chanctx_conf *chanctx_conf; 3475 3480 unsigned int link_id; 3476 3481 3477 3482 lockdep_assert_wiphy(local->hw.wiphy); ··· 3487 3482 link = sdata_dereference(sdata->link[link_id], 3488 3483 sdata); 3489 3484 if (!link) 3485 + continue; 3486 + 3487 + chanctx_conf = sdata_dereference(link->conf->chanctx_conf, 3488 + sdata); 3489 + if (ctx && &ctx->conf != chanctx_conf) 3490 3490 continue; 3491 3491 3492 3492 wiphy_delayed_work_cancel(local->hw.wiphy, ··· 3514 3504 { 3515 3505 struct ieee80211_local *local = 3516 3506 container_of(work, struct ieee80211_local, radar_detected_work); 3517 - struct cfg80211_chan_def chandef = local->hw.conf.chandef; 3507 + struct cfg80211_chan_def chandef; 3518 3508 struct ieee80211_chanctx *ctx; 3519 - int num_chanctx = 0; 3520 3509 3521 3510 lockdep_assert_wiphy(local->hw.wiphy); 3522 3511 ··· 3523 3514 if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) 3524 3515 continue; 3525 3516 3526 - num_chanctx++; 3517 + if (!ctx->radar_detected) 3518 + continue; 3519 + 3520 + ctx->radar_detected = false; 3521 + 3527 3522 chandef = ctx->conf.def; 3528 - } 3529 3523 3530 - ieee80211_dfs_cac_cancel(local); 3531 - 3532 - if (num_chanctx > 1) 3533 - /* XXX: multi-channel is not supported yet */ 3534 - WARN_ON(1); 3535 - else 3524 + ieee80211_dfs_cac_cancel(local, ctx); 3536 3525 cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); 3526 + } 3537 3527 } 3538 3528 3539 - void ieee80211_radar_detected(struct ieee80211_hw *hw) 3529 + static void 3530 + ieee80211_radar_mark_chan_ctx_iterator(struct ieee80211_hw *hw, 3531 + struct ieee80211_chanctx_conf *chanctx_conf, 3532 + void *data) 3533 + { 3534 + struct ieee80211_chanctx *ctx = 3535 + container_of(chanctx_conf, struct ieee80211_chanctx, 3536 + conf); 3537 + 3538 + if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) 3539 + return; 3540 + 3541 + if (data && data != chanctx_conf) 3542 + return; 3543 + 3544 + ctx->radar_detected = true; 3545 + } 3546 + 3547 + void ieee80211_radar_detected(struct ieee80211_hw *hw, 3548 + struct ieee80211_chanctx_conf *chanctx_conf) 3540 3549 { 3541 3550 struct ieee80211_local *local = hw_to_local(hw); 3542 3551 3543 3552 trace_api_radar_detected(local); 3553 + 3554 + ieee80211_iter_chan_contexts_atomic(hw, ieee80211_radar_mark_chan_ctx_iterator, 3555 + chanctx_conf); 3544 3556 3545 3557 wiphy_work_queue(hw->wiphy, &local->radar_detected_work); 3546 3558 }