2019-02-07 13:47:33

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/7] mt76: fix software encryption issues

Software encrypted packets can be passed not just through the drv_tx callback,
but also through the intermediate tx queue.
In order to deal with that, move the override to mt76x02_mac_write_txwi and
also take care of filling in the per-packet rate information

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 7 +++++++
drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c | 9 +--------
2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 2dc80ea26752..6bd7f87644a4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -291,6 +291,13 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,

memset(txwi, 0, sizeof(*txwi));

+ if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff &&
+ ieee80211_has_protected(hdr->frame_control)) {
+ wcid = NULL;
+ ieee80211_get_tx_rates(info->control.vif, sta, skb,
+ info->control.rates, 1);
+ }
+
if (wcid)
txwi->wcid = wcid->idx;
else
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
index 7861a832940b..94f47248c59f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
@@ -22,7 +22,6 @@
void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct mt76x02_dev *dev = hw->priv;
struct ieee80211_vif *vif = info->control.vif;
@@ -33,13 +32,7 @@ void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,

msta = (struct mt76x02_sta *)control->sta->drv_priv;
wcid = &msta->wcid;
- /* sw encrypted frames */
- if (!info->control.hw_key && wcid->hw_key_idx != 0xff &&
- ieee80211_has_protected(hdr->frame_control))
- control->sta = NULL;
- }
-
- if (vif && !control->sta) {
+ } else if (vif) {
struct mt76x02_vif *mvif;

mvif = (struct mt76x02_vif *)vif->drv_priv;
--
2.17.0



2019-02-07 13:47:29

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 6/7] mt76: measure the time between mt76x02_edcca_check runs

Based on system load and time needed by other calibration runs, the time
between dev->mac_work runs can vary quite a bit.
Calculate busy time based on the actual time difference in order to avoid
potentially over-estimating busy time, which could lead to unnecessary tx
blocking.

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

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 7e405297028f..3464b4ca2ea8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -117,6 +117,7 @@ struct mt76x02_dev {
bool ed_monitor;
u8 ed_trigger;
u8 ed_silent;
+ ktime_t ed_time;
};

extern struct ieee80211_rate mt76x02_rates[12];
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index aecf514bb89b..462ac030c08a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -922,6 +922,7 @@ void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable)

/* clear previous CCA timer value */
mt76_rr(dev, MT_ED_CCA_TIMER);
+ dev->ed_time = ktime_get_boottime();
}
EXPORT_SYMBOL_GPL(mt76x02_edcca_init);

@@ -929,10 +930,16 @@ EXPORT_SYMBOL_GPL(mt76x02_edcca_init);
#define MT_EDCCA_BLOCK_TH 2
static void mt76x02_edcca_check(struct mt76x02_dev *dev)
{
- u32 val, busy;
+ ktime_t cur_time;
+ u32 active, val, busy;

+ cur_time = ktime_get_boottime();
val = mt76_rr(dev, MT_ED_CCA_TIMER);
- busy = (val * 100) / jiffies_to_usecs(MT_MAC_WORK_INTERVAL);
+
+ active = ktime_to_us(ktime_sub(cur_time, dev->ed_time));
+ dev->ed_time = cur_time;
+
+ busy = (val * 100) / active;
busy = min_t(u32, busy, 100);

if (busy > MT_EDCCA_TH) {
--
2.17.0


2019-02-07 13:47:34

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 4/7] mt76: run MAC work every 100ms

ED/CCA Tx blocking checks need to be run every 100 ms in order to avoid
triggering too late and keeping tx blocking on for too long

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 +
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 ++--
drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 2 +-
6 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index 1472c8699b29..6992b3d7dfec 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -30,7 +30,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw)
mt76x02_mac_start(dev);
mt76x0_phy_calibrate(dev, true);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
- MT_CALIBRATE_INTERVAL);
+ MT_MAC_WORK_INTERVAL);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL);
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index f66e1b2f0980..a271d81c3338 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -118,7 +118,7 @@ static int mt76x0u_start(struct ieee80211_hw *hw)

mt76x0_phy_calibrate(dev, true);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
- MT_CALIBRATE_INTERVAL);
+ MT_MAC_WORK_INTERVAL);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL);
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 6d9d9ddacc32..7e405297028f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -27,6 +27,7 @@
#include "mt76x02_dma.h"

#define MT_CALIBRATE_INTERVAL HZ
+#define MT_MAC_WORK_INTERVAL (HZ / 10)

#define MT_WATCHDOG_TIME (HZ / 10)
#define MT_TX_HANG_TH 10
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 636e69a7a407..89c7368cbd52 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -929,7 +929,7 @@ static void mt76x02_edcca_check(struct mt76x02_dev *dev)
u32 val, busy;

val = mt76_rr(dev, MT_ED_CCA_TIMER);
- busy = (val * 100) / jiffies_to_usecs(MT_CALIBRATE_INTERVAL);
+ busy = (val * 100) / jiffies_to_usecs(MT_MAC_WORK_INTERVAL);
busy = min_t(u32, busy, 100);

if (busy > MT_EDCCA_TH) {
@@ -975,7 +975,7 @@ void mt76x02_mac_work(struct work_struct *work)
mt76_tx_status_check(&dev->mt76, NULL, false);

ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work,
- MT_CALIBRATE_INTERVAL);
+ MT_MAC_WORK_INTERVAL);
}

void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
index 06a26a152ba4..878ce92405ed 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
@@ -33,7 +33,7 @@ mt76x2_start(struct ieee80211_hw *hw)
goto out;

ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work,
- MT_CALIBRATE_INTERVAL);
+ MT_MAC_WORK_INTERVAL);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work,
MT_WATCHDOG_TIME);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
index 5256c6f879a7..10633b8de8e8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -28,7 +28,7 @@ static int mt76x2u_start(struct ieee80211_hw *hw)
goto out;

ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work,
- MT_CALIBRATE_INTERVAL);
+ MT_MAC_WORK_INTERVAL);
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);

out:
--
2.17.0


2019-02-07 13:47:34

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 7/7] mt76: increase ED/CCA tx block threshold

Block only when the busy time reaches 92%, as lower values can be reached with
heavy 802.11 traffic as well.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 462ac030c08a..bf39624c9b98 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -926,7 +926,7 @@ void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable)
}
EXPORT_SYMBOL_GPL(mt76x02_edcca_init);

-#define MT_EDCCA_TH 90
+#define MT_EDCCA_TH 92
#define MT_EDCCA_BLOCK_TH 2
static void mt76x02_edcca_check(struct mt76x02_dev *dev)
{
--
2.17.0


2019-02-07 13:47:37

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/7] mt76: mt76x2: avoid running DPD calibration if tx is blocked

Doing so could lead to hangs

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x2/phy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c
index e2ee5e498da7..1848e8ab2e21 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c
@@ -241,7 +241,7 @@ void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev)
t.offset1 = txp.chain[1].tssi_offset;
mt76x2_mcu_tssi_comp(dev, &t);

- if (t.pa_mode || dev->cal.dpd_cal_done)
+ if (t.pa_mode || dev->cal.dpd_cal_done || dev->ed_tx_blocked)
return;

usleep_range(10000, 20000);
--
2.17.0


2019-02-07 13:47:37

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 5/7] mt76: clear CCA timer stats in mt76x02_edcca_init

Avoid triggering too early

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

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 89c7368cbd52..aecf514bb89b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -919,6 +919,9 @@ void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable)
}
}
mt76x02_edcca_tx_enable(dev, true);
+
+ /* clear previous CCA timer value */
+ mt76_rr(dev, MT_ED_CCA_TIMER);
}
EXPORT_SYMBOL_GPL(mt76x02_edcca_init);

--
2.17.0


2019-02-07 13:47:39

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 3/7] mt76: explicitly disable energy detect cca during scan

Avoid reusing the previous channel's tx blocking state

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 6 ++++--
drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 ++--
drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +-
drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c | 6 ++++--
5 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index 5a4c6f34267e..66b22bd7b4b4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -1006,14 +1006,16 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev,

/* enable vco */
mt76x0_rf_set(dev, MT_RF(0, 4), BIT(7));
- if (scan)
+ if (scan) {
+ mt76x02_edcca_init(dev, false);
return 0;
+ }

mt76x02_init_agc_gain(dev);
mt76x0_phy_calibrate(dev, false);
mt76x0_phy_set_txpower(dev);

- mt76x02_edcca_init(dev);
+ mt76x02_edcca_init(dev, true);

ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
index 19fdcab746a0..e4649103efd4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
@@ -886,7 +886,7 @@ mt76x02_dfs_set_domain(struct mt76x02_dev *dev,
tasklet_disable(&dfs_pd->dfs_tasklet);

dev->ed_monitor = region == NL80211_DFS_ETSI;
- mt76x02_edcca_init(dev);
+ mt76x02_edcca_init(dev, true);

dfs_pd->region = region;
mt76x02_dfs_init_params(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 6bd7f87644a4..636e69a7a407 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -891,12 +891,12 @@ mt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable)
dev->ed_tx_blocked = !enable;
}

-void mt76x02_edcca_init(struct mt76x02_dev *dev)
+void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable)
{
dev->ed_trigger = 0;
dev->ed_silent = 0;

- if (dev->ed_monitor) {
+ if (dev->ed_monitor && enable) {
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20;

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
index 3b04b1bd0abd..6b1f25d2f64c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
@@ -207,5 +207,5 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
struct ieee80211_vif *vif, bool val);

-void mt76x02_edcca_init(struct mt76x02_dev *dev);
+void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
index 65ed62229a5b..97ec575699d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
@@ -240,8 +240,10 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev,
mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070);
mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x04101B3F);

- if (scan)
+ if (scan) {
+ mt76x02_edcca_init(dev, false);
return 0;
+ }

mt76x2_phy_channel_calibrate(dev, true);
mt76x02_init_agc_gain(dev);
@@ -254,7 +256,7 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev,
0x38);
}

- mt76x02_edcca_init(dev);
+ mt76x02_edcca_init(dev, true);

ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work,
MT_CALIBRATE_INTERVAL);
--
2.17.0