@@ -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;
}
@@ -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);
}
}
@@ -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)
@@ -8356,7 +8356,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();
@@ -6785,7 +6785,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();
@@ -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);
}
/*
@@ -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;
}
@@ -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++;
}
@@ -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;
@@ -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++;
}
@@ -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++;
}
@@ -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) {
@@ -1137,7 +1137,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;
}
@@ -6724,8 +6724,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()
+ * @radar_channel: Channel pointer 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_channel *radar_channel);
/**
* ieee80211_chswitch_done - Complete channel switch process
@@ -1329,6 +1329,11 @@ enum mac80211_scan_state {
DECLARE_STATIC_KEY_FALSE(aql_disable);
+struct radar_info {
+ struct list_head list;
+ struct ieee80211_channel *channel;
+};
+
struct ieee80211_local {
/* embed the driver visible part.
* don't cast (use the static inlines below), but we keep
@@ -1430,6 +1435,7 @@ struct ieee80211_local {
bool wowlan;
struct wiphy_work radar_detected_work;
+ struct list_head radar_info_list;
/* number of RX chains the hardware has */
u8 rx_chains;
@@ -943,6 +943,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
INIT_LIST_HEAD(&local->interfaces);
INIT_LIST_HEAD(&local->mon_list);
+ INIT_LIST_HEAD(&local->radar_info_list);
__hw_addr_init(&local->mc_list);
@@ -1638,6 +1639,7 @@ EXPORT_SYMBOL(ieee80211_register_hw);
void ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct radar_info *radar_info, *temp;
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
@@ -1673,6 +1675,12 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
ieee80211_clear_tx_pending(local);
rate_control_deinitialize(local);
+ list_for_each_entry_safe(radar_info, temp, &local->radar_info_list,
+ list) {
+ list_del(&radar_info->list);
+ kfree(radar_info);
+ }
+
if (skb_queue_len(&local->skb_queue) ||
skb_queue_len(&local->skb_queue_unreliable))
wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
@@ -3488,12 +3488,12 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
}
}
-void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
- struct wiphy_work *work)
+static void
+ieee80211_dfs_handle_radar_detection(struct ieee80211_local *local,
+ struct ieee80211_channel *radar_channel)
{
- 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 *radar_chandef = NULL;
struct ieee80211_chanctx *ctx;
int num_chanctx = 0;
@@ -3505,23 +3505,69 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
num_chanctx++;
chandef = ctx->conf.def;
+
+ if (radar_channel &&
+ (chandef.chan == radar_channel))
+ radar_chandef = &ctx->conf.def;
}
ieee80211_dfs_cac_cancel(local);
- if (num_chanctx > 1)
- /* XXX: multi-channel is not supported yet */
- WARN_ON(1);
- else
+ if (num_chanctx > 1) {
+ if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) {
+ if (WARN_ON(!radar_chandef))
+ return;
+
+ cfg80211_radar_event(local->hw.wiphy, radar_chandef, GFP_KERNEL);
+ } else {
+ /* XXX: multi-channel is not supported yet */
+ WARN_ON(1);
+ }
+ } else {
cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
+ }
}
-void ieee80211_radar_detected(struct ieee80211_hw *hw)
+void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
+ struct wiphy_work *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local, radar_detected_work);
+ struct radar_info *radar_info, *temp;
+ struct ieee80211_channel *radar_channel;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ if (list_empty(&local->radar_info_list)) {
+ ieee80211_dfs_handle_radar_detection(local, NULL);
+ return;
+ }
+
+ list_for_each_entry_safe(radar_info, temp, &local->radar_info_list,
+ list) {
+ radar_channel = radar_info->channel;
+ ieee80211_dfs_handle_radar_detection(local, radar_channel);
+ list_del(&radar_info->list);
+ kfree(radar_info);
+ }
+}
+
+void ieee80211_radar_detected(struct ieee80211_hw *hw,
+ struct ieee80211_channel *radar_channel)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct radar_info *radar_info;
trace_api_radar_detected(local);
+ radar_info = kzalloc(sizeof(*radar_info), GFP_ATOMIC);
+ if (!radar_info)
+ return;
+
+ INIT_LIST_HEAD(&radar_info->list);
+ radar_info->channel = radar_channel;
+ list_add_tail(&radar_info->list, &local->radar_info_list);
+
wiphy_work_queue(hw->wiphy, &local->radar_detected_work);
}
EXPORT_SYMBOL(ieee80211_radar_detected);
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. Hence, in order to support DFS with MLO, do the following changes - * Add channel pointer as an argument to the function ieee80211_radar_detected(). During MLO, drivers would have to pass on which channel radar is detected. * In order to pass on this channel information to the radar detected worker later on, introduce a linked list 'radar_info' in the structure local. * When driver calls radar detected, a node is created and added to this list and work is scheduled. The work handler takes care to process each node and take further action. * 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> --- drivers/net/wireless/ath/ath10k/debug.c | 4 +- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.c | 2 +- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- drivers/net/wireless/ath/ath9k/dfs.c | 2 +- drivers/net/wireless/ath/ath9k/dfs_debug.c | 2 +- .../net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_dfs.c | 4 +- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- drivers/net/wireless/ti/wl18xx/event.c | 2 +- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- include/net/mac80211.h | 5 +- net/mac80211/ieee80211_i.h | 6 ++ net/mac80211/main.c | 8 +++ net/mac80211/util.c | 64 ++++++++++++++++--- 17 files changed, 88 insertions(+), 25 deletions(-)