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>
This commit is contained in:
Aditya Kumar Singh 2024-09-06 12:14:26 +05:30 committed by Johannes Berg
parent 0b7798232e
commit bca8bc0399
18 changed files with 67 additions and 30 deletions

View 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;
}

View 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);
}
}

View 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)

View 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();

View 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();

View 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);
}
/*

View 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;
}

View 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++;
}

View 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;

View 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++;
}

View 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++;
}

View 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) {

View 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;
}

View 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

View 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;

View 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,

View 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);

View 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);
if (num_chanctx > 1)
/* XXX: multi-channel is not supported yet */
WARN_ON(1);
else
ieee80211_dfs_cac_cancel(local, ctx);
cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
}
}
void ieee80211_radar_detected(struct ieee80211_hw *hw)
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 (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,
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);