2022-06-24 19:19:16

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/4] mt76: mt7615: add sta_rec with EXTRA_INFO_NEW for the first time only

Set EXTRA_INFO_NEW for the first time only to prevent adding the same
starec entry, otherwise the entry might be removed in fw.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 9 ++++++++-
drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 +
2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 194e9ccd4a73..989b2a41b670 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -844,6 +844,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct mt7615_dev *dev = phy->dev;
struct wtbl_req_hdr *wtbl_hdr;
struct mt7615_sta *msta;
+ bool new_entry = true;
int cmd, err;

msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta;
@@ -853,7 +854,13 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
if (IS_ERR(sskb))
return PTR_ERR(sskb);

- mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, true);
+ if (!sta) {
+ if (mvif->sta_added)
+ new_entry = false;
+ else
+ mvif->sta_added = true;
+ }
+ mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, new_entry);
if (enable && sta)
mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
MT76_STA_INFO_STATE_ASSOC);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 653181905d09..8499cdc4bb0d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -141,6 +141,7 @@ struct mt7615_sta {
struct mt7615_vif {
struct mt76_vif mt76; /* must be first */
struct mt7615_sta sta;
+ bool sta_added;
};

struct mib_stats {
--
2.36.1


2022-06-24 19:19:40

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 3/4] mt76: allow receiving frames with invalid CCMP PN via monitor interfaces

This can be useful for debugging

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 24 ++++++++-----------
1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index ecf5bd9605db..cb41f54bdd1c 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -1018,7 +1018,7 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
*hw = mt76_phy_hw(dev, mstat.ext_phy);
}

-static int
+static void
mt76_check_ccmp_pn(struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
@@ -1028,13 +1028,13 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
int ret;

if (!(status->flag & RX_FLAG_DECRYPTED))
- return 0;
+ return;

if (status->flag & RX_FLAG_ONLY_MONITOR)
- return 0;
+ return;

if (!wcid || !wcid->rx_check_pn)
- return 0;
+ return;

security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
if (status->flag & RX_FLAG_8023)
@@ -1048,7 +1048,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
*/
if (ieee80211_is_frag(hdr) &&
!ieee80211_is_first_frag(hdr->frame_control))
- return 0;
+ return;
}

/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
@@ -1065,15 +1065,15 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
sizeof(status->iv));
- if (ret <= 0)
- return -EINVAL; /* replay */
+ if (ret <= 0) {
+ status->flag |= RX_FLAG_ONLY_MONITOR;
+ return;
+ }

memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));

if (status->flag & RX_FLAG_IV_STRIPPED)
status->flag |= RX_FLAG_PN_VALIDATED;
-
- return 0;
}

static void
@@ -1246,11 +1246,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
while ((skb = __skb_dequeue(frames)) != NULL) {
struct sk_buff *nskb = skb_shinfo(skb)->frag_list;

- if (mt76_check_ccmp_pn(skb)) {
- dev_kfree_skb(skb);
- continue;
- }
-
+ mt76_check_ccmp_pn(skb);
skb_shinfo(skb)->frag_list = NULL;
mt76_rx_convert(dev, skb, &hw, &sta);
ieee80211_rx_list(hw, sta, skb, &list);
--
2.36.1

2022-06-24 19:19:40

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/4] mt76: mt76x02: improve reliability of the beacon hang check

Increment the counter only when writing beacons to the hardware in order
to avoid triggering restarts if beacons are disabled.
Additionally, avoid resetting the MAC if stopping it failed

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c | 6 +++++-
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 11 ++++++++---
2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index b72510949877..ad4dc8e17b58 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -57,8 +57,11 @@ void mt76x02_mac_set_beacon(struct mt76x02_dev *dev,
int bcn_len = dev->beacon_ops->slot_size;
int bcn_addr = MT_BEACON_BASE + (bcn_len * dev->beacon_data_count);

- if (!mt76x02_write_beacon(dev, bcn_addr, skb))
+ if (!mt76x02_write_beacon(dev, bcn_addr, skb)) {
+ if (!dev->beacon_data_count)
+ dev->beacon_hang_check++;
dev->beacon_data_count++;
+ }
dev_kfree_skb(skb);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);
@@ -74,6 +77,7 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
if (!dev->mt76.beacon_mask)
dev->tbtt_count = 0;

+ dev->beacon_hang_check = 0;
if (enable) {
dev->mt76.beacon_mask |= BIT(mvif->idx);
} else {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index cf4d4110cc99..de30cf5e2d2f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -1044,10 +1044,9 @@ static void mt76x02_check_mac_err(struct mt76x02_dev *dev)
return;
}

- if (++dev->beacon_hang_check < 10)
+ if (dev->beacon_hang_check < 10)
return;

- dev->beacon_hang_check = 0;
} else {
u32 val = mt76_rr(dev, 0x10f4);
if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
@@ -1057,10 +1056,16 @@ static void mt76x02_check_mac_err(struct mt76x02_dev *dev)
dev_err(dev->mt76.dev, "MAC error detected\n");

mt76_wr(dev, MT_MAC_SYS_CTRL, 0);
- mt76x02_wait_for_txrx_idle(&dev->mt76);
+ if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) {
+ dev_err(dev->mt76.dev, "MAC stop failed\n");
+ goto out;
+ }

+ dev->beacon_hang_check = 0;
mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
udelay(10);
+
+out:
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
}
--
2.36.1

2022-06-24 19:20:02

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 4/4] mt76: mt7615: fix throughput regression on DFS channels

For some reason, mt7615 reacts badly to repeatedly enabling/disabling the radar
detector without also switching the channel.
This results in very bad throughput on DFS channels, because
hw->conf.radar_enabled can get toggled a few times after CAC ends.
Fix this by always leaving the DFS detector enabled on DFS channels and instead
suppress unwanted detection events.

Fixes: 2c86f6752046 ("mt76: mt7615: fix/rewrite the dfs state handling logic")
Signed-off-by: Felix Fietkau <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7615/mac.c | 7 ++++---
.../net/wireless/mediatek/mt76/mt7615/main.c | 21 -------------------
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 3 +++
.../wireless/mediatek/mt76/mt7615/mt7615.h | 1 -
4 files changed, 7 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index d9dd3d404986..038774b3ced0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -2231,6 +2231,7 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy)

int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy)
{
+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
struct mt7615_dev *dev = phy->dev;
bool ext_phy = phy != &dev->phy;
enum mt76_dfs_state dfs_state, prev_state;
@@ -2241,13 +2242,13 @@ int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy)

prev_state = phy->mt76->dfs_state;
dfs_state = mt76_phy_dfs_state(phy->mt76);
+ if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
+ dfs_state < MT_DFS_STATE_CAC)
+ dfs_state = MT_DFS_STATE_ACTIVE;

if (prev_state == dfs_state)
return 0;

- if (prev_state == MT_DFS_STATE_UNKNOWN)
- mt7615_dfs_stop_radar_detector(phy);
-
if (dfs_state == MT_DFS_STATE_DISABLED)
goto stop;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 277c22a4d049..28bc76c8e8e7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -282,26 +282,6 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid);
}

-static void mt7615_init_dfs_state(struct mt7615_phy *phy)
-{
- struct mt76_phy *mphy = phy->mt76;
- struct ieee80211_hw *hw = mphy->hw;
- struct cfg80211_chan_def *chandef = &hw->conf.chandef;
-
- if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
- return;
-
- if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
- !(mphy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
- return;
-
- if (mphy->chandef.chan->center_freq == chandef->chan->center_freq &&
- mphy->chandef.width == chandef->width)
- return;
-
- phy->dfs_state = -1;
-}
-
int mt7615_set_channel(struct mt7615_phy *phy)
{
struct mt7615_dev *dev = phy->dev;
@@ -314,7 +294,6 @@ int mt7615_set_channel(struct mt7615_phy *phy)

set_bit(MT76_RESET, &phy->mt76->state);

- mt7615_init_dfs_state(phy);
mt76_set_channel(phy->mt76);

if (is_mt7615(&dev->mt76) && dev->flash_eeprom) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 989b2a41b670..3d35381013f1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -391,6 +391,9 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)
if (r->band_idx && dev->mt76.phy2)
mphy = dev->mt76.phy2;

+ if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC)
+ return;
+
ieee80211_radar_detected(mphy->hw);
dev->hw_pattern++;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 8499cdc4bb0d..93a9e8f46193 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -178,7 +178,6 @@ struct mt7615_phy {

u8 chfreq;
u8 rdd_state;
- int dfs_state;

u32 rx_ampdu_ts;
u32 ampdu_ref;
--
2.36.1