Skip to contentSkip to conversation

mt76: mt7915: fix STA mode connection on DFS channels

PATCH In review [email protected] 2 participants 6 messages Aug 20, 2021 – Nov 10, 2021

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v3 1/2 mt76: mt7915: fix STA mode connection on DFS channels

From: Ben Greear <[email protected]>

Only AP, adhoc and mesh mode needs to check CAC.
Stations, in particular, do not need this check.

---
v3: Fix typo in SOB in 1/2, fix rebase typo in 2/2,
split long line in 2/2

 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 38 +++++++++++++++++--
 1 file changed, 35 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +35 -3
index 8747e452e114..a6e142d27b60 100644
@@ -2455,6 +2455,32 @@ static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy)
 	return 0;
 }
 
+struct mt7915_vif_counts {
+	u32 mesh;
+	u32 adhoc;
+	u32 ap;
+};
+
+static void
+mt7915_vif_counts(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+	struct mt7915_vif_counts *counts = priv;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_ADHOC:
+		counts->adhoc++;
+		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		counts->mesh++;
+		break;
+	case NL80211_IFTYPE_AP:
+		counts->ap++;
+		break;
+	default:
+		break;
+	}
+}
+
 static int
 mt7915_dfs_init_radar_specs(struct mt7915_phy *phy)
 {
@@ -2495,6 +2521,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
 	struct mt7915_dev *dev = phy->dev;
 	bool ext_phy = phy != &dev->phy;
 	int err;
+	struct mt7915_vif_counts counts = {0};
 
 	if (dev->mt76.region == NL80211_DFS_UNSET) {
 		phy->dfs_state = -1;
@@ -2519,9 +2546,14 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
 	phy->dfs_state = chandef->chan->dfs_state;
 
 	if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
-		if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
-			return mt7915_dfs_start_radar_detector(phy);
-
+		if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) {
+			ieee80211_iterate_active_interfaces(phy->mt76->hw,
+				IEEE80211_IFACE_ITER_RESUME_ALL,
+				mt7915_vif_counts, &counts);
+			if (counts.ap + counts.adhoc + counts.mesh)
+				mt7915_dfs_start_radar_detector(phy);
+			return 0;
+		}
 		return mt7915_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy,
 					  MT_RX_SEL0, 0);
 	}
Signature · 1 line
2.20.1
#1 lore raw

PATCH v3 2/2 mt76: mt7915: fix radar detector logic

From: Ben Greear <[email protected]>

Before this patch, if AP went from ch 100 to ch 36, the radar detector logic in the firmware was not being disabled. This made the AP appear to be up, but no beacons were seen on air until module reload or reboot.

To reproduce this, I change hostapd.conf and restart hostapd. Others on openwrt used their UI to make changes and problem was seen, but stil others changed channels in some other way and/or had some other difference and could *not* reproduce it. So, something perhaps a bit subtle.

To fix the problem, stop depending on comparing dfs_state, store last freq/bandwidth to detect changes in that, and streamline code that checks to enable/disable radar detection. And add in error checking and dev_dbg logic so one can see what is actually happening if need to debug this again.

---
 .../net/wireless/mediatek/mt76/mt7915/init.c  |   7 +-
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 102 ++++++++++++------
 .../net/wireless/mediatek/mt76/mt7915/main.c  |  23 +++-
 .../wireless/mediatek/mt76/mt7915/mt7915.h    |   6 +-
 4 files changed, 100 insertions(+), 38 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/init.c +5 -2
index f46ea989a348..543bb1e947e3 100644
@@ -205,6 +205,7 @@ mt7915_regd_notifier(struct wiphy *wiphy,
 	struct mt76_phy *mphy = hw->priv;
 	struct mt7915_phy *phy = mphy->priv;
 	struct cfg80211_chan_def *chandef = &mphy->chandef;
+	int ret;
 
 	memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
 	dev->mt76.region = request->dfs_region;
@@ -215,7 +216,10 @@ mt7915_regd_notifier(struct wiphy *wiphy,
 	if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
 		return;
 
-	mt7915_dfs_init_radar_detector(phy);
+	ret = mt7915_dfs_init_radar_detector(phy);
+	if (ret < 0)
+		dev_err(dev->mt76.dev, "init-wifi: dfs-init-radar-detector failed: %d",
+			ret);
 }
 
 static void
@@ -832,7 +836,6 @@ int mt7915_register_device(struct mt7915_dev *dev)
 
 	dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
 	dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
-	dev->phy.dfs_state = -1;
 
 #ifdef CONFIG_NL80211_TESTMODE
 	dev->mt76.test_ops = &mt7915_testmode_ops;
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +71 -31

142 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt7915/main.c +20 -3
index f3df5ea066a2..6bffddb63461 100644
@@ -298,6 +298,8 @@ static void mt7915_init_dfs_state(struct mt7915_phy *phy)
 	struct mt76_phy *mphy = phy->mt76;
 	struct ieee80211_hw *hw = mphy->hw;
 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
+	struct mt7915_dev *dev = phy->dev;
+	bool ext_phy = phy != &dev->phy;
 
 	if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
 		return;
@@ -305,11 +307,23 @@ static void mt7915_init_dfs_state(struct mt7915_phy *phy)
 	if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
 		return;
 
-	if (mphy->chandef.chan->center_freq == chandef->chan->center_freq &&
-	    mphy->chandef.width == chandef->width)
+	if (phy->dfs_center_freq == chandef->chan->center_freq &&
+	    phy->dfs_ch_width == chandef->width)
 		return;
 
-	phy->dfs_state = -1;
+	/* We are being moved to a new frequency/bw, still on DFS.  Stop
+	 * any existing DFS, then will start it again in the
+	 * init-radar-detector logic.
+	 */
+	if (phy->rdd_state) {
+		dev_dbg(dev->mt76.dev,
+			"init-dfs-state, channel changed, old: %d:%d  new: %d:%d, stopping radar.",
+			phy->dfs_center_freq, phy->dfs_ch_width,
+			chandef->chan->center_freq, chandef->width);
+		mt7915_dfs_stop_radar_detector(phy, ext_phy);
+	}
+	phy->dfs_center_freq = chandef->chan->center_freq;
+	phy->dfs_ch_width = chandef->width;
 }
 
 int mt7915_set_channel(struct mt7915_phy *phy)
@@ -337,6 +351,9 @@ int mt7915_set_channel(struct mt7915_phy *phy)
 
 	mt7915_mac_set_timing(phy);
 	ret = mt7915_dfs_init_radar_detector(phy);
+	if (ret < 0)
+		dev_err(dev->mt76.dev, "set-channel: dfs-init-radar-detector failed: %d",
+			ret);
 	mt7915_mac_cca_stats_reset(phy);
 
 	mt7915_mac_reset_counters(phy);
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +4 -2
index f46816cefa3f..a9f55748cf1e 100644
@@ -284,8 +284,9 @@ struct mt7915_phy {
 	s16 coverage_class;
 	u8 slottime;
 
-	u8 rdd_state;
-	int dfs_state;
+	u8 rdd_state; /* radar detection started bitfield */
+	enum nl80211_chan_width dfs_ch_width;
+	u32 dfs_center_freq;
 
 	u32 rx_ampdu_ts;
 	u32 ampdu_ref;
@@ -574,6 +575,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);
 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);
+int mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy, bool ext_phy);
 int mt7915_init_debugfs(struct mt7915_dev *dev);
 #ifdef CONFIG_MAC80211_DEBUGFS
 void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Signature · 1 line
2.20.1
author
#2 lore raw

Re: [PATCH v3 2/2] mt76: mt7915: fix radar detector logic

Quoted 13 lines · On 8/20/21 1:35 PM, [email protected] wrote:

From: Ben Greear <[email protected]>

Before this patch, if AP went from ch 100 to ch 36, the radar detector logic in the firmware was not being disabled. This made the AP appear to be up, but no beacons were seen on air until module reload or reboot.

To reproduce this, I change hostapd.conf and restart hostapd. Others on openwrt used their UI to make changes and problem was seen, but stil others changed channels in some other way and/or had some other difference and could *not* reproduce it. So, something perhaps a bit subtle.

Quoted 5 lines

To fix the problem, stop depending on comparing dfs_state, store last freq/bandwidth to detect changes in that, and streamline code that checks to enable/disable radar detection. And add in error checking and dev_dbg logic so one can see what is actually happening if need to debug this again.

Back when I was working on this, someone sent me an email or chat or something about some other way to do this that was simpler and just relied on mac80211 timers. But, I cannot find that email for the life of me.

In case you are reading, please resend! Evidently this 2/2 patch had some regression for someone so it is not acceptable upstream in current state...maybe the mac80211 option is best.

Thanks,
Ben

Signature · 2 lines
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com
#3 lore raw

Re: [PATCH v3 2/2] mt76: mt7915: fix radar detector logic

śr., 10 lis 2021 o 21:36 Ben Greear <[email protected]> napisał(a):

Quoted 25 lines · On 8/20/21 1:35 PM, [email protected] wrote:
Quoted 13 lines

From: Ben Greear <[email protected]>

Before this patch, if AP went from ch 100 to ch 36, the radar detector logic in the firmware was not being disabled. This made the AP appear to be up, but no beacons were seen on air until module reload or reboot.

To reproduce this, I change hostapd.conf and restart hostapd. Others on openwrt used their UI to make changes and problem was seen, but stil others changed channels in some other way and/or had some other difference and could *not* reproduce it. So, something perhaps a bit subtle.

Quoted 5 lines

To fix the problem, stop depending on comparing dfs_state, store last freq/bandwidth to detect changes in that, and streamline code that checks to enable/disable radar detection. And add in error checking and dev_dbg logic so one can see what is actually happening if need to debug this again.

Back when I was working on this, someone sent me an email or chat or something about some other way to do this that was simpler and just relied on mac80211 timers. But, I cannot find that email for the life of me.

Quoted 5 lines

In case you are reading, please resend! Evidently this 2/2 patch had some regression for someone so it is not acceptable upstream in current state...maybe the mac80211 option is best.

Thanks,

mt7615/mac.c +6 -6
@@ -2034,6 +2034,11 @@ static int mt7615_dfs_start_radar_detect
  phy->rdd_state |= BIT(1);
  }
 
+   /* end CAC - upper layer will care about it, lock tx, beacon setup */
+   err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy, MT_RX_SEL0, 0);
+   if (err < 0)
+       return err;
+
  return 0;
 }
 
@@ -2104,11 +2109,7 @@ int mt7615_dfs_init_radar_detector(struc
  phy->dfs_state = chandef->chan->dfs_state;
 
  if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
-   if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
-     return mt7615_dfs_start_radar_detector(phy);
-
-   return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy,
-   MT_RX_SEL0, 0);
+   return mt7615_dfs_start_radar_detector(phy);
  }
 
-- 

Janusz Dziedzic

#4 lore raw
In reply to [email protected]

pt., 20 sie 2021 o 22:37 <[email protected]> napisał(a):

Quoted 78 lines

From: Ben Greear <[email protected]>

Only AP, adhoc and mesh mode needs to check CAC.
Stations, in particular, do not need this check.

---
v3: Fix typo in SOB in 1/2, fix rebase typo in 2/2,
split long line in 2/2

 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 38 +++++++++++++++++--
 1 file changed, 35 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +35 -4
index 8747e452e114..a6e142d27b60 100644
@@ -2455,6 +2455,32 @@ static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy)
        return 0;
 }
 
+struct mt7915_vif_counts {
+       u32 mesh;
+       u32 adhoc;
+       u32 ap;
+};
+
+static void
+mt7915_vif_counts(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct mt7915_vif_counts *counts = priv;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_ADHOC:
+               counts->adhoc++;
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               counts->mesh++;
+               break;
+       case NL80211_IFTYPE_AP:
+               counts->ap++;
+               break;
+       default:
+               break;
+       }
+}
+
 static int
 mt7915_dfs_init_radar_specs(struct mt7915_phy *phy)
 {
@@ -2495,6 +2521,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
        struct mt7915_dev *dev = phy->dev;
        bool ext_phy = phy != &dev->phy;
        int err;
+       struct mt7915_vif_counts counts = {0};
 
        if (dev->mt76.region == NL80211_DFS_UNSET) {
                phy->dfs_state = -1;
@@ -2519,9 +2546,14 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
        phy->dfs_state = chandef->chan->dfs_state;
 
        if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
-               if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
-                       return mt7915_dfs_start_radar_detector(phy);
-
+               if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) {
+                       ieee80211_iterate_active_interfaces(phy->mt76->hw,
+                               IEEE80211_IFACE_ITER_RESUME_ALL,
+                               mt7915_vif_counts, &counts);
+                       if (counts.ap + counts.adhoc + counts.mesh)
+                               mt7915_dfs_start_radar_detector(phy);
+                       return 0;
+               }
                return mt7915_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy,
                                          MT_RX_SEL0, 0);
        }
--
Quoted 2 lines

2.20.1

This depends on spec interpretation - when we have multiple ifaces on the same radio/channel (STA + APs).
Maybe this is good time to start discussion about it - how we handle DFS and if we should improve.

Some vendors "derive" CAC from STA.
So, while STA don't need to run CAC and first VIF sta will be connected on DFS channel, assume don't need to run CAC for second, third ... AP VIF. Still required ISM (In service monitoring, radar detection if AP ifaces) but simple skip CAC. This simplify implementation a lot for multi-vif (STA+APs) case.

So, maybe we should/could add kconfig for that - CONFIG_DFS_DERIVE_STA_CAC. When set, we could simple set NL80211_DFS_AVAILABLE when STA will connect on DFS channel - then any other APs we will add on the same channel will not require CAC, radar detection still required.

Regarding STA connection on DFS channel, I agree - today MT76x have a bug for that (eg. single VIF station).
I have much older code and fix it simplest way I could.

mt7615/mac.c +6 -5
@@ -2034,6 +2034,11 @@ static int mt7615_dfs_start_radar_detect
  phy->rdd_state |= BIT(1);
  }
 
+   /* end CAC - upper layer will care about it, lock tx, beacon setup */
+   err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy, MT_RX_SEL0, 0);
+   if (err < 0)
+       return err;
+
  return 0;
 }
 
@@ -2104,11 +2109,7 @@ int mt7615_dfs_init_radar_detector(struc
  phy->dfs_state = chandef->chan->dfs_state;
 
  if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
-   if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
-     return mt7615_dfs_start_radar_detector(phy);
-
-   return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy,
-   MT_RX_SEL0, 0);
+   return mt7615_dfs_start_radar_detector(phy);
  }
 
 stop:

BR
Janusz

author
#5 lore raw
Quoted 94 lines · Janusz Dziedzic

pt., 20 sie 2021 o 22:37 <[email protected]> napisał(a):

Quoted 78 lines

From: Ben Greear <[email protected]>

Only AP, adhoc and mesh mode needs to check CAC.
Stations, in particular, do not need this check.

---
v3: Fix typo in SOB in 1/2, fix rebase typo in 2/2,
split long line in 2/2

  .../net/wireless/mediatek/mt76/mt7915/mac.c   | 38 +++++++++++++++++--
  1 file changed, 35 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +35 -4
index 8747e452e114..a6e142d27b60 100644
@@ -2455,6 +2455,32 @@ static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy)
         return 0;
  }
 
+struct mt7915_vif_counts {
+       u32 mesh;
+       u32 adhoc;
+       u32 ap;
+};
+
+static void
+mt7915_vif_counts(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct mt7915_vif_counts *counts = priv;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_ADHOC:
+               counts->adhoc++;
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               counts->mesh++;
+               break;
+       case NL80211_IFTYPE_AP:
+               counts->ap++;
+               break;
+       default:
+               break;
+       }
+}
+
  static int
  mt7915_dfs_init_radar_specs(struct mt7915_phy *phy)
  {
@@ -2495,6 +2521,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
         struct mt7915_dev *dev = phy->dev;
         bool ext_phy = phy != &dev->phy;
         int err;
+       struct mt7915_vif_counts counts = {0};
 
         if (dev->mt76.region == NL80211_DFS_UNSET) {
                 phy->dfs_state = -1;
@@ -2519,9 +2546,14 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
         phy->dfs_state = chandef->chan->dfs_state;
 
         if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
-               if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
-                       return mt7915_dfs_start_radar_detector(phy);
-
+               if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) {
+                       ieee80211_iterate_active_interfaces(phy->mt76->hw,
+                               IEEE80211_IFACE_ITER_RESUME_ALL,
+                               mt7915_vif_counts, &counts);
+                       if (counts.ap + counts.adhoc + counts.mesh)
+                               mt7915_dfs_start_radar_detector(phy);
+                       return 0;
+               }
                 return mt7915_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy,
                                           MT_RX_SEL0, 0);
         }
--
Quoted 2 lines

2.20.1

This depends on spec interpretation - when we have multiple ifaces on the same radio/channel (STA + APs).
Maybe this is good time to start discussion about it - how we handle DFS and if we should improve.

Some vendors "derive" CAC from STA.
So, while STA don't need to run CAC and first VIF sta will be connected on DFS channel, assume don't need to run CAC for second, third ... AP VIF. Still required ISM (In service monitoring, radar detection if AP ifaces) but simple skip CAC. This simplify implementation a lot for multi-vif (STA+APs) case.

Quoted 4 lines

So, maybe we should/could add kconfig for that - CONFIG_DFS_DERIVE_STA_CAC. When set, we could simple set NL80211_DFS_AVAILABLE when STA will connect on DFS channel - then any other APs we will add on the same channel will not require CAC, radar detection still required.

So this config option would mean 'I think CAC spec means I don't have to do CAC if station is already on this channel', with the understanding that this may actually be an incorrect interpretation? That seems like something that would not be acceptable upstream for good reasons.

Do you have any pointers to the specification(s) section(s) that apply to this?

Quoted 21 lines

Regarding STA connection on DFS channel, I agree - today MT76x have a bug for that (eg. single VIF station).
I have much older code and fix it simplest way I could.

mt7615/mac.c +5 -0
@@ -2034,6 +2034,11 @@ static int mt7615_dfs_start_radar_detect
   phy->rdd_state |= BIT(1);
   }
 
+   /* end CAC - upper layer will care about it, lock tx, beacon setup */
+   err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy, MT_RX_SEL0, 0);
+   if (err < 0)
+       return err;
+
   return 0;
  }
 
@@ -2104,11 +2109,7 @@ int mt7615_dfs_init_radar_detector(struc
   phy->dfs_state = chandef->chan->dfs_state;
 

mt7615/mac.c int mt7615_dfs_init_radar_detector(struc · line 2115

Quoted 10 lines
mt7615/mac.c +1 -5
   if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
-   if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
-     return mt7615_dfs_start_radar_detector(phy);
-
-   return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy,
-   MT_RX_SEL0, 0);
+   return mt7615_dfs_start_radar_detector(phy);
   }
 
  stop:

It would certainly be nice to simplify the code, but I don't know enough about the firmware/driver details to comment intelligently on this part.

Thanks,
Ben

Quoted 4 lines

BR
Janusz

Signature · 2 lines
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com