Commit 69d54ce7 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

wifi: mt76: mt7996: switch to single multi-radio wiphy

Use generic mt76 chanctx functions and look up phy from vif link.
The driver now uses only a single phy to handle multiple interfaces on
different channels. This is preparation for full MLO support.

Link: https://patch.msgid.link/20250102163508.52945-23-nbd@nbd.name


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 1f8dd568
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)

	mphy->antenna_mask = BIT(nss) - 1;
	mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx];
	phy->orig_chainmask = mphy->chainmask;
	dev->chainmask |= mphy->chainmask;
	if (band_idx < MT_BAND2)
		dev->chainshift[band_idx + 1] = dev->chainshift[band_idx] +
+141 −103
Original line number Diff line number Diff line
@@ -14,6 +14,28 @@
#include "coredump.h"
#include "eeprom.h"

static const struct ieee80211_iface_limit if_limits_global = {
	.max = MT7996_MAX_INTERFACES * MT7996_MAX_RADIOS,
	.types = BIT(NL80211_IFTYPE_STATION)
		 | BIT(NL80211_IFTYPE_ADHOC)
		 | BIT(NL80211_IFTYPE_AP)
#ifdef CONFIG_MAC80211_MESH
		 | BIT(NL80211_IFTYPE_MESH_POINT)
#endif
};

static const struct ieee80211_iface_combination if_comb_global = {
	.limits = &if_limits_global,
	.n_limits = 1,
	.max_interfaces = MT7996_MAX_INTERFACES * MT7996_MAX_RADIOS,
	.num_different_channels = MT7996_MAX_RADIOS,
	.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
			       BIT(NL80211_CHAN_WIDTH_20) |
			       BIT(NL80211_CHAN_WIDTH_40) |
			       BIT(NL80211_CHAN_WIDTH_80) |
			       BIT(NL80211_CHAN_WIDTH_160),
};

static const struct ieee80211_iface_limit if_limits[] = {
	{
		.max = 16,
@@ -27,8 +49,7 @@ static const struct ieee80211_iface_limit if_limits[] = {
	}
};

static const struct ieee80211_iface_combination if_comb[] = {
	{
static const struct ieee80211_iface_combination if_comb = {
	.limits = if_limits,
	.n_limits = ARRAY_SIZE(if_limits),
	.max_interfaces = MT7996_MAX_INTERFACES,
@@ -40,7 +61,6 @@ static const struct ieee80211_iface_combination if_comb[] = {
			       BIT(NL80211_CHAN_WIDTH_80) |
			       BIT(NL80211_CHAN_WIDTH_160),
	.beacon_int_min_gcd = 100,
	}
};

static ssize_t mt7996_thermal_temp_show(struct device *dev,
@@ -177,28 +197,32 @@ static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
static void mt7996_unregister_thermal(struct mt7996_phy *phy)
{
	struct wiphy *wiphy = phy->mt76->hw->wiphy;
	char name[sizeof("cooling_deviceXXX")];

	if (!phy->cdev)
		return;

	sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
	snprintf(name, sizeof(name), "cooling_device%d", phy->mt76->band_idx);
	sysfs_remove_link(&wiphy->dev.kobj, name);
	thermal_cooling_device_unregister(phy->cdev);
}

static int mt7996_thermal_init(struct mt7996_phy *phy)
{
	struct wiphy *wiphy = phy->mt76->hw->wiphy;
	char cname[sizeof("cooling_deviceXXX")];
	struct thermal_cooling_device *cdev;
	struct device *hwmon;
	const char *name;

	name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
			      wiphy_name(wiphy));
	name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s.%d",
			      wiphy_name(wiphy), phy->mt76->band_idx);
	snprintf(cname, sizeof(cname), "cooling_device%d", phy->mt76->band_idx);

	cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
	if (!IS_ERR(cdev)) {
		if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
				      "cooling_device") < 0)
				      cname) < 0)
			thermal_cooling_device_unregister(cdev);
		else
			phy->cdev = cdev;
@@ -330,27 +354,87 @@ mt7996_regd_notifier(struct wiphy *wiphy,
{
	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
	struct mt7996_dev *dev = mt7996_hw_dev(hw);
	struct mt7996_phy *phy = mt7996_hw_phy(hw);
	struct mt7996_phy *phy;

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

	mt7996_for_each_phy(dev, phy) {
		if (dev->mt76.region == NL80211_DFS_UNSET)
			mt7996_mcu_rdd_background_enable(phy, NULL);

		mt7996_init_txpower(phy);

		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
		mt7996_dfs_init_radar_detector(phy);
	}
}

static void
mt7996_init_wiphy_band(struct ieee80211_hw *hw, struct mt7996_phy *phy)
{
	struct mt7996_dev *dev = phy->dev;
	struct wiphy *wiphy = hw->wiphy;
	int n_radios = hw->wiphy->n_radio;
	struct wiphy_radio_freq_range *freq = &dev->radio_freqs[n_radios];
	struct wiphy_radio *radio = &dev->radios[n_radios];

	phy->slottime = 9;
	phy->beacon_rate = -1;

	if (phy->mt76->cap.has_2ghz) {
		phy->mt76->sband_2g.sband.ht_cap.cap |=
			IEEE80211_HT_CAP_LDPC_CODING |
			IEEE80211_HT_CAP_MAX_AMSDU;
		phy->mt76->sband_2g.sband.ht_cap.ampdu_density =
			IEEE80211_HT_MPDU_DENSITY_2;
		freq->start_freq = 2400000;
		freq->end_freq = 2500000;
	} else if (phy->mt76->cap.has_5ghz) {
		phy->mt76->sband_5g.sband.ht_cap.cap |=
			IEEE80211_HT_CAP_LDPC_CODING |
			IEEE80211_HT_CAP_MAX_AMSDU;

		phy->mt76->sband_5g.sband.vht_cap.cap |=
			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
			IEEE80211_VHT_CAP_SHORT_GI_160 |
			IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
		phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
			IEEE80211_HT_MPDU_DENSITY_1;

		ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
		freq->start_freq = 5000000;
		freq->end_freq = 5900000;
	} else if (phy->mt76->cap.has_6ghz) {
		freq->start_freq = 5900000;
		freq->end_freq = 7200000;
	} else {
		return;
	}

	dev->radio_phy[n_radios] = phy;
	radio->freq_range = freq;
	radio->n_freq_range = 1;
	radio->iface_combinations = &if_comb;
	radio->n_iface_combinations = 1;
	hw->wiphy->n_radio++;

	wiphy->available_antennas_rx |= phy->mt76->chainmask;
	wiphy->available_antennas_tx |= phy->mt76->chainmask;

	mt76_set_stream_caps(phy->mt76, true);
	mt7996_set_stream_vht_txbf_caps(phy);
	mt7996_set_stream_he_eht_caps(phy);
	mt7996_init_txpower(phy);
}

static void
mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
{
	struct mt7996_phy *phy = mt7996_hw_phy(hw);
	struct mt76_dev *mdev = &phy->dev->mt76;
	struct mt7996_dev *dev = mt7996_hw_dev(hw);
	struct mt76_dev *mdev = &dev->mt76;
	struct wiphy *wiphy = hw->wiphy;
	u16 max_subframes = phy->dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT :
	u16 max_subframes = dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT :
					   IEEE80211_MAX_AMPDU_BUF_HE;

	hw->queues = 4;
@@ -363,14 +447,15 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
	hw->radiotap_timestamp.units_pos =
		IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;

	phy->slottime = 9;
	phy->beacon_rate = -1;

	hw->sta_data_size = sizeof(struct mt7996_sta);
	hw->vif_data_size = sizeof(struct mt7996_vif);
	hw->chanctx_data_size = sizeof(struct mt76_chanctx);

	wiphy->iface_combinations = &if_comb_global;
	wiphy->n_iface_combinations = 1;

	wiphy->radio = dev->radios;

	wiphy->iface_combinations = if_comb;
	wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
	wiphy->reg_notifier = mt7996_regd_notifier;
	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
	wiphy->mbssid_max_interfaces = 16;
@@ -387,7 +472,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);

	if (mt7996_has_background_radar(phy->dev) &&
	if (mt7996_has_background_radar(dev) &&
	    (!mdev->dev->of_node ||
	     !of_property_read_bool(mdev->dev->of_node,
				    "mediatek,disable-radar-background")))
@@ -397,51 +482,21 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
	ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
	ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
	ieee80211_hw_set(hw, WANT_MONITOR_VIF);
	ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR);
	ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);

	hw->max_tx_fragments = 4;

	if (phy->mt76->cap.has_2ghz) {
		phy->mt76->sband_2g.sband.ht_cap.cap |=
			IEEE80211_HT_CAP_LDPC_CODING |
			IEEE80211_HT_CAP_MAX_AMSDU;
		phy->mt76->sband_2g.sband.ht_cap.ampdu_density =
			IEEE80211_HT_MPDU_DENSITY_2;
	}

	if (phy->mt76->cap.has_5ghz) {
		phy->mt76->sband_5g.sband.ht_cap.cap |=
			IEEE80211_HT_CAP_LDPC_CODING |
			IEEE80211_HT_CAP_MAX_AMSDU;

		phy->mt76->sband_5g.sband.vht_cap.cap |=
			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
			IEEE80211_VHT_CAP_SHORT_GI_160 |
			IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
		phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
			IEEE80211_HT_MPDU_DENSITY_1;

		ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
	}

	/* init led callbacks */
	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
		phy->mt76->leds.cdev.brightness_set = mt7996_led_set_brightness;
		phy->mt76->leds.cdev.blink_set = mt7996_led_set_blink;
		dev->mphy.leds.cdev.brightness_set = mt7996_led_set_brightness;
		dev->mphy.leds.cdev.blink_set = mt7996_led_set_blink;
	}

	mt76_set_stream_caps(phy->mt76, true);
	mt7996_set_stream_vht_txbf_caps(phy);
	mt7996_set_stream_he_eht_caps(phy);
	mt7996_init_txpower(phy);

	wiphy->available_antennas_rx = phy->mt76->antenna_mask;
	wiphy->available_antennas_tx = phy->mt76->antenna_mask;

	wiphy->max_scan_ssids = 4;
	wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;

	mt7996_init_wiphy_band(hw, &dev->phy);
}

static void
@@ -562,18 +617,15 @@ int mt7996_txbf_init(struct mt7996_dev *dev)
	return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
}

static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
			       enum mt76_band_id band)
static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
{
	struct mt7996_phy *phy;
	struct mt76_phy *mphy;
	u32 mac_ofs, hif1_ofs = 0;
	int ret;
	struct mtk_wed_device *wed = &dev->mt76.mmio.wed;

	if (!mt7996_band_valid(dev, band) || band == MT_BAND0)
		return 0;

	if (phy)
	if (!mt7996_band_valid(dev, band))
		return 0;

	if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) {
@@ -581,7 +633,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
		wed = &dev->mt76.mmio.wed_hif2;
	}

	mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band);
	mphy = mt76_alloc_radio_phy(&dev->mt76, sizeof(*phy), band);
	if (!mphy)
		return -ENOMEM;

@@ -612,7 +664,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
	mt76_eeprom_override(mphy);

	/* init wiphy according to mphy and phy */
	mt7996_init_wiphy(mphy->hw, wed);
	mt7996_init_wiphy_band(mphy->hw, phy);
	ret = mt7996_init_tx_queues(mphy->priv,
				    MT_TXQ_ID(band),
				    MT7996_TX_RING_SIZE,
@@ -626,10 +678,6 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
	if (ret)
		goto error;

	ret = mt7996_thermal_init(phy);
	if (ret)
		goto error;

	if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) {
		u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2;

@@ -641,24 +689,14 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,

error:
	mphy->dev->phys[band] = NULL;
	ieee80211_free_hw(mphy->hw);
	return ret;
}

static void
mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
mt7996_unregister_phy(struct mt7996_phy *phy)
{
	struct mt76_phy *mphy;

	if (!phy)
		return;

	if (phy)
		mt7996_unregister_thermal(phy);

	mphy = phy->dev->mt76.phys[band];
	mt76_unregister_phy(mphy);
	ieee80211_free_hw(mphy->hw);
	phy->dev->mt76.phys[band] = NULL;
}

static void mt7996_init_work(struct work_struct *work)
@@ -1412,6 +1450,7 @@ void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy)
int mt7996_register_device(struct mt7996_dev *dev)
{
	struct ieee80211_hw *hw = mt76_hw(dev);
	struct mt7996_phy *phy;
	int ret;

	dev->phy.dev = dev;
@@ -1433,22 +1472,21 @@ int mt7996_register_device(struct mt7996_dev *dev)

	mt7996_init_wiphy(hw, &dev->mt76.mmio.wed);

	ret = mt76_register_device(&dev->mt76, true, mt76_rates,
				   ARRAY_SIZE(mt76_rates));
	ret = mt7996_register_phy(dev, MT_BAND1);
	if (ret)
		return ret;

	ret = mt7996_thermal_init(&dev->phy);
	ret = mt7996_register_phy(dev, MT_BAND2);
	if (ret)
		return ret;

	ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
	ret = mt76_register_device(&dev->mt76, true, mt76_rates,
				   ARRAY_SIZE(mt76_rates));
	if (ret)
		return ret;

	ret = mt7996_register_phy(dev, mt7996_phy3(dev), MT_BAND2);
	if (ret)
		return ret;
	mt7996_for_each_phy(dev, phy)
		mt7996_thermal_init(phy);

	ieee80211_queue_work(mt76_hw(dev), &dev->init_work);

@@ -1473,8 +1511,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
void mt7996_unregister_device(struct mt7996_dev *dev)
{
	cancel_work_sync(&dev->wed_rro.work);
	mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
	mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
	mt7996_unregister_phy(mt7996_phy3(dev));
	mt7996_unregister_phy(mt7996_phy2(dev));
	mt7996_unregister_thermal(&dev->phy);
	mt7996_coredump_unregister(dev);
	mt76_unregister_device(&dev->mt76);
+3 −3
Original line number Diff line number Diff line
@@ -1738,19 +1738,19 @@ mt7996_mac_restart(struct mt7996_dev *dev)
	ret = mt7996_txbf_init(dev);

	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
		ret = mt7996_run(dev->mphy.hw);
		ret = mt7996_run(&dev->phy);
		if (ret)
			goto out;
	}

	if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
		ret = mt7996_run(phy2->mt76->hw);
		ret = mt7996_run(phy2);
		if (ret)
			goto out;
	}

	if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
		ret = mt7996_run(phy3->mt76->hw);
		ret = mt7996_run(phy3);
		if (ret)
			goto out;
	}
+392 −259

File changed.

Preview size limit exceeded, changes collapsed.

+10 −5
Original line number Diff line number Diff line
@@ -2572,18 +2572,24 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
#define OFFLOAD_TX_MODE_SU	BIT(0)
#define OFFLOAD_TX_MODE_MU	BIT(1)
	struct ieee80211_hw *hw = mt76_hw(dev);
	struct mt7996_phy *phy = mt7996_hw_phy(hw);
	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
	struct cfg80211_chan_def *chandef = &mvif->deflink.phy->mt76->chandef;
	enum nl80211_band band = chandef->chan->band;
	struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink);
	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
	struct bss_inband_discovery_tlv *discov;
	struct ieee80211_tx_info *info;
	struct sk_buff *rskb, *skb = NULL;
	struct cfg80211_chan_def *chandef;
	enum nl80211_band band;
	struct tlv *tlv;
	u8 *buf, interval;
	int len;

	if (!phy)
		return -EINVAL;

	chandef = &phy->mt76->chandef;
	band = chandef->chan->band;

	if (vif->bss_conf.nontransmitted)
		return 0;

@@ -4495,7 +4501,6 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
#define TX_POWER_LIMIT_TABLE_RATE	0
	struct mt7996_dev *dev = phy->dev;
	struct mt76_phy *mphy = phy->mt76;
	struct ieee80211_hw *hw = mphy->hw;
	struct tx_power_limit_table_ctrl {
		u8 __rsv1[4];

@@ -4515,7 +4520,7 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
	struct sk_buff *skb;
	int i, tx_power;

	tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
	tx_power = mt7996_get_power_bound(phy, phy->txpower);
	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
					      &la, tx_power);
	mphy->txpower_cur = tx_power;
Loading