]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mac80211: handle ieee80211_radar_detected() for MLO
authorAditya Kumar Singh <quic_adisi@quicinc.com>
Fri, 6 Sep 2024 06:44:26 +0000 (12:14 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 6 Sep 2024 11:01:05 +0000 (13:01 +0200)
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>
18 files changed:
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/ath/ath12k/wmi.c
drivers/net/wireless/ath/ath9k/dfs.c
drivers/net/wireless/ath/ath9k/dfs_debug.c
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
drivers/net/wireless/ti/wl18xx/event.c
drivers/net/wireless/virtual/mac80211_hwsim.c
include/net/mac80211.h
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/pm.c
net/mac80211/util.c

index b93a64bf8190187e417c66e8eebf2258868cd3af..35bfe7232e95edd86aeaf70fe8ca943c90f1360a 100644 (file)
@@ -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 <linux/module.h>
@@ -1774,7 +1774,7 @@ static ssize_t ath10k_write_simulate_radar(struct file *file,
        if (!arvif->is_started)
                return -EINVAL;
 
-       ieee80211_radar_detected(ar->hw);
+       ieee80211_radar_detected(ar->hw, NULL);
 
        return count;
 }
index a5da32e87106c71225e0f7740c2bedd0c1784d06..646e1737d4c47c4c29abbec8cae8d02dc476accd 100644 (file)
@@ -1437,7 +1437,7 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
                 * 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);
        }
 }
 
index fe2344598364973eae9916a5368744b70ec6325c..4861179b221786ef0f673c0ea508d49b2579bdd7 100644 (file)
@@ -3990,7 +3990,7 @@ static void ath10k_radar_detected(struct ath10k *ar)
        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)
index 2662092ee00a9c1963ce2aee0f5d47c605f4ac4c..87abfa54752953c819a37bbef86327e8b75241ba 100644 (file)
@@ -8358,7 +8358,7 @@ ath11k_wmi_pdev_dfs_radar_detected_event(struct ath11k_base *ab, struct sk_buff
        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();
index a76413320dbf2f5f854c544506938e674ac65d8f..2cd3ff9b0164c8fae0ff95295499596c39bc1c3c 100644 (file)
@@ -6789,7 +6789,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
        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();
index 11349218bc21c77ddc873fd09b7a60855c8ccc92..3689e12db9f74f91489dd07eca5d065d488c2a40 100644 (file)
@@ -280,7 +280,7 @@ ath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe)
        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);
 }
 
 /*
index 8e18e9b4ef483527a0104d588ba5f54af55cff07..426caa057396d2ac60fe613d25c17121093dd224 100644 (file)
@@ -116,7 +116,7 @@ static ssize_t write_file_simulate_radar(struct file *file,
 {
        struct ath_softc *sc = file->private_data;
 
-       ieee80211_radar_detected(sc->hw);
+       ieee80211_radar_detected(sc->hw, NULL);
 
        return count;
 }
index d50d967828be0d3bb4ef9757e04b7ad90dd4bec5..53c8ebe179dd55520ec955d9d08df949e82f1ee8 100644 (file)
@@ -394,7 +394,7 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)
        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++;
 }
 
index 024a5c0a5a5750bf1073528f5e47abfa3710d90c..7a07636d09c65fa615edab919b96d8a274eaa3a9 100644 (file)
@@ -630,7 +630,7 @@ static void mt76x02_dfs_tasklet(struct 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 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;
index 2185cd24e2e1cd8e098e502bc03a25ab712e8674..5f180851060df2637e852d481dd049416908f20b 100644 (file)
@@ -293,7 +293,7 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
                                                &dev->rdd2_chandef,
                                                GFP_ATOMIC);
        else
-               ieee80211_radar_detected(mphy->hw);
+               ieee80211_radar_detected(mphy->hw, NULL);
        dev->hw_pattern++;
 }
 
index 2e4fa9f48dfbeeb4477e3ce97c4d835549a81300..f8921546a5e6412337cbede248eb399d6ed09266 100644 (file)
@@ -371,7 +371,7 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
                                                &dev->rdd2_chandef,
                                                GFP_ATOMIC);
        else
-               ieee80211_radar_detected(mphy->hw);
+               ieee80211_radar_detected(mphy->hw, NULL);
        dev->hw_pattern++;
 }
 
index 34d95f458e1a92f2e53b00e1493270ff48a096aa..a9f090e15cbbea0a8b8cbe82b90064bd2e9563ef 100644 (file)
@@ -142,7 +142,7 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl)
                            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) {
index 5fe9e4e261429d362c23a30e27ecab88937f98eb..f0e528abb1b46f6becbfc73ab3fb7ce5a5ce05cf 100644 (file)
@@ -1146,7 +1146,7 @@ static int hwsim_write_simulate_radar(void *dat, u64 val)
 {
        struct mac80211_hwsim_data *data = dat;
 
-       ieee80211_radar_detected(data->hw);
+       ieee80211_radar_detected(data->hw, NULL);
 
        return 0;
 }
index adfec877f392ad9473371f257adb722143610cc8..954dff901b697d3288162d5a6193872cbc5a68b4 100644 (file)
@@ -6748,8 +6748,11 @@ void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp);
  * 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
index b72e4036526bfaa3ea97d8f39fbfe542c9f04e64..cca6d14084d2142c00b2c5dab9da78422b684ea9 100644 (file)
@@ -683,6 +683,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
        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;
index 9c2c826ef90cee488d2c9171e8be8bb59a725593..4f0390918b60027bc7eb7c7b30e840a983f91a76 100644 (file)
@@ -893,6 +893,8 @@ struct ieee80211_chanctx {
        struct ieee80211_chan_req req;
 
        struct ieee80211_chanctx_conf conf;
+
+       bool radar_detected;
 };
 
 struct mac80211_qos_map {
@@ -2649,7 +2651,8 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
 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,
index d823d58303e87216a86998766a383a450754091c..7be52345f218c59aa1b35a308c803c7dee224bed 100644 (file)
@@ -32,7 +32,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
        ieee80211_scan_cancel(local);
 
-       ieee80211_dfs_cac_cancel(local);
+       ieee80211_dfs_cac_cancel(local, NULL);
 
        ieee80211_roc_purge(local, NULL);
 
index 2e37d26390745eef8b0281031b5371728ef67a9a..f94faa86ba8a358d19ec5d8897b106fc654aefe2 100644 (file)
@@ -3467,11 +3467,16 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
        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);
@@ -3484,6 +3489,11 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
                        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);
 
@@ -3504,9 +3514,8 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
 {
        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);
 
@@ -3514,25 +3523,46 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
                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);