diff mbox series

[RFC,4/7] mt76: mt7915: introduce mt7915_set_offchan_chain routine

Message ID a45939bb6dbc5acdfc1d50b3e3266bbf82838ce8.1632841652.git.lorenzo@kernel.org (mailing list archive)
State RFC
Delegated to: Felix Fietkau
Headers show
Series add offchannel monitor chain support | expand

Commit Message

Lorenzo Bianconi Sept. 28, 2021, 3:14 p.m. UTC
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.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 .../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(+)
diff mbox series

Patch

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 8c42a1668013..ba4d644fe846 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -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;
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 899d2e228c1f..a2f94bedf9a1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -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);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index ce1c68cf061a..406517bfbfc2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -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,
 };
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index df3a9dc1ca35..6249be262825 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -3204,6 +3204,58 @@  int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
 				 sizeof(req), true);
 }
 
+int mt7915_mcu_set_offchan_ctrl(struct mt7915_phy *phy, int cmd)
+{
+	struct mt7915_dev *dev = phy->dev;
+	struct mt76_phy *mphy = phy->mt76;
+	struct ieee80211_channel *chan = mphy->chandef.chan;
+	struct cfg80211_chan_def *off_chandef = &dev->offchan_chain.chandef;
+	struct ieee80211_channel *off_chan = off_chandef->chan;
+	int offchan_freq = off_chandef->center_freq1;
+	int freq = mphy->chandef.center_freq1;
+	struct mt7915_mcu_offchan_ctrl req = {
+		.monitor_scan_type = 2, /* simple rx */
+	};
+
+	if (!off_chan)
+		return -EINVAL;
+
+	switch (cmd) {
+	case CH_SWITCH_BACKGROUND_SCAN_START: {
+		req.chan = chan->hw_value;
+		req.central_chan = ieee80211_frequency_to_channel(freq);
+		req.bw = mt7915_mcu_chan_bw(&mphy->chandef);
+		req.monitor_chan = off_chan->hw_value;
+		req.monitor_central_chan =
+			ieee80211_frequency_to_channel(offchan_freq);
+		req.monitor_bw = mt7915_mcu_chan_bw(off_chandef);
+		req.band_idx = phy != &dev->phy;
+		req.scan_mode = 1;
+		break;
+	}
+	case CH_SWITCH_BACKGROUND_SCAN_RUNNING:
+		req.monitor_chan = off_chan->hw_value;
+		req.monitor_central_chan =
+			ieee80211_frequency_to_channel(offchan_freq);
+		req.band_idx = phy != &dev->phy;
+		req.scan_mode = 2;
+		break;
+	case CH_SWITCH_BACKGROUND_SCAN_STOP:
+		req.chan = chan->hw_value;
+		req.central_chan = ieee80211_frequency_to_channel(freq);
+		req.bw = mt7915_mcu_chan_bw(&mphy->chandef);
+		req.tx_stream = hweight8(mphy->antenna_mask);
+		req.rx_stream = mphy->antenna_mask;
+		break;
+	default:
+		return -EINVAL;
+	}
+	req.band = off_chan->band == NL80211_BAND_5GHZ;
+
+	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL),
+				 &req, sizeof(req), false);
+}
+
 int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
 {
 	struct mt7915_dev *dev = phy->dev;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 0bd66c5136e9..8e0b219de8bc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -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,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index 0cd09767455a..65017a4347b9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -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);