From 60a4d67ca920bdc87a1386e0af273ed77cdf6f1a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 16 Nov 2017 19:10:29 +0100 Subject: [PATCH] mt76x2: implement dynamic AGC tuning based on false packet detection count Significantly improves radio performance Signed-off-by: Felix Fietkau --- mt76x2.h | 3 ++ mt76x2_phy.c | 98 +++++++++++++++++++++++++++++++++++++++------------ mt76x2_regs.h | 1 + 3 files changed, 79 insertions(+), 23 deletions(-) diff --git a/mt76x2.h b/mt76x2.h index 79ccb7c9..a12dfce8 100644 --- a/mt76x2.h +++ b/mt76x2.h @@ -64,9 +64,12 @@ struct mt76x2_calibration { struct mt76x2_rx_freq_cal rx; u8 agc_gain_init[MT_MAX_CHAINS]; + u8 agc_gain_cur[MT_MAX_CHAINS]; + int avg_rssi[MT_MAX_CHAINS]; int avg_rssi_all; + s8 agc_gain_adjust; s8 low_gain; u8 temp; diff --git a/mt76x2_phy.c b/mt76x2_phy.c index 2fe6376c..d587bcc6 100644 --- a/mt76x2_phy.c +++ b/mt76x2_phy.c @@ -406,25 +406,27 @@ mt76x2_get_rssi_gain_thresh(struct mt76x2_dev *dev) } } -static void -mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) +static int +mt76x2_get_low_rssi_gain_thresh(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, gain_delta; - bool low_gain; + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: + return -76; + case NL80211_CHAN_WIDTH_40: + return -79; + default: + return -82; + } +} - dev->cal.avg_rssi[0] = (dev->cal.avg_rssi[0] * 15) / 16 + (rssi0 << 8); - dev->cal.avg_rssi[1] = (dev->cal.avg_rssi[1] * 15) / 16 + (rssi1 << 8); - dev->cal.avg_rssi_all = (dev->cal.avg_rssi[0] + - dev->cal.avg_rssi[1]) / 512; +static void +mt76x2_phy_set_gain_val(struct mt76x2_dev *dev) +{ + u32 val; + u8 gain_val[2]; - low_gain = dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev); - if (dev->cal.low_gain == low_gain) - return; - - dev->cal.low_gain = low_gain; + gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust; + gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust; if (dev->mt76.chandef.width >= NL80211_CHAN_WIDTH_40) val = 0x1e42 << 16; @@ -433,6 +435,57 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) val |= 0xf8; + mt76_wr(dev, MT_BBP(AGC, 8), + val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0])); + mt76_wr(dev, MT_BBP(AGC, 9), + val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1])); + + if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) + mt76x2_dfs_adjust_agc(dev); +} + +static void +mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) +{ + u32 false_cca; + u8 limit = dev->cal.low_gain > 1 ? 4 : 16; + + 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) + dev->cal.agc_gain_adjust += 2; + else if (false_cca < 10 && dev->cal.agc_gain_adjust > 0) + dev->cal.agc_gain_adjust -= 2; + else + return; + + mt76x2_phy_set_gain_val(dev); +} + +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; + + dev->cal.avg_rssi[0] = (dev->cal.avg_rssi[0] * 15) / 16 + (rssi0 << 8); + dev->cal.avg_rssi[1] = (dev->cal.avg_rssi[1] * 15) / 16 + (rssi1 << 8); + dev->cal.avg_rssi_all = (dev->cal.avg_rssi[0] + + dev->cal.avg_rssi[1]) / 512; + + 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) { + 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), 0x00560411); else @@ -454,13 +507,10 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) gain_delta = 0; } - mt76_wr(dev, MT_BBP(AGC, 8), - val | FIELD_PREP(MT_BBP_AGC_GAIN, gain[0] - gain_delta)); - mt76_wr(dev, MT_BBP(AGC, 9), - val | FIELD_PREP(MT_BBP_AGC_GAIN, gain[1] - gain_delta)); - - if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) - mt76x2_dfs_adjust_agc(dev); + 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); } int mt76x2_phy_set_channel(struct mt76x2_dev *dev, @@ -591,6 +641,8 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, dev->cal.low_gain = -1; mt76x2_phy_channel_calibrate(dev, true); mt76x2_get_agc_gain(dev, dev->cal.agc_gain_init); + memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init, + sizeof(dev->cal.agc_gain_cur)); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, MT_CALIBRATE_INTERVAL); diff --git a/mt76x2_regs.h b/mt76x2_regs.h index e9da7867..ce3ab85c 100644 --- a/mt76x2_regs.h +++ b/mt76x2_regs.h @@ -511,6 +511,7 @@ #define MT_BBP_AGC_LNA_ULOW_GAIN GENMASK(5, 0) /* AGC, R8/R9 */ +#define MT_BBP_AGC_LNA_GAIN_MODE GENMASK(7, 6) #define MT_BBP_AGC_GAIN GENMASK(14, 8) #define MT_BBP_AGC20_RSSI0 GENMASK(7, 0)