Commit 49de79ad authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau

mt76: mt7615: add Smart Carrier Sense support

Introduce Smart Carrier Sense support in order to tune device
sensitivity according to RTS error rate and False CCA reported by the
radio
Tested-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 7fe96541
......@@ -13,6 +13,42 @@ mt7615_radar_pattern_set(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_pattern, NULL,
mt7615_radar_pattern_set, "%lld\n");
static int
mt7615_scs_set(void *data, u64 val)
{
struct mt7615_dev *dev = data;
mt7615_mac_set_scs(dev, val);
return 0;
}
static int
mt7615_scs_get(void *data, u64 *val)
{
struct mt7615_dev *dev = data;
*val = dev->scs_en;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get,
mt7615_scs_set, "%lld\n");
static int
mt7615_radio_read(struct seq_file *s, void *data)
{
struct mt7615_dev *dev = dev_get_drvdata(s->private);
seq_printf(s, "Sensitivity: ofdm=%d cck=%d\n",
dev->ofdm_sensitivity, dev->cck_sensitivity);
seq_printf(s, "False CCA: ofdm=%d cck=%d\n",
dev->false_cca_ofdm, dev->false_cca_cck);
return 0;
}
int mt7615_init_debugfs(struct mt7615_dev *dev)
{
struct dentry *dir;
......@@ -21,6 +57,9 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
if (!dir)
return -ENOMEM;
debugfs_create_file("scs", 0600, dir, dev, &fops_scs);
debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir,
mt7615_radio_read);
debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);
/* test pattern knobs */
debugfs_create_u8("pattern_len", 0600, dir,
......
......@@ -50,6 +50,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
MT_TMAC_CTCR0_INS_DDLMT_EN);
mt7615_mcu_set_rts_thresh(dev, 0x92b);
mt7615_mac_set_scs(dev, false);
mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS,
MT_AGG_SCR_NLNAV_MID_PTEC_DIS);
......
......@@ -986,6 +986,175 @@ void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
dev_kfree_skb(skb);
}
static void
mt7615_mac_set_default_sensitivity(struct mt7615_dev *dev)
{
mt76_rmw(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
MT_WF_PHY_B0_PD_OFDM_MASK,
MT_WF_PHY_B0_PD_OFDM(0x13c));
mt76_rmw(dev, MT_WF_PHY_B1_MIN_PRI_PWR,
MT_WF_PHY_B1_PD_OFDM_MASK,
MT_WF_PHY_B1_PD_OFDM(0x13c));
mt76_rmw(dev, MT_WF_PHY_B0_RXTD_CCK_PD,
MT_WF_PHY_B0_PD_CCK_MASK,
MT_WF_PHY_B0_PD_CCK(0x92));
mt76_rmw(dev, MT_WF_PHY_B1_RXTD_CCK_PD,
MT_WF_PHY_B1_PD_CCK_MASK,
MT_WF_PHY_B1_PD_CCK(0x92));
dev->ofdm_sensitivity = -98;
dev->cck_sensitivity = -110;
dev->last_cca_adj = jiffies;
}
void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable)
{
mutex_lock(&dev->mt76.mutex);
if (dev->scs_en == enable)
goto out;
if (enable) {
/* DBDC not supported */
mt76_set(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
MT_WF_PHY_B0_PD_BLK);
if (is_mt7622(&dev->mt76)) {
mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7 << 8);
mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7);
}
} else {
mt76_clear(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
MT_WF_PHY_B0_PD_BLK);
mt76_clear(dev, MT_WF_PHY_B1_MIN_PRI_PWR,
MT_WF_PHY_B1_PD_BLK);
}
mt7615_mac_set_default_sensitivity(dev);
dev->scs_en = enable;
out:
mutex_unlock(&dev->mt76.mutex);
}
void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev)
{
mt76_clear(dev, MT_WF_PHY_R0_B0_PHYMUX_5, GENMASK(22, 20));
mt76_set(dev, MT_WF_PHY_R0_B0_PHYMUX_5, BIT(22) | BIT(20));
}
static void
mt7615_mac_adjust_sensitivity(struct mt7615_dev *dev,
u32 rts_err_rate, bool ofdm)
{
int false_cca = ofdm ? dev->false_cca_ofdm : dev->false_cca_cck;
u16 def_th = ofdm ? -98 : -110;
bool update = false;
s8 *sensitivity;
int signal;
sensitivity = ofdm ? &dev->ofdm_sensitivity : &dev->cck_sensitivity;
signal = mt76_get_min_avg_rssi(&dev->mt76);
if (!signal) {
mt7615_mac_set_default_sensitivity(dev);
return;
}
signal = min(signal, -72);
if (false_cca > 500) {
if (rts_err_rate > MT_FRAC(40, 100))
return;
/* decrease coverage */
if (*sensitivity == def_th && signal > -90) {
*sensitivity = -90;
update = true;
} else if (*sensitivity + 2 < signal) {
*sensitivity += 2;
update = true;
}
} else if ((false_cca > 0 && false_cca < 50) ||
rts_err_rate > MT_FRAC(60, 100)) {
/* increase coverage */
if (*sensitivity - 2 >= def_th) {
*sensitivity -= 2;
update = true;
}
}
if (*sensitivity > signal) {
*sensitivity = signal;
update = true;
}
if (update) {
u16 val;
if (ofdm) {
/* DBDC not supported */
val = *sensitivity * 2 + 512;
mt76_rmw(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
MT_WF_PHY_B0_PD_OFDM_MASK,
MT_WF_PHY_B0_PD_OFDM(val));
} else {
val = *sensitivity + 256;
mt76_rmw(dev, MT_WF_PHY_B0_RXTD_CCK_PD,
MT_WF_PHY_B0_PD_CCK_MASK,
MT_WF_PHY_B0_PD_CCK(val));
mt76_rmw(dev, MT_WF_PHY_B1_RXTD_CCK_PD,
MT_WF_PHY_B1_PD_CCK_MASK,
MT_WF_PHY_B1_PD_CCK(val));
}
dev->last_cca_adj = jiffies;
}
}
static void
mt7615_mac_scs_check(struct mt7615_dev *dev)
{
u32 val, rts_cnt = 0, rts_retries_cnt = 0, rts_err_rate = 0;
u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm;
int i;
if (!dev->scs_en)
return;
for (i = 0; i < 4; i++) {
u32 data;
val = mt76_rr(dev, MT_MIB_MB_SDR0(i));
data = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val);
if (data > rts_retries_cnt) {
rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val);
rts_retries_cnt = data;
}
}
val = mt76_rr(dev, MT_WF_PHY_R0_B0_PHYCTRL_STS0);
pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val);
pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val);
val = mt76_rr(dev, MT_WF_PHY_R0_B0_PHYCTRL_STS5);
mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val);
mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val);
dev->false_cca_ofdm = pd_ofdm - mdrdy_ofdm;
dev->false_cca_cck = pd_cck - mdrdy_cck;
mt7615_mac_cca_stats_reset(dev);
if (rts_cnt + rts_retries_cnt)
rts_err_rate = MT_FRAC(rts_retries_cnt,
rts_cnt + rts_retries_cnt);
/* cck */
mt7615_mac_adjust_sensitivity(dev, rts_err_rate, false);
/* ofdm */
mt7615_mac_adjust_sensitivity(dev, rts_err_rate, true);
if (time_after(jiffies, dev->last_cca_adj + 10 * HZ))
mt7615_mac_set_default_sensitivity(dev);
}
void mt7615_mac_work(struct work_struct *work)
{
struct mt7615_dev *dev;
......@@ -993,6 +1162,13 @@ void mt7615_mac_work(struct work_struct *work)
dev = (struct mt7615_dev *)container_of(work, struct mt76_dev,
mac_work.work);
mutex_lock(&dev->mt76.mutex);
if (++dev->mac_work_count == 5) {
mt7615_mac_scs_check(dev);
dev->mac_work_count = 0;
}
mutex_unlock(&dev->mt76.mutex);
mt76_tx_status_check(&dev->mt76, NULL, false);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
MT7615_WATCHDOG_TIME);
......
......@@ -148,6 +148,7 @@ static int mt7615_set_channel(struct mt7615_dev *dev)
goto out;
ret = mt7615_dfs_init_radar_detector(dev);
mt7615_mac_cca_stats_reset(dev);
out:
clear_bit(MT76_RESET, &dev->mt76.state);
......
......@@ -33,6 +33,9 @@
#define MT7615_EEPROM_SIZE 1024
#define MT7615_TOKEN_SIZE 4096
#define MT_FRAC_SCALE 12
#define MT_FRAC(val, div) (((val) << MT_FRAC_SCALE) / (div))
struct mt7615_vif;
struct mt7615_sta;
......@@ -87,6 +90,13 @@ struct mt7615_dev {
u32 hw_pattern;
int dfs_state;
int false_cca_ofdm, false_cca_cck;
unsigned long last_cca_adj;
u8 mac_work_count;
s8 ofdm_sensitivity;
s8 cck_sensitivity;
bool scs_en;
spinlock_t token_lock;
struct idr token;
};
......@@ -192,6 +202,11 @@ int mt7615_dfs_start_radar_detector(struct mt7615_dev *dev);
int mt7615_dfs_stop_radar_detector(struct mt7615_dev *dev);
int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev);
static inline bool is_mt7622(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7622;
}
static inline void mt7615_dfs_check_channel(struct mt7615_dev *dev)
{
enum nl80211_chan_width width = dev->mt76.chandef.width;
......@@ -213,6 +228,8 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask)
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
}
void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev);
void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable);
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta, int pid,
......
......@@ -71,6 +71,34 @@
#define MT_WF_PHY_WF2_RFCTRL0 MT_WF_PHY(0x1900)
#define MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN BIT(9)
#define MT_WF_PHY_R0_B0_PHYMUX_5 MT_WF_PHY(0x0614)
#define MT_WF_PHY_R0_B0_PHYCTRL_STS0 MT_WF_PHY(0x020c)
#define MT_WF_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16)
#define MT_WF_PHYCTRL_STAT_PD_CCK GENMASK(15, 0)
#define MT_WF_PHY_R0_B0_PHYCTRL_STS5 MT_WF_PHY(0x0220)
#define MT_WF_PHYCTRL_STAT_MDRDY_OFDM GENMASK(31, 16)
#define MT_WF_PHYCTRL_STAT_MDRDY_CCK GENMASK(15, 0)
#define MT_WF_PHY_B0_MIN_PRI_PWR MT_WF_PHY(0x229c)
#define MT_WF_PHY_B0_PD_OFDM_MASK GENMASK(28, 20)
#define MT_WF_PHY_B0_PD_OFDM(v) ((v) << 20)
#define MT_WF_PHY_B0_PD_BLK BIT(19)
#define MT_WF_PHY_B1_MIN_PRI_PWR MT_WF_PHY(0x084)
#define MT_WF_PHY_B1_PD_OFDM_MASK GENMASK(24, 16)
#define MT_WF_PHY_B1_PD_OFDM(v) ((v) << 16)
#define MT_WF_PHY_B1_PD_BLK BIT(25)
#define MT_WF_PHY_B0_RXTD_CCK_PD MT_WF_PHY(0x2310)
#define MT_WF_PHY_B0_PD_CCK_MASK GENMASK(8, 1)
#define MT_WF_PHY_B0_PD_CCK(v) ((v) << 1)
#define MT_WF_PHY_B1_RXTD_CCK_PD MT_WF_PHY(0x2314)
#define MT_WF_PHY_B1_PD_CCK_MASK GENMASK(31, 24)
#define MT_WF_PHY_B1_PD_CCK(v) ((v) << 24)
#define MT_WF_CFG_BASE 0x20200
#define MT_WF_CFG(ofs) (MT_WF_CFG_BASE + (ofs))
......@@ -219,6 +247,14 @@
#define MT_LPON_UTTR0 MT_LPON(0x018)
#define MT_LPON_UTTR1 MT_LPON(0x01c)
#define MT_WF_MIB_BASE 0x24800
#define MT_WF_MIB(ofs) (MT_WF_MIB_BASE + (ofs))
#define MT_MIB_M0_MISC_CR MT_WF_MIB(0x00c)
#define MT_MIB_MB_SDR0(n) MT_WF_MIB(0x100 + ((n) << 4))
#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16)
#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
#define MT_EFUSE_BASE 0x81070000
#define MT_EFUSE_BASE_CTRL 0x000
#define MT_EFUSE_BASE_CTRL_EMPTY BIT(30)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment