Commit 18369a4f authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau
Browse files

mt76: introduce single-sku support for mt7663/mt7921



Introduce support for rate-txpower compensation for mt7663/mt7921 chipsets.
Rate-txpower limit is specified through dts

Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 729d3dbd
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -323,8 +323,11 @@ mt7615_regd_notifier(struct wiphy *wiphy,

	if (chandef->chan->flags & IEEE80211_CHAN_RADAR)
		mt7615_dfs_init_radar_detector(phy);
	if (mt7615_firmware_offload(phy->dev))

	if (mt7615_firmware_offload(phy->dev)) {
		mt76_connac_mcu_set_channel_domain(mphy);
		mt76_connac_mcu_set_rate_txpower(mphy);
	}

	mt7615_mutex_release(dev);
}
+4 −0
Original line number Diff line number Diff line
@@ -66,6 +66,10 @@ static int mt7615_start(struct ieee80211_hw *hw)
		ret = mt76_connac_mcu_set_channel_domain(phy->mt76);
		if (ret)
			goto out;

		ret = mt76_connac_mcu_set_rate_txpower(phy->mt76);
		if (ret)
			goto out;
	}

	ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
+133 −0
Original line number Diff line number Diff line
@@ -1560,6 +1560,139 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);

static void
mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
			  struct mt76_power_limits *limits,
			  enum nl80211_band band)
{
	int max_power = is_mt7921(dev) ? 127 : 63;
	int i, offset = sizeof(limits->cck);

	memset(sku, max_power, MT_SKU_POWER_LIMIT);

	if (band == NL80211_BAND_2GHZ) {
		/* cck */
		memcpy(sku, limits->cck, sizeof(limits->cck));
	}

	/* ofdm */
	memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm));
	offset += sizeof(limits->ofdm);

	/* ht */
	for (i = 0; i < 2; i++) {
		memcpy(&sku[offset], limits->mcs[i], 8);
		offset += 8;
	}
	sku[offset++] = limits->mcs[0][0];

	/* vht */
	for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) {
		memcpy(&sku[offset], limits->mcs[i],
		       ARRAY_SIZE(limits->mcs[i]));
		offset += 12;
	}

	if (!is_mt7921(dev))
		return;

	/* he */
	for (i = 0; i < ARRAY_SIZE(limits->ru); i++) {
		memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i]));
		offset += ARRAY_SIZE(limits->ru[i]);
	}
}

static int
mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
				  enum nl80211_band band)
{
	struct mt76_dev *dev = phy->dev;
	int sku_len, batch_len = is_mt7921(dev) ? 8 : 16;
	static const u8 chan_list_2ghz[] = {
		1, 2,  3,  4,  5,  6,  7,
		8, 9, 10, 11, 12, 13, 14
	};
	static const u8 chan_list_5ghz[] = {
		 36,  38,  40,  42,  44,  46,  48,
		 50,  52,  54,  56,  58,  60,  62,
		 64, 100, 102, 104, 106, 108, 110,
		112, 114, 116, 118, 120, 122, 124,
		126, 128, 132, 134, 136, 138, 140,
		142, 144, 149, 151, 153, 155, 157,
		159, 161, 165
	};
	struct mt76_connac_sku_tlv sku_tlbv;
	int i, n_chan, batch_size, idx = 0;
	struct mt76_power_limits limits;
	const u8 *ch_list;

	sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;

	if (band == NL80211_BAND_2GHZ) {
		n_chan = ARRAY_SIZE(chan_list_2ghz);
		ch_list = chan_list_2ghz;
	} else {
		n_chan = ARRAY_SIZE(chan_list_5ghz);
		ch_list = chan_list_5ghz;
	}
	batch_size = DIV_ROUND_UP(n_chan, batch_len);

	for (i = 0; i < batch_size; i++) {
		bool last_msg = i == batch_size - 1;
		int num_ch = last_msg ? n_chan % batch_len : batch_len;
		struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {
			.band = band == NL80211_BAND_2GHZ ? 1 : 2,
			.n_chan = num_ch,
			.last_msg = last_msg,
		};
		struct sk_buff *skb;
		int j, err, msg_len;

		msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv);
		skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);
		if (!skb)
			return -ENOMEM;

		BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2));
		memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));

		skb_put_data(skb, &tx_power_tlv, sizeof(tx_power_tlv));
		for (j = 0; j < num_ch; j++, idx++) {
			struct ieee80211_channel chan = {
				.hw_value = ch_list[idx],
				.band = band,
			};

			mt76_get_rate_power_limits(phy, &chan, &limits, 127);

			sku_tlbv.channel = ch_list[idx];
			mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit,
						  &limits, band);
			skb_put_data(skb, &sku_tlbv, sku_len);
		}

		err = mt76_mcu_skb_send_msg(dev, skb,
					    MCU_CMD_SET_RATE_TX_POWER, false);
		if (err < 0)
			return err;
	}

	return 0;
}

int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)
{
	int err;

	err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_2GHZ);
	if (err < 0)
		return err;

	return mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_5GHZ);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);

#ifdef CONFIG_PM

const struct wiphy_wowlan_support mt76_connac_wowlan_support = {
+23 −0
Original line number Diff line number Diff line
@@ -895,6 +895,28 @@ struct mt76_sta_cmd_info {
	u8 rcpi;
};

#define MT_SKU_POWER_LIMIT	161

struct mt76_connac_sku_tlv {
	u8 channel;
	s8 pwr_limit[MT_SKU_POWER_LIMIT];
} __packed;

struct mt76_connac_tx_power_limit_tlv {
	/* DW0 - common info*/
	u8 ver;
	u8 pad0;
	__le16 len;
	/* DW1 - cmd hint */
	u8 n_chan; /* # channel */
	u8 band; /* 2.4GHz - 5GHz */
	u8 last_msg;
	u8 pad1;
	/* DW3 */
	u8 alpha2[4]; /* regulatory_request.alpha2 */
	u8 pad2[32];
} __packed;

#define to_wcid_lo(id)		FIELD_GET(GENMASK(7, 0), (u16)id)
#define to_wcid_hi(id)		FIELD_GET(GENMASK(9, 8), (u16)id)

@@ -996,4 +1018,5 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
int mt76_connac_mcu_chip_config(struct mt76_dev *dev);
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
				    struct mt76_connac_coredump *coredump);
int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy);
#endif /* __MT76_CONNAC_MCU_H */
+2 −0
Original line number Diff line number Diff line
@@ -58,12 +58,14 @@ mt7921_regd_notifier(struct wiphy *wiphy,
{
	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
	struct mt7921_dev *dev = mt7921_hw_dev(hw);
	struct mt7921_phy *phy = mt7921_hw_phy(hw);

	memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
	dev->mt76.region = request->dfs_region;

	mt7921_mutex_acquire(dev);
	mt76_connac_mcu_set_channel_domain(hw->priv);
	mt76_connac_mcu_set_rate_txpower(phy->mt76);
	mt7921_mutex_release(dev);
}

Loading