| diff --git a/package/kernel/mt76/patches/1005-mt76-zero-wait-dfs.patch b/package/kernel/mt76/patches/1005-mt76-zero-wait-dfs.patch |
| new file mode 100644 |
| index 0000000..68883e4 |
| --- /dev/null |
| +++ b/package/kernel/mt76/patches/1005-mt76-zero-wait-dfs.patch |
| @@ -0,0 +1,369 @@ |
| +diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c |
| +index 3a0ec43..2ce6973 100644 |
| +--- a/mt7915/debugfs.c |
| ++++ b/mt7915/debugfs.c |
| +@@ -75,12 +75,62 @@ 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, |
| + 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->rdd2_chandef; |
| ++ const char *bw; |
| ++ int ret = 0; |
| ++ |
| ++ mutex_lock(&dev->mt76.mutex); |
| ++ |
| ++ if (!cfg80211_chandef_valid(chandef)) { |
| ++ ret = -EINVAL; |
| ++ goto out; |
| ++ } |
| ++ |
| ++ if (!dev->rdd2_phy) { |
| ++ seq_printf(s, "not running\n"); |
| ++ goto out; |
| ++ } |
| ++ |
| ++ 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, "channel %d (%d MHz) width %s MHz center1: %d MHz\n", |
| ++ chandef->chan->hw_value, chandef->chan->center_freq, |
| ++ bw, chandef->center_freq1); |
| ++out: |
| ++ mutex_unlock(&dev->mt76.mutex); |
| ++ |
| ++ return ret; |
| ++} |
| ++ |
| + static int |
| + mt7915_fw_debug_wm_set(void *data, u64 val) |
| + { |
| +@@ -552,6 +602,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); |
| + } |
| + |
| + #ifdef MTK_DEBUG |
| +diff --git a/mt7915/init.c b/mt7915/init.c |
| +index e32cefc..6767702 100644 |
| +--- a/mt7915/init.c |
| ++++ b/mt7915/init.c |
| +@@ -294,6 +294,9 @@ mt7915_regd_notifier(struct wiphy *wiphy, |
| + memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); |
| + dev->mt76.region = request->dfs_region; |
| + |
| ++ if (dev->mt76.region == NL80211_DFS_UNSET) |
| ++ mt7915_mcu_rdd_offchan_enable(phy, NULL); |
| ++ |
| + mt7915_init_txpower(dev, &mphy->sband_2g.sband); |
| + mt7915_init_txpower(dev, &mphy->sband_5g.sband); |
| + |
| +@@ -307,6 +310,7 @@ static void |
| + mt7915_init_wiphy(struct ieee80211_hw *hw) |
| + { |
| + struct mt7915_phy *phy = mt7915_hw_phy(hw); |
| ++ struct mt76_dev *mdev = &phy->dev->mt76; |
| + struct wiphy *wiphy = hw->wiphy; |
| + |
| + hw->queues = 4; |
| +@@ -334,6 +338,12 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) |
| + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT); |
| + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE); |
| + |
| ++ if (!mdev->dev->of_node || |
| ++ !of_property_read_bool(mdev->dev->of_node, |
| ++ "mediatek,disable-radar-offchan")) |
| ++ wiphy_ext_feature_set(wiphy, |
| ++ NL80211_EXT_FEATURE_RADAR_OFFCHAN); |
| ++ |
| + ieee80211_hw_set(hw, HAS_RATE_CONTROL); |
| + ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); |
| + ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); |
| +diff --git a/mt7915/main.c b/mt7915/main.c |
| +index 31efe2c..c9dba1f 100644 |
| +--- a/mt7915/main.c |
| ++++ b/mt7915/main.c |
| +@@ -1312,6 +1312,55 @@ mt7915_twt_teardown_request(struct ieee80211_hw *hw, |
| + mutex_unlock(&dev->mt76.mutex); |
| + } |
| + |
| ++static int |
| ++mt7915_set_radar_offchan(struct ieee80211_hw *hw, |
| ++ struct cfg80211_chan_def *chandef) |
| ++{ |
| ++ struct mt7915_phy *phy = mt7915_hw_phy(hw); |
| ++ struct mt7915_dev *dev = phy->dev; |
| ++ int ret = -EINVAL; |
| ++ bool running; |
| ++ |
| ++ mutex_lock(&dev->mt76.mutex); |
| ++ |
| ++ if (dev->mt76.region == NL80211_DFS_UNSET) |
| ++ goto out; |
| ++ |
| ++ if (dev->rdd2_phy && dev->rdd2_phy != phy) { |
| ++ /* rdd2 is already locked */ |
| ++ ret = -EBUSY; |
| ++ goto out; |
| ++ } |
| ++ |
| ++ /* rdd2 already configured on a radar channel */ |
| ++ running = dev->rdd2_phy && |
| ++ cfg80211_chandef_valid(&dev->rdd2_chandef) && |
| ++ !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); |
| ++ |
| ++ if (!chandef || running || |
| ++ !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { |
| ++ ret = mt7915_mcu_rdd_offchan_enable(phy, NULL); |
| ++ if (ret) |
| ++ goto out; |
| ++ |
| ++ if (!running) |
| ++ goto update_phy; |
| ++ } |
| ++ |
| ++ ret = mt7915_mcu_rdd_offchan_enable(phy, chandef); |
| ++ if (ret) |
| ++ goto out; |
| ++ |
| ++update_phy: |
| ++ dev->rdd2_phy = chandef ? phy : NULL; |
| ++ if (chandef) |
| ++ dev->rdd2_chandef = *chandef; |
| ++out: |
| ++ mutex_unlock(&dev->mt76.mutex); |
| ++ |
| ++ return ret; |
| ++} |
| ++ |
| + const struct ieee80211_ops mt7915_ops = { |
| + .tx = mt7915_tx, |
| + .start = mt7915_start, |
| +@@ -1357,4 +1406,5 @@ const struct ieee80211_ops mt7915_ops = { |
| + #ifdef CONFIG_MAC80211_DEBUGFS |
| + .sta_add_debugfs = mt7915_sta_add_debugfs, |
| + #endif |
| ++ .set_radar_offchan = mt7915_set_radar_offchan, |
| + }; |
| +diff --git a/mt7915/mcu.c b/mt7915/mcu.c |
| +index a5fb821..b361f68 100644 |
| +--- a/mt7915/mcu.c |
| ++++ b/mt7915/mcu.c |
| +@@ -487,7 +487,12 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) |
| + if (r->band_idx && dev->mt76.phy2) |
| + mphy = dev->mt76.phy2; |
| + |
| +- ieee80211_radar_detected(mphy->hw); |
| ++ if (r->band_idx == MT_RX_SEL2) |
| ++ cfg80211_offchan_radar_event(mphy->hw->wiphy, |
| ++ &dev->rdd2_chandef, |
| ++ GFP_ATOMIC); |
| ++ else |
| ++ ieee80211_radar_detected(mphy->hw); |
| + dev->hw_pattern++; |
| + } |
| + |
| +@@ -3409,6 +3414,97 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, |
| + sizeof(req), true); |
| + } |
| + |
| ++static int |
| ++mt7915_mcu_offchan_chain_ctrl(struct mt7915_phy *phy, |
| ++ struct cfg80211_chan_def *chandef, |
| ++ int cmd) |
| ++{ |
| ++ struct mt7915_dev *dev = phy->dev; |
| ++ struct mt76_phy *mphy = phy->mt76; |
| ++ struct ieee80211_channel *chan = mphy->chandef.chan; |
| ++ int freq = mphy->chandef.center_freq1; |
| ++ struct mt7915_mcu_offchan_chain_ctrl req = { |
| ++ .monitor_scan_type = 2, /* simple rx */ |
| ++ }; |
| ++ |
| ++ if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP) |
| ++ return -EINVAL; |
| ++ |
| ++ if (!cfg80211_chandef_valid(&mphy->chandef)) |
| ++ 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 = chandef->chan->hw_value; |
| ++ req.monitor_central_chan = |
| ++ ieee80211_frequency_to_channel(chandef->center_freq1); |
| ++ req.monitor_bw = mt7915_mcu_chan_bw(chandef); |
| ++ req.band_idx = phy != &dev->phy; |
| ++ req.scan_mode = 1; |
| ++ break; |
| ++ } |
| ++ case CH_SWITCH_BACKGROUND_SCAN_RUNNING: |
| ++ req.monitor_chan = chandef->chan->hw_value; |
| ++ req.monitor_central_chan = |
| ++ ieee80211_frequency_to_channel(chandef->center_freq1); |
| ++ 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 = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1; |
| ++ |
| ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL), |
| ++ &req, sizeof(req), false); |
| ++} |
| ++ |
| ++int mt7915_mcu_rdd_offchan_enable(struct mt7915_phy *phy, |
| ++ struct cfg80211_chan_def *chandef) |
| ++{ |
| ++ struct mt7915_dev *dev = phy->dev; |
| ++ int err, region; |
| ++ |
| ++ if (!chandef) { /* disable offchain */ |
| ++ err = mt7915_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2, 0, 0); |
| ++ if (err) |
| ++ return err; |
| ++ |
| ++ return mt7915_mcu_offchan_chain_ctrl(phy, NULL, |
| ++ CH_SWITCH_BACKGROUND_SCAN_STOP); |
| ++ } |
| ++ |
| ++ err = mt7915_mcu_offchan_chain_ctrl(phy, chandef, |
| ++ 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); |
| ++} |
| ++ |
| + int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) |
| + { |
| + struct mt7915_dev *dev = phy->dev; |
| +diff --git a/mt7915/mcu.h b/mt7915/mcu.h |
| +index 2f856ae..64bea9a 100644 |
| +--- a/mt7915/mcu.h |
| ++++ b/mt7915/mcu.h |
| +@@ -153,6 +153,29 @@ struct mt7915_mcu_rdd_report { |
| + } hw_pulse[32]; |
| + } __packed; |
| + |
| ++struct mt7915_mcu_offchan_chain_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; |
| +@@ -286,6 +309,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/mt7915/mt7915.h b/mt7915/mt7915.h |
| +index 27dcd3f..f3449eb 100644 |
| +--- a/mt7915/mt7915.h |
| ++++ b/mt7915/mt7915.h |
| +@@ -298,6 +298,10 @@ struct mt7915_dev { |
| + struct tasklet_struct irq_tasklet; |
| + struct mt7915_phy phy; |
| + |
| ++ /* monitor rx chain configured channel */ |
| ++ struct cfg80211_chan_def rdd2_chandef; |
| ++ struct mt7915_phy *rdd2_phy; |
| ++ |
| + u16 chainmask; |
| + u32 hif_idx; |
| + |
| +@@ -379,6 +383,7 @@ enum { |
| + enum { |
| + MT_RX_SEL0, |
| + MT_RX_SEL1, |
| ++ MT_RX_SEL2, /* monitor chain */ |
| + }; |
| + |
| + enum mt7915_rdd_cmd { |
| +@@ -516,6 +521,8 @@ 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_rdd_offchan_enable(struct mt7915_phy *phy, |
| ++ struct cfg80211_chan_def *chandef); |
| + int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); |
| + int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl); |
| + int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level); |
| + |