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: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Felix Fietkau 2025-01-02 17:35:07 +01:00
parent 1f8dd5686e
commit 69d54ce749
7 changed files with 597 additions and 383 deletions

View file

@ -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] +

View file

@ -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 = mt7996_register_phy(dev, MT_BAND1);
if (ret)
return ret;
ret = mt7996_register_phy(dev, MT_BAND2);
if (ret)
return ret;
ret = mt76_register_device(&dev->mt76, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
return ret;
ret = mt7996_thermal_init(&dev->phy);
if (ret)
return ret;
ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
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 @@ error:
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);

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -605,6 +605,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp),
.link_data_size = sizeof(struct mt7996_vif_link),
.drv_flags = MT_DRV_TXWI_NO_FREE |
MT_DRV_AMSDU_OFFLOAD |
MT_DRV_HW_MGMT_TXQ,
@ -622,6 +623,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
.sta_remove = mt7996_mac_sta_remove,
.update_survey = mt7996_update_channel,
.set_channel = mt7996_set_channel,
.vif_link_add = mt7996_vif_link_add,
.vif_link_remove = mt7996_vif_link_remove,
};
struct mt7996_dev *dev;
struct mt76_dev *mdev;

View file

@ -11,6 +11,7 @@
#include "../mt76_connac.h"
#include "regs.h"
#define MT7996_MAX_RADIOS 3
#define MT7996_MAX_INTERFACES 19 /* per-band */
#define MT7996_MAX_WMM_SETS 4
#define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64)
@ -270,11 +271,15 @@ struct mt7996_phy {
u32 rx_ampdu_ts;
u32 ampdu_ref;
int txpower;
struct mt76_mib_stats mib;
struct mt76_channel_state state_ts;
u16 orig_chainmask;
bool has_aux_rx;
bool counter_reset;
};
struct mt7996_dev {
@ -283,6 +288,10 @@ struct mt7996_dev {
struct mt76_phy mphy;
};
struct mt7996_phy *radio_phy[MT7996_MAX_RADIOS];
struct wiphy_radio radios[MT7996_MAX_RADIOS];
struct wiphy_radio_freq_range radio_freqs[MT7996_MAX_RADIOS];
struct mt7996_hif *hif2;
struct mt7996_reg_desc reg;
u8 q_id[MT7996_MAX_QUEUE];
@ -402,14 +411,6 @@ enum mt7996_rdd_cmd {
RDD_IRQ_OFF,
};
static inline struct mt7996_phy *
mt7996_hw_phy(struct ieee80211_hw *hw)
{
struct mt76_phy *phy = hw->priv;
return phy->priv;
}
static inline struct mt7996_dev *
mt7996_hw_dev(struct ieee80211_hw *hw)
{
@ -469,12 +470,35 @@ mt7996_has_background_radar(struct mt7996_dev *dev)
return true;
}
static inline struct mt7996_phy *
mt7996_band_phy(struct mt7996_dev *dev, enum nl80211_band band)
{
struct mt76_phy *mphy;
mphy = dev->mt76.band_phys[band];
if (!mphy)
return NULL;
return mphy->priv;
}
static inline struct mt7996_vif_link *
mt7996_vif_link(struct mt7996_dev *dev, struct ieee80211_vif *vif, int link_id)
{
return (struct mt7996_vif_link *)mt76_vif_link(&dev->mt76, vif, link_id);
}
static inline struct mt7996_phy *
mt7996_vif_link_phy(struct mt7996_vif_link *link)
{
struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76);
if (!mphy)
return NULL;
return mphy->priv;
}
static inline struct mt7996_vif_link *
mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
@ -483,6 +507,10 @@ mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif,
link_conf);
}
#define mt7996_for_each_phy(dev, phy) \
for (int __i = 0; __i < ARRAY_SIZE((dev)->radio_phy); __i++) \
if (((phy) = (dev)->radio_phy[__i]) != NULL)
extern const struct ieee80211_ops mt7996_ops;
extern struct pci_driver mt7996_pci_driver;
extern struct pci_driver mt7996_hif_driver;
@ -494,6 +522,12 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance);
u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
int mt7996_register_device(struct mt7996_dev *dev);
void mt7996_unregister_device(struct mt7996_dev *dev);
int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct mt76_vif_link *mlink);
void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct mt76_vif_link *mlink);
int mt7996_eeprom_init(struct mt7996_dev *dev);
int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
@ -509,7 +543,7 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx,
void mt7996_init_txpower(struct mt7996_phy *phy);
int mt7996_txbf_init(struct mt7996_dev *dev);
void mt7996_reset(struct mt7996_dev *dev);
int mt7996_run(struct ieee80211_hw *hw);
int mt7996_run(struct mt7996_phy *phy);
int mt7996_mcu_init(struct mt7996_dev *dev);
int mt7996_mcu_init_firmware(struct mt7996_dev *dev);
int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,