Skip to contentSkip to conversation

add offchannel monitor chain support

RFC New Lorenzo Bianconi 1 participant 8 messages Sep 28, 2021

Subsystems (4)
lore
Share & tools
lore

Lorenzo Bianconi

author maintainer
#0 lore raw

cover add offchannel monitor chain support

Introduce the capability to configure a dedicated chain available for radar detection on some hw (e.g. mt7915). The driver is supposed to implement CAC management in sw or fw while hostapd (or iw) will implement the logic to select and configure the monitored channel.
Using a dedicated chain to perform the CAC, the AP can avoid the CAC downtime switching to a new DFS channel.

Lorenzo Bianconi (7):
mac80211: introduce set_offchan_chain callback
cfg80211: introduce nl80211_set_offchan_chain callback
cfg80211: introduce cfg80211_cac_offchan_event routine
mt76: mt7915: introduce mt7915_set_offchan_chain routine
mt76: mt7915: enable radar trigger on rdd2
mt76: mt7915: introduce rdd_monitor debugfs node
mt76: mt7915: add cac support for offchannel chain

 .../wireless/mediatek/mt76/mt7915/debugfs.c   | 37 +++++++++-
 .../net/wireless/mediatek/mt76/mt7915/init.c  |  4 ++
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 57 ++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7915/main.c  | 33 +++++++++
 .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 67 ++++++++++++++++++-
 .../net/wireless/mediatek/mt76/mt7915/mcu.h   | 24 +++++++
 .../wireless/mediatek/mt76/mt7915/mt7915.h    | 10 +++
 include/net/cfg80211.h                        | 19 ++++++
 include/net/mac80211.h                        |  5 ++
 include/uapi/linux/nl80211.h                  |  6 ++
 net/mac80211/cfg.c                            | 13 ++++
 net/wireless/mlme.c                           | 26 +++++++
 net/wireless/nl80211.c                        | 41 ++++++++++++
 net/wireless/rdev-ops.h                       | 17 +++++
 net/wireless/trace.h                          | 19 ++++++
 15 files changed, 375 insertions(+), 3 deletions(-)
Signature · 1 line
2.31.1
author maintainer
#1 lore raw

RFC 1/7 mac80211: introduce set_offchan_chain callback

Introduce set_offchan_chain callback in cfg80211/mac80211_ops in order to configure a dedicated chain available on some hw (e.g. mt7915) to perfrom offchannel CAC detection.

---
 include/net/cfg80211.h  |  6 ++++++
 include/net/mac80211.h  |  5 +++++
 net/mac80211/cfg.c      | 13 +++++++++++++
 net/wireless/rdev-ops.h | 17 +++++++++++++++++
 net/wireless/trace.h    | 19 +++++++++++++++++++
 5 files changed, 60 insertions(+)
include/net/cfg80211.h +6 -0
index 62dd8422e0dc..fa31b0919be9 100644
@@ -4018,6 +4018,10 @@ struct mgmt_frame_regs {
  * @set_sar_specs: Update the SAR (TX power) settings.
  *
  * @color_change: Initiate a color change.
+ *
+ * @set_offchan_chain: Configure dedicated chain available for radar detection
+ *	on some hw. The driver is supposed to implement CAC management in sw
+ *	or fw.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4348,6 +4352,8 @@ struct cfg80211_ops {
 	int	(*color_change)(struct wiphy *wiphy,
 				struct net_device *dev,
 				struct cfg80211_color_change_settings *params);
+	int	(*set_offchan_chain)(struct wiphy *wiphy,
+				     struct cfg80211_chan_def *chandef);
 };
 
 /*
include/net/mac80211.h +5 -0
index af0fc13cea34..e7161850d091 100644
@@ -3933,6 +3933,9 @@ struct ieee80211_prep_tx_info {
  *	twt structure.
  * @twt_teardown_request: Update the hw with TWT teardown request received
  *	from the peer.
+ * @set_offchan_chain: Configure dedicated chain available for radar detection
+ *	on some hw. The driver is supposed to implement CAC management in sw
+ *	or fw.
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw,
@@ -4261,6 +4264,8 @@ struct ieee80211_ops {
 			      struct ieee80211_twt_setup *twt);
 	void (*twt_teardown_request)(struct ieee80211_hw *hw,
 				     struct ieee80211_sta *sta, u8 flowid);
+	int (*set_offchan_chain)(struct ieee80211_hw *hw,
+				 struct cfg80211_chan_def *chandef);
 };
 
 /**
net/mac80211/cfg.c +13 -0
index d69b31c20fe2..5eaa66b3886a 100644
@@ -4341,6 +4341,18 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev,
 	return err;
 }
 
+static int
+ieee80211_set_offchan_chain(struct wiphy *wiphy,
+			    struct cfg80211_chan_def *chandef)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+
+	if (!local->ops->set_offchan_chain)
+		return -EOPNOTSUPP;
+
+	return local->ops->set_offchan_chain(&local->hw, chandef);
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -4445,4 +4457,5 @@ const struct cfg80211_ops mac80211_config_ops = {
 	.reset_tid_config = ieee80211_reset_tid_config,
 	.set_sar_specs = ieee80211_set_sar_specs,
 	.color_change = ieee80211_color_change,
+	.set_offchan_chain = ieee80211_set_offchan_chain,
 };
net/wireless/rdev-ops.h +17 -0
index ce6bf218a1a3..f24ae15fb9b3 100644
@@ -1381,4 +1381,21 @@ static inline int rdev_color_change(struct cfg80211_registered_device *rdev,
 	return ret;
 }
 
+static inline int
+rdev_set_offchan_chain(struct cfg80211_registered_device *rdev,
+		       struct cfg80211_chan_def *chandef)
+{
+	struct wiphy *wiphy = &rdev->wiphy;
+	int ret;
+
+	if (!rdev->ops->set_offchan_chain)
+		return -EOPNOTSUPP;
+
+	trace_rdev_set_offchan_chain(wiphy, chandef);
+	ret = rdev->ops->set_offchan_chain(wiphy, chandef);
+	trace_rdev_return_int(wiphy, ret);
+
+	return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
net/wireless/trace.h +19 -0
index 19b78d472283..4d905f584301 100644
@@ -3643,6 +3643,25 @@ TRACE_EVENT(cfg80211_bss_color_notify,
 		  __entry->color_bitmap)
 );
 
+TRACE_EVENT(rdev_set_offchan_chain,
+	TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
+
+	TP_ARGS(wiphy, chandef),
+
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		CHAN_DEF_ENTRY
+	),
+
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		CHAN_DEF_ASSIGN(chandef)
+	),
+
+	TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
+		  WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+);
+
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
Signature · 1 line
2.31.1
author maintainer
#2 lore raw

RFC 2/7 cfg80211: introduce nl80211_set_offchan_chain callback

In reply to Lorenzo Bianconi

Introduce NL80211_CMD_OFFCHAN_CHAIN command in order to configure offchannel chain if supported by the underlay driver.

---
 include/uapi/linux/nl80211.h |  6 ++++++
 net/wireless/nl80211.c       | 41 ++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
include/uapi/linux/nl80211.h +6 -0
index c2efea98e060..51ddd6f198d4 100644
@@ -1200,6 +1200,10 @@
  * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change
  *	has completed
  *
+ * @NL80211_CMD_OFFCHAN_CHAIN: Configure dedicated chain available for radar
+ *	detection on some hw. The driver is supposed to implement CAC
+ *	management in sw or fw.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1440,6 +1444,8 @@ enum nl80211_commands {
 	NL80211_CMD_COLOR_CHANGE_ABORTED,
 	NL80211_CMD_COLOR_CHANGE_COMPLETED,
 
+	NL80211_CMD_OFFCHAN_CHAIN,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
net/wireless/nl80211.c +41 -0

53 lines not on this page · raw message

Signature · 1 line
2.31.1
author maintainer
#3 lore raw

RFC 3/7 cfg80211: introduce cfg80211_cac_offchan_event routine

In reply to Lorenzo Bianconi

Introduce cfg80211_cac_offchan_event routine in order to notify userland when a Channel Availability Check (CAC) is finished or aborted by offchannel dedicated chain.

---
 include/net/cfg80211.h | 13 +++++++++++++
 net/wireless/mlme.c    | 26 ++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)
include/net/cfg80211.h +13 -0
index fa31b0919be9..7c1bcd406a34 100644
@@ -7564,6 +7564,19 @@ void cfg80211_cac_event(struct net_device *netdev,
 			const struct cfg80211_chan_def *chandef,
 			enum nl80211_radar_event event, gfp_t gfp);
 
+/**
+ * cfg80211_cac_offchan_event - Channel Availability Check (CAC) offchan event
+ * @wiphy: the wiphy
+ * @chandef: chandef for the current channel
+ * @event: type of event
+ * @gfp: context flags
+ *
+ * This function is called when a Channel Availability Check (CAC) is finished
+ * or aborted by offchannel dedicated chain.
+ */
+void cfg80211_cac_offchan_event(struct wiphy *wiphy,
+				const struct cfg80211_chan_def *chandef,
+				enum nl80211_radar_event event, gfp_t gfp);
 
 /**
  * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
net/wireless/mlme.c +26 -0
index 3aa69b375a10..4362f4f49bb4 100644
@@ -968,3 +968,29 @@ void cfg80211_cac_event(struct net_device *netdev,
 	nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
 }
 EXPORT_SYMBOL(cfg80211_cac_event);
+
+void cfg80211_cac_offchan_event(struct wiphy *wiphy,
+				const struct cfg80211_chan_def *chandef,
+				enum nl80211_radar_event event, gfp_t gfp)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+	switch (event) {
+	case NL80211_RADAR_CAC_FINISHED:
+		cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
+		memcpy(&rdev->cac_done_chandef, chandef,
+		       sizeof(struct cfg80211_chan_def));
+		queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
+		cfg80211_sched_dfs_chan_update(rdev);
+		break;
+	case NL80211_RADAR_CAC_ABORTED:
+	case NL80211_RADAR_CAC_STARTED:
+		break;
+	default:
+		WARN_ON(1);
+		return;
+	}
+
+	nl80211_radar_notify(rdev, chandef, event, NULL, gfp);
+}
+EXPORT_SYMBOL(cfg80211_cac_offchan_event);
Signature · 1 line
2.31.1
author maintainer
#4 lore raw

RFC 4/7 mt76: mt7915: introduce mt7915_set_offchan_chain routine

In reply to Lorenzo Bianconi

Introduce mt7915_dfs_set_rdd_monitor and mt7915_mcu_set_offchan_ctrl routines to configure rx dfs dedicated chain.
This is a preliminary patch to add zero-wait dfs support performing CAC detection on rdd2.

---
 .../net/wireless/mediatek/mt76/mt7915/init.c  |  2 +
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 35 +++++++++++++
 .../net/wireless/mediatek/mt76/mt7915/main.c  | 32 ++++++++++++
 .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 52 +++++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7915/mcu.h   | 24 +++++++++
 .../wireless/mediatek/mt76/mt7915/mt7915.h    |  8 +++
 6 files changed, 153 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7915/init.c +2 -0
index 8c42a1668013..ba4d644fe846 100644
@@ -296,6 +296,8 @@ mt7915_regd_notifier(struct wiphy *wiphy,
 	mt7915_init_txpower(dev, &mphy->sband_2g.sband);
 	mt7915_init_txpower(dev, &mphy->sband_5g.sband);
 
+	mt7915_dfs_set_rdd_monitor(phy, dev->mt76.region != NL80211_DFS_UNSET);
+
 	if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
 		return;
 
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +35 -0
index 899d2e228c1f..a2f94bedf9a1 100644
@@ -2316,3 +2316,38 @@ void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev,
 	dev->twt.table_mask &= ~BIT(flow->table_id);
 	dev->twt.n_agrt--;
 }
+
+int mt7915_dfs_set_rdd_monitor(struct mt7915_phy *phy, bool enable)
+{
+	struct mt7915_dev *dev = phy->dev;
+	int err, region;
+
+	if (!enable || dev->mt76.region == NL80211_DFS_UNSET) {
+		err = mt7915_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2, 0, 0);
+		if (err)
+			return err;
+
+		return mt7915_mcu_set_offchan_ctrl(phy,
+						   CH_SWITCH_BACKGROUND_SCAN_STOP);
+	}
+
+	err = mt7915_mcu_set_offchan_ctrl(phy,
+					  CH_SWITCH_BACKGROUND_SCAN_START);
+	if (err)
+		return err;
+
+	switch (dev->mt76.region) {
+	case NL80211_DFS_ETSI:
+		region = 0;
+		break;
+	case NL80211_DFS_JP:
+		region = 2;
+		break;
+	case NL80211_DFS_FCC:
+	default:
+		region = 1;
+		break;
+	}
+
+	return mt7915_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2, 0, region);
+}
drivers/net/wireless/mediatek/mt76/mt7915/main.c +32 -0
index ce1c68cf061a..406517bfbfc2 100644
@@ -1085,6 +1085,37 @@ mt7915_twt_teardown_request(struct ieee80211_hw *hw,
 	mutex_unlock(&dev->mt76.mutex);
 }
 
+static int
+mt7915_set_offchan_chain(struct ieee80211_hw *hw,
+			 struct cfg80211_chan_def *chandef)
+{
+	struct mt7915_phy *phy = mt7915_hw_phy(hw);
+	struct cfg80211_chan_def *off_chandef;
+	struct mt7915_dev *dev = phy->dev;
+	bool running;
+
+	off_chandef = &dev->offchan_chain.chandef;
+	if (cfg80211_chandef_identical(chandef, off_chandef))
+		return 0;
+
+	if (cfg80211_chandef_identical(&phy->mt76->chandef, off_chandef))
+		return 0;
+
+	running = off_chandef->chan &&
+		  !!(off_chandef->chan->flags & IEEE80211_CHAN_RADAR);
+	*off_chandef = *chandef;
+
+	if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR) || running) {
+		int ret;
+
+		ret = mt7915_dfs_set_rdd_monitor(phy, false);
+		if (ret || !running)
+			return ret;
+	}
+
+	return mt7915_dfs_set_rdd_monitor(phy, true);
+}
+
 const struct ieee80211_ops mt7915_ops = {
 	.tx = mt7915_tx,
 	.start = mt7915_start,
@@ -1127,4 +1158,5 @@ const struct ieee80211_ops mt7915_ops = {
 #ifdef CONFIG_MAC80211_DEBUGFS
 	.sta_add_debugfs = mt7915_sta_add_debugfs,
 #endif
+	.set_offchan_chain = mt7915_set_offchan_chain,
 };
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +52 -0

58 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +24 -0
index 0bd66c5136e9..8e0b219de8bc 100644
@@ -152,6 +152,29 @@ struct mt7915_mcu_rdd_report {
 	} hw_pulse[32];
 } __packed;
 
+struct mt7915_mcu_offchan_ctrl  {
+	u8 chan;		/* primary channel */
+	u8 central_chan;	/* central channel */
+	u8 bw;
+	u8 tx_stream;
+	u8 rx_stream;
+
+	u8 monitor_chan;	/* monitor channel */
+	u8 monitor_central_chan;/* monitor central channel */
+	u8 monitor_bw;
+	u8 monitor_tx_stream;
+	u8 monitor_rx_stream;
+
+	u8 scan_mode;		/* 0: ScanStop
+				 * 1: ScanStart
+				 * 2: ScanRunning
+				 */
+	u8 band_idx;		/* DBDC */
+	u8 monitor_scan_type;
+	u8 band;		/* 0: 2.4GHz, 1: 5GHz */
+	u8 rsv[2];
+} __packed;
+
 struct mt7915_mcu_eeprom {
 	u8 buffer_mode;
 	u8 format;
@@ -279,6 +302,7 @@ enum {
 	MCU_EXT_CMD_SCS_CTRL = 0x82,
 	MCU_EXT_CMD_TWT_AGRT_UPDATE = 0x94,
 	MCU_EXT_CMD_FW_DBG_CTRL = 0x95,
+	MCU_EXT_CMD_OFFCH_SCAN_CTRL = 0x9a,
 	MCU_EXT_CMD_SET_RDD_TH = 0x9d,
 	MCU_EXT_CMD_MURU_CTRL = 0x9f,
 	MCU_EXT_CMD_SET_SPR = 0xa8,
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +8 -0
index 0cd09767455a..65017a4347b9 100644
@@ -191,6 +191,11 @@ struct mt7915_dev {
 	struct tasklet_struct irq_tasklet;
 	struct mt7915_phy phy;
 
+	/* monitor rx chain configured channel */
+	struct {
+		struct cfg80211_chan_def chandef;
+	} offchan_chain;
+
 	u16 chainmask;
 	u32 hif_idx;
 
@@ -251,6 +256,7 @@ enum {
 enum {
 	MT_RX_SEL0,
 	MT_RX_SEL1,
+	MT_RX_SEL2, /* monitor chain */
 };
 
 enum mt7915_rdd_cmd {
@@ -389,6 +395,7 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
 			   struct ieee80211_sta *sta, struct rate_info *rate);
 int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd,
 		       u8 index, u8 rx_sel, u8 val);
+int mt7915_mcu_set_offchan_ctrl(struct mt7915_phy *phy, int cmd);
 int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl);
 int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level);
 void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb);
@@ -455,6 +462,7 @@ void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
 void mt7915_stats_work(struct work_struct *work);
 int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force);
 int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);
+int mt7915_dfs_set_rdd_monitor(struct mt7915_phy *phy, bool enable);
 void mt7915_set_stream_he_caps(struct mt7915_phy *phy);
 void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy);
 void mt7915_update_channel(struct mt76_phy *mphy);
Signature · 1 line
2.31.1
author maintainer
#5 lore raw

RFC 5/7 mt76: mt7915: enable radar trigger on rdd2

In reply to Lorenzo Bianconi

Enable radar trigger for rdd2 in mt7915_radar_trigger.

---
 drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +4 -1
index df8a498429df..2c010221e32d 100644
@@ -75,7 +75,10 @@ mt7915_radar_trigger(void *data, u64 val)
 {
 	struct mt7915_dev *dev = data;
 
-	return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0);
+	if (val > MT_RX_SEL2)
+		return -EINVAL;
+
+	return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, val, 0, 0);
 }
 
 DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
Signature · 1 line
2.31.1
author maintainer
#6 lore raw

RFC 6/7 mt76: mt7915: introduce rdd_monitor debugfs node

In reply to Lorenzo Bianconi

Introduce rdd_monitor debugfs node in order to dump rdd2 configuration.

---
 .../wireless/mediatek/mt76/mt7915/debugfs.c   | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +32 -0
index 2c010221e32d..7d8b7dbc5b58 100644
@@ -84,6 +84,36 @@ mt7915_radar_trigger(void *data, u64 val)
 DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
 			 mt7915_radar_trigger, "%lld\n");
 
+static int
+mt7915_rdd_monitor(struct seq_file *s, void *data)
+{
+	struct mt7915_dev *dev = dev_get_drvdata(s->private);
+	struct cfg80211_chan_def *chandef = &dev->offchan_chain.chandef;
+	const char *bw;
+
+	switch (chandef->width) {
+	case NL80211_CHAN_WIDTH_40:
+		bw = "40";
+		break;
+	case NL80211_CHAN_WIDTH_80:
+		bw = "80";
+		break;
+	case NL80211_CHAN_WIDTH_160:
+		bw = "160";
+		break;
+	case NL80211_CHAN_WIDTH_80P80:
+		bw = "80P80";
+		break;
+	default:
+		bw = "20";
+		break;
+	}
+
+	seq_printf(s, " freq %d MHz bw %s MHz\n", chandef->center_freq1, bw);
+
+	return 0;
+}
+
 static int
 mt7915_fw_debug_set(void *data, u64 val)
 {
@@ -498,6 +528,8 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
 				   &dev->hw_pattern);
 		debugfs_create_file("radar_trigger", 0200, dir, dev,
 				    &fops_radar_trigger);
+		debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,
+					    mt7915_rdd_monitor);
 	}
 
 	return 0;
Signature · 1 line
2.31.1
author maintainer
#7 lore raw

RFC 7/7 mt76: mt7915: add cac support for offchannel chain

In reply to Lorenzo Bianconi

Introduce cac management for dedicated offchannel chain.

---
 .../net/wireless/mediatek/mt76/mt7915/init.c  |  2 ++
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 24 ++++++++++++++++++-
 .../net/wireless/mediatek/mt76/mt7915/main.c  |  1 +
 .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 15 ++++++++++--
 .../wireless/mediatek/mt76/mt7915/mt7915.h    |  2 ++
 5 files changed, 41 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/init.c +2 -0
index ba4d644fe846..a3630953d7c7 100644
@@ -907,6 +907,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
 	dev->mt76.phy.priv = &dev->phy;
 	INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
 	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
+	INIT_DELAYED_WORK(&dev->offchan_chain.cac_work,
+			  mt7915_offchan_cac_work);
 	INIT_LIST_HEAD(&dev->sta_rc_list);
 	INIT_LIST_HEAD(&dev->sta_poll_list);
 	INIT_LIST_HEAD(&dev->twt_list);
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +23 -1
index a2f94bedf9a1..5d588fe1056d 100644
@@ -2320,9 +2320,13 @@ void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev,
 int mt7915_dfs_set_rdd_monitor(struct mt7915_phy *phy, bool enable)
 {
 	struct mt7915_dev *dev = phy->dev;
+	struct ieee80211_channel *chan = dev->offchan_chain.chandef.chan;
+	struct delayed_work *cac_work = &dev->offchan_chain.cac_work;
 	int err, region;
 
 	if (!enable || dev->mt76.region == NL80211_DFS_UNSET) {
+		cancel_delayed_work_sync(cac_work);
+
 		err = mt7915_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2, 0, 0);
 		if (err)
 			return err;
@@ -2349,5 +2353,23 @@ int mt7915_dfs_set_rdd_monitor(struct mt7915_phy *phy, bool enable)
 		break;
 	}
 
-	return mt7915_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2, 0, region);
+	err = mt7915_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2, 0, region);
+	if (err)
+		return err;
+
+	ieee80211_queue_delayed_work(mt76_hw(dev), cac_work,
+				     msecs_to_jiffies(chan->dfs_cac_ms));
+
+	return 0;
+}
+
+void mt7915_offchan_cac_work(struct work_struct *work)
+{
+	struct mt7915_dev *dev;
+
+	dev = (struct mt7915_dev *)container_of(work, struct mt7915_dev,
+						offchan_chain.cac_work.work);
+	cfg80211_cac_offchan_event(dev->mphy.hw->wiphy,
+				   &dev->offchan_chain.chandef,
+				   NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
 }
drivers/net/wireless/mediatek/mt76/mt7915/main.c +1 -0
index 406517bfbfc2..9020aa7bf359 100644
@@ -98,6 +98,7 @@ static void mt7915_stop(struct ieee80211_hw *hw)
 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
 
 	cancel_delayed_work_sync(&phy->mt76->mac_work);
+	cancel_delayed_work_sync(&dev->offchan_chain.cac_work);
 
 	mutex_lock(&dev->mt76.mutex);
 
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +13 -2
index 6249be262825..d24eade6667b 100644
@@ -481,10 +481,21 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
 
 	r = (struct mt7915_mcu_rdd_report *)skb->data;
 
-	if (r->band_idx && dev->mt76.phy2)
+	if (r->band_idx == MT_RX_SEL1 && dev->mt76.phy2)
 		mphy = dev->mt76.phy2;
 
-	ieee80211_radar_detected(mphy->hw);
+	if (r->band_idx == MT_RX_SEL2) {
+		cancel_delayed_work_sync(&dev->offchan_chain.cac_work);
+		cfg80211_cac_offchan_event(dev->mphy.hw->wiphy,
+					   &dev->offchan_chain.chandef,
+					   NL80211_RADAR_CAC_ABORTED,
+					   GFP_KERNEL);
+		cfg80211_radar_event(mphy->hw->wiphy,
+				     &dev->offchan_chain.chandef,
+				     GFP_KERNEL);
+	} else {
+		ieee80211_radar_detected(mphy->hw);
+	}
 	dev->hw_pattern++;
 }
 
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +2 -0
index 65017a4347b9..6576eb34d211 100644
@@ -194,6 +194,7 @@ struct mt7915_dev {
 	/* monitor rx chain configured channel */
 	struct {
 		struct cfg80211_chan_def chandef;
+		struct delayed_work cac_work;
 	} offchan_chain;
 
 	u16 chainmask;
@@ -463,6 +464,7 @@ void mt7915_stats_work(struct work_struct *work);
 int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force);
 int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);
 int mt7915_dfs_set_rdd_monitor(struct mt7915_phy *phy, bool enable);
+void mt7915_offchan_cac_work(struct work_struct *work);
 void mt7915_set_stream_he_caps(struct mt7915_phy *phy);
 void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy);
 void mt7915_update_channel(struct mt76_phy *mphy);
Signature · 1 line
2.31.1