Commit 4f0bce1c authored by Felix Fietkau's avatar Felix Fietkau
Browse files

mt76: mt7615: implement testmode support



Supports sending a configurable number of packets with a specific rate
and configurable tx power levels / antenna settings, as well as displaying
rx statistics.

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent f0efa862
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ CFLAGS_trace.o := -I$(src)

mt7615-common-y := main.o init.o mcu.o eeprom.o mac.o \
		   debugfs.o trace.o
mt7615-common-$(CONFIG_NL80211_TESTMODE) += testmode.o

mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o
mt7615e-$(CONFIG_MT7622_WMAC) += soc.o
+5 −3
Original line number Diff line number Diff line
@@ -321,6 +321,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)

	ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
	ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
	ieee80211_hw_set(hw, WANT_MONITOR_VIF);

	if (is_mt7615(&phy->dev->mt76))
		hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM;
@@ -405,9 +406,6 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
	mphy->sband_2g.sband.n_channels = 0;
	mphy->hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;

	/* The second interface does not get any packets unless it has a vif */
	ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF);

	ret = mt76_register_phy(mphy);
	if (ret)
		ieee80211_free_hw(mphy->hw);
@@ -457,5 +455,9 @@ void mt7615_init_device(struct mt7615_dev *dev)
			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
	mt7615_cap_dbdc_disable(dev);
	dev->phy.dfs_state = -1;

#ifdef CONFIG_NL80211_TESTMODE
	dev->mt76.test_ops = &mt7615_testmode_ops;
#endif
}
EXPORT_SYMBOL_GPL(mt7615_init_device);
+36 −0
Original line number Diff line number Diff line
@@ -186,6 +186,40 @@ mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy,
	status->freq = ieee80211_channel_to_frequency(chfreq, status->band);
}

static void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv)
{
#ifdef CONFIG_NL80211_TESTMODE
	u32 rxv1 = le32_to_cpu(rxv[0]);
	u32 rxv3 = le32_to_cpu(rxv[2]);
	u32 rxv4 = le32_to_cpu(rxv[3]);
	u32 rxv5 = le32_to_cpu(rxv[4]);
	u8 cbw = FIELD_GET(MT_RXV1_FRAME_MODE, rxv1);
	u8 mode = FIELD_GET(MT_RXV1_TX_MODE, rxv1);
	s16 foe = FIELD_GET(MT_RXV5_FOE, rxv5);
	u32 foe_const = (BIT(cbw + 1) & 0xf) * 10000;

	if (!mode) {
		/* CCK */
		foe &= ~BIT(11);
		foe *= 1000;
		foe >>= 11;
	} else {
		if (foe > 2048)
			foe -= 4096;

		foe = (foe * foe_const) >> 15;
	}

	dev->test.last_freq_offset = foe;
	dev->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4);
	dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4);
	dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4);
	dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4);
	dev->test.last_ib_rssi = FIELD_GET(MT_RXV3_IB_RSSI, rxv3);
	dev->test.last_wb_rssi = FIELD_GET(MT_RXV3_WB_RSSI, rxv3);
#endif
}

static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
{
	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
@@ -401,6 +435,8 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
					     status->chain_signal[i]);
		}

		mt7615_mac_fill_tm_rx(dev, rxd);

		rxd += 6;
		if ((u8 *)rxd - skb->data >= skb->len)
			return -EINVAL;
+5 −0
Original line number Diff line number Diff line
@@ -100,11 +100,16 @@ enum rx_pkt_type {
#define MT_RXV2_GROUP_ID		GENMASK(26, 21)
#define MT_RXV2_LENGTH			GENMASK(20, 0)

#define MT_RXV3_WB_RSSI			GENMASK(31, 24)
#define MT_RXV3_IB_RSSI			GENMASK(23, 16)

#define MT_RXV4_RCPI3			GENMASK(31, 24)
#define MT_RXV4_RCPI2			GENMASK(23, 16)
#define MT_RXV4_RCPI1			GENMASK(15, 8)
#define MT_RXV4_RCPI0			GENMASK(7, 0)

#define MT_RXV5_FOE			GENMASK(11, 0)

#define MT_RXV6_NF3			GENMASK(31, 24)
#define MT_RXV6_NF2			GENMASK(23, 16)
#define MT_RXV6_NF1			GENMASK(15, 8)
+39 −5
Original line number Diff line number Diff line
@@ -76,6 +76,8 @@ static void mt7615_stop(struct ieee80211_hw *hw)

	mutex_lock(&dev->mt76.mutex);

	mt76_testmode_reset(&dev->mt76, true);

	clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
	cancel_delayed_work_sync(&phy->scan_work);

@@ -137,6 +139,12 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,

	mutex_lock(&dev->mt76.mutex);

	mt76_testmode_reset(&dev->mt76, true);

	if (vif->type == NL80211_IFTYPE_MONITOR &&
	    is_zero_ether_addr(vif->addr))
		phy->monitor_vif = vif;

	mvif->idx = ffs(~dev->mphy.vif_mask) - 1;
	if (mvif->idx >= MT7615_MAX_INTERFACES) {
		ret = -ENOSPC;
@@ -197,6 +205,13 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,

	/* TODO: disable beacon for the bss */

	mutex_lock(&dev->mt76.mutex);
	mt76_testmode_reset(&dev->mt76, true);
	mutex_unlock(&dev->mt76.mutex);

	if (vif == phy->monitor_vif)
	    phy->monitor_vif = NULL;

	mt7615_mcu_add_dev_info(dev, vif, false);

	rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
@@ -234,7 +249,7 @@ static void mt7615_init_dfs_state(struct mt7615_phy *phy)
	phy->dfs_state = -1;
}

static int mt7615_set_channel(struct mt7615_phy *phy)
int mt7615_set_channel(struct mt7615_phy *phy)
{
	struct mt7615_dev *dev = phy->dev;
	bool ext_phy = phy != &dev->phy;
@@ -260,7 +275,7 @@ static int mt7615_set_channel(struct mt7615_phy *phy)
	mt7615_mac_set_timing(phy);
	ret = mt7615_dfs_init_radar_detector(phy);
	mt7615_mac_cca_stats_reset(phy);
	mt7615_mcu_set_sku_en(phy, true);
	mt7615_mcu_set_sku_en(phy, !mt76_testmode_enabled(&dev->mt76));

	mt7615_mac_reset_counters(dev);
	phy->noise = 0;
@@ -271,8 +286,11 @@ static int mt7615_set_channel(struct mt7615_phy *phy)
	mutex_unlock(&dev->mt76.mutex);

	mt76_txq_schedule_all(phy->mt76);

	if (!mt76_testmode_enabled(&dev->mt76))
		ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
					     MT7615_WATCHDOG_TIME);

	return ret;
}

@@ -369,6 +387,13 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)

	if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
		       IEEE80211_CONF_CHANGE_POWER)) {
#ifdef CONFIG_NL80211_TESTMODE
		if (dev->mt76.test.state != MT76_TM_STATE_OFF) {
			mutex_lock(&dev->mt76.mutex);
			mt76_testmode_reset(&dev->mt76, false);
			mutex_unlock(&dev->mt76.mutex);
		}
#endif
		ieee80211_stop_queues(hw);
		ret = mt7615_set_channel(phy);
		ieee80211_wake_queues(hw);
@@ -377,6 +402,8 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
	mutex_lock(&dev->mt76.mutex);

	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
		mt76_testmode_reset(&dev->mt76, true);

		if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
			phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
		else
@@ -419,9 +446,12 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
			MT_WF_RFCR1_DROP_CFACK;
	u32 flags = 0;

	mutex_lock(&dev->mt76.mutex);

#define MT76_FILTER(_flag, _hw) do { \
		flags |= *total_flags & FIF_##_flag;			\
		phy->rxfilter &= ~(_hw);				\
		if (!mt76_testmode_enabled(&dev->mt76))			\
			phy->rxfilter |= !(flags & FIF_##_flag) * (_hw);\
	} while (0)

@@ -455,6 +485,8 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
		mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags);
	else
		mt76_set(dev, MT_WF_RFCR1(band), ctl_flags);

	mutex_unlock(&dev->mt76.mutex);
}

static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
@@ -1069,6 +1101,8 @@ const struct ieee80211_ops mt7615_ops = {
	.sched_scan_stop = mt7615_stop_sched_scan,
	.remain_on_channel = mt7615_remain_on_channel,
	.cancel_remain_on_channel = mt7615_cancel_remain_on_channel,
	CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
	CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
#ifdef CONFIG_PM
	.suspend = mt7615_suspend,
	.resume = mt7615_resume,
Loading