All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.