linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/9] mt76: fix beacon timer drift
@ 2018-06-21  9:17 Felix Fietkau
  2018-06-21  9:17 ` [PATCH 2/9] mt76: fix threshold for gain adjustment Felix Fietkau
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:17 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

The beacon timer drifts by 1 microsecond every TBTT. After 20 minutes
with a beacon interval of 100, the drift will be almost 12 ms, enough to
cause weird issues for devices in powersave mode.

Since the beacon timer is configured in units of 1/16 TU (64 us), we
need to adjust it once every 64 beacons and only for one beacon.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2.h   |  5 ++-
 .../net/wireless/mediatek/mt76/mt76x2_main.c  |  5 ++-
 .../net/wireless/mediatek/mt76/mt76x2_tx.c    | 33 +++++++++++++++++++
 3 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h
index dc12bbdbb2ee..06ca5a77dfdf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h
@@ -120,10 +120,13 @@ struct mt76x2_dev {
 	u8 beacon_mask;
 	u8 beacon_data_mask;
 
-	u32 rxfilter;
+	u8 tbtt_count;
+	u16 beacon_int;
 
 	u16 chainmask;
 
+	u32 rxfilter;
+
 	struct mt76x2_calibration cal;
 
 	s8 target_power;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
index ce90ff999b49..e4e41faf6739 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
@@ -238,10 +238,13 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	if (changed & BSS_CHANGED_BSSID)
 		mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid);
 
-	if (changed & BSS_CHANGED_BEACON_INT)
+	if (changed & BSS_CHANGED_BEACON_INT) {
 		mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
 			       MT_BEACON_TIME_CFG_INTVAL,
 			       info->beacon_int << 4);
+		dev->beacon_int = info->beacon_int;
+		dev->tbtt_count = 0;
+	}
 
 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
 		tasklet_disable(&dev->pre_tbtt_tasklet);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c
index e46eafc4c436..560376dd1133 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c
@@ -218,6 +218,37 @@ mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
 	data->tail[mvif->idx] = skb;
 }
 
+static void
+mt76x2_resync_beacon_timer(struct mt76x2_dev *dev)
+{
+	u32 timer_val = dev->beacon_int << 4;
+
+	dev->tbtt_count++;
+
+	/*
+	 * Beacon timer drifts by 1us every tick, the timer is configured
+	 * in 1/16 TU (64us) units.
+	 */
+	if (dev->tbtt_count < 62)
+		return;
+
+	if (dev->tbtt_count >= 64) {
+		dev->tbtt_count = 0;
+		return;
+	}
+
+	/*
+	 * The updated beacon interval takes effect after two TBTT, because
+	 * at this point the original interval has already been loaded into
+	 * the next TBTT_TIMER value
+	 */
+	if (dev->tbtt_count == 62)
+		timer_val -= 1;
+
+	mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
+		       MT_BEACON_TIME_CFG_INTVAL, timer_val);
+}
+
 void mt76x2_pre_tbtt_tasklet(unsigned long arg)
 {
 	struct mt76x2_dev *dev = (struct mt76x2_dev *) arg;
@@ -226,6 +257,8 @@ void mt76x2_pre_tbtt_tasklet(unsigned long arg)
 	struct sk_buff *skb;
 	int i, nframes;
 
+	mt76x2_resync_beacon_timer(dev);
+
 	data.dev = dev;
 	__skb_queue_head_init(&data.q);
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/9] mt76: fix threshold for gain adjustment
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
@ 2018-06-21  9:17 ` Felix Fietkau
  2018-06-21  9:17 ` [PATCH 3/9] mt76: fix swapped values for RXO-18 in gain control Felix Fietkau
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:17 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

The gain should be reduced only for very strong connections, not for mid
range.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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 c1c38ca3330a..4ed6641c3a32 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -530,7 +530,7 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 	else
 		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423);
 
-	if (low_gain) {
+	if (low_gain == 2) {
 		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991);
 		mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808);
 		mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808);
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/9] mt76: fix swapped values for RXO-18 in gain control
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
  2018-06-21  9:17 ` [PATCH 2/9] mt76: fix threshold for gain adjustment Felix Fietkau
@ 2018-06-21  9:17 ` Felix Fietkau
  2018-06-21  9:17 ` [PATCH 4/9] mt76: adjust AGC control register 26 based on gain for VHT80 Felix Fietkau
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:17 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

The lowest bit should be set to 0 only for strong links, not for weak
ones.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
index 4ed6641c3a32..a510f116d52a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -531,7 +531,7 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423);
 
 	if (low_gain == 2) {
-		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991);
+		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990);
 		mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808);
 		mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808);
 		if (mt76x2_has_ext_lna(dev))
@@ -539,7 +539,7 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 		else
 			gain_delta = 14;
 	} else {
-		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990);
+		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991);
 		if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80)
 			mt76_wr(dev, MT_BBP(AGC, 35), 0x10101014);
 		else
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/9] mt76: adjust AGC control register 26 based on gain for VHT80
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
  2018-06-21  9:17 ` [PATCH 2/9] mt76: fix threshold for gain adjustment Felix Fietkau
  2018-06-21  9:17 ` [PATCH 3/9] mt76: fix swapped values for RXO-18 in gain control Felix Fietkau
@ 2018-06-21  9:17 ` Felix Fietkau
  2018-06-21  9:17 ` [PATCH 5/9] mt76: clear false CCA counters after changing gain settings Felix Fietkau
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:17 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

Use values based on the vendor driver

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
index a510f116d52a..a2c3f0e35f86 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -525,10 +525,17 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 
 	dev->cal.low_gain = low_gain;
 
-	if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80)
+	if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) {
 		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211);
-	else
+		val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf;
+		if (low_gain == 2)
+			val |= 0x3;
+		else
+			val |= 0x5;
+		mt76_wr(dev, MT_BBP(AGC, 26), val);
+	} else {
 		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423);
+	}
 
 	if (low_gain == 2) {
 		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990);
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/9] mt76: clear false CCA counters after changing gain settings
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
                   ` (2 preceding siblings ...)
  2018-06-21  9:17 ` [PATCH 4/9] mt76: adjust AGC control register 26 based on gain for VHT80 Felix Fietkau
@ 2018-06-21  9:17 ` Felix Fietkau
  2018-06-21  9:17 ` [PATCH 6/9] mt76: fix variable gain adjustment range Felix Fietkau
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:17 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

They will be read on the next calibration step without gain change and
must not count earlier events

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
index a2c3f0e35f86..51fd7ddfa8f5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -559,6 +559,9 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 	dev->cal.agc_gain_cur[1] = gain[1] - gain_delta;
 	dev->cal.agc_gain_adjust = 0;
 	mt76x2_phy_set_gain_val(dev);
+
+	/* clear false CCA counters */
+	mt76_rr(dev, MT_RX_STAT_1);
 }
 
 int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/9] mt76: fix variable gain adjustment range
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
                   ` (3 preceding siblings ...)
  2018-06-21  9:17 ` [PATCH 5/9] mt76: clear false CCA counters after changing gain settings Felix Fietkau
@ 2018-06-21  9:17 ` Felix Fietkau
  2018-06-21  9:17 ` [PATCH 7/9] mt76: add a debugfs file to dump agc calibration information Felix Fietkau
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:17 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

The range should only be limited to 4 for really weak signals, for all
other gain settings the range is 16.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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 51fd7ddfa8f5..9c7b19ce73f2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -485,7 +485,7 @@ static void
 mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev)
 {
 	u32 false_cca;
-	u8 limit = dev->cal.low_gain > 1 ? 4 : 16;
+	u8 limit = dev->cal.low_gain > 0 ? 16 : 4;
 
 	false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1));
 	if (false_cca > 800 && dev->cal.agc_gain_adjust < limit)
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/9] mt76: add a debugfs file to dump agc calibration information
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
                   ` (4 preceding siblings ...)
  2018-06-21  9:17 ` [PATCH 6/9] mt76: fix variable gain adjustment range Felix Fietkau
@ 2018-06-21  9:17 ` Felix Fietkau
  2018-06-21  9:18 ` [PATCH 8/9] mt76: track ewma rssi for gain adjustment per station Felix Fietkau
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:17 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

Useful for debugging gain adjustment issues triggered by signal strength
changes.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2.h        |  1 +
 .../net/wireless/mediatek/mt76/mt76x2_debugfs.c    | 14 ++++++++++++++
 drivers/net/wireless/mediatek/mt76/mt76x2_phy.c    |  1 +
 3 files changed, 16 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h
index 06ca5a77dfdf..21de1168076d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h
@@ -72,6 +72,7 @@ struct mt76x2_calibration {
 	int avg_rssi[MT_MAX_CHAINS];
 	int avg_rssi_all;
 
+	u16 false_cca;
 	s8 agc_gain_adjust;
 	s8 low_gain;
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c
index 955ea3e692dd..3f86e01049f3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c
@@ -115,6 +115,18 @@ static const struct file_operations fops_dfs_stat = {
 	.release = single_release,
 };
 
+static int read_agc(struct seq_file *file, void *data)
+{
+	struct mt76x2_dev *dev = dev_get_drvdata(file->private);
+
+	seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all);
+	seq_printf(file, "low_gain: %d\n", dev->cal.low_gain);
+	seq_printf(file, "false_cca: %d\n", dev->cal.false_cca);
+	seq_printf(file, "agc_gain_adjust: %d\n", dev->cal.agc_gain_adjust);
+
+	return 0;
+}
+
 void mt76x2_init_debugfs(struct mt76x2_dev *dev)
 {
 	struct dentry *dir;
@@ -130,4 +142,6 @@ void mt76x2_init_debugfs(struct mt76x2_dev *dev)
 	debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat);
 	debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir,
 				    read_txpower);
+
+	debugfs_create_devm_seqfile(dev->mt76.dev, "agc", dir, read_agc);
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
index 9c7b19ce73f2..94943aeb249d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -488,6 +488,7 @@ mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev)
 	u8 limit = dev->cal.low_gain > 0 ? 16 : 4;
 
 	false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1));
+	dev->cal.false_cca = false_cca;
 	if (false_cca > 800 && dev->cal.agc_gain_adjust < limit)
 		dev->cal.agc_gain_adjust += 2;
 	else if (false_cca < 10 && dev->cal.agc_gain_adjust > 0)
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/9] mt76: track ewma rssi for gain adjustment per station
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
                   ` (5 preceding siblings ...)
  2018-06-21  9:17 ` [PATCH 7/9] mt76: add a debugfs file to dump agc calibration information Felix Fietkau
@ 2018-06-21  9:18 ` Felix Fietkau
  2018-06-21  9:18 ` [PATCH 9/9] mt76: improve gain adjustment in noisy environments Felix Fietkau
  2018-06-27 16:16 ` [1/9] mt76: fix beacon timer drift Kalle Valo
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

This preserves more sensitivity when weak stations are active and avoids
counting signal measurements from other unrelated networks

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/mt76x2.h   | 10 +++-
 .../net/wireless/mediatek/mt76/mt76x2_mac.c   | 33 ++++++++---
 .../net/wireless/mediatek/mt76/mt76x2_main.c  |  2 +
 .../net/wireless/mediatek/mt76/mt76x2_phy.c   | 58 ++++++++++++++++---
 4 files changed, 83 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h
index 21de1168076d..71fcfa44fb2e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h
@@ -27,6 +27,7 @@
 #include <linux/mutex.h>
 #include <linux/bitops.h>
 #include <linux/kfifo.h>
+#include <linux/average.h>
 
 #define MT7662_FIRMWARE		"mt7662.bin"
 #define MT7662_ROM_PATCH	"mt7662_rom_patch.bin"
@@ -47,6 +48,8 @@
 #include "mt76x2_mac.h"
 #include "mt76x2_dfs.h"
 
+DECLARE_EWMA(signal, 10, 8)
+
 struct mt76x2_mcu {
 	struct mutex mutex;
 
@@ -69,10 +72,8 @@ struct mt76x2_calibration {
 	u8 agc_gain_init[MT_MAX_CHAINS];
 	u8 agc_gain_cur[MT_MAX_CHAINS];
 
-	int avg_rssi[MT_MAX_CHAINS];
-	int avg_rssi_all;
-
 	u16 false_cca;
+	s8 avg_rssi_all;
 	s8 agc_gain_adjust;
 	s8 low_gain;
 
@@ -153,6 +154,9 @@ struct mt76x2_sta {
 	struct mt76x2_vif *vif;
 	struct mt76x2_tx_status status;
 	int n_frames;
+
+	struct ewma_signal rssi;
+	int inactive_count;
 };
 
 static inline bool is_mt7612(struct mt76x2_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
index b49aea4da2d6..f34b4d6413e3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
@@ -269,21 +269,31 @@ static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len)
 	skb_pull(skb, len);
 }
 
-static struct mt76_wcid *
-mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, u8 idx, bool unicast)
+static struct mt76x2_sta *
+mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx)
 {
-	struct mt76x2_sta *sta;
 	struct mt76_wcid *wcid;
 
 	if (idx >= ARRAY_SIZE(dev->wcid))
 		return NULL;
 
 	wcid = rcu_dereference(dev->wcid[idx]);
-	if (unicast || !wcid)
-		return wcid;
+	if (!wcid)
+		return NULL;
 
-	sta = container_of(wcid, struct mt76x2_sta, wcid);
-	return &sta->vif->group_wcid;
+	return container_of(wcid, struct mt76x2_sta, wcid);
+}
+
+static struct mt76_wcid *
+mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x2_sta *sta, bool unicast)
+{
+	if (!sta)
+		return NULL;
+
+	if (unicast)
+		return &sta->wcid;
+	else
+		return &sta->vif->group_wcid;
 }
 
 int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
@@ -291,6 +301,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
 {
 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
 	struct mt76x2_rxwi *rxwi = rxi;
+	struct mt76x2_sta *sta;
 	u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
 	u32 ctl = le32_to_cpu(rxwi->ctl);
 	u16 rate = le16_to_cpu(rxwi->rate);
@@ -315,7 +326,8 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
 	}
 
 	wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
-	status->wcid = mt76x2_rx_get_sta_wcid(dev, wcid, unicast);
+	sta = mt76x2_rx_get_sta(dev, wcid);
+	status->wcid = mt76x2_rx_get_sta_wcid(dev, sta, unicast);
 
 	len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
 	pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
@@ -361,6 +373,11 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
 	status->tid = FIELD_GET(MT_RXWI_TID, tid_sn);
 	status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn);
 
+	if (sta) {
+		ewma_signal_add(&sta->rssi, status->signal);
+		sta->inactive_count = 0;
+	}
+
 	return mt76x2_mac_process_rate(status, rate);
 }
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
index e4e41faf6739..3c0ebe6d231c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
@@ -294,6 +294,8 @@ mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	if (vif->type == NL80211_IFTYPE_AP)
 		set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
 
+	ewma_signal_init(&msta->rssi);
+
 	rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
 
 out:
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
index 94943aeb249d..14aedc3ef731 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -499,22 +499,62 @@ mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev)
 	mt76x2_phy_set_gain_val(dev);
 }
 
+static int
+mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev)
+{
+	struct mt76x2_sta *sta;
+	struct mt76_wcid *wcid;
+	int i, j, min_rssi = 0;
+	s8 cur_rssi;
+
+	local_bh_disable();
+	rcu_read_lock();
+
+	for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
+		unsigned long mask = dev->wcid_mask[i];
+
+		if (!mask)
+			continue;
+
+		for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) {
+			if (!(mask & 1))
+				continue;
+
+			wcid = rcu_dereference(dev->wcid[j]);
+			if (!wcid)
+				continue;
+
+			sta = container_of(wcid, struct mt76x2_sta, wcid);
+			spin_lock(&dev->mt76.rx_lock);
+			if (sta->inactive_count++ < 5)
+				cur_rssi = ewma_signal_read(&sta->rssi);
+			else
+				cur_rssi = 0;
+			spin_unlock(&dev->mt76.rx_lock);
+
+			if (cur_rssi < min_rssi)
+				min_rssi = cur_rssi;
+		}
+	}
+
+	rcu_read_unlock();
+	local_bh_enable();
+
+	if (!min_rssi)
+		return -75;
+
+	return min_rssi;
+}
+
 static void
 mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 {
-	u32 val = mt76_rr(dev, MT_BBP(AGC, 20));
-	int rssi0 = (s8) FIELD_GET(MT_BBP_AGC20_RSSI0, val);
-	int rssi1 = (s8) FIELD_GET(MT_BBP_AGC20_RSSI1, val);
 	u8 *gain = dev->cal.agc_gain_init;
 	u8 gain_delta;
 	int low_gain;
+	u32 val;
 
-	dev->cal.avg_rssi[0] = (dev->cal.avg_rssi[0] * 15) / 16 +
-			       (rssi0 << 8) / 16;
-	dev->cal.avg_rssi[1] = (dev->cal.avg_rssi[1] * 15) / 16 +
-			       (rssi1 << 8) / 16;
-	dev->cal.avg_rssi_all = (dev->cal.avg_rssi[0] +
-				 dev->cal.avg_rssi[1]) / 512;
+	dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev);
 
 	low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) +
 		   (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev));
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 9/9] mt76: improve gain adjustment in noisy environments
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
                   ` (6 preceding siblings ...)
  2018-06-21  9:18 ` [PATCH 8/9] mt76: track ewma rssi for gain adjustment per station Felix Fietkau
@ 2018-06-21  9:18 ` Felix Fietkau
  2018-06-27 16:16 ` [1/9] mt76: fix beacon timer drift Kalle Valo
  8 siblings, 0 replies; 10+ messages in thread
From: Felix Fietkau @ 2018-06-21  9:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo

When switching between low gain (high RSSI) and high gain settings, it
can take a few seconds to adjust to the current environment.
This can lead to short periods of time with extreme packet loss.

When switching from low_gain=1 to low_gain=2, start with the same gain
adjustment value instead of the lowest to avoid spikes of huge numbers
of false CCA events

Also avoid resetting adjustment values on switching between low_gain
values 0 and 1, since it affects only the upper limit of vga adjustment

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 .../net/wireless/mediatek/mt76/mt76x2_phy.c   | 26 ++++++++++++-------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
index 14aedc3ef731..20ffa6a40d39 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
@@ -491,7 +491,8 @@ mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev)
 	dev->cal.false_cca = false_cca;
 	if (false_cca > 800 && dev->cal.agc_gain_adjust < limit)
 		dev->cal.agc_gain_adjust += 2;
-	else if (false_cca < 10 && dev->cal.agc_gain_adjust > 0)
+	else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) ||
+		 (dev->cal.agc_gain_adjust >= limit && false_cca < 500))
 		dev->cal.agc_gain_adjust -= 2;
 	else
 		return;
@@ -550,7 +551,8 @@ static void
 mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 {
 	u8 *gain = dev->cal.agc_gain_init;
-	u8 gain_delta;
+	u8 low_gain_delta, gain_delta;
+	bool gain_change;
 	int low_gain;
 	u32 val;
 
@@ -559,13 +561,14 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 	low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) +
 		   (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev));
 
-	if (dev->cal.low_gain == low_gain) {
+	gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2);
+	dev->cal.low_gain = low_gain;
+
+	if (!gain_change) {
 		mt76x2_phy_adjust_vga_gain(dev);
 		return;
 	}
 
-	dev->cal.low_gain = low_gain;
-
 	if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) {
 		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211);
 		val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf;
@@ -578,14 +581,17 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 		mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423);
 	}
 
+	if (mt76x2_has_ext_lna(dev))
+		low_gain_delta = 10;
+	else
+		low_gain_delta = 14;
+
 	if (low_gain == 2) {
 		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990);
 		mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808);
 		mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808);
-		if (mt76x2_has_ext_lna(dev))
-			gain_delta = 10;
-		else
-			gain_delta = 14;
+		gain_delta = low_gain_delta;
+		dev->cal.agc_gain_adjust = 0;
 	} else {
 		mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991);
 		if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80)
@@ -594,11 +600,11 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
 			mt76_wr(dev, MT_BBP(AGC, 35), 0x11111116);
 		mt76_wr(dev, MT_BBP(AGC, 37), 0x2121262C);
 		gain_delta = 0;
+		dev->cal.agc_gain_adjust = low_gain_delta;
 	}
 
 	dev->cal.agc_gain_cur[0] = gain[0] - gain_delta;
 	dev->cal.agc_gain_cur[1] = gain[1] - gain_delta;
-	dev->cal.agc_gain_adjust = 0;
 	mt76x2_phy_set_gain_val(dev);
 
 	/* clear false CCA counters */
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [1/9] mt76: fix beacon timer drift
  2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
                   ` (7 preceding siblings ...)
  2018-06-21  9:18 ` [PATCH 9/9] mt76: improve gain adjustment in noisy environments Felix Fietkau
@ 2018-06-27 16:16 ` Kalle Valo
  8 siblings, 0 replies; 10+ messages in thread
From: Kalle Valo @ 2018-06-27 16:16 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless

Felix Fietkau <nbd@nbd.name> wrote:

> The beacon timer drifts by 1 microsecond every TBTT. After 20 minutes
> with a beacon interval of 100, the drift will be almost 12 ms, enough to
> cause weird issues for devices in powersave mode.
> 
> Since the beacon timer is configured in units of 1/16 TU (64 us), we
> need to adjust it once every 64 beacons and only for one beacon.
> 
> Signed-off-by: Felix Fietkau <nbd@nbd.name>

9 patches applied to wireless-drivers-next.git, thanks.

aea38272920c mt76: fix beacon timer drift
9afef0fddaa1 mt76: fix threshold for gain adjustment
6cdb9614a818 mt76: fix swapped values for RXO-18 in gain control
929211687197 mt76: adjust AGC control register 26 based on gain for VHT80
fa967b586031 mt76: clear false CCA counters after changing gain settings
8e31f0d35a88 mt76: fix variable gain adjustment range
108ec4dafd61 mt76: add a debugfs file to dump agc calibration information
32e49efe0f15 mt76: track ewma rssi for gain adjustment per station
c3ae2103e069 mt76: improve gain adjustment in noisy environments

-- 
https://patchwork.kernel.org/patch/10479537/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-06-27 16:16 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-06-21  9:17 [PATCH 1/9] mt76: fix beacon timer drift Felix Fietkau
2018-06-21  9:17 ` [PATCH 2/9] mt76: fix threshold for gain adjustment Felix Fietkau
2018-06-21  9:17 ` [PATCH 3/9] mt76: fix swapped values for RXO-18 in gain control Felix Fietkau
2018-06-21  9:17 ` [PATCH 4/9] mt76: adjust AGC control register 26 based on gain for VHT80 Felix Fietkau
2018-06-21  9:17 ` [PATCH 5/9] mt76: clear false CCA counters after changing gain settings Felix Fietkau
2018-06-21  9:17 ` [PATCH 6/9] mt76: fix variable gain adjustment range Felix Fietkau
2018-06-21  9:17 ` [PATCH 7/9] mt76: add a debugfs file to dump agc calibration information Felix Fietkau
2018-06-21  9:18 ` [PATCH 8/9] mt76: track ewma rssi for gain adjustment per station Felix Fietkau
2018-06-21  9:18 ` [PATCH 9/9] mt76: improve gain adjustment in noisy environments Felix Fietkau
2018-06-27 16:16 ` [1/9] mt76: fix beacon timer drift Kalle Valo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).