- fixes
 - connac code unification
 - mt7921 p2p support
 - mt7996 mesh a-msdu support
 - mt7996 eht support
 - mt7996 coredump support
 -----BEGIN PGP SIGNATURE-----
 Comment: GPGTools - http://gpgtools.org
 
 iF0EABECAB0WIQR10Rp9kadxD0kAQu/XfRQdAqdu9QUCZD+h2wAKCRDXfRQdAqdu
 9dqxAJ0cqAw0rJbQ39bq903geCEx7EZ5UgCfVG7zlnA+iAOee07ilmBwDJ8E7ho=
 =Ef06
 -----END PGP SIGNATURE-----

Merge tag 'mt76-for-kvalo-2023-04-18' of https://github.com/nbd168/wireless

mt76 patches for 6.4

- fixes
- connac code unification
- mt7921 p2p support
- mt7996 mesh a-msdu support
- mt7996 eht support
- mt7996 coredump support
This commit is contained in:
Kalle Valo 2023-04-20 15:53:58 +03:00
Родитель 6c6d62ae82 3b522caded
Коммит d2a158d113
72 изменённых файлов: 1714 добавлений и 1032 удалений

Просмотреть файл

@ -111,6 +111,11 @@ properties:
$ref: /schemas/leds/common.yaml#
additionalProperties: false
properties:
led-active-low:
description:
LED is enabled with ground signal.
type: boolean
led-sources:
maxItems: 1

Просмотреть файл

@ -402,8 +402,8 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
*info = le32_to_cpu(desc->info);
if (mt76_queue_is_wed_rx(q)) {
u32 token = FIELD_GET(MT_DMA_CTL_TOKEN,
le32_to_cpu(desc->buf1));
u32 buf1 = le32_to_cpu(desc->buf1);
u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1);
struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token);
if (!t)
@ -424,6 +424,8 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
*drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A |
MT_DMA_CTL_DROP));
*drop |= !!(buf1 & MT_DMA_CTL_WO_DROP);
}
} else {
buf = e->buf;
@ -576,7 +578,9 @@ free:
free_skb:
status.skb = tx_info.skb;
hw = mt76_tx_status_get_hw(dev, tx_info.skb);
spin_lock_bh(&dev->rx_lock);
ieee80211_tx_status_ext(hw, &status);
spin_unlock_bh(&dev->rx_lock);
return ret;
}
@ -849,7 +853,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
!(dev->drv->rx_check(dev, data, len)))
goto free_frag;
skb = build_skb(data, q->buf_size);
skb = napi_build_skb(data, q->buf_size);
if (!skb)
goto free_frag;

Просмотреть файл

@ -19,6 +19,7 @@
#define MT_DMA_CTL_TO_HOST_A BIT(12)
#define MT_DMA_CTL_DROP BIT(14)
#define MT_DMA_CTL_TOKEN GENMASK(31, 16)
#define MT_DMA_CTL_WO_DROP BIT(8)
#define MT_DMA_PPE_CPU_REASON GENMASK(15, 11)
#define MT_DMA_PPE_ENTRY GENMASK(30, 16)

Просмотреть файл

@ -418,7 +418,8 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
SET_IEEE80211_DEV(hw, dev->dev);
SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_AP_UAPSD;
@ -1066,9 +1067,14 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
status->enc_flags = mstat.enc_flags;
status->encoding = mstat.encoding;
status->bw = mstat.bw;
status->he_ru = mstat.he_ru;
status->he_gi = mstat.he_gi;
status->he_dcm = mstat.he_dcm;
if (status->encoding == RX_ENC_EHT) {
status->eht.ru = mstat.eht.ru;
status->eht.gi = mstat.eht.gi;
} else {
status->he_ru = mstat.he_ru;
status->he_gi = mstat.he_gi;
status->he_dcm = mstat.he_dcm;
}
status->rate_idx = mstat.rate_idx;
status->nss = mstat.nss;
status->band = mstat.band;
@ -1303,7 +1309,8 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
if (ps)
set_bit(MT_WCID_FLAG_PS, &wcid->flags);
dev->drv->sta_ps(dev, sta, ps);
if (dev->drv->sta_ps)
dev->drv->sta_ps(dev, sta, ps);
if (!ps)
clear_bit(MT_WCID_FLAG_PS, &wcid->flags);

Просмотреть файл

@ -621,12 +621,22 @@ struct mt76_rx_status {
u16 freq;
u32 flag;
u8 enc_flags;
u8 encoding:2, bw:3, he_ru:3;
u8 he_gi:2, he_dcm:1;
u8 encoding:3, bw:4;
union {
struct {
u8 he_ru:3;
u8 he_gi:2;
u8 he_dcm:1;
};
struct {
u8 ru:4;
u8 gi:2;
} eht;
};
u8 amsdu:1, first_amsdu:1, last_amsdu:1;
u8 rate_idx;
u8 nss;
u8 band;
u8 nss:5, band:3;
s8 signal;
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
@ -778,6 +788,7 @@ struct mt76_dev {
spinlock_t rx_lock;
struct napi_struct napi[__MT_RXQ_MAX];
struct sk_buff_head rx_skb[__MT_RXQ_MAX];
struct tasklet_struct irq_tasklet;
struct list_head txwi_cache;
struct list_head rxwi_cache;

Просмотреть файл

@ -1279,8 +1279,11 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
if (wcidx >= MT7603_WTBL_STA || !sta)
goto out;
if (mt7603_fill_txs(dev, msta, &info, txs_data))
if (mt7603_fill_txs(dev, msta, &info, txs_data)) {
spin_lock_bh(&dev->mt76.rx_lock);
ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info);
spin_unlock_bh(&dev->mt76.rx_lock);
}
out:
rcu_read_unlock();

Просмотреть файл

@ -76,7 +76,8 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
if (napi_complete(napi))
mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));
mt76_connac_irq_enable(&dev->mt76,
mt7615_tx_mcu_int_mask(dev));
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
@ -297,7 +298,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
else
mask |= MT_INT_MCU_CMD;
mt7615_irq_enable(dev, mask);
mt76_connac_irq_enable(&dev->mt76, mask);
mt7615_dma_start(dev);

Просмотреть файл

@ -47,6 +47,9 @@ static int mt7615_efuse_init(struct mt7615_dev *dev, u32 base)
void *buf;
u32 val;
if (is_mt7663(&dev->mt76))
len = MT7663_EEPROM_SIZE;
val = mt76_rr(dev, base + MT_EFUSE_BASE_CTRL);
if (val & MT_EFUSE_BASE_CTRL_EMPTY)
return 0;
@ -72,6 +75,8 @@ static int mt7615_eeprom_load(struct mt7615_dev *dev, u32 addr)
{
int ret;
BUILD_BUG_ON(MT7615_EEPROM_FULL_SIZE < MT7663_EEPROM_SIZE);
ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_FULL_SIZE);
if (ret < 0)
return ret;
@ -336,7 +341,7 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr)
ret = mt7615_check_eeprom(&dev->mt76);
if (ret && dev->mt76.otp.data) {
memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
MT7615_EEPROM_SIZE);
dev->mt76.otp.size);
} else {
dev->flash_eeprom = true;
mt7615_cal_free_data(dev);

Просмотреть файл

@ -46,7 +46,7 @@ enum mt7615_eeprom_field {
MT7615_EE_MAX = 0x3bf,
MT7622_EE_MAX = 0x3db,
MT7663_EE_MAX = 0x400,
MT7663_EE_MAX = 0x600,
};
#define MT_EE_RATE_POWER_MASK GENMASK(5, 0)

Просмотреть файл

@ -396,6 +396,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);

Просмотреть файл

@ -655,11 +655,6 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
return 0;
}
void mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
{
}
EXPORT_SYMBOL_GPL(mt7615_sta_ps);
static u16
mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
struct mt76_phy *mphy,
@ -1558,8 +1553,11 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
if (wcid->phy_idx && dev->mt76.phys[MT_BAND1])
mphy = dev->mt76.phys[MT_BAND1];
if (mt7615_fill_txs(dev, msta, &info, txs_data))
if (mt7615_fill_txs(dev, msta, &info, txs_data)) {
spin_lock_bh(&dev->mt76.rx_lock);
ieee80211_tx_status_noskb(mphy->hw, sta, &info);
spin_unlock_bh(&dev->mt76.rx_lock);
}
out:
rcu_read_unlock();
@ -2380,7 +2378,7 @@ void mt7615_coredump_work(struct work_struct *work)
break;
skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
if (data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {
if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {
dev_kfree_skb(skb);
continue;
}
@ -2390,6 +2388,8 @@ void mt7615_coredump_work(struct work_struct *work)
dev_kfree_skb(skb);
}
dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
GFP_KERNEL);
if (dump)
dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
GFP_KERNEL);
}

Просмотреть файл

@ -19,18 +19,6 @@
#define MT_RXD0_NORMAL_GROUP_3 BIT(27)
#define MT_RXD0_NORMAL_GROUP_4 BIT(28)
enum rx_pkt_type {
PKT_TYPE_TXS,
PKT_TYPE_TXRXV,
PKT_TYPE_NORMAL,
PKT_TYPE_RX_DUP_RFB,
PKT_TYPE_RX_TMR,
PKT_TYPE_RETRIEVE,
PKT_TYPE_TXRX_NOTIFY,
PKT_TYPE_RX_EVENT,
PKT_TYPE_NORMAL_MCU,
};
#define MT_RXD1_NORMAL_BSSID GENMASK(31, 26)
#define MT_RXD1_NORMAL_PAYLOAD_FORMAT GENMASK(25, 24)
#define MT_RXD1_FIRST_AMSDU_FRAME GENMASK(1, 0)

Просмотреть файл

@ -163,16 +163,16 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
cmd == MCU_UNI_CMD(HIF_CTRL) ||
cmd == MCU_UNI_CMD(OFFLOAD) ||
cmd == MCU_UNI_CMD(SUSPEND)) {
struct mt7615_mcu_uni_event *event;
struct mt76_connac_mcu_uni_event *event;
skb_pull(skb, sizeof(*rxd));
event = (struct mt7615_mcu_uni_event *)skb->data;
event = (struct mt76_connac_mcu_uni_event *)skb->data;
ret = le32_to_cpu(event->status);
} else if (cmd == MCU_CE_QUERY(REG_READ)) {
struct mt7615_mcu_reg_event *event;
struct mt76_connac_mcu_reg_event *event;
skb_pull(skb, sizeof(*rxd));
event = (struct mt7615_mcu_reg_event *)skb->data;
event = (struct mt76_connac_mcu_reg_event *)skb->data;
ret = (int)le32_to_cpu(event->val);
}
@ -861,7 +861,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
else
mvif->sta_added = true;
}
mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, new_entry);
mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable,
new_entry);
if (enable && sta)
mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
MT76_STA_INFO_STATE_ASSOC);

Просмотреть файл

@ -206,17 +206,6 @@ enum {
MCU_ATE_SET_TX_POWER_CONTROL = 0x15,
};
struct mt7615_mcu_uni_event {
u8 cid;
u8 pad[3];
__le32 status; /* 0: success, others: fail */
} __packed;
struct mt7615_mcu_reg_event {
__le32 reg;
__le32 val;
} __packed;
struct mt7615_roc_tlv {
u8 bss_idx;
u8 token;

Просмотреть файл

@ -66,9 +66,7 @@ const u32 mt7663e_reg_map[] = {
static void
mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
mt7615_irq_enable(dev, MT_INT_RX_DONE(q));
mt76_connac_irq_enable(mdev, MT_INT_RX_DONE(q));
}
static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
@ -80,14 +78,14 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return IRQ_NONE;
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
return IRQ_HANDLED;
}
static void mt7615_irq_tasklet(struct tasklet_struct *t)
{
struct mt7615_dev *dev = from_tasklet(dev, t, irq_tasklet);
struct mt7615_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet);
u32 intr, mask = 0, tx_mcu_mask = mt7615_tx_mcu_int_mask(dev);
u32 mcu_int;
@ -181,7 +179,6 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
.rx_check = mt7615_rx_check,
.rx_skb = mt7615_queue_rx_skb,
.rx_poll_complete = mt7615_rx_poll_complete,
.sta_ps = mt7615_sta_ps,
.sta_add = mt7615_mac_sta_add,
.sta_remove = mt7615_mac_sta_remove,
.update_survey = mt7615_update_channel,
@ -202,7 +199,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
dev = container_of(mdev, struct mt7615_dev, mt76);
mt76_mmio_init(&dev->mt76, mem_base);
tasklet_setup(&dev->irq_tasklet, mt7615_irq_tasklet);
tasklet_setup(&mdev->irq_tasklet, mt7615_irq_tasklet);
dev->reg_map = map;
dev->ops = ops;

Просмотреть файл

@ -51,6 +51,7 @@
#define MT7663_FIRMWARE_N9 "mediatek/mt7663_n9_rebb.bin"
#define MT7615_EEPROM_SIZE 1024
#define MT7663_EEPROM_SIZE 1536
#define MT7615_TOKEN_SIZE 4096
#define MT_FRAC_SCALE 12
@ -245,8 +246,6 @@ struct mt7615_dev {
};
const struct mt76_bus_ops *bus_ops;
struct tasklet_struct irq_tasklet;
struct mt7615_phy phy;
u64 omac_mask;
@ -412,13 +411,6 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb);
int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev);
int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl);
static inline void mt7615_irq_enable(struct mt7615_dev *dev, u32 mask)
{
mt76_set_irq_mask(&dev->mt76, 0, 0, mask);
tasklet_schedule(&dev->irq_tasklet);
}
static inline bool mt7615_firmware_offload(struct mt7615_dev *dev)
{
return dev->fw_ver > MT7615_FIRMWARE_V2;
@ -520,7 +512,6 @@ void mt7615_tx_token_put(struct mt7615_dev *dev);
bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len);
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info);
void mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,

Просмотреть файл

@ -94,7 +94,7 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state)
mt76_for_each_q_rx(mdev, i) {
napi_disable(&mdev->napi[i]);
}
tasklet_kill(&dev->irq_tasklet);
tasklet_kill(&mdev->irq_tasklet);
mt7615_dma_reset(dev);

Просмотреть файл

@ -122,7 +122,7 @@ void mt7615_unregister_device(struct mt7615_dev *dev)
mt7615_tx_token_put(dev);
mt7615_dma_cleanup(dev);
tasklet_disable(&dev->irq_tasklet);
tasklet_disable(&dev->mt76.irq_tasklet);
mt76_free_device(&dev->mt76);
}

Просмотреть файл

@ -84,7 +84,6 @@ static int mt7663s_probe(struct sdio_func *func,
.tx_status_data = mt7663_usb_sdio_tx_status_data,
.rx_skb = mt7615_queue_rx_skb,
.rx_check = mt7615_rx_check,
.sta_ps = mt7615_sta_ps,
.sta_add = mt7615_mac_sta_add,
.sta_remove = mt7615_mac_sta_remove,
.update_survey = mt7615_update_channel,

Просмотреть файл

@ -120,7 +120,6 @@ static int mt7663u_probe(struct usb_interface *usb_intf,
.tx_status_data = mt7663_usb_sdio_tx_status_data,
.rx_skb = mt7615_queue_rx_skb,
.rx_check = mt7615_rx_check,
.sta_ps = mt7615_sta_ps,
.sta_add = mt7615_mac_sta_add,
.sta_remove = mt7615_mac_sta_remove,
.update_survey = mt7615_update_channel,

Просмотреть файл

@ -6,6 +6,20 @@
#include "mt76.h"
enum rx_pkt_type {
PKT_TYPE_TXS,
PKT_TYPE_TXRXV,
PKT_TYPE_NORMAL,
PKT_TYPE_RX_DUP_RFB,
PKT_TYPE_RX_TMR,
PKT_TYPE_RETRIEVE,
PKT_TYPE_TXRX_NOTIFY,
PKT_TYPE_RX_EVENT,
PKT_TYPE_NORMAL_MCU,
PKT_TYPE_RX_FW_MONITOR = 0x0c,
PKT_TYPE_TXRX_NOTIFY_V0 = 0x18,
};
#define MT76_CONNAC_SCAN_IE_LEN 600
#define MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL 10
#define MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL U16_MAX
@ -279,6 +293,12 @@ static inline u8 mt76_connac_spe_idx(u8 antenna_mask)
return ant_to_spe[antenna_mask];
}
static inline void mt76_connac_irq_enable(struct mt76_dev *dev, u32 mask)
{
mt76_set_irq_mask(dev, 0, 0, mask);
tasklet_schedule(&dev->irq_tasklet);
}
int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm);
void mt76_connac_power_save_sched(struct mt76_phy *phy,
struct mt76_connac_pm *pm);
@ -353,6 +373,7 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm)
mutex_unlock(&dev->mutex);
}
void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss);
int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
int ring_base, u32 flags);
void mt76_connac_write_hw_txp(struct mt76_dev *dev,

Просмотреть файл

@ -32,6 +32,16 @@ enum {
MT_LMAC_PSMP0,
};
#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0)
#define MT_TX_FREE_WLAN_ID GENMASK(23, 14)
#define MT_TX_FREE_LATENCY GENMASK(12, 0)
/* 0: success, others: dropped */
#define MT_TX_FREE_STATUS GENMASK(14, 13)
#define MT_TX_FREE_MSDU_ID GENMASK(30, 16)
#define MT_TX_FREE_PAIR BIT(31)
/* will support this field in further revision */
#define MT_TX_FREE_RATE GENMASK(13, 0)
#define MT_TXD0_Q_IDX GENMASK(31, 25)
#define MT_TXD0_PKT_FMT GENMASK(24, 23)
#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
@ -166,6 +176,15 @@ enum {
#define MT_TXS7_MPDU_RETRY_CNT GENMASK(31, 23)
/* RXD DW0 */
#define MT_RXD0_LENGTH GENMASK(15, 0)
#define MT_RXD0_PKT_FLAG GENMASK(19, 16)
#define MT_RXD0_PKT_TYPE GENMASK(31, 27)
#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
/* RXD DW1 */
#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0)
#define MT_RXD1_NORMAL_GROUP_1 BIT(11)
@ -308,6 +327,9 @@ enum {
#define MT_CRXV_FOE_HI GENMASK(6, 0)
#define MT_CRXV_FOE_SHIFT 13
#define MT_CT_PARSE_LEN 72
#define MT_CT_DMA_BUF_NUM 2
#define MT_CT_INFO_APPLY_TXD BIT(0)
#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1)
#define MT_CT_INFO_MGMT_FRAME BIT(2)

Просмотреть файл

@ -9,6 +9,27 @@
#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
IEEE80211_RADIOTAP_HE_##f)
void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss)
{
static const u8 ppet16_ppet8_ru3_ru0[] = { 0x1c, 0xc7, 0x71 };
u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
ru_bit_mask);
ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
nss * hweight8(ru_bit_mask) * 2;
ppet_size = DIV_ROUND_UP(ppet_bits, 8);
for (i = 0; i < ppet_size - 1; i++)
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
(0xff >> (8 - (ppet_bits - 1) % 8));
}
EXPORT_SYMBOL_GPL(mt76_connac_gen_ppe_thresh);
int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
{
struct mt76_dev *dev = phy->dev;
@ -267,11 +288,29 @@ int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
}
EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues);
#define __bitrate_mask_check(_mcs, _mode) \
({ \
u8 i = 0; \
for (nss = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \
if (!mask->control[band]._mcs[i]) \
continue; \
if (hweight16(mask->control[band]._mcs[i]) == 1) { \
mode = MT_PHY_TYPE_##_mode; \
rateidx = ffs(mask->control[band]._mcs[i]) - 1; \
if (mode == MT_PHY_TYPE_HT) \
rateidx += 8 * i; \
else \
nss = i + 1; \
goto out; \
} \
} \
})
u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
struct ieee80211_vif *vif,
bool beacon, bool mcast)
{
u8 mode = 0, band = mphy->chandef.chan->band;
u8 nss = 0, mode = 0, band = mphy->chandef.chan->band;
int rateidx = 0, mcast_rate;
if (!vif)
@ -286,19 +325,12 @@ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
struct cfg80211_bitrate_mask *mask;
mask = &vif->bss_conf.beacon_tx_rate;
if (hweight16(mask->control[band].he_mcs[0]) == 1) {
rateidx = ffs(mask->control[band].he_mcs[0]) - 1;
mode = MT_PHY_TYPE_HE_SU;
goto out;
} else if (hweight16(mask->control[band].vht_mcs[0]) == 1) {
rateidx = ffs(mask->control[band].vht_mcs[0]) - 1;
mode = MT_PHY_TYPE_VHT;
goto out;
} else if (hweight8(mask->control[band].ht_mcs[0]) == 1) {
rateidx = ffs(mask->control[band].ht_mcs[0]) - 1;
mode = MT_PHY_TYPE_HT;
goto out;
} else if (hweight32(mask->control[band].legacy) == 1) {
__bitrate_mask_check(he_mcs, HE_SU);
__bitrate_mask_check(vht_mcs, VHT);
__bitrate_mask_check(ht_mcs, HT);
if (hweight32(mask->control[band].legacy) == 1) {
rateidx = ffs(mask->control[band].legacy) - 1;
goto legacy;
}
@ -314,9 +346,9 @@ legacy:
rateidx = mt76_calculate_default_rate(mphy, rateidx);
mode = rateidx >> 8;
rateidx &= GENMASK(7, 0);
out:
return FIELD_PREP(MT_TX_RATE_IDX, rateidx) |
return FIELD_PREP(MT_TX_RATE_NSS, nss) |
FIELD_PREP(MT_TX_RATE_IDX, rateidx) |
FIELD_PREP(MT_TX_RATE_MODE, mode);
}
EXPORT_SYMBOL_GPL(mt76_connac2_mac_tx_rate_val);
@ -537,7 +569,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {
/* Fixed rata is available just for 802.11 txd */
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
bool multicast = is_multicast_ether_addr(hdr->addr1);
bool multicast = ieee80211_is_data(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1);
u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon,
multicast);
u32 val = MT_TXD6_FIXED_BW;
@ -582,6 +615,17 @@ bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
stats->tx_retries +=
le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT);
if (wcid->sta) {
struct ieee80211_sta *sta;
u8 tid;
sta = container_of((void *)wcid, struct ieee80211_sta,
drv_priv);
tid = FIELD_GET(MT_TXS0_TID, txs);
ieee80211_refresh_tx_agg_session_timer(sta, tid);
}
}
txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);

Просмотреть файл

@ -363,7 +363,7 @@ void mt76_connac_mcu_bss_omac_tlv(struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_omac_tlv);
void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
bool enable, bool newly)
@ -394,7 +394,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
if (vif->p2p)
if (vif->p2p && !is_mt7921(dev))
conn_type = CONNECTION_P2P_GC;
else
conn_type = CONNECTION_INFRA_STA;
@ -402,7 +402,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
basic->aid = cpu_to_le16(sta->aid);
break;
case NL80211_IFTYPE_STATION:
if (vif->p2p)
if (vif->p2p && !is_mt7921(dev))
conn_type = CONNECTION_P2P_GO;
else
conn_type = CONNECTION_INFRA_AP;
@ -1029,7 +1029,7 @@ int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,
return PTR_ERR(skb);
if (info->sta || !info->offload_fw)
mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta,
mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, info->sta,
info->enable, info->newly);
if (info->sta && info->enable)
mt76_connac_mcu_sta_tlv(phy, skb, info->sta,
@ -1678,8 +1678,16 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
req->channel_min_dwell_time = cpu_to_le16(duration);
req->channel_dwell_time = cpu_to_le16(duration);
req->channels_num = min_t(u8, sreq->n_channels, 32);
req->ext_channels_num = min_t(u8, ext_channels_num, 32);
if (sreq->n_channels == 0 || sreq->n_channels > 64) {
req->channel_type = 0;
req->channels_num = 0;
req->ext_channels_num = 0;
} else {
req->channel_type = 4;
req->channels_num = min_t(u8, sreq->n_channels, 32);
req->ext_channels_num = min_t(u8, ext_channels_num, 32);
}
for (i = 0; i < req->channels_num + req->ext_channels_num; i++) {
if (i >= 32)
chan = &req->ext_channels[i - 32];
@ -1699,7 +1707,6 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
}
chan->channel_num = scan_list[i]->hw_value;
}
req->channel_type = sreq->n_channels ? 4 : 0;
if (sreq->ie_len > 0) {
memcpy(req->ies, sreq->ie, sreq->ie_len);

Просмотреть файл

@ -127,7 +127,7 @@ struct mt76_connac2_mcu_rxd {
u8 rsv1[2];
u8 s2d_index;
u8 tlv[0];
u8 tlv[];
};
struct mt76_connac2_patch_hdr {
@ -967,9 +967,6 @@ enum {
DEV_INFO_MAX_NUM
};
#define MCU_UNI_CMD_EVENT BIT(1)
#define MCU_UNI_CMD_UNSOLICITED_EVENT BIT(2)
/* event table */
enum {
MCU_EVENT_TARGET_ADDRESS_LEN = 0x01,
@ -1224,6 +1221,7 @@ enum {
MCU_UNI_CMD_VOW = 0x37,
MCU_UNI_CMD_RRO = 0x57,
MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
MCU_UNI_CMD_ASSERT_DUMP = 0x6f,
};
enum {
@ -1692,6 +1690,17 @@ struct mt76_connac_config {
u8 data[320];
} __packed;
struct mt76_connac_mcu_uni_event {
u8 cid;
u8 pad[3];
__le32 status; /* 0: success, others: fail */
} __packed;
struct mt76_connac_mcu_reg_event {
__le32 reg;
__le32 val;
} __packed;
static inline enum mcu_cipher_type
mt76_connac_mcu_get_cipher(int cipher)
{
@ -1779,7 +1788,7 @@ mt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len)
int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy);
int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif);
void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable,
bool newly);

Просмотреть файл

@ -631,8 +631,11 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
mt76_tx_status_unlock(mdev, &list);
if (!status.skb)
if (!status.skb) {
spin_lock_bh(&dev->mt76.rx_lock);
ieee80211_tx_status_ext(mt76_hw(dev), &status);
spin_unlock_bh(&dev->mt76.rx_lock);
}
if (!len)
goto out;

Просмотреть файл

@ -958,10 +958,10 @@ mt7915_xmit_queues_show(struct seq_file *file, void *data)
DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);
#define mt7915_txpower_puts(prefix, rate) \
#define mt7915_txpower_puts(rate) \
({ \
len += scnprintf(buf + len, sz - len, "%-16s:", #prefix " (tmac)"); \
for (i = 0; i < mt7915_sku_group_len[rate]; i++, offs++) \
len += scnprintf(buf + len, sz - len, "%-16s:", #rate " (TMAC)"); \
for (i = 0; i < mt7915_sku_group_len[SKU_##rate]; i++, offs++) \
len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]); \
len += scnprintf(buf + len, sz - len, "\n"); \
})
@ -1004,41 +1004,41 @@ mt7915_rate_txpower_get(struct file *file, char __user *user_buf,
phy != &dev->phy, phy->mt76->chandef.chan->hw_value);
len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s\n",
" ", "1m", "2m", "5m", "11m");
mt7915_txpower_puts(CCK, SKU_CCK);
mt7915_txpower_puts(CCK);
len += scnprintf(buf + len, sz - len,
"%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n",
" ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
"54m");
mt7915_txpower_puts(OFDM, SKU_OFDM);
mt7915_txpower_puts(OFDM);
len += scnprintf(buf + len, sz - len,
"%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n",
" ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
"mcs5", "mcs6", "mcs7");
mt7915_txpower_puts(HT20, SKU_HT_BW20);
mt7915_txpower_puts(HT_BW20);
len += scnprintf(buf + len, sz - len,
"%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
" ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
"mcs6", "mcs7", "mcs32");
mt7915_txpower_puts(HT40, SKU_HT_BW40);
mt7915_txpower_puts(HT_BW40);
len += scnprintf(buf + len, sz - len,
"%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
" ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
"mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
mt7915_txpower_puts(VHT20, SKU_VHT_BW20);
mt7915_txpower_puts(VHT40, SKU_VHT_BW40);
mt7915_txpower_puts(VHT80, SKU_VHT_BW80);
mt7915_txpower_puts(VHT160, SKU_VHT_BW160);
mt7915_txpower_puts(HE26, SKU_HE_RU26);
mt7915_txpower_puts(HE52, SKU_HE_RU52);
mt7915_txpower_puts(HE106, SKU_HE_RU106);
mt7915_txpower_puts(HE242, SKU_HE_RU242);
mt7915_txpower_puts(HE484, SKU_HE_RU484);
mt7915_txpower_puts(HE996, SKU_HE_RU996);
mt7915_txpower_puts(HE996x2, SKU_HE_RU2x996);
mt7915_txpower_puts(VHT_BW20);
mt7915_txpower_puts(VHT_BW40);
mt7915_txpower_puts(VHT_BW80);
mt7915_txpower_puts(VHT_BW160);
mt7915_txpower_puts(HE_RU26);
mt7915_txpower_puts(HE_RU52);
mt7915_txpower_puts(HE_RU106);
mt7915_txpower_puts(HE_RU242);
mt7915_txpower_puts(HE_RU484);
mt7915_txpower_puts(HE_RU996);
mt7915_txpower_puts(HE_RU2x996);
reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) :
MT_WF_PHY_TPC_CTRL_STAT_MT7916(band);

Просмотреть файл

@ -87,8 +87,14 @@ static void mt7915_dma_config(struct mt7915_dev *dev)
MT7916_RXQ_BAND0);
RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MT7916,
MT7916_RXQ_MCU_WA);
RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_WED_RX_DONE_BAND1_MT7916,
MT7916_RXQ_BAND1);
if (dev->hif2)
RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0,
MT_INT_RX_DONE_BAND1_MT7916,
MT7916_RXQ_BAND1);
else
RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0,
MT_INT_WED_RX_DONE_BAND1_MT7916,
MT7916_RXQ_BAND1);
RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MAIN_MT7916,
MT7916_RXQ_MCU_WA_MAIN);
TXQ_CONFIG(0, WFDMA0, MT_INT_WED_TX_DONE_BAND0,

Просмотреть файл

@ -89,6 +89,7 @@ static ssize_t mt7915_thermal_temp_store(struct device *dev,
val < phy->throttle_temp[MT7915_CRIT_TEMP_IDX])) {
dev_err(phy->dev->mt76.dev,
"temp1_max shall be greater than temp1_crit.");
mutex_unlock(&phy->dev->mt76.mutex);
return -EINVAL;
}
@ -202,6 +203,10 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
phy->cdev = cdev;
}
/* initialize critical/maximum high temperature */
phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP;
phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP;
if (!IS_REACHABLE(CONFIG_HWMON))
return 0;
@ -210,10 +215,6 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
/* initialize critical/maximum high temperature */
phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP;
phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP;
return 0;
}
@ -368,6 +369,7 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
if (!is_mt7915(&dev->mt76))
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
@ -930,27 +932,6 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy,
}
}
static void
mt7915_gen_ppe_thresh(u8 *he_ppet, int nss)
{
u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
static const u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71};
he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
ru_bit_mask);
ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
nss * hweight8(ru_bit_mask) * 2;
ppet_size = DIV_ROUND_UP(ppet_bits, 8);
for (i = 0; i < ppet_size - 1; i++)
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
(0xff >> (8 - (ppet_bits - 1) % 8));
}
static int
mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
struct ieee80211_sband_iftype_data *data)
@ -1100,7 +1081,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
mt7915_gen_ppe_thresh(he_cap->ppe_thres, nss);
mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
@ -1179,7 +1160,7 @@ static void mt7915_stop_hardware(struct mt7915_dev *dev)
mt7915_mcu_exit(dev);
mt7915_tx_token_put(dev);
mt7915_dma_cleanup(dev);
tasklet_disable(&dev->irq_tasklet);
tasklet_disable(&dev->mt76.irq_tasklet);
if (is_mt7986(&dev->mt76))
mt7986_wmac_disable(dev);

Просмотреть файл

@ -73,10 +73,6 @@ static struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev,
return &sta->vif->sta.wcid;
}
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
{
}
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
{
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
@ -1627,7 +1623,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
}
local_bh_enable();
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);

Просмотреть файл

@ -6,43 +6,12 @@
#include "../mt76_connac2_mac.h"
#define MT_CT_PARSE_LEN 72
#define MT_CT_DMA_BUF_NUM 2
#define MT_RXD0_LENGTH GENMASK(15, 0)
#define MT_RXD0_PKT_TYPE GENMASK(31, 27)
#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
enum rx_pkt_type {
PKT_TYPE_TXS,
PKT_TYPE_TXRXV,
PKT_TYPE_NORMAL,
PKT_TYPE_RX_DUP_RFB,
PKT_TYPE_RX_TMR,
PKT_TYPE_RETRIEVE,
PKT_TYPE_TXRX_NOTIFY,
PKT_TYPE_RX_EVENT,
PKT_TYPE_RX_FW_MONITOR = 0x0c,
PKT_TYPE_TXRX_NOTIFY_V0 = 0x18,
};
#define MT_TX_FREE_VER GENMASK(18, 16)
#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0)
#define MT_TX_FREE_MSDU_CNT_V0 GENMASK(6, 0)
#define MT_TX_FREE_WLAN_ID GENMASK(23, 14)
#define MT_TX_FREE_LATENCY GENMASK(12, 0)
#define MT_TX_FREE_MSDU_CNT_V0 GENMASK(6, 0)
/* 0: success, others: dropped */
#define MT_TX_FREE_MSDU_ID GENMASK(30, 16)
#define MT_TX_FREE_PAIR BIT(31)
#define MT_TX_FREE_MPDU_HEADER BIT(30)
#define MT_TX_FREE_MSDU_ID_V3 GENMASK(14, 0)
/* will support this field in further revision */
#define MT_TX_FREE_RATE GENMASK(13, 0)
#define MT_TXS5_F0_FINAL_MPDU BIT(31)
#define MT_TXS5_F0_QOS BIT(30)
#define MT_TXS5_F0_TX_COUNT GENMASK(29, 25)

Просмотреть файл

@ -269,7 +269,6 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
mt7915_init_bitrate_mask(vif);
memset(&mvif->cap, -1, sizeof(mvif->cap));
mt7915_mcu_add_bss_info(phy, vif, true);
mt7915_mcu_add_sta(dev, vif, NULL, true);

Просмотреть файл

@ -706,7 +706,6 @@ static void
mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
struct ieee80211_vif *vif)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
struct ieee80211_he_mcs_nss_supp mcs_map;
struct sta_rec_he *he;
@ -740,7 +739,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
if (mvif->cap.he_ldpc &&
if (vif->bss_conf.he_ldpc &&
(elem->phy_cap_info[1] &
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
cap |= STA_REC_HE_CAP_LDPC;
@ -849,7 +848,6 @@ static void
mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
struct ieee80211_sta *sta, struct ieee80211_vif *vif)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
struct sta_rec_muru *muru;
struct tlv *tlv;
@ -862,9 +860,9 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
muru = (struct sta_rec_muru *)tlv;
muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
mvif->cap.vht_mu_ebfer ||
mvif->cap.vht_mu_ebfee;
muru->cfg.mimo_dl_en = vif->bss_conf.he_mu_beamformer ||
vif->bss_conf.vht_mu_beamformer ||
vif->bss_conf.vht_mu_beamformee;
if (!is_mt7915(&dev->mt76))
muru->cfg.mimo_ul_en = true;
muru->cfg.ofdma_dl_en = true;
@ -997,8 +995,8 @@ mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr);
if (sta)
mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv,
wtbl_hdr, mvif->cap.ht_ldpc,
mvif->cap.vht_ldpc);
wtbl_hdr, vif->bss_conf.ht_ldpc,
vif->bss_conf.vht_ldpc);
return 0;
}
@ -1007,7 +1005,6 @@ static inline bool
mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool bfee)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
int tx_ant = hweight8(phy->mt76->chainmask) - 1;
if (vif->type != NL80211_IFTYPE_STATION &&
@ -1021,10 +1018,10 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
if (bfee)
return mvif->cap.he_su_ebfee &&
return vif->bss_conf.he_su_beamformee &&
HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
else
return mvif->cap.he_su_ebfer &&
return vif->bss_conf.he_su_beamformer &&
HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
}
@ -1032,10 +1029,10 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
u32 cap = sta->deflink.vht_cap.cap;
if (bfee)
return mvif->cap.vht_su_ebfee &&
return vif->bss_conf.vht_su_beamformee &&
(cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
else
return mvif->cap.vht_su_ebfer &&
return vif->bss_conf.vht_su_beamformer &&
(cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
}
@ -1530,7 +1527,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_TX_STBC;
if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
cap |= STA_CAP_RX_STBC;
if (mvif->cap.ht_ldpc &&
if (vif->bss_conf.ht_ldpc &&
(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
cap |= STA_CAP_LDPC;
@ -1556,7 +1553,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_VHT_TX_STBC;
if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
cap |= STA_CAP_VHT_RX_STBC;
if (mvif->cap.vht_ldpc &&
if (vif->bss_conf.vht_ldpc &&
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
cap |= STA_CAP_VHT_LDPC;
@ -1657,8 +1654,8 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
/* starec basic */
mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable,
!rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable,
!rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
if (!enable)
goto out;
@ -1875,84 +1872,6 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
}
static void
mt7915_mcu_beacon_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct sk_buff *skb)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct mt7915_vif_cap *vc = &mvif->cap;
const struct ieee80211_he_cap_elem *he;
const struct ieee80211_vht_cap *vht;
const struct ieee80211_ht_cap *ht;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
const u8 *ie;
u32 len, bc;
/* Check missing configuration options to allow AP mode in mac80211
* to remain in sync with hostapd settings, and get a subset of
* beacon and hardware capabilities.
*/
if (WARN_ON_ONCE(skb->len <= (mgmt->u.beacon.variable - skb->data)))
return;
memset(vc, 0, sizeof(*vc));
len = skb->len - (mgmt->u.beacon.variable - skb->data);
ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, mgmt->u.beacon.variable,
len);
if (ie && ie[1] >= sizeof(*ht)) {
ht = (void *)(ie + 2);
vc->ht_ldpc = !!(le16_to_cpu(ht->cap_info) &
IEEE80211_HT_CAP_LDPC_CODING);
}
ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, mgmt->u.beacon.variable,
len);
if (ie && ie[1] >= sizeof(*vht)) {
u32 pc = phy->mt76->sband_5g.sband.vht_cap.cap;
vht = (void *)(ie + 2);
bc = le32_to_cpu(vht->vht_cap_info);
vc->vht_ldpc = !!(bc & IEEE80211_VHT_CAP_RXLDPC);
vc->vht_su_ebfer =
(bc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
vc->vht_su_ebfee =
(bc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
vc->vht_mu_ebfer =
(bc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
vc->vht_mu_ebfee =
(bc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
}
ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY,
mgmt->u.beacon.variable, len);
if (ie && ie[1] >= sizeof(*he) + 1) {
const struct ieee80211_sta_he_cap *pc =
mt76_connac_get_he_phy_cap(phy->mt76, vif);
const struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
he = (void *)(ie + 3);
vc->he_ldpc =
HE_PHY(CAP1_LDPC_CODING_IN_PAYLOAD, pe->phy_cap_info[1]);
vc->he_su_ebfer =
HE_PHY(CAP3_SU_BEAMFORMER, he->phy_cap_info[3]) &&
HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
vc->he_su_ebfee =
HE_PHY(CAP4_SU_BEAMFORMEE, he->phy_cap_info[4]) &&
HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
vc->he_mu_ebfer =
HE_PHY(CAP4_MU_BEAMFORMER, he->phy_cap_info[4]) &&
HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4]);
}
}
static void
mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct sk_buff *rskb, struct bss_info_bcn *bcn,
@ -2063,8 +1982,6 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
info = IEEE80211_SKB_CB(skb);
info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
mt7915_mcu_beacon_check_caps(phy, vif, skb);
mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs);
mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs);
mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
@ -2370,7 +2287,9 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
if (ret)
return ret;
if (mtk_wed_device_active(&dev->mt76.mmio.wed) && is_mt7915(&dev->mt76))
if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
is_mt7915(&dev->mt76)) ||
!mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
ret = mt7915_mcu_set_mwds(dev, 1);

Просмотреть файл

@ -916,7 +916,7 @@ static void mt7915_rx_poll_complete(struct mt76_dev *mdev,
/* TODO: support 2/4/6/8 MSI-X vectors */
static void mt7915_irq_tasklet(struct tasklet_struct *t)
{
struct mt7915_dev *dev = from_tasklet(dev, t, irq_tasklet);
struct mt7915_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet);
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
u32 intr, intr1, mask;
@ -989,18 +989,18 @@ irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
struct mt7915_dev *dev = dev_instance;
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
if (mtk_wed_device_active(wed)) {
if (mtk_wed_device_active(wed))
mtk_wed_device_irq_set_mask(wed, 0);
} else {
else
mt76_wr(dev, MT_INT_MASK_CSR, 0);
if (dev->hif2)
mt76_wr(dev, MT_INT1_MASK_CSR, 0);
}
if (dev->hif2)
mt76_wr(dev, MT_INT1_MASK_CSR, 0);
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return IRQ_NONE;
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
return IRQ_HANDLED;
}
@ -1022,7 +1022,6 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev,
.rx_skb = mt7915_queue_rx_skb,
.rx_check = mt7915_rx_check,
.rx_poll_complete = mt7915_rx_poll_complete,
.sta_ps = mt7915_sta_ps,
.sta_add = mt7915_mac_sta_add,
.sta_remove = mt7915_mac_sta_remove,
.update_survey = mt7915_update_channel,
@ -1041,7 +1040,7 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev,
if (ret)
goto error;
tasklet_setup(&dev->irq_tasklet, mt7915_irq_tasklet);
tasklet_setup(&mdev->irq_tasklet, mt7915_irq_tasklet);
return dev;

Просмотреть файл

@ -147,23 +147,9 @@ struct mt7915_sta {
} twt;
};
struct mt7915_vif_cap {
bool ht_ldpc:1;
bool vht_ldpc:1;
bool he_ldpc:1;
bool vht_su_ebfer:1;
bool vht_su_ebfee:1;
bool vht_mu_ebfer:1;
bool vht_mu_ebfee:1;
bool he_su_ebfer:1;
bool he_su_ebfee:1;
bool he_mu_ebfer:1;
};
struct mt7915_vif {
struct mt76_vif mt76; /* must be first */
struct mt7915_vif_cap cap;
struct mt7915_sta sta;
struct mt7915_phy *phy;
@ -308,7 +294,6 @@ struct mt7915_dev {
u32 wfdma_mask;
const struct mt76_bus_ops *bus_ops;
struct tasklet_struct irq_tasklet;
struct mt7915_phy phy;
/* monitor rx chain configured channel */
@ -581,7 +566,7 @@ static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask)
else
mt76_set_irq_mask(&dev->mt76, 0, 0, mask);
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
}
static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask)
@ -631,7 +616,6 @@ void mt7915_tx_token_put(struct mt7915_dev *dev);
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info);
bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len);
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
void mt7915_stats_work(struct work_struct *work);
int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force);
int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);

Просмотреть файл

@ -1239,6 +1239,8 @@ static const struct of_device_id mt7986_wmac_of_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, mt7986_wmac_of_match);
struct platform_driver mt7986_wmac_driver = {
.driver = {
.name = "mt7986-wmac",

Просмотреть файл

@ -24,7 +24,7 @@ struct mt7921_asar_dyn {
u8 names[4];
u8 enable;
u8 nr_tbl;
struct mt7921_asar_dyn_limit tbl[0];
DECLARE_FLEX_ARRAY(struct mt7921_asar_dyn_limit, tbl);
} __packed;
struct mt7921_asar_dyn_limit_v2 {
@ -37,7 +37,7 @@ struct mt7921_asar_dyn_v2 {
u8 enable;
u8 rsvd;
u8 nr_tbl;
struct mt7921_asar_dyn_limit_v2 tbl[0];
DECLARE_FLEX_ARRAY(struct mt7921_asar_dyn_limit_v2, tbl);
} __packed;
struct mt7921_asar_geo_band {
@ -55,7 +55,7 @@ struct mt7921_asar_geo {
u8 names[4];
u8 version;
u8 nr_tbl;
struct mt7921_asar_geo_limit tbl[0];
DECLARE_FLEX_ARRAY(struct mt7921_asar_geo_limit, tbl);
} __packed;
struct mt7921_asar_geo_limit_v2 {
@ -69,7 +69,7 @@ struct mt7921_asar_geo_v2 {
u8 version;
u8 rsvd;
u8 nr_tbl;
struct mt7921_asar_geo_limit_v2 tbl[0];
DECLARE_FLEX_ARRAY(struct mt7921_asar_geo_limit_v2, tbl);
} __packed;
struct mt7921_asar_cl {
@ -85,7 +85,7 @@ struct mt7921_asar_fg {
u8 rsvd;
u8 nr_flag;
u8 rsvd1;
u8 flag[0];
u8 flag[];
} __packed;
struct mt7921_acpi_sar {

Просмотреть файл

@ -2,7 +2,6 @@
/* Copyright (C) 2020 MediaTek Inc. */
#include "mt7921.h"
#include "eeprom.h"
static int
mt7921_reg_set(void *data, u64 val)

Просмотреть файл

@ -3,7 +3,7 @@
#include "mt7921.h"
#include "../dma.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
static int mt7921_poll_tx(struct napi_struct *napi, int budget)
{
@ -19,7 +19,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget)
mt76_connac_tx_cleanup(&dev->mt76);
if (napi_complete(napi))
mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL);
mt76_connac_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL);
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
return 0;
@ -66,6 +66,24 @@ static void mt7921_dma_prefetch(struct mt7921_dev *dev)
static int mt7921_dma_disable(struct mt7921_dev *dev, bool force)
{
/* disable WFDMA0 */
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
if (!mt76_poll_msec_tick(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1))
return -ETIMEDOUT;
/* disable dmashdl */
mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0,
MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS);
if (force) {
/* reset */
mt76_clear(dev, MT_WFDMA0_RST,
@ -77,24 +95,6 @@ static int mt7921_dma_disable(struct mt7921_dev *dev, bool force)
MT_WFDMA0_RST_LOGIC_RST);
}
/* disable dmashdl */
mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0,
MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS);
/* disable WFDMA0 */
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
if (!mt76_poll(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000))
return -ETIMEDOUT;
return 0;
}
@ -123,9 +123,9 @@ static int mt7921_dma_enable(struct mt7921_dev *dev)
mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
/* enable interrupts for TX/RX rings */
mt7921_irq_enable(dev,
MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
mt76_connac_irq_enable(&dev->mt76,
MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
return 0;
@ -301,6 +301,10 @@ void mt7921_dma_cleanup(struct mt7921_dev *dev)
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
mt76_poll_msec_tick(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1);
/* reset */
mt76_clear(dev, MT_WFDMA0_RST,
MT_WFDMA0_RST_DMASHDL_ALL_RST |

Просмотреть файл

@ -1,30 +0,0 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7921_EEPROM_H
#define __MT7921_EEPROM_H
#include "mt7921.h"
enum mt7921_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_WIFI_CONF = 0x07c,
MT_EE_HW_TYPE = 0x55b,
__MT_EE_MAX = 0x9ff
};
#define MT_EE_WIFI_CONF_TX_MASK BIT(0)
#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(3, 2)
#define MT_EE_HW_TYPE_ENCAP BIT(0)
enum mt7921_eeprom_band {
MT_EE_NA,
MT_EE_5GHZ,
MT_EE_2GHZ,
MT_EE_DUAL_BAND,
};
#endif

Просмотреть файл

@ -4,9 +4,8 @@
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include "mt7921.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
#include "mcu.h"
#include "eeprom.h"
static const struct ieee80211_iface_limit if_limits[] = {
{
@ -32,11 +31,13 @@ static const struct ieee80211_iface_combination if_comb[] = {
static const struct ieee80211_iface_limit if_limits_chanctx[] = {
{
.max = 2,
.types = BIT(NL80211_IFTYPE_STATION),
.types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT)
},
{
.max = 1,
.types = BIT(NL80211_IFTYPE_AP),
.types = BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO)
}
};
@ -100,7 +101,9 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
WIPHY_FLAG_4ADDR_STATION);
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP);
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
wiphy->max_remain_on_channel_duration = 5000;
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
wiphy->max_scan_ssids = 4;
@ -121,6 +124,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
@ -169,7 +173,8 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
}
u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm)
static u8
mt7921_get_offload_capability(struct device *dev, const char *fw_wm)
{
struct mt7921_fw_features *features = NULL;
const struct mt76_connac2_fw_trailer *hdr;
@ -220,7 +225,31 @@ out:
return features ? features->data : 0;
}
EXPORT_SYMBOL_GPL(mt7921_check_offload_capability);
struct ieee80211_ops *
mt7921_get_mac80211_ops(struct device *dev, void *drv_data, u8 *fw_features)
{
struct ieee80211_ops *ops;
ops = devm_kmemdup(dev, &mt7921_ops, sizeof(mt7921_ops), GFP_KERNEL);
if (!ops)
return NULL;
*fw_features = mt7921_get_offload_capability(dev, drv_data);
if (!(*fw_features & MT7921_FW_CAP_CNM)) {
ops->remain_on_channel = NULL;
ops->cancel_remain_on_channel = NULL;
ops->add_chanctx = NULL;
ops->remove_chanctx = NULL;
ops->change_chanctx = NULL;
ops->assign_vif_chanctx = NULL;
ops->unassign_vif_chanctx = NULL;
ops->mgd_prepare_tx = NULL;
ops->mgd_complete_tx = NULL;
}
return ops;
}
EXPORT_SYMBOL_GPL(mt7921_get_mac80211_ops);
int mt7921_mac_init(struct mt7921_dev *dev)
{

Просмотреть файл

@ -6,9 +6,20 @@
#include <linux/timekeeping.h>
#include "mt7921.h"
#include "../dma.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
#include "mcu.h"
#define MT_WTBL_TXRX_CAP_RATE_OFFSET 7
#define MT_WTBL_TXRX_RATE_G2_HE 24
#define MT_WTBL_TXRX_RATE_G2 12
#define MT_WTBL_AC0_CTT_OFFSET 20
static u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset)
{
return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4;
}
static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev,
u16 idx, bool unicast)
{
@ -32,11 +43,6 @@ static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev,
return &sta->vif->sta.wcid;
}
void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
{
}
EXPORT_SYMBOL_GPL(mt7921_sta_ps);
bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask)
{
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,

Просмотреть файл

@ -1,53 +0,0 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7921_MAC_H
#define __MT7921_MAC_H
#include "../mt76_connac2_mac.h"
#define MT_CT_PARSE_LEN 72
#define MT_CT_DMA_BUF_NUM 2
#define MT_RXD0_LENGTH GENMASK(15, 0)
#define MT_RXD0_PKT_FLAG GENMASK(19, 16)
#define MT_RXD0_PKT_TYPE GENMASK(31, 27)
#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
enum rx_pkt_type {
PKT_TYPE_TXS,
PKT_TYPE_TXRXV,
PKT_TYPE_NORMAL,
PKT_TYPE_RX_DUP_RFB,
PKT_TYPE_RX_TMR,
PKT_TYPE_RETRIEVE,
PKT_TYPE_TXRX_NOTIFY,
PKT_TYPE_RX_EVENT,
PKT_TYPE_NORMAL_MCU,
};
#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0)
#define MT_TX_FREE_WLAN_ID GENMASK(23, 14)
#define MT_TX_FREE_LATENCY GENMASK(12, 0)
/* 0: success, others: dropped */
#define MT_TX_FREE_STATUS GENMASK(14, 13)
#define MT_TX_FREE_MSDU_ID GENMASK(30, 16)
#define MT_TX_FREE_PAIR BIT(31)
/* will support this field in further revision */
#define MT_TX_FREE_RATE GENMASK(13, 0)
#define MT_WTBL_TXRX_CAP_RATE_OFFSET 7
#define MT_WTBL_TXRX_RATE_G2_HE 24
#define MT_WTBL_TXRX_RATE_G2 12
#define MT_WTBL_AC0_CTT_OFFSET 20
static inline u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset)
{
return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4;
}
#endif

Просмотреть файл

@ -9,27 +9,6 @@
#include "mt7921.h"
#include "mcu.h"
static void
mt7921_gen_ppe_thresh(u8 *he_ppet, int nss)
{
u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
static const u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71};
he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
ru_bit_mask);
ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
nss * hweight8(ru_bit_mask) * 2;
ppet_size = DIV_ROUND_UP(ppet_bits, 8);
for (i = 0; i < ppet_size - 1; i++)
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
(0xff >> (8 - (ppet_bits - 1) % 8));
}
static int
mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
struct ieee80211_sband_iftype_data *data)
@ -168,7 +147,7 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
mt7921_gen_ppe_thresh(he_cap->ppe_thres, nss);
mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
@ -703,10 +682,25 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
unsigned int *total_flags,
u64 multicast)
{
#define MT7921_FILTER_FCSFAIL BIT(2)
#define MT7921_FILTER_CONTROL BIT(5)
#define MT7921_FILTER_OTHER_BSS BIT(6)
#define MT7921_FILTER_ENABLE BIT(31)
struct mt7921_dev *dev = mt7921_hw_dev(hw);
u32 flags = MT7921_FILTER_ENABLE;
#define MT7921_FILTER(_fif, _type) do { \
if (*total_flags & (_fif)) \
flags |= MT7921_FILTER_##_type; \
} while (0)
MT7921_FILTER(FIF_FCSFAIL, FCSFAIL);
MT7921_FILTER(FIF_CONTROL, CONTROL);
MT7921_FILTER(FIF_OTHER_BSS, OTHER_BSS);
mt7921_mutex_acquire(dev);
mt7921_mcu_set_rxfilter(dev, *total_flags, 0, 0);
mt7921_mcu_set_rxfilter(dev, flags, 0, 0);
mt7921_mutex_release(dev);
*total_flags &= (FIF_OTHER_BSS | FIF_FCSFAIL | FIF_CONTROL);
@ -1695,7 +1689,7 @@ static void mt7921_ctx_iter(void *priv, u8 *mac,
if (ctx != mvif->ctx)
return;
if (vif->type & NL80211_IFTYPE_MONITOR)
if (vif->type == NL80211_IFTYPE_MONITOR)
mt7921_mcu_config_sniffer(mvif, ctx);
else
mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx);

Просмотреть файл

@ -5,9 +5,8 @@
#include <linux/firmware.h>
#include "mt7921.h"
#include "mt7921_trace.h"
#include "eeprom.h"
#include "mcu.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
#define MT_STA_BFER BIT(0)
#define MT_STA_BFEE BIT(1)
@ -16,24 +15,6 @@ static bool mt7921_disable_clc;
module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
MODULE_PARM_DESC(disable_clc, "disable CLC support");
static int
mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb)
{
struct mt7921_mcu_eeprom_info *res;
u8 *buf;
if (!skb)
return -EINVAL;
skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
res = (struct mt7921_mcu_eeprom_info *)skb->data;
buf = dev->eeprom.data + le32_to_cpu(res->addr);
memcpy(buf, res->data, 16);
return 0;
}
int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
{
@ -60,27 +41,25 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
skb_pull(skb, sizeof(*rxd) + 4);
ret = le32_to_cpu(*(__le32 *)skb->data);
} else if (cmd == MCU_EXT_CMD(EFUSE_ACCESS)) {
ret = mt7921_mcu_parse_eeprom(mdev, skb);
} else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
cmd == MCU_UNI_CMD(HIF_CTRL) ||
cmd == MCU_UNI_CMD(OFFLOAD) ||
cmd == MCU_UNI_CMD(SUSPEND)) {
struct mt7921_mcu_uni_event *event;
struct mt76_connac_mcu_uni_event *event;
skb_pull(skb, sizeof(*rxd));
event = (struct mt7921_mcu_uni_event *)skb->data;
event = (struct mt76_connac_mcu_uni_event *)skb->data;
ret = le32_to_cpu(event->status);
/* skip invalid event */
if (mcu_cmd != event->cid)
ret = -EAGAIN;
} else if (cmd == MCU_CE_QUERY(REG_READ)) {
struct mt7921_mcu_reg_event *event;
struct mt76_connac_mcu_reg_event *event;
skb_pull(skb, sizeof(*rxd));
event = (struct mt7921_mcu_reg_event *)skb->data;
event = (struct mt76_connac_mcu_reg_event *)skb->data;
ret = (int)le32_to_cpu(event->val);
} else {
skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));

Просмотреть файл

@ -50,22 +50,11 @@ struct mt7921_mcu_eeprom_info {
#define MT_RA_RATE_DCM_EN BIT(4)
#define MT_RA_RATE_BW GENMASK(14, 13)
struct mt7921_mcu_uni_event {
u8 cid;
u8 pad[3];
__le32 status; /* 0: success, others: fail */
} __packed;
enum {
MT_EBF = BIT(0), /* explicit beamforming */
MT_IBF = BIT(1) /* implicit beamforming */
};
struct mt7921_mcu_reg_event {
__le32 reg;
__le32 val;
} __packed;
struct mt7921_mcu_ant_id_config {
u8 ant_id[4];
} __packed;

Просмотреть файл

@ -266,6 +266,17 @@ struct mt7921_phy {
bool roc_grant;
};
enum mt7921_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_WIFI_CONF = 0x07c,
MT_EE_HW_TYPE = 0x55b,
__MT_EE_MAX = 0x9ff
};
#define MT_EE_HW_TYPE_ENCAP BIT(0)
#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
@ -287,7 +298,6 @@ struct mt7921_dev {
const struct mt76_bus_ops *bus_ops;
struct mt7921_phy phy;
struct tasklet_struct irq_tasklet;
struct work_struct reset_work;
bool hw_full_reset:1;
@ -391,13 +401,6 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb);
int mt7921_mcu_set_rxfilter(struct mt7921_dev *dev, u32 fif,
u8 bit_op, u32 bit_map);
static inline void mt7921_irq_enable(struct mt7921_dev *dev, u32 mask)
{
mt76_set_irq_mask(&dev->mt76, 0, 0, mask);
tasklet_schedule(&dev->irq_tasklet);
}
static inline u32
mt7921_reg_map_l1(struct mt7921_dev *dev, u32 addr)
{
@ -478,7 +481,6 @@ void mt7921_tx_token_put(struct mt7921_dev *dev);
bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len);
void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info);
void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
void mt7921_stats_work(struct work_struct *work);
void mt7921_set_stream_he_caps(struct mt7921_phy *phy);
void mt7921_update_channel(struct mt76_phy *mphy);
@ -593,5 +595,6 @@ int mt7921_mcu_set_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
enum mt7921_roc_req type, u8 token_id);
int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
u8 token_id);
u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm);
struct ieee80211_ops *mt7921_get_mac80211_ops(struct device *dev,
void *drv_data, u8 *fw_features);
#endif

Просмотреть файл

@ -8,7 +8,7 @@
#include <linux/pci.h>
#include "mt7921.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
#include "mcu.h"
#include "../trace.h"
@ -31,14 +31,12 @@ MODULE_PARM_DESC(disable_aspm, "disable PCI ASPM support");
static void
mt7921_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
if (q == MT_RXQ_MAIN)
mt7921_irq_enable(dev, MT_INT_RX_DONE_DATA);
mt76_connac_irq_enable(mdev, MT_INT_RX_DONE_DATA);
else if (q == MT_RXQ_MCU_WA)
mt7921_irq_enable(dev, MT_INT_RX_DONE_WM2);
mt76_connac_irq_enable(mdev, MT_INT_RX_DONE_WM2);
else
mt7921_irq_enable(dev, MT_INT_RX_DONE_WM);
mt76_connac_irq_enable(mdev, MT_INT_RX_DONE_WM);
}
static irqreturn_t mt7921_irq_handler(int irq, void *dev_instance)
@ -50,7 +48,7 @@ static irqreturn_t mt7921_irq_handler(int irq, void *dev_instance)
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return IRQ_NONE;
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
return IRQ_HANDLED;
}
@ -115,14 +113,15 @@ static void mt7921e_unregister_device(struct mt7921_dev *dev)
napi_disable(&dev->mt76.napi[i]);
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
cancel_work_sync(&dev->reset_work);
mt7921_tx_token_put(dev);
mt7921_mcu_drv_pmctrl(dev);
__mt7921_mcu_drv_pmctrl(dev);
mt7921_dma_cleanup(dev);
mt7921_wfsys_reset(dev);
skb_queue_purge(&dev->mt76.mcu.res_q);
tasklet_disable(&dev->irq_tasklet);
tasklet_disable(&dev->mt76.irq_tasklet);
}
static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
@ -243,7 +242,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.rx_check = mt7921_rx_check,
.rx_skb = mt7921_queue_rx_skb,
.rx_poll_complete = mt7921_rx_poll_complete,
.sta_ps = mt7921_sta_ps,
.sta_add = mt7921_mac_sta_add,
.sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
@ -256,13 +254,13 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.drv_own = mt7921e_mcu_drv_pmctrl,
.fw_own = mt7921e_mcu_fw_pmctrl,
};
struct ieee80211_ops *ops;
struct mt76_bus_ops *bus_ops;
struct mt7921_dev *dev;
struct mt76_dev *mdev;
u8 features;
int ret;
u16 cmd;
ret = pcim_enable_device(pdev);
if (ret)
@ -272,6 +270,11 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_MEMORY)) {
cmd |= PCI_COMMAND_MEMORY;
pci_write_config_word(pdev, PCI_COMMAND, cmd);
}
pci_set_master(pdev);
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
@ -285,27 +288,13 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (mt7921_disable_aspm)
mt76_pci_disable_aspm(pdev);
features = mt7921_check_offload_capability(&pdev->dev, (const char *)
id->driver_data);
ops = devm_kmemdup(&pdev->dev, &mt7921_ops, sizeof(mt7921_ops),
GFP_KERNEL);
ops = mt7921_get_mac80211_ops(&pdev->dev, (void *)id->driver_data,
&features);
if (!ops) {
ret = -ENOMEM;
goto err_free_pci_vec;
}
if (!(features & MT7921_FW_CAP_CNM)) {
ops->remain_on_channel = NULL;
ops->cancel_remain_on_channel = NULL;
ops->add_chanctx = NULL;
ops->remove_chanctx = NULL;
ops->change_chanctx = NULL;
ops->assign_vif_chanctx = NULL;
ops->unassign_vif_chanctx = NULL;
ops->mgd_prepare_tx = NULL;
ops->mgd_complete_tx = NULL;
}
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops);
if (!mdev) {
ret = -ENOMEM;
@ -318,7 +307,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
dev->fw_features = features;
dev->hif_ops = &mt7921_pcie_ops;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
tasklet_init(&mdev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
@ -430,7 +419,7 @@ static int mt7921_pci_suspend(struct device *device)
mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
synchronize_irq(pdev->irq);
tasklet_kill(&dev->irq_tasklet);
tasklet_kill(&mdev->irq_tasklet);
err = mt7921_mcu_fw_pmctrl(dev);
if (err)
@ -474,8 +463,9 @@ static int mt7921_pci_resume(struct device *device)
/* enable interrupt */
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
mt76_connac_irq_enable(&dev->mt76,
MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
/* put dma enabled */
@ -509,17 +499,7 @@ failed:
static void mt7921_pci_shutdown(struct pci_dev *pdev)
{
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
struct mt76_connac_pm *pm = &dev->pm;
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
/* chip cleanup before reboot */
mt7921_mcu_drv_pmctrl(dev);
mt7921_dma_cleanup(dev);
mt7921_wfsys_reset(dev);
mt7921_pci_remove(pdev);
}
static DEFINE_SIMPLE_DEV_PM_OPS(mt7921_pm_ops, mt7921_pci_suspend, mt7921_pci_resume);

Просмотреть файл

@ -3,7 +3,7 @@
#include "mt7921.h"
#include "../dma.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,

Просмотреть файл

@ -13,7 +13,7 @@
#include "mt7921.h"
#include "../sdio.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
#include "mcu.h"
static const struct sdio_device_id mt7921s_table[] = {
@ -99,7 +99,6 @@ static int mt7921s_probe(struct sdio_func *func,
.tx_status_data = mt7921_usb_sdio_tx_status_data,
.rx_skb = mt7921_queue_rx_skb,
.rx_check = mt7921_rx_check,
.sta_ps = mt7921_sta_ps,
.sta_add = mt7921_mac_sta_add,
.sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
@ -122,33 +121,17 @@ static int mt7921s_probe(struct sdio_func *func,
.drv_own = mt7921s_mcu_drv_pmctrl,
.fw_own = mt7921s_mcu_fw_pmctrl,
};
struct ieee80211_ops *ops;
struct mt7921_dev *dev;
struct mt76_dev *mdev;
u8 features;
int ret;
features = mt7921_check_offload_capability(&func->dev, (const char *)
id->driver_data);
ops = devm_kmemdup(&func->dev, &mt7921_ops, sizeof(mt7921_ops),
GFP_KERNEL);
ops = mt7921_get_mac80211_ops(&func->dev, (void *)id->driver_data,
&features);
if (!ops)
return -ENOMEM;
if (!(features & MT7921_FW_CAP_CNM)) {
ops->remain_on_channel = NULL;
ops->cancel_remain_on_channel = NULL;
ops->add_chanctx = NULL;
ops->remove_chanctx = NULL;
ops->change_chanctx = NULL;
ops->assign_vif_chanctx = NULL;
ops->unassign_vif_chanctx = NULL;
ops->mgd_prepare_tx = NULL;
ops->mgd_complete_tx = NULL;
}
mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);
if (!mdev)
return -ENOMEM;

Просмотреть файл

@ -4,7 +4,7 @@
#include <linux/iopoll.h>
#include <linux/mmc/sdio_func.h>
#include "mt7921.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
#include "../sdio.h"
static void mt7921s_enable_irq(struct mt76_dev *dev)

Просмотреть файл

@ -8,7 +8,7 @@
#include "mt7921.h"
#include "../sdio.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
#include "mcu.h"
#include "regs.h"

Просмотреть файл

@ -10,7 +10,7 @@
#include "mt7921.h"
#include "mcu.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
static const struct usb_device_id mt7921u_device_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff),
@ -18,6 +18,9 @@ static const struct usb_device_id mt7921u_device_table[] = {
/* Comfast CF-952AX */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6211, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
/* Netgear, Inc. [A8000,AXE3000] */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9060, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
{ },
};
@ -183,7 +186,6 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
.tx_status_data = mt7921_usb_sdio_tx_status_data,
.rx_skb = mt7921_queue_rx_skb,
.rx_check = mt7921_rx_check,
.sta_ps = mt7921_sta_ps,
.sta_add = mt7921_mac_sta_add,
.sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
@ -210,27 +212,12 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
u8 features;
int ret;
features = mt7921_check_offload_capability(&usb_intf->dev, (const char *)
id->driver_info);
ops = devm_kmemdup(&usb_intf->dev, &mt7921_ops, sizeof(mt7921_ops),
GFP_KERNEL);
ops = mt7921_get_mac80211_ops(&usb_intf->dev, (void *)id->driver_info,
&features);
if (!ops)
return -ENOMEM;
if (!(features & MT7921_FW_CAP_CNM)) {
ops->remain_on_channel = NULL;
ops->cancel_remain_on_channel = NULL;
ops->add_chanctx = NULL;
ops->remove_chanctx = NULL;
ops->change_chanctx = NULL;
ops->assign_vif_chanctx = NULL;
ops->unassign_vif_chanctx = NULL;
ops->mgd_prepare_tx = NULL;
ops->mgd_complete_tx = NULL;
}
ops->stop = mt7921u_stop;
mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);
if (!mdev)
return -ENOMEM;
@ -272,7 +259,7 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
ret = mt7921u_dma_init(dev, false);
if (ret)
return ret;
goto error;
hw = mt76_hw(dev);
/* check hw sg support in order to enable AMSDU */

Просмотреть файл

@ -10,7 +10,7 @@
#include "mt7921.h"
#include "mcu.h"
#include "mac.h"
#include "../mt76_connac2_mac.h"
static u32 mt7921u_uhw_rr(struct mt76_dev *dev, u32 addr)
{

Просмотреть файл

@ -2,6 +2,7 @@
config MT7996E
tristate "MediaTek MT7996 (PCIe) support"
select MT76_CONNAC_LIB
select WANT_DEV_COREDUMP
select RELAY
depends on MAC80211
depends on PCI

Просмотреть файл

@ -4,3 +4,5 @@ obj-$(CONFIG_MT7996E) += mt7996e.o
mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
debugfs.o mmio.o
mt7996e-$(CONFIG_DEV_COREDUMP) += coredump.o

Просмотреть файл

@ -0,0 +1,268 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2023 MediaTek Inc. */
#include <linux/devcoredump.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/utsname.h>
#include "coredump.h"
static bool coredump_memdump;
module_param(coredump_memdump, bool, 0644);
MODULE_PARM_DESC(coredump_memdump, "Optional ability to dump firmware memory");
static const struct mt7996_mem_region mt7996_mem_regions[] = {
{
.start = 0x00800000,
.len = 0x0004ffff,
.name = "ULM0",
},
{
.start = 0x00900000,
.len = 0x00037fff,
.name = "ULM1",
},
{
.start = 0x02200000,
.len = 0x0003ffff,
.name = "ULM2",
},
{
.start = 0x00400000,
.len = 0x00067fff,
.name = "SRAM",
},
{
.start = 0xe0000000,
.len = 0x0015ffff,
.name = "CRAM0",
},
{
.start = 0xe0160000,
.len = 0x0011bfff,
.name = "CRAM1",
},
};
const struct mt7996_mem_region*
mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u32 *num)
{
switch (mt76_chip(&dev->mt76)) {
case 0x7990:
case 0x7991:
*num = ARRAY_SIZE(mt7996_mem_regions);
return &mt7996_mem_regions[0];
default:
return NULL;
}
}
static int mt7996_coredump_get_mem_size(struct mt7996_dev *dev)
{
const struct mt7996_mem_region *mem_region;
size_t size = 0;
u32 num;
int i;
mem_region = mt7996_coredump_get_mem_layout(dev, &num);
if (!mem_region)
return 0;
for (i = 0; i < num; i++) {
size += mem_region->len;
mem_region++;
}
/* reserve space for the headers */
size += num * sizeof(struct mt7996_mem_hdr);
/* make sure it is aligned 4 bytes for debug message print out */
size = ALIGN(size, 4);
return size;
}
struct mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev)
{
struct mt7996_crash_data *crash_data = dev->coredump.crash_data;
lockdep_assert_held(&dev->dump_mutex);
if (coredump_memdump &&
!mt76_poll_msec(dev, MT_FW_DUMP_STATE, 0x3, 0x2, 500))
return NULL;
guid_gen(&crash_data->guid);
ktime_get_real_ts64(&crash_data->timestamp);
return crash_data;
}
static void
mt7996_coredump_fw_state(struct mt7996_dev *dev, struct mt7996_coredump *dump,
bool *exception)
{
u32 count;
count = mt76_rr(dev, MT_FW_ASSERT_CNT);
/* normal mode: driver can manually trigger assert for detail info */
if (!count)
strscpy(dump->fw_state, "normal", sizeof(dump->fw_state));
else
strscpy(dump->fw_state, "exception", sizeof(dump->fw_state));
*exception = !!count;
}
static void
mt7996_coredump_fw_stack(struct mt7996_dev *dev, struct mt7996_coredump *dump,
bool exception)
{
u32 oldest, i, idx;
strscpy(dump->pc_current, "program counter", sizeof(dump->pc_current));
/* 0: WM PC log output */
mt76_wr(dev, MT_CONN_DBG_CTL_OUT_SEL, 0);
/* choose 33th PC log buffer to read current PC index */
mt76_wr(dev, MT_CONN_DBG_CTL_PC_LOG_SEL, 0x3f);
/* read current PC */
dump->pc_stack[0] = mt76_rr(dev, MT_CONN_DBG_CTL_PC_LOG);
/* stop call stack record */
if (!exception) {
mt76_clear(dev, MT_MCU_WM_EXCP_PC_CTRL, BIT(0));
mt76_clear(dev, MT_MCU_WM_EXCP_LR_CTRL, BIT(0));
}
oldest = (u32)mt76_get_field(dev, MT_MCU_WM_EXCP_PC_CTRL,
GENMASK(20, 16)) + 2;
for (i = 0; i < 16; i++) {
idx = ((oldest + 2 * i + 1) % 32);
dump->pc_stack[i + 1] =
mt76_rr(dev, MT_MCU_WM_EXCP_PC_LOG + idx * 4);
}
oldest = (u32)mt76_get_field(dev, MT_MCU_WM_EXCP_LR_CTRL,
GENMASK(20, 16)) + 2;
for (i = 0; i < 16; i++) {
idx = ((oldest + 2 * i + 1) % 32);
dump->lr_stack[i] =
mt76_rr(dev, MT_MCU_WM_EXCP_LR_LOG + idx * 4);
}
/* start call stack record */
if (!exception) {
mt76_set(dev, MT_MCU_WM_EXCP_PC_CTRL, BIT(0));
mt76_set(dev, MT_MCU_WM_EXCP_LR_CTRL, BIT(0));
}
}
static struct mt7996_coredump *mt7996_coredump_build(struct mt7996_dev *dev)
{
struct mt7996_crash_data *crash_data = dev->coredump.crash_data;
struct mt7996_coredump *dump;
struct mt7996_coredump_mem *dump_mem;
size_t len, sofar = 0, hdr_len = sizeof(*dump);
unsigned char *buf;
bool exception;
len = hdr_len;
if (coredump_memdump && crash_data->memdump_buf_len)
len += sizeof(*dump_mem) + crash_data->memdump_buf_len;
sofar += hdr_len;
/* this is going to get big when we start dumping memory and such,
* so go ahead and use vmalloc.
*/
buf = vzalloc(len);
if (!buf)
return NULL;
mutex_lock(&dev->dump_mutex);
dump = (struct mt7996_coredump *)(buf);
dump->len = len;
/* plain text */
strscpy(dump->magic, "mt76-crash-dump", sizeof(dump->magic));
strscpy(dump->kernel, init_utsname()->release, sizeof(dump->kernel));
strscpy(dump->fw_ver, dev->mt76.hw->wiphy->fw_version,
sizeof(dump->fw_ver));
guid_copy(&dump->guid, &crash_data->guid);
dump->tv_sec = crash_data->timestamp.tv_sec;
dump->tv_nsec = crash_data->timestamp.tv_nsec;
dump->device_id = mt76_chip(&dev->mt76);
mt7996_coredump_fw_state(dev, dump, &exception);
mt7996_coredump_fw_stack(dev, dump, exception);
/* gather memory content */
dump_mem = (struct mt7996_coredump_mem *)(buf + sofar);
dump_mem->len = crash_data->memdump_buf_len;
if (coredump_memdump && crash_data->memdump_buf_len)
memcpy(dump_mem->data, crash_data->memdump_buf,
crash_data->memdump_buf_len);
mutex_unlock(&dev->dump_mutex);
return dump;
}
int mt7996_coredump_submit(struct mt7996_dev *dev)
{
struct mt7996_coredump *dump;
dump = mt7996_coredump_build(dev);
if (!dump) {
dev_warn(dev->mt76.dev, "no crash dump data found\n");
return -ENODATA;
}
dev_coredumpv(dev->mt76.dev, dump, dump->len, GFP_KERNEL);
return 0;
}
int mt7996_coredump_register(struct mt7996_dev *dev)
{
struct mt7996_crash_data *crash_data;
crash_data = vzalloc(sizeof(*dev->coredump.crash_data));
if (!crash_data)
return -ENOMEM;
dev->coredump.crash_data = crash_data;
if (coredump_memdump) {
crash_data->memdump_buf_len = mt7996_coredump_get_mem_size(dev);
if (!crash_data->memdump_buf_len)
/* no memory content */
return 0;
crash_data->memdump_buf = vzalloc(crash_data->memdump_buf_len);
if (!crash_data->memdump_buf) {
vfree(crash_data);
return -ENOMEM;
}
}
return 0;
}
void mt7996_coredump_unregister(struct mt7996_dev *dev)
{
if (dev->coredump.crash_data->memdump_buf) {
vfree(dev->coredump.crash_data->memdump_buf);
dev->coredump.crash_data->memdump_buf = NULL;
dev->coredump.crash_data->memdump_buf_len = 0;
}
vfree(dev->coredump.crash_data);
dev->coredump.crash_data = NULL;
}

Просмотреть файл

@ -0,0 +1,97 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2023 MediaTek Inc. */
#ifndef _COREDUMP_H_
#define _COREDUMP_H_
#include "mt7996.h"
struct mt7996_coredump {
char magic[16];
u32 len;
guid_t guid;
/* time-of-day stamp */
u64 tv_sec;
/* time-of-day stamp, nano-seconds */
u64 tv_nsec;
/* kernel version */
char kernel[64];
/* firmware version */
char fw_ver[ETHTOOL_FWVERS_LEN];
u32 device_id;
/* exception state */
char fw_state[12];
/* program counters */
char pc_current[16];
u32 pc_stack[17];
/* link registers */
u32 lr_stack[16];
/* memory content */
u8 data[];
} __packed;
struct mt7996_coredump_mem {
u32 len;
u8 data[];
} __packed;
struct mt7996_mem_hdr {
u32 start;
u32 len;
u8 data[];
};
struct mt7996_mem_region {
u32 start;
size_t len;
const char *name;
};
#ifdef CONFIG_DEV_COREDUMP
const struct mt7996_mem_region *
mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u32 *num);
struct mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev);
int mt7996_coredump_submit(struct mt7996_dev *dev);
int mt7996_coredump_register(struct mt7996_dev *dev);
void mt7996_coredump_unregister(struct mt7996_dev *dev);
#else /* CONFIG_DEV_COREDUMP */
static inline const struct mt7996_mem_region *
mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u32 *num)
{
return NULL;
}
static inline int mt7996_coredump_submit(struct mt7996_dev *dev)
{
return 0;
}
static inline struct
mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev)
{
return NULL;
}
static inline int mt7996_coredump_register(struct mt7996_dev *dev)
{
return 0;
}
static inline void mt7996_coredump_unregister(struct mt7996_dev *dev)
{
}
#endif /* CONFIG_DEV_COREDUMP */
#endif /* _COREDUMP_H_ */

Просмотреть файл

@ -48,12 +48,12 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7996_implicit_txbf_get,
/* test knob of system error recovery */
static ssize_t
mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
mt7996_sys_recovery_set(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct mt7996_phy *phy = file->private_data;
struct mt7996_dev *dev = phy->dev;
u8 band_idx = phy->mt76->band_idx;
bool band = phy->mt76->band_idx;
char buf[16];
int ret = 0;
u16 val;
@ -73,17 +73,47 @@ mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
return -EINVAL;
switch (val) {
case SER_SET_RECOVER_L1:
case SER_SET_RECOVER_L2:
case SER_SET_RECOVER_L3_RX_ABORT:
case SER_SET_RECOVER_L3_TX_ABORT:
case SER_SET_RECOVER_L3_TX_DISABLE:
case SER_SET_RECOVER_L3_BF:
ret = mt7996_mcu_set_ser(dev, SER_ENABLE, BIT(val), band_idx);
/*
* 0: grab firmware current SER state.
* 1: trigger & enable system error L1 recovery.
* 2: trigger & enable system error L2 recovery.
* 3: trigger & enable system error L3 rx abort.
* 4: trigger & enable system error L3 tx abort
* 5: trigger & enable system error L3 tx disable.
* 6: trigger & enable system error L3 bf recovery.
* 7: trigger & enable system error L4 mdp recovery.
* 8: trigger & enable system error full recovery.
* 9: trigger firmware crash.
*/
case UNI_CMD_SER_QUERY:
ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_QUERY, 0, band);
break;
case UNI_CMD_SER_SET_RECOVER_L1:
case UNI_CMD_SER_SET_RECOVER_L2:
case UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT:
case UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT:
case UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE:
case UNI_CMD_SER_SET_RECOVER_L3_BF:
case UNI_CMD_SER_SET_RECOVER_L4_MDP:
ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_SET, BIT(val), band);
if (ret)
return ret;
ret = mt7996_mcu_set_ser(dev, SER_RECOVER, val, band_idx);
ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, val, band);
break;
/* enable full chip reset */
case UNI_CMD_SER_SET_RECOVER_FULL:
mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
mt7996_reset(dev);
break;
/* WARNING: trigger firmware crash */
case UNI_CMD_SER_SET_SYSTEM_ASSERT:
ret = mt7996_mcu_trigger_assert(dev);
if (ret)
return ret;
break;
default:
break;
@ -92,9 +122,97 @@ mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
return ret ? ret : count;
}
static const struct file_operations mt7996_fw_ser_ops = {
.write = mt7996_fw_ser_set,
/* TODO: ser read */
static ssize_t
mt7996_sys_recovery_get(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct mt7996_phy *phy = file->private_data;
struct mt7996_dev *dev = phy->dev;
char *buff;
int desc = 0;
ssize_t ret;
static const size_t bufsz = 1024;
buff = kmalloc(bufsz, GFP_KERNEL);
if (!buff)
return -ENOMEM;
/* HELP */
desc += scnprintf(buff + desc, bufsz - desc,
"Please echo the correct value ...\n");
desc += scnprintf(buff + desc, bufsz - desc,
"0: grab firmware transient SER state\n");
desc += scnprintf(buff + desc, bufsz - desc,
"1: trigger system error L1 recovery\n");
desc += scnprintf(buff + desc, bufsz - desc,
"2: trigger system error L2 recovery\n");
desc += scnprintf(buff + desc, bufsz - desc,
"3: trigger system error L3 rx abort\n");
desc += scnprintf(buff + desc, bufsz - desc,
"4: trigger system error L3 tx abort\n");
desc += scnprintf(buff + desc, bufsz - desc,
"5: trigger system error L3 tx disable\n");
desc += scnprintf(buff + desc, bufsz - desc,
"6: trigger system error L3 bf recovery\n");
desc += scnprintf(buff + desc, bufsz - desc,
"7: trigger system error L4 mdp recovery\n");
desc += scnprintf(buff + desc, bufsz - desc,
"8: trigger system error full recovery\n");
desc += scnprintf(buff + desc, bufsz - desc,
"9: trigger firmware crash\n");
/* SER statistics */
desc += scnprintf(buff + desc, bufsz - desc,
"\nlet's dump firmware SER statistics...\n");
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_STATUS = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_SER_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_PLE_ERR = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_PLE_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_PLE_ERR_1 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_PLE1_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_PLE_ERR_AMSDU = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_PSE_ERR = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_PSE_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_PSE_ERR_1 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_PSE1_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_LMAC_WISR6_B0 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_LMAC_WISR6_B1 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_LMAC_WISR6_B2 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN2_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_LMAC_WISR7_B0 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_LMAC_WISR7_B1 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"::E R , SER_LMAC_WISR7_B2 = 0x%08x\n",
mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN2_STATS));
desc += scnprintf(buff + desc, bufsz - desc,
"\nSYS_RESET_COUNT: WM %d, WA %d\n",
dev->recovery.wm_reset_count,
dev->recovery.wa_reset_count);
ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
kfree(buff);
return ret;
}
static const struct file_operations mt7996_sys_recovery_ops = {
.write = mt7996_sys_recovery_set,
.read = mt7996_sys_recovery_get,
.open = simple_open,
.llseek = default_llseek,
};
@ -674,6 +792,8 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
debugfs_create_file("xmit-queues", 0400, dir, phy,
&mt7996_xmit_queues_fops);
debugfs_create_file("tx_stats", 0400, dir, phy, &mt7996_tx_stats_fops);
debugfs_create_file("sys_recovery", 0600, dir, phy,
&mt7996_sys_recovery_ops);
debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
@ -684,7 +804,6 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
&fops_implicit_txbf);
debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
mt7996_twt_stats);
debugfs_create_file("fw_ser", 0600, dir, phy, &mt7996_fw_ser_ops);
debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
if (phy->mt76->cap.has_5ghz) {

Просмотреть файл

@ -352,6 +352,70 @@ int mt7996_dma_init(struct mt7996_dev *dev)
return 0;
}
void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
{
struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1];
struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2];
u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
int i;
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
if (dev->hif2)
mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
usleep_range(1000, 2000);
for (i = 0; i < __MT_TXQ_MAX; i++) {
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
if (phy2)
mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true);
if (phy3)
mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true);
}
for (i = 0; i < __MT_MCUQ_MAX; i++)
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
mt76_tx_status_check(&dev->mt76, true);
/* reset wfsys */
if (force)
mt7996_wfsys_reset(dev);
mt7996_dma_disable(dev, force);
/* reset hw queues */
for (i = 0; i < __MT_TXQ_MAX; i++) {
mt76_queue_reset(dev, dev->mphy.q_tx[i]);
if (phy2)
mt76_queue_reset(dev, phy2->q_tx[i]);
if (phy3)
mt76_queue_reset(dev, phy3->q_tx[i]);
}
for (i = 0; i < __MT_MCUQ_MAX; i++)
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
}
mt76_tx_status_check(&dev->mt76, true);
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_reset(dev, i);
mt7996_dma_enable(dev);
}
void mt7996_dma_cleanup(struct mt7996_dev *dev)
{
mt7996_dma_disable(dev, true);

Просмотреть файл

@ -138,10 +138,6 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
case MT_EE_BAND_SEL_6GHZ:
phy->mt76->cap.has_6ghz = true;
break;
case MT_EE_BAND_SEL_5GHZ_6GHZ:
phy->mt76->cap.has_5ghz = true;
phy->mt76->cap.has_6ghz = true;
break;
default:
ret = -EINVAL;
break;

Просмотреть файл

@ -31,11 +31,11 @@ enum mt7996_eeprom_field {
#define MT_EE_WIFI_CONF2_BAND_SEL GENMASK(2, 0)
#define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(2, 0)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3)
#define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(5, 3)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(2, 0)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3)
#define MT_EE_RATE_DELTA_MASK GENMASK(5, 0)
#define MT_EE_RATE_DELTA_SIGN BIT(6)
@ -46,7 +46,6 @@ enum mt7996_eeprom_band {
MT_EE_BAND_SEL_2GHZ,
MT_EE_BAND_SEL_5GHZ,
MT_EE_BAND_SEL_6GHZ,
MT_EE_BAND_SEL_5GHZ_6GHZ,
};
static inline int

Просмотреть файл

@ -8,6 +8,7 @@
#include "mt7996.h"
#include "mac.h"
#include "mcu.h"
#include "coredump.h"
#include "eeprom.h"
static const struct ieee80211_iface_limit if_limits[] = {
@ -99,9 +100,8 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev,
mt7996_led_set_config(led_cdev, 0xff, 0);
}
static void
mt7996_init_txpower(struct mt7996_dev *dev,
struct ieee80211_supported_band *sband)
void mt7996_init_txpower(struct mt7996_dev *dev,
struct ieee80211_supported_band *sband)
{
int i, nss = hweight8(dev->mphy.antenna_mask);
int nss_delta = mt76_tx_power_nss_delta(nss);
@ -182,6 +182,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
if (!mdev->dev->of_node ||
!of_property_read_bool(mdev->dev->of_node,
@ -196,10 +197,13 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
hw->max_tx_fragments = 4;
if (phy->mt76->cap.has_2ghz)
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 |=
@ -211,6 +215,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
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;
}
mt76_set_stream_caps(phy->mt76, true);
@ -250,7 +256,21 @@ mt7996_mac_init_band(struct mt7996_dev *dev, u8 band)
mt76_rmw(dev, MT_WTBLOFF_RSCR(band), mask, set);
}
static void mt7996_mac_init(struct mt7996_dev *dev)
static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) {
u16 rate = mt76_rates[i].hw_value;
u16 idx = MT7996_BASIC_RATES_TBL + i;
rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) |
FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0));
mt7996_mac_set_fixed_rate_table(dev, idx, rate);
}
}
void mt7996_mac_init(struct mt7996_dev *dev)
{
#define HIF_TXD_V2_1 4
int i;
@ -282,9 +302,11 @@ static void mt7996_mac_init(struct mt7996_dev *dev)
for (i = MT_BAND0; i <= MT_BAND2; i++)
mt7996_mac_init_band(dev, i);
mt7996_mac_init_basic_rates(dev);
}
static int mt7996_txbf_init(struct mt7996_dev *dev)
int mt7996_txbf_init(struct mt7996_dev *dev)
{
int ret;
@ -552,27 +574,6 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy,
elem->phy_cap_info[7] |= c;
}
static void
mt7996_gen_ppe_thresh(u8 *he_ppet, int nss)
{
u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
static const u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71};
he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
ru_bit_mask);
ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
nss * hweight8(ru_bit_mask) * 2;
ppet_size = DIV_ROUND_UP(ppet_bits, 8);
for (i = 0; i < ppet_size - 1; i++)
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
(0xff >> (8 - (ppet_bits - 1) % 8));
}
static void
mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
struct ieee80211_sband_iftype_data *data,
@ -678,7 +679,7 @@ mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
mt7996_gen_ppe_thresh(he_cap->ppe_thres, nss);
mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
@ -689,7 +690,7 @@ mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2,
cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_0_5,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
@ -858,6 +859,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
init_waitqueue_head(&dev->reset_wait);
INIT_WORK(&dev->reset_work, mt7996_mac_reset_work);
INIT_WORK(&dev->dump_work, mt7996_mac_dump_work);
mutex_init(&dev->dump_mutex);
ret = mt7996_init_hardware(dev);
if (ret)
@ -886,18 +889,25 @@ int mt7996_register_device(struct mt7996_dev *dev)
if (ret)
return ret;
return mt7996_init_debugfs(&dev->phy);
dev->recovery.hw_init_done = true;
ret = mt7996_init_debugfs(&dev->phy);
if (ret)
return ret;
return mt7996_coredump_register(dev);
}
void mt7996_unregister_device(struct mt7996_dev *dev)
{
mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
mt7996_coredump_unregister(dev);
mt76_unregister_device(&dev->mt76);
mt7996_mcu_exit(dev);
mt7996_tx_token_put(dev);
mt7996_dma_cleanup(dev);
tasklet_disable(&dev->irq_tasklet);
tasklet_disable(&dev->mt76.irq_tasklet);
mt76_free_device(&dev->mt76);
}

Просмотреть файл

@ -5,6 +5,7 @@
#include <linux/etherdevice.h>
#include <linux/timekeeping.h>
#include "coredump.h"
#include "mt7996.h"
#include "../dma.h"
#include "mac.h"
@ -78,10 +79,6 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
return &sta->vif->sta.wcid;
}
void mt7996_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
{
}
bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
{
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
@ -255,17 +252,25 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
mt76_clear(dev, addr, BIT(5));
}
void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
u8 tbl_idx, u16 rate_idx)
{
u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;
mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);
/* use wtbl spe idx */
mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);
mt76_wr(dev, MT_WTBL_ITCR, ctrl);
}
static void
mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
struct ieee80211_radiotap_he *he,
__le32 *rxv)
{
u32 ru_h, ru_l;
u8 ru, offs = 0;
u32 ru, offs = 0;
ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L);
ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H);
ru = (u8)(ru_l | ru_h << 4);
ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC);
status->bw = RATE_INFO_BW_HE_RU;
@ -330,18 +335,23 @@ mt7996_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));
le32_get_bits(rxv[4], MT_CRXV_HE_NUM_USER));
he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);
he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff;
if (status->bw >= RATE_INFO_BW_40) {
he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1);
he_mu->ru_ch2[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU1) & 0xff;
}
if (status->bw >= RATE_INFO_BW_80) {
he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2);
he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3);
u32 ru_h, ru_l;
he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff;
ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
}
}
@ -364,23 +374,23 @@ mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
HE_BITS(DATA2_TXOP_KNOWN),
};
struct ieee80211_radiotap_he *he = NULL;
u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;
u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
status->flag |= RX_FLAG_RADIOTAP_HE;
he = skb_push(skb, sizeof(known));
memcpy(he, &known, sizeof(known));
he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |
HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);
he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
le16_encode_bits(ltf_size,
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
he->data5 |= HE_BITS(DATA5_TXBF);
he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
switch (mode) {
case MT_PHY_TYPE_HE_SU:
@ -389,22 +399,22 @@ mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |
HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[8]) |
HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
break;
case MT_PHY_TYPE_HE_EXT_SU:
he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
HE_BITS(DATA1_UL_DL_KNOWN) |
HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
break;
case MT_PHY_TYPE_HE_MU:
he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
HE_BITS(DATA1_UL_DL_KNOWN);
he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);
he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
mt7996_mac_decode_he_mu_radiotap(skb, rxv);
@ -415,10 +425,10 @@ mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |
HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |
HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |
HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);
he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[13]) |
HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
break;
@ -570,11 +580,12 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
case MT_PHY_TYPE_EHT_SU:
case MT_PHY_TYPE_EHT_TRIG:
case MT_PHY_TYPE_EHT_MU:
/* TODO: currently report rx rate with HE rate */
status->nss = nss;
status->encoding = RX_ENC_HE;
bw = min_t(int, bw, IEEE80211_STA_RX_BW_160);
i = min_t(int, i & 0xf, 11);
status->encoding = RX_ENC_EHT;
i &= GENMASK(3, 0);
if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
status->eht.gi = gi;
break;
default:
return -EINVAL;
@ -630,6 +641,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
u32 rxd4 = le32_to_cpu(rxd[4]);
u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
u32 csum_status = *(u32 *)skb->cb;
u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP;
bool is_mesh = (rxd0 & mesh_mask) == mesh_mask;
bool unicast, insert_ccmp_hdr = false;
u8 remove_pad, amsdu_info, band_idx;
u8 mode = 0, qos_ctl = 0;
@ -821,19 +834,16 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
int pad_start = 0;
skb_pull(skb, hdr_gap);
if (!hdr_trans && status->amsdu) {
if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) {
pad_start = ieee80211_get_hdrlen_from_skb(skb);
} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR) &&
get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) {
/* When header translation failure is indicated,
* the hardware will insert an extra 2-byte field
* containing the data length after the protocol
* type field.
*/
pad_start = 12;
if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
pad_start += 4;
else
pad_start = 0;
pad_start = 16;
}
if (pad_start) {
@ -854,8 +864,17 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
hdr = mt76_skb_get_hdr(skb);
fc = hdr->frame_control;
if (ieee80211_is_data_qos(fc)) {
u8 *qos = ieee80211_get_qos_ctl(hdr);
seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
qos_ctl = *ieee80211_get_qos_ctl(hdr);
qos_ctl = *qos;
/* Mesh DA/SA/Length will be stripped after hardware
* de-amsdu, so here needs to clear amsdu present bit
* to mark it as a normal mesh frame.
*/
if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
*qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
}
} else {
status->flag |= RX_FLAG_8023;
@ -979,12 +998,13 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
}
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
struct ieee80211_key_conf *key, u32 changed)
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
enum mt76_txq_id qid, u32 changed)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct mt76_phy *mphy = &dev->mphy;
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
@ -996,22 +1016,18 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
BSS_CHANGED_FILS_DISCOVERY));
if (vif) {
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
omac_idx = mvif->mt76.omac_idx;
wmm_idx = mvif->mt76.wmm_idx;
band_idx = mvif->mt76.band_idx;
}
mphy = mt76_dev_phy(&dev->mt76, band_idx);
if (inband_disc) {
p_fmt = MT_TX_TYPE_FW;
q_idx = MT_LMAC_ALTX0;
} else if (beacon) {
p_fmt = MT_TX_TYPE_FW;
q_idx = MT_LMAC_BCN0;
} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
} else if (qid >= MT_TXQ_PSD) {
p_fmt = MT_TX_TYPE_CT;
q_idx = MT_LMAC_ALTX0;
} else {
@ -1062,18 +1078,17 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
mt7996_mac_write_txwi_80211(dev, txwi, skb, key);
if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
/* Fixed rata is available just for 802.11 txd */
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
bool multicast = is_multicast_ether_addr(hdr->addr1);
u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon,
multicast);
bool mcast = ieee80211_is_data(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1);
u8 idx = mvif->basic_rates_idx;
/* fix to bw 20 */
val = MT_TXD6_FIXED_BW |
FIELD_PREP(MT_TXD6_BW, 0) |
FIELD_PREP(MT_TXD6_TX_RATE, rate);
if (mcast && mvif->mcast_rates_idx)
idx = mvif->mcast_rates_idx;
else if (beacon && mvif->beacon_rates_idx)
idx = mvif->beacon_rates_idx;
txwi[6] |= cpu_to_le32(val);
txwi[6] |= FIELD_PREP(MT_TXD6_TX_RATE, idx);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
}
@ -1117,11 +1132,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
return id;
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
memset(txwi_ptr, 0, MT_TXD_SIZE);
/* Transmit non qos data by 802.11 header and need to fill txd by host*/
if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
key, 0);
mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
pid, qid, 0);
txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
@ -1130,10 +1142,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
}
txp->fw.nbuf = nbuf;
txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
txp->fw.flags =
cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD);
if (!key)
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
@ -1704,7 +1714,7 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
bool ret;
ret = wait_event_timeout(dev->reset_wait,
(READ_ONCE(dev->reset_state) & state),
(READ_ONCE(dev->recovery.state) & state),
MT7996_RESET_TIMEOUT);
WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
@ -1753,53 +1763,6 @@ mt7996_update_beacons(struct mt7996_dev *dev)
mt7996_update_vif_beacon, phy3->hw);
}
static void
mt7996_dma_reset(struct mt7996_dev *dev)
{
struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1];
struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2];
u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
int i;
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
if (dev->hif2)
mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
usleep_range(1000, 2000);
for (i = 0; i < __MT_TXQ_MAX; i++) {
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
if (phy2)
mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true);
if (phy3)
mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true);
}
for (i = 0; i < __MT_MCUQ_MAX; i++)
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_reset(dev, i);
mt76_tx_status_check(&dev->mt76, true);
/* re-init prefetch settings after reset */
mt7996_dma_prefetch(dev);
mt76_set(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
if (dev->hif2)
mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
}
void mt7996_tx_token_put(struct mt7996_dev *dev)
{
struct mt76_txwi_cache *txwi;
@ -1814,7 +1777,193 @@ void mt7996_tx_token_put(struct mt7996_dev *dev)
idr_destroy(&dev->mt76.token);
}
/* system error recovery */
static int
mt7996_mac_restart(struct mt7996_dev *dev)
{
struct mt7996_phy *phy2, *phy3;
struct mt76_dev *mdev = &dev->mt76;
int i, ret;
phy2 = mt7996_phy2(dev);
phy3 = mt7996_phy3(dev);
if (dev->hif2) {
mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
}
if (dev_is_pci(mdev->dev)) {
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
if (dev->hif2)
mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
}
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
if (phy2) {
set_bit(MT76_RESET, &phy2->mt76->state);
set_bit(MT76_MCU_RESET, &phy2->mt76->state);
}
if (phy3) {
set_bit(MT76_RESET, &phy3->mt76->state);
set_bit(MT76_MCU_RESET, &phy3->mt76->state);
}
/* lock/unlock all queues to ensure that no tx is pending */
mt76_txq_schedule_all(&dev->mphy);
if (phy2)
mt76_txq_schedule_all(phy2->mt76);
if (phy3)
mt76_txq_schedule_all(phy3->mt76);
/* disable all tx/rx napi */
mt76_worker_disable(&dev->mt76.tx_worker);
mt76_for_each_q_rx(mdev, i) {
if (mdev->q_rx[i].ndesc)
napi_disable(&dev->mt76.napi[i]);
}
napi_disable(&dev->mt76.tx_napi);
/* token reinit */
mt7996_tx_token_put(dev);
idr_init(&dev->mt76.token);
mt7996_dma_reset(dev, true);
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
if (mdev->q_rx[i].ndesc) {
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
}
local_bh_enable();
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
if (dev->hif2) {
mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
}
if (dev_is_pci(mdev->dev)) {
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
if (dev->hif2)
mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
}
/* load firmware */
ret = mt7996_mcu_init_firmware(dev);
if (ret)
goto out;
/* set the necessary init items */
ret = mt7996_mcu_set_eeprom(dev);
if (ret)
goto out;
mt7996_mac_init(dev);
mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
ret = mt7996_txbf_init(dev);
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
ret = mt7996_run(dev->mphy.hw);
if (ret)
goto out;
}
if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
ret = mt7996_run(phy2->mt76->hw);
if (ret)
goto out;
}
if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
ret = mt7996_run(phy3->mt76->hw);
if (ret)
goto out;
}
out:
/* reset done */
clear_bit(MT76_RESET, &dev->mphy.state);
if (phy2)
clear_bit(MT76_RESET, &phy2->mt76->state);
if (phy3)
clear_bit(MT76_RESET, &phy3->mt76->state);
local_bh_disable();
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
local_bh_enable();
mt76_worker_enable(&dev->mt76.tx_worker);
return ret;
}
static void
mt7996_mac_full_reset(struct mt7996_dev *dev)
{
struct mt7996_phy *phy2, *phy3;
int i;
phy2 = mt7996_phy2(dev);
phy3 = mt7996_phy3(dev);
dev->recovery.hw_full_reset = true;
wake_up(&dev->mt76.mcu.wait);
ieee80211_stop_queues(mt76_hw(dev));
if (phy2)
ieee80211_stop_queues(phy2->mt76->hw);
if (phy3)
ieee80211_stop_queues(phy3->mt76->hw);
cancel_delayed_work_sync(&dev->mphy.mac_work);
if (phy2)
cancel_delayed_work_sync(&phy2->mt76->mac_work);
if (phy3)
cancel_delayed_work_sync(&phy3->mt76->mac_work);
mutex_lock(&dev->mt76.mutex);
for (i = 0; i < 10; i++) {
if (!mt7996_mac_restart(dev))
break;
}
mutex_unlock(&dev->mt76.mutex);
if (i == 10)
dev_err(dev->mt76.dev, "chip full reset failed\n");
ieee80211_restart_hw(mt76_hw(dev));
if (phy2)
ieee80211_restart_hw(phy2->mt76->hw);
if (phy3)
ieee80211_restart_hw(phy3->mt76->hw);
ieee80211_wake_queues(mt76_hw(dev));
if (phy2)
ieee80211_wake_queues(phy2->mt76->hw);
if (phy3)
ieee80211_wake_queues(phy3->mt76->hw);
dev->recovery.hw_full_reset = false;
ieee80211_queue_delayed_work(mt76_hw(dev),
&dev->mphy.mac_work,
MT7996_WATCHDOG_TIME);
if (phy2)
ieee80211_queue_delayed_work(phy2->mt76->hw,
&phy2->mt76->mac_work,
MT7996_WATCHDOG_TIME);
if (phy3)
ieee80211_queue_delayed_work(phy3->mt76->hw,
&phy3->mt76->mac_work,
MT7996_WATCHDOG_TIME);
}
void mt7996_mac_reset_work(struct work_struct *work)
{
struct mt7996_phy *phy2, *phy3;
@ -1825,9 +1974,36 @@ void mt7996_mac_reset_work(struct work_struct *work)
phy2 = mt7996_phy2(dev);
phy3 = mt7996_phy3(dev);
if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
/* chip full reset */
if (dev->recovery.restart) {
/* disable WA/WM WDT */
mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
MT_MCU_CMD_WDT_MASK);
if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
dev->recovery.wa_reset_count++;
else
dev->recovery.wm_reset_count++;
mt7996_mac_full_reset(dev);
/* enable mcu irq */
mt7996_irq_enable(dev, MT_INT_MCU_CMD);
mt7996_irq_disable(dev, 0);
/* enable WA/WM WDT */
mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
dev->recovery.restart = false;
return;
}
if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
return;
dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
wiphy_name(dev->mt76.hw->wiphy));
ieee80211_stop_queues(mt76_hw(dev));
if (phy2)
ieee80211_stop_queues(phy2->mt76->hw);
@ -1856,7 +2032,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
mt7996_dma_reset(dev);
mt7996_dma_reset(dev, false);
mt7996_tx_token_put(dev);
idr_init(&dev->mt76.token);
@ -1879,7 +2055,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
}
local_bh_enable();
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
@ -1911,6 +2087,101 @@ void mt7996_mac_reset_work(struct work_struct *work)
ieee80211_queue_delayed_work(phy3->mt76->hw,
&phy3->mt76->mac_work,
MT7996_WATCHDOG_TIME);
dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.",
wiphy_name(dev->mt76.hw->wiphy));
}
/* firmware coredump */
void mt7996_mac_dump_work(struct work_struct *work)
{
const struct mt7996_mem_region *mem_region;
struct mt7996_crash_data *crash_data;
struct mt7996_dev *dev;
struct mt7996_mem_hdr *hdr;
size_t buf_len;
int i;
u32 num;
u8 *buf;
dev = container_of(work, struct mt7996_dev, dump_work);
mutex_lock(&dev->dump_mutex);
crash_data = mt7996_coredump_new(dev);
if (!crash_data) {
mutex_unlock(&dev->dump_mutex);
goto skip_coredump;
}
mem_region = mt7996_coredump_get_mem_layout(dev, &num);
if (!mem_region || !crash_data->memdump_buf_len) {
mutex_unlock(&dev->dump_mutex);
goto skip_memdump;
}
buf = crash_data->memdump_buf;
buf_len = crash_data->memdump_buf_len;
/* dumping memory content... */
memset(buf, 0, buf_len);
for (i = 0; i < num; i++) {
if (mem_region->len > buf_len) {
dev_warn(dev->mt76.dev, "%s len %zu is too large\n",
mem_region->name, mem_region->len);
break;
}
/* reserve space for the header */
hdr = (void *)buf;
buf += sizeof(*hdr);
buf_len -= sizeof(*hdr);
mt7996_memcpy_fromio(dev, buf, mem_region->start,
mem_region->len);
hdr->start = mem_region->start;
hdr->len = mem_region->len;
if (!mem_region->len)
/* note: the header remains, just with zero length */
break;
buf += mem_region->len;
buf_len -= mem_region->len;
mem_region++;
}
mutex_unlock(&dev->dump_mutex);
skip_memdump:
mt7996_coredump_submit(dev);
skip_coredump:
queue_work(dev->mt76.wq, &dev->reset_work);
}
void mt7996_reset(struct mt7996_dev *dev)
{
if (!dev->recovery.hw_init_done)
return;
if (dev->recovery.hw_full_reset)
return;
/* wm/wa exception: do full recovery */
if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
dev->recovery.restart = true;
dev_info(dev->mt76.dev,
"%s indicated firmware crash, attempting recovery\n",
wiphy_name(dev->mt76.hw->wiphy));
mt7996_irq_disable(dev, MT_INT_MCU_CMD);
queue_work(dev->mt76.wq, &dev->dump_work);
return;
}
queue_work(dev->mt76.wq, &dev->reset_work);
wake_up(&dev->reset_wait);
}
void mt7996_mac_update_stats(struct mt7996_phy *phy)

Просмотреть файл

@ -12,6 +12,8 @@
#define MT_RXD0_LENGTH GENMASK(15, 0)
#define MT_RXD0_PKT_TYPE GENMASK(31, 27)
#define MT_RXD0_MESH BIT(18)
#define MT_RXD0_MHCP BIT(19)
#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
@ -20,18 +22,6 @@
#define MT_RXD0_SW_PKT_TYPE_MAP 0x380F
#define MT_RXD0_SW_PKT_TYPE_FRAME 0x3801
enum rx_pkt_type {
PKT_TYPE_TXS,
PKT_TYPE_TXRXV,
PKT_TYPE_NORMAL,
PKT_TYPE_RX_DUP_RFB,
PKT_TYPE_RX_TMR,
PKT_TYPE_RETRIEVE,
PKT_TYPE_TXRX_NOTIFY,
PKT_TYPE_RX_EVENT,
PKT_TYPE_RX_FW_MONITOR = 0x0c,
};
/* RXD DW1 */
#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(11, 0)
#define MT_RXD1_NORMAL_GROUP_1 BIT(16)
@ -102,8 +92,7 @@ enum rx_pkt_type {
#define MT_PRXV_NSTS GENMASK(10, 7)
#define MT_PRXV_TXBF BIT(11)
#define MT_PRXV_HT_AD_CODE BIT(12)
#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28)
#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0)
#define MT_PRXV_HE_RU_ALLOC GENMASK(30, 22)
#define MT_PRXV_RCPI3 GENMASK(31, 24)
#define MT_PRXV_RCPI2 GENMASK(23, 16)
#define MT_PRXV_RCPI1 GENMASK(15, 8)
@ -113,34 +102,32 @@ enum rx_pkt_type {
#define MT_PRXV_TX_MODE GENMASK(14, 11)
#define MT_PRXV_FRAME_MODE GENMASK(2, 0)
#define MT_PRXV_DCM BIT(5)
#define MT_PRXV_NUM_RX BIT(8, 6)
/* C-RXV */
#define MT_CRXV_HT_STBC GENMASK(1, 0)
#define MT_CRXV_TX_MODE GENMASK(7, 4)
#define MT_CRXV_FRAME_MODE GENMASK(10, 8)
#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13)
#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17)
#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20)
#define MT_CRXV_HE_PE_DISAMBIG BIT(23)
#define MT_CRXV_HE_NUM_USER GENMASK(30, 24)
#define MT_CRXV_HE_UPLINK BIT(31)
#define MT_CRXV_HE_RU0 GENMASK(7, 0)
#define MT_CRXV_HE_RU1 GENMASK(15, 8)
#define MT_CRXV_HE_RU2 GENMASK(23, 16)
#define MT_CRXV_HE_RU3 GENMASK(31, 24)
#define MT_CRXV_HE_NUM_USER GENMASK(26, 20)
#define MT_CRXV_HE_LTF_SIZE GENMASK(28, 27)
#define MT_CRXV_HE_LDPC_EXT_SYM BIT(30)
#define MT_CRXV_HE_MU_AID GENMASK(30, 20)
#define MT_CRXV_HE_PE_DISAMBIG BIT(1)
#define MT_CRXV_HE_UPLINK BIT(2)
#define MT_CRXV_HE_MU_AID GENMASK(27, 17)
#define MT_CRXV_HE_BEAM_CHNG BIT(29)
#define MT_CRXV_HE_DOPPLER BIT(0)
#define MT_CRXV_HE_BSS_COLOR GENMASK(15, 10)
#define MT_CRXV_HE_TXOP_DUR GENMASK(19, 17)
#define MT_CRXV_HE_SR_MASK GENMASK(11, 8)
#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12)
#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17)
#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21)
#define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0)
#define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6)
#define MT_CRXV_HE_BEAM_CHNG BIT(13)
#define MT_CRXV_HE_DOPPLER BIT(16)
#define MT_CRXV_HE_RU0 GENMASK(8, 0)
#define MT_CRXV_HE_RU1 GENMASK(17, 9)
#define MT_CRXV_HE_RU2 GENMASK(26, 18)
#define MT_CRXV_HE_RU3_L GENMASK(31, 27)
#define MT_CRXV_HE_RU3_H GENMASK(3, 0)
enum tx_header_format {
MT_HDR_FORMAT_802_3,
@ -239,14 +226,11 @@ enum tx_mgnt_type {
#define MT_TXD6_TX_SRC GENMASK(31, 30)
#define MT_TXD6_VTA BIT(28)
#define MT_TXD6_FIXED_BW BIT(25)
#define MT_TXD6_BW GENMASK(24, 22)
#define MT_TXD6_BW GENMASK(25, 22)
#define MT_TXD6_TX_RATE GENMASK(21, 16)
#define MT_TXD6_TIMESTAMP_OFS_EN BIT(15)
#define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10)
#define MT_TXD6_MSDU_CNT GENMASK(9, 4)
#define MT_TXD6_SPE_ID_IDX BIT(10)
#define MT_TXD6_ANT_ID GENMASK(7, 4)
#define MT_TXD6_DIS_MAT BIT(3)
#define MT_TXD6_DAS BIT(2)
#define MT_TXD6_AMSDU_CAP BIT(1)
@ -260,7 +244,7 @@ enum tx_mgnt_type {
#define MT_TXD7_UDP_TCP_SUM BIT(15)
#define MT_TXD7_TX_TIME GENMASK(9, 0)
#define MT_TX_RATE_STBC BIT(13)
#define MT_TX_RATE_STBC BIT(14)
#define MT_TX_RATE_NSS GENMASK(13, 10)
#define MT_TX_RATE_MODE GENMASK(9, 6)
#define MT_TX_RATE_SU_EXT_TONE BIT(5)

Просмотреть файл

@ -5,6 +5,7 @@
#include "mt7996.h"
#include "mcu.h"
#include "mac.h"
static bool mt7996_dev_running(struct mt7996_dev *dev)
{
@ -22,17 +23,13 @@ static bool mt7996_dev_running(struct mt7996_dev *dev)
return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
}
static int mt7996_start(struct ieee80211_hw *hw)
int mt7996_run(struct ieee80211_hw *hw)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
bool running;
int ret;
flush_work(&dev->init_work);
mutex_lock(&dev->mt76.mutex);
running = mt7996_dev_running(dev);
if (!running) {
ret = mt7996_mcu_set_hdr_trans(dev, true);
@ -52,10 +49,6 @@ static int mt7996_start(struct ieee80211_hw *hw)
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_interfaces(dev->mt76.hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7996_mcu_set_pm, dev->mt76.hw);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
MT7996_WATCHDOG_TIME);
@ -63,6 +56,18 @@ static int mt7996_start(struct ieee80211_hw *hw)
mt7996_mac_reset_counters(phy);
out:
return ret;
}
static int mt7996_start(struct ieee80211_hw *hw)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
int ret;
flush_work(&dev->init_work);
mutex_lock(&dev->mt76.mutex);
ret = mt7996_run(hw);
mutex_unlock(&dev->mt76.mutex);
return ret;
@ -79,10 +84,6 @@ static void mt7996_stop(struct ieee80211_hw *hw)
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_interfaces(dev->mt76.hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7996_mcu_set_pm, dev->mt76.hw);
mutex_unlock(&dev->mt76.mutex);
}
@ -219,8 +220,12 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
vif->offload_flags = 0;
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ)
mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
else
mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL;
mt7996_init_bitrate_mask(vif);
memset(&mvif->cap, -1, sizeof(mvif->cap));
mt7996_mcu_add_bss_info(phy, vif, true);
mt7996_mcu_add_sta(dev, vif, NULL, true);
@ -497,11 +502,41 @@ mt7996_update_bss_color(struct ieee80211_hw *hw,
}
}
static u8
mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
bool beacon, bool mcast)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt76_phy *mphy = hw->priv;
u16 rate;
u8 i, idx, ht;
rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast);
ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM;
if (beacon && ht) {
struct mt7996_dev *dev = mt7996_hw_dev(hw);
/* must odd index */
idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->mt76.idx % 20);
mt7996_mac_set_fixed_rate_table(dev, idx, rate);
return idx;
}
idx = FIELD_GET(MT_TX_RATE_IDX, rate);
for (i = 0; i < ARRAY_SIZE(mt76_rates); i++)
if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx)
return MT7996_BASIC_RATES_TBL + i;
return mvif->basic_rates_idx;
}
static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u64 changed)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt7996_dev *dev = mt7996_hw_dev(hw);
@ -533,6 +568,14 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
}
}
if (changed & BSS_CHANGED_MCAST_RATE)
mvif->mcast_rates_idx =
mt7996_get_rates_table(hw, vif, false, true);
if (changed & BSS_CHANGED_BASIC_RATES)
mvif->basic_rates_idx =
mt7996_get_rates_table(hw, vif, false, false);
if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
mt7996_mcu_add_bss_info(phy, vif, true);
mt7996_mcu_add_sta(dev, vif, NULL, true);
@ -549,8 +592,12 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
mt7996_update_bss_color(hw, vif, &info->he_bss_color);
if (changed & (BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED))
BSS_CHANGED_BEACON_ENABLED)) {
mvif->beacon_rates_idx =
mt7996_get_rates_table(hw, vif, true, false);
mt7996_mcu_add_beacon(hw, vif, info->enable_beacon);
}
if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP ||
changed & BSS_CHANGED_FILS_DISCOVERY)
@ -892,6 +939,7 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
mt7996_set_stream_vht_txbf_caps(phy);
mt7996_set_stream_he_eht_caps(phy);
/* TODO: update bmc_wtbl spe_idx when antenna changes */
mutex_unlock(&dev->mt76.mutex);
return 0;

Просмотреть файл

@ -422,7 +422,8 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
if (hdr->band && dev->mt76.phys[hdr->band])
mphy = dev->mt76.phys[hdr->band];
tail = skb->data + le16_to_cpu(rxd->len);
tail = skb->data + skb->len;
data += sizeof(struct header);
while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) {
switch (le16_to_cpu(tlv->tag)) {
case UNI_EVENT_IE_COUNTDOWN_CSA:
@ -596,25 +597,24 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
}
static void
mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7996_phy *phy)
mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
struct mt7996_phy *phy)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct bss_rate_tlv *bmc;
struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
enum nl80211_band band = chandef->chan->band;
struct tlv *tlv;
u8 idx = mvif->mcast_rates_idx ?
mvif->mcast_rates_idx : mvif->basic_rates_idx;
tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc));
bmc = (struct bss_rate_tlv *)tlv;
if (band == NL80211_BAND_2GHZ) {
bmc->short_preamble = true;
} else {
bmc->bc_trans = cpu_to_le16(0x8080);
bmc->mc_trans = cpu_to_le16(0x8080);
bmc->bc_fixed_rate = 1;
bmc->mc_fixed_rate = 1;
bmc->short_preamble = 1;
}
bmc->short_preamble = (band == NL80211_BAND_2GHZ);
bmc->bc_fixed_rate = idx;
bmc->mc_fixed_rate = idx;
}
static void
@ -822,7 +822,7 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
if (enable) {
mt7996_mcu_bss_rfch_tlv(skb, vif, phy);
mt7996_mcu_bss_bmc_tlv(skb, phy);
mt7996_mcu_bss_bmc_tlv(skb, vif, phy);
mt7996_mcu_bss_ra_tlv(skb, vif, phy);
mt7996_mcu_bss_txcmd_tlv(skb, true);
@ -1022,6 +1022,7 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
struct tlv *tlv;
if (vif->type != NL80211_IFTYPE_STATION &&
vif->type != NL80211_IFTYPE_MESH_POINT &&
vif->type != NL80211_IFTYPE_AP)
return;
@ -1053,7 +1054,6 @@ static inline bool
mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool bfee)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
int sts = hweight16(phy->mt76->chainmask);
if (vif->type != NL80211_IFTYPE_STATION &&
@ -1068,10 +1068,10 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
if (bfee)
return mvif->cap.eht_su_ebfee &&
return vif->bss_conf.eht_su_beamformee &&
EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
else
return mvif->cap.eht_su_ebfer &&
return vif->bss_conf.eht_su_beamformer &&
EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);
}
@ -1079,10 +1079,10 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
if (bfee)
return mvif->cap.he_su_ebfee &&
return vif->bss_conf.he_su_beamformee &&
HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
else
return mvif->cap.he_su_ebfer &&
return vif->bss_conf.he_su_beamformer &&
HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
}
@ -1090,10 +1090,10 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
u32 cap = sta->deflink.vht_cap.cap;
if (bfee)
return mvif->cap.vht_su_ebfee &&
return vif->bss_conf.vht_su_beamformee &&
(cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
else
return mvif->cap.vht_su_ebfer &&
return vif->bss_conf.vht_su_beamformer &&
(cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
}
@ -1471,6 +1471,12 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
hdr_trans->to_ds = true;
hdr_trans->from_ds = true;
}
if (vif->type == NL80211_IFTYPE_MESH_POINT) {
hdr_trans->to_ds = true;
hdr_trans->from_ds = true;
hdr_trans->mesh = true;
}
}
static enum mcu_mmps_mode
@ -1572,7 +1578,7 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
cap |= STA_CAP_TX_STBC;
if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
cap |= STA_CAP_RX_STBC;
if (mvif->cap.ht_ldpc &&
if (vif->bss_conf.ht_ldpc &&
(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
cap |= STA_CAP_LDPC;
@ -1598,7 +1604,7 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
cap |= STA_CAP_VHT_TX_STBC;
if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
cap |= STA_CAP_VHT_RX_STBC;
if (mvif->cap.vht_ldpc &&
if (vif->bss_conf.vht_ldpc &&
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
cap |= STA_CAP_VHT_LDPC;
@ -1694,8 +1700,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
/* starec basic */
mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable,
!rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable,
!rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
if (!enable)
goto out;
@ -1906,107 +1912,12 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
}
buf = (u8 *)bcn + sizeof(*bcn) - MAX_BEACON_SIZE;
mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0,
BSS_CHANGED_BEACON);
memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
}
static void
mt7996_mcu_beacon_check_caps(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct sk_buff *skb)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_vif_cap *vc = &mvif->cap;
const struct ieee80211_eht_cap_elem_fixed *eht;
const struct ieee80211_he_cap_elem *he;
const struct ieee80211_vht_cap *vht;
const struct ieee80211_ht_cap *ht;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
const u8 *ie;
u32 len, bc;
/* Check missing configuration options to allow AP mode in mac80211
* to remain in sync with hostapd settings, and get a subset of
* beacon and hardware capabilities.
*/
if (WARN_ON_ONCE(skb->len <= (mgmt->u.beacon.variable - skb->data)))
return;
memset(vc, 0, sizeof(*vc));
len = skb->len - (mgmt->u.beacon.variable - skb->data);
ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, mgmt->u.beacon.variable,
len);
if (ie && ie[1] >= sizeof(*ht)) {
ht = (void *)(ie + 2);
vc->ht_ldpc |= !!(le16_to_cpu(ht->cap_info) &
IEEE80211_HT_CAP_LDPC_CODING);
}
ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, mgmt->u.beacon.variable,
len);
if (ie && ie[1] >= sizeof(*vht)) {
u32 pc = phy->mt76->sband_5g.sband.vht_cap.cap;
vht = (void *)(ie + 2);
bc = le32_to_cpu(vht->vht_cap_info);
vc->vht_ldpc |= !!(bc & IEEE80211_VHT_CAP_RXLDPC);
vc->vht_su_ebfer =
(bc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
vc->vht_su_ebfee =
(bc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
vc->vht_mu_ebfer =
(bc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
vc->vht_mu_ebfee =
(bc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
(pc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
}
ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY,
mgmt->u.beacon.variable, len);
if (ie && ie[1] >= sizeof(*he) + 1) {
const struct ieee80211_sta_he_cap *pc =
mt76_connac_get_he_phy_cap(phy->mt76, vif);
const struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
he = (void *)(ie + 3);
vc->he_ldpc =
HE_PHY(CAP1_LDPC_CODING_IN_PAYLOAD, pe->phy_cap_info[1]);
vc->he_su_ebfer =
HE_PHY(CAP3_SU_BEAMFORMER, he->phy_cap_info[3]) &&
HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
vc->he_su_ebfee =
HE_PHY(CAP4_SU_BEAMFORMEE, he->phy_cap_info[4]) &&
HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
vc->he_mu_ebfer =
HE_PHY(CAP4_MU_BEAMFORMER, he->phy_cap_info[4]) &&
HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4]);
}
ie = cfg80211_find_ext_ie(WLAN_EID_EXT_EHT_CAPABILITY,
mgmt->u.beacon.variable, len);
if (ie && ie[1] >= sizeof(*eht) + 1) {
const struct ieee80211_sta_eht_cap *pc =
mt76_connac_get_eht_phy_cap(phy->mt76, vif);
const struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
eht = (void *)(ie + 3);
vc->eht_su_ebfer =
EHT_PHY(CAP0_SU_BEAMFORMER, eht->phy_cap_info[0]) &&
EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);
vc->eht_su_ebfee =
EHT_PHY(CAP0_SU_BEAMFORMEE, eht->phy_cap_info[0]) &&
EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
}
}
int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int en)
{
@ -2045,8 +1956,6 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);
info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx);
mt7996_mcu_beacon_check_caps(phy, vif, skb);
mt7996_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
/* TODO: subtag - 11v MBSSID */
mt7996_mcu_beacon_cntdwn(vif, rskb, skb, &offs);
@ -2115,8 +2024,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
buf = (u8 *)tlv + sizeof(*discov) - MAX_INBAND_FRAME_SIZE;
mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
changed);
mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, changed);
memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
@ -2523,17 +2431,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
MCU_WM_UNI_CMD(VOW), true);
}
int mt7996_mcu_init(struct mt7996_dev *dev)
int mt7996_mcu_init_firmware(struct mt7996_dev *dev)
{
static const struct mt76_mcu_ops mt7996_mcu_ops = {
.headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
.mcu_skb_send_msg = mt7996_mcu_send_message,
.mcu_parse_response = mt7996_mcu_parse_response,
};
int ret;
dev->mt76.mcu_ops = &mt7996_mcu_ops;
/* force firmware operation mode into normal state,
* which should be set before firmware download stage.
*/
@ -2574,6 +2475,19 @@ int mt7996_mcu_init(struct mt7996_dev *dev)
MCU_WA_PARAM_RED, 0, 0);
}
int mt7996_mcu_init(struct mt7996_dev *dev)
{
static const struct mt76_mcu_ops mt7996_mcu_ops = {
.headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
.mcu_skb_send_msg = mt7996_mcu_send_message,
.mcu_parse_response = mt7996_mcu_parse_response,
};
dev->mt76.mcu_ops = &mt7996_mcu_ops;
return mt7996_mcu_init_firmware(dev);
}
void mt7996_mcu_exit(struct mt7996_dev *dev)
{
mt7996_mcu_restart(&dev->mt76);
@ -3133,7 +3047,7 @@ int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap)
break;
default:
break;
};
}
buf += le16_to_cpu(tlv->len);
}
@ -3576,32 +3490,6 @@ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
&req, sizeof(req), true);
}
void mt7996_mcu_set_pm(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
#define EXIT_PM_STATE 0
#define ENTER_PM_STATE 1
struct ieee80211_hw *hw = priv;
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct bss_power_save *ps;
struct sk_buff *skb;
struct tlv *tlv;
bool running = test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
MT7996_BSS_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
return;
tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_PS, sizeof(*ps));
ps = (struct bss_power_save *)tlv;
ps->profile = running ? EXIT_PM_STATE : ENTER_PM_STATE;
mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
}
int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val)
{
struct {
@ -3733,6 +3621,22 @@ int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set)
return 0;
}
int mt7996_mcu_trigger_assert(struct mt7996_dev *dev)
{
struct {
__le16 tag;
__le16 len;
u8 enable;
u8 rsv[3];
} __packed req = {
.len = cpu_to_le16(sizeof(req) - 4),
.enable = true,
};
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ASSERT_DUMP),
&req, sizeof(req), false);
}
int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
{
struct {

Просмотреть файл

@ -396,7 +396,7 @@ struct sta_rec_hdr_trans {
u8 from_ds;
u8 to_ds;
u8 dis_rx_hdr_tran;
u8 rsv;
u8 mesh;
} __packed;
struct hdr_trans_en {
@ -648,23 +648,21 @@ enum {
};
enum {
UNI_CMD_SER_QUERY = 0x0,
UNI_CMD_SER_SET = 0x2,
UNI_CMD_SER_TRIGGER = 0x3,
};
enum {
SER_QUERY,
UNI_CMD_SER_QUERY,
/* recovery */
SER_SET_RECOVER_L1,
SER_SET_RECOVER_L2,
SER_SET_RECOVER_L3_RX_ABORT,
SER_SET_RECOVER_L3_TX_ABORT,
SER_SET_RECOVER_L3_TX_DISABLE,
SER_SET_RECOVER_L3_BF,
UNI_CMD_SER_SET_RECOVER_L1,
UNI_CMD_SER_SET_RECOVER_L2,
UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT,
UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT,
UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE,
UNI_CMD_SER_SET_RECOVER_L3_BF,
UNI_CMD_SER_SET_RECOVER_L4_MDP,
UNI_CMD_SER_SET_RECOVER_FULL,
UNI_CMD_SER_SET_SYSTEM_ASSERT,
/* action */
SER_ENABLE = 2,
SER_RECOVER
UNI_CMD_SER_ENABLE = 1,
UNI_CMD_SER_SET,
UNI_CMD_SER_TRIGGER
};
enum {

Просмотреть файл

@ -162,6 +162,14 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)
return mt7996_reg_map_l2(dev, addr);
}
void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset,
size_t len)
{
u32 addr = __mt7996_reg_addr(dev, offset);
memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len);
}
static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset)
{
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
@ -251,7 +259,7 @@ static void mt7996_rx_poll_complete(struct mt76_dev *mdev,
/* TODO: support 2/4/6/8 MSI-X vectors */
static void mt7996_irq_tasklet(struct tasklet_struct *t)
{
struct mt7996_dev *dev = from_tasklet(dev, t, irq_tasklet);
struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet);
u32 i, intr, mask, intr1;
mt76_wr(dev, MT_INT_MASK_CSR, 0);
@ -289,10 +297,9 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
u32 val = mt76_rr(dev, MT_MCU_CMD);
mt76_wr(dev, MT_MCU_CMD, val);
if (val & MT_MCU_CMD_ERROR_MASK) {
dev->reset_state = val;
ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
wake_up(&dev->reset_wait);
if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) {
dev->recovery.state = val;
mt7996_reset(dev);
}
}
}
@ -308,7 +315,7 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance)
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return IRQ_NONE;
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
return IRQ_HANDLED;
}
@ -320,6 +327,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp),
.drv_flags = MT_DRV_TXWI_NO_FREE |
MT_DRV_AMSDU_OFFLOAD |
MT_DRV_HW_MGMT_TXQ,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
@ -330,7 +338,6 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
.rx_skb = mt7996_queue_rx_skb,
.rx_check = mt7996_rx_check,
.rx_poll_complete = mt7996_rx_poll_complete,
.sta_ps = mt7996_sta_ps,
.sta_add = mt7996_mac_sta_add,
.sta_remove = mt7996_mac_sta_remove,
.update_survey = mt7996_update_channel,
@ -349,7 +356,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
if (ret)
goto error;
tasklet_setup(&dev->irq_tasklet, mt7996_irq_tasklet);
tasklet_setup(&mdev->irq_tasklet, mt7996_irq_tasklet);
mt76_wr(dev, MT_INT_MASK_CSR, 0);

Просмотреть файл

@ -43,6 +43,10 @@
#define MT7996_MAX_STA_TWT_AGRT 8
#define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3)
/* NOTE: used to map mt76_rates. idx may change if firmware expands table */
#define MT7996_BASIC_RATES_TBL 11
#define MT7996_BEACON_RATES_TBL 25
struct mt7996_vif;
struct mt7996_sta;
struct mt7996_dfs_pulse;
@ -112,30 +116,18 @@ struct mt7996_sta {
} twt;
};
struct mt7996_vif_cap {
bool ht_ldpc:1;
bool vht_ldpc:1;
bool he_ldpc:1;
bool vht_su_ebfer:1;
bool vht_su_ebfee:1;
bool vht_mu_ebfer:1;
bool vht_mu_ebfee:1;
bool he_su_ebfer:1;
bool he_su_ebfee:1;
bool he_mu_ebfer:1;
bool eht_su_ebfer:1;
bool eht_su_ebfee:1;
};
struct mt7996_vif {
struct mt76_vif mt76; /* must be first */
struct mt7996_vif_cap cap;
struct mt7996_sta sta;
struct mt7996_phy *phy;
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
struct cfg80211_bitrate_mask bitrate_mask;
u8 basic_rates_idx;
u8 mcast_rates_idx;
u8 beacon_rates_idx;
};
/* per-phy stats. */
@ -192,6 +184,15 @@ struct mib_stats {
u32 tx_amsdu_cnt;
};
/* crash-dump */
struct mt7996_crash_data {
guid_t guid;
struct timespec64 timestamp;
u8 *memdump_buf;
size_t memdump_buf_len;
};
struct mt7996_hif {
struct list_head list;
@ -238,7 +239,6 @@ struct mt7996_dev {
u32 q_wfdma_mask;
const struct mt76_bus_ops *bus_ops;
struct tasklet_struct irq_tasklet;
struct mt7996_phy phy;
/* monitor rx chain configured channel */
@ -251,9 +251,25 @@ struct mt7996_dev {
struct work_struct init_work;
struct work_struct rc_work;
struct work_struct dump_work;
struct work_struct reset_work;
wait_queue_head_t reset_wait;
u32 reset_state;
struct {
u32 state;
u32 wa_reset_count;
u32 wm_reset_count;
bool hw_full_reset:1;
bool hw_init_done:1;
bool restart:1;
} recovery;
/* protects coredump data */
struct mutex dump_mutex;
#ifdef CONFIG_DEV_COREDUMP
struct {
struct mt7996_crash_data *crash_data;
} coredump;
#endif
struct list_head sta_rc_list;
struct list_head sta_poll_list;
@ -386,9 +402,16 @@ int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
struct ieee80211_channel *chan);
s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band);
int mt7996_dma_init(struct mt7996_dev *dev);
void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
void mt7996_dma_prefetch(struct mt7996_dev *dev);
void mt7996_dma_cleanup(struct mt7996_dev *dev);
void mt7996_init_txpower(struct mt7996_dev *dev,
struct ieee80211_supported_band *sband);
int mt7996_txbf_init(struct mt7996_dev *dev);
void mt7996_reset(struct mt7996_dev *dev);
int mt7996_run(struct ieee80211_hw *hw);
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,
struct mt7996_vif *mvif,
struct mt7996_twt_flow *flow,
@ -432,7 +455,6 @@ int mt7996_mcu_set_pulse_th(struct mt7996_dev *dev,
int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
const struct mt7996_dfs_pattern *pattern);
int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
void mt7996_mcu_set_pm(void *priv, u8 *mac, struct ieee80211_vif *vif);
int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
@ -445,6 +467,7 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val);
int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl);
int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
@ -468,7 +491,7 @@ static inline void mt7996_irq_enable(struct mt7996_dev *dev, u32 mask)
else
mt76_set_irq_mask(&dev->mt76, 0, 0, mask);
tasklet_schedule(&dev->irq_tasklet);
tasklet_schedule(&dev->mt76.irq_tasklet);
}
static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask)
@ -479,6 +502,10 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask)
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
}
void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset,
size_t len);
void mt7996_mac_init(struct mt7996_dev *dev);
u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw);
bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask);
void mt7996_mac_reset_counters(struct mt7996_phy *phy);
@ -486,9 +513,12 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy);
void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
struct ieee80211_vif *vif, bool enable);
void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
u8 tbl_idx, u16 rate_idx);
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
struct ieee80211_key_conf *key, u32 changed);
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
enum mt76_txq_id qid, u32 changed);
void mt7996_mac_set_timing(struct mt7996_phy *phy);
int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@ -496,6 +526,7 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7996_mac_work(struct work_struct *work);
void mt7996_mac_reset_work(struct work_struct *work);
void mt7996_mac_dump_work(struct work_struct *work);
void mt7996_mac_sta_rc_work(struct work_struct *work);
void mt7996_mac_update_stats(struct mt7996_phy *phy);
void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
@ -512,7 +543,6 @@ void mt7996_tx_token_put(struct mt7996_dev *dev);
void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info);
bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
void mt7996_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
void mt7996_stats_work(struct work_struct *work);
int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy);

Просмотреть файл

@ -228,6 +228,13 @@ enum base_rev {
#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(14)
#define MT_WTBL_UPDATE_BUSY BIT(31)
#define MT_WTBL_ITCR MT_WTBLON_TOP(0x3b0)
#define MT_WTBL_ITCR_WR BIT(16)
#define MT_WTBL_ITCR_EXEC BIT(31)
#define MT_WTBL_ITDR0 MT_WTBLON_TOP(0x3b8)
#define MT_WTBL_ITDR1 MT_WTBLON_TOP(0x3bc)
#define MT_WTBL_SPE_IDX_SEL BIT(6)
/* WTBL */
#define MT_WTBL_BASE 0x820d8000
#define MT_WTBL_LMAC_ID GENMASK(14, 8)
@ -317,6 +324,8 @@ enum base_rev {
#define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154)
#define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3)
#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
@ -444,6 +453,10 @@ enum base_rev {
#define MT_MCU_CMD_NORMAL_STATE BIT(5)
#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
#define MT_MCU_CMD_WA_WDT BIT(31)
#define MT_MCU_CMD_WM_WDT BIT(30)
#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30)
/* l1/l2 remap */
#define MT_HIF_REMAP_L1 0x155024
#define MT_HIF_REMAP_L1_MASK GENMASK(31, 16)
@ -468,9 +481,28 @@ enum base_rev {
#define MT_INFRA_MCU_END 0x7c3fffff
/* FW MODE SYNC */
#define MT_SWDEF_MODE 0x9143c
#define MT_FW_ASSERT_CNT 0x02208274
#define MT_FW_DUMP_STATE 0x02209e90
#define MT_SWDEF_BASE 0x00401400
#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
#define MT_SWDEF_MODE MT_SWDEF(0x3c)
#define MT_SWDEF_NORMAL_MODE 0
#define MT_SWDEF_SER_STATS MT_SWDEF(0x040)
#define MT_SWDEF_PLE_STATS MT_SWDEF(0x044)
#define MT_SWDEF_PLE1_STATS MT_SWDEF(0x048)
#define MT_SWDEF_PLE_AMSDU_STATS MT_SWDEF(0x04c)
#define MT_SWDEF_PSE_STATS MT_SWDEF(0x050)
#define MT_SWDEF_PSE1_STATS MT_SWDEF(0x054)
#define MT_SWDEF_LAMC_WISR6_BN0_STATS MT_SWDEF(0x058)
#define MT_SWDEF_LAMC_WISR6_BN1_STATS MT_SWDEF(0x05c)
#define MT_SWDEF_LAMC_WISR6_BN2_STATS MT_SWDEF(0x060)
#define MT_SWDEF_LAMC_WISR7_BN0_STATS MT_SWDEF(0x064)
#define MT_SWDEF_LAMC_WISR7_BN1_STATS MT_SWDEF(0x068)
#define MT_SWDEF_LAMC_WISR7_BN2_STATS MT_SWDEF(0x06c)
/* LED */
#define MT_LED_TOP_BASE 0x18013000
#define MT_LED_PHYS(_n) (MT_LED_TOP_BASE + (_n))
@ -486,6 +518,13 @@ enum base_rev {
#define MT_LED_EN(_n) MT_LED_PHYS(0x40 + ((_n) * 4))
/* CONN DBG */
#define MT_CONN_DBG_CTL_BASE 0x18023000
#define MT_CONN_DBG_CTL(ofs) (MT_CONN_DBG_CTL_BASE + (ofs))
#define MT_CONN_DBG_CTL_OUT_SEL MT_CONN_DBG_CTL(0x604)
#define MT_CONN_DBG_CTL_PC_LOG_SEL MT_CONN_DBG_CTL(0x60c)
#define MT_CONN_DBG_CTL_PC_LOG MT_CONN_DBG_CTL(0x610)
#define MT_LED_GPIO_MUX2 0x70005058 /* GPIO 18 */
#define MT_LED_GPIO_MUX3 0x7000505C /* GPIO 26 */
#define MT_LED_GPIO_SEL_MASK GENMASK(11, 8)
@ -506,7 +545,7 @@ enum base_rev {
#define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
#define MT_HW_REV 0x70010204
#define MT_WF_SUBSYS_RST 0x70002600
#define MT_WF_SUBSYS_RST 0x70028600
/* PCIE MAC */
#define MT_PCIE_MAC_BASE 0x74030000
@ -539,4 +578,12 @@ enum base_rev {
#define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
#define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR BIT(29)
/* CONN MCU EXCP CON */
#define MT_MCU_WM_EXCP_BASE 0x89050000
#define MT_MCU_WM_EXCP(ofs) (MT_MCU_WM_EXCP_BASE + (ofs))
#define MT_MCU_WM_EXCP_PC_CTRL MT_MCU_WM_EXCP(0x100)
#define MT_MCU_WM_EXCP_PC_LOG MT_MCU_WM_EXCP(0x104)
#define MT_MCU_WM_EXCP_LR_CTRL MT_MCU_WM_EXCP(0x200)
#define MT_MCU_WM_EXCP_LR_LOG MT_MCU_WM_EXCP(0x204)
#endif

Просмотреть файл

@ -77,7 +77,9 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
}
hw = mt76_tx_status_get_hw(dev, skb);
spin_lock_bh(&dev->rx_lock);
ieee80211_tx_status_ext(hw, &status);
spin_unlock_bh(&dev->rx_lock);
}
rcu_read_unlock();
}
@ -263,7 +265,9 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
if (cb->pktid < MT_PACKET_ID_FIRST) {
hw = mt76_tx_status_get_hw(dev, skb);
status.sta = wcid_to_sta(wcid);
spin_lock_bh(&dev->rx_lock);
ieee80211_tx_status_ext(hw, &status);
spin_unlock_bh(&dev->rx_lock);
goto out;
}