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

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
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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);
+176 −0
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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);
+17 −0
Original line number Diff line number Diff line
@@ -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,
Loading