Path: blob/main/sys/contrib/dev/mediatek/mt76/mt76_connac_mac.c
48375 views
// SPDX-License-Identifier: ISC1/* Copyright (C) 2020 MediaTek Inc. */23#include "mt76_connac.h"4#include "mt76_connac2_mac.h"5#include "dma.h"67#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)8#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\9IEEE80211_RADIOTAP_HE_##f)1011void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss, enum nl80211_band band)12{13static const u8 ppet16_ppet8_ru3_ru0[] = { 0x1c, 0xc7, 0x71 };14u8 i, ppet_bits, ppet_size, ru_bit_mask = 0xf;1516if (band == NL80211_BAND_2GHZ)17ru_bit_mask = 0x3;1819he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |20FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,21ru_bit_mask);2223ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *24nss * hweight8(ru_bit_mask) * 2;25ppet_size = DIV_ROUND_UP(ppet_bits, 8);2627for (i = 0; i < ppet_size - 1; i++)28he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];2930he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &31(0xff >> (8 - (ppet_bits - 1) % 8));32}33EXPORT_SYMBOL_GPL(mt76_connac_gen_ppe_thresh);3435int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)36{37struct mt76_dev *dev = phy->dev;3839if (mt76_is_usb(dev))40return 0;4142cancel_delayed_work_sync(&pm->ps_work);43if (!test_bit(MT76_STATE_PM, &phy->state))44return 0;4546if (pm->suspended)47return 0;4849queue_work(dev->wq, &pm->wake_work);50if (!wait_event_timeout(pm->wait,51!test_bit(MT76_STATE_PM, &phy->state),523 * HZ)) {53ieee80211_wake_queues(phy->hw);54return -ETIMEDOUT;55}5657return 0;58}59EXPORT_SYMBOL_GPL(mt76_connac_pm_wake);6061void mt76_connac_power_save_sched(struct mt76_phy *phy,62struct mt76_connac_pm *pm)63{64struct mt76_dev *dev = phy->dev;6566if (mt76_is_usb(dev))67return;6869if (!pm->enable)70return;7172if (pm->suspended)73return;7475pm->last_activity = jiffies;7677if (!test_bit(MT76_STATE_PM, &phy->state)) {78cancel_delayed_work(&phy->mac_work);79queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout);80}81}82EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched);8384void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm,85struct mt76_wcid *wcid)86{87int i;8889spin_lock_bh(&pm->txq_lock);90for (i = 0; i < IEEE80211_NUM_ACS; i++) {91if (wcid && pm->tx_q[i].wcid != wcid)92continue;9394dev_kfree_skb(pm->tx_q[i].skb);95pm->tx_q[i].skb = NULL;96}97spin_unlock_bh(&pm->txq_lock);98}99EXPORT_SYMBOL_GPL(mt76_connac_free_pending_tx_skbs);100101void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw,102struct mt76_connac_pm *pm,103struct mt76_wcid *wcid,104struct sk_buff *skb)105{106int qid = skb_get_queue_mapping(skb);107struct mt76_phy *phy = hw->priv;108109spin_lock_bh(&pm->txq_lock);110if (!pm->tx_q[qid].skb) {111ieee80211_stop_queues(hw);112pm->tx_q[qid].wcid = wcid;113pm->tx_q[qid].skb = skb;114queue_work(phy->dev->wq, &pm->wake_work);115} else {116dev_kfree_skb(skb);117}118spin_unlock_bh(&pm->txq_lock);119}120EXPORT_SYMBOL_GPL(mt76_connac_pm_queue_skb);121122void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy,123struct mt76_connac_pm *pm)124{125int i;126127spin_lock_bh(&pm->txq_lock);128for (i = 0; i < IEEE80211_NUM_ACS; i++) {129struct mt76_wcid *wcid = pm->tx_q[i].wcid;130struct ieee80211_sta *sta = NULL;131132if (!pm->tx_q[i].skb)133continue;134135if (wcid && wcid->sta)136sta = container_of((void *)wcid, struct ieee80211_sta,137drv_priv);138139mt76_tx(phy, sta, wcid, pm->tx_q[i].skb);140pm->tx_q[i].skb = NULL;141}142spin_unlock_bh(&pm->txq_lock);143144mt76_worker_schedule(&phy->dev->tx_worker);145}146EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs);147148void mt76_connac_tx_complete_skb(struct mt76_dev *mdev,149struct mt76_queue_entry *e)150{151if (!e->txwi) {152dev_kfree_skb_any(e->skb);153return;154}155156if (e->skb)157mt76_tx_complete_skb(mdev, e->wcid, e->skb);158}159EXPORT_SYMBOL_GPL(mt76_connac_tx_complete_skb);160161void mt76_connac_write_hw_txp(struct mt76_dev *dev,162struct mt76_tx_info *tx_info,163void *txp_ptr, u32 id)164{165struct mt76_connac_hw_txp *txp = txp_ptr;166struct mt76_connac_txp_ptr *ptr = &txp->ptr[0];167int i, nbuf = tx_info->nbuf - 1;168u32 last_mask;169170tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp);171tx_info->nbuf = 1;172173txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);174175if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev))176last_mask = MT_TXD_LEN_LAST;177else178last_mask = MT_TXD_LEN_AMSDU_LAST |179MT_TXD_LEN_MSDU_LAST;180181for (i = 0; i < nbuf; i++) {182u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK;183u32 addr = tx_info->buf[i + 1].addr;184185if (i == nbuf - 1)186len |= last_mask;187188if (i & 1) {189ptr->buf1 = cpu_to_le32(addr);190ptr->len1 = cpu_to_le16(len);191ptr++;192} else {193ptr->buf0 = cpu_to_le32(addr);194ptr->len0 = cpu_to_le16(len);195}196}197}198EXPORT_SYMBOL_GPL(mt76_connac_write_hw_txp);199200static void201mt76_connac_txp_skb_unmap_fw(struct mt76_dev *mdev,202struct mt76_connac_fw_txp *txp)203{204struct device *dev = is_connac_v1(mdev) ? mdev->dev : mdev->dma_dev;205int i;206207for (i = 0; i < txp->nbuf; i++)208dma_unmap_single(dev, le32_to_cpu(txp->buf[i]),209le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);210}211212static void213mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev,214struct mt76_connac_hw_txp *txp)215{216u32 last_mask;217int i;218219if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev))220last_mask = MT_TXD_LEN_LAST;221else222last_mask = MT_TXD_LEN_MSDU_LAST;223224for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) {225struct mt76_connac_txp_ptr *ptr = &txp->ptr[i];226bool last;227u16 len;228229len = le16_to_cpu(ptr->len0);230last = len & last_mask;231len &= MT_TXD_LEN_MASK;232dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len,233DMA_TO_DEVICE);234if (last)235break;236237len = le16_to_cpu(ptr->len1);238last = len & last_mask;239len &= MT_TXD_LEN_MASK;240dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len,241DMA_TO_DEVICE);242if (last)243break;244}245}246247void mt76_connac_txp_skb_unmap(struct mt76_dev *dev,248struct mt76_txwi_cache *t)249{250struct mt76_connac_txp_common *txp;251252txp = mt76_connac_txwi_to_txp(dev, t);253if (is_mt76_fw_txp(dev))254mt76_connac_txp_skb_unmap_fw(dev, &txp->fw);255else256mt76_connac_txp_skb_unmap_hw(dev, &txp->hw);257}258EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap);259260int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,261int ring_base, void *wed, u32 flags)262{263int i, err;264265err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base,266wed, flags);267if (err < 0)268return err;269270for (i = 1; i <= MT_TXQ_PSD; i++)271phy->q_tx[i] = phy->q_tx[0];272273return 0;274}275EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues);276277#define __bitrate_mask_check(_mcs, _mode) \278({ \279u8 i = 0; \280for (nss = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \281if (!mask->control[band]._mcs[i]) \282continue; \283if (hweight16(mask->control[band]._mcs[i]) == 1) { \284mode = MT_PHY_TYPE_##_mode; \285rateidx = ffs(mask->control[band]._mcs[i]) - 1; \286if (mode == MT_PHY_TYPE_HT) \287rateidx += 8 * i; \288else \289nss = i + 1; \290goto out; \291} \292} \293})294295u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,296struct ieee80211_bss_conf *conf,297bool beacon, bool mcast)298{299struct mt76_vif_link *mvif = mt76_vif_conf_link(mphy->dev, conf->vif, conf);300struct cfg80211_chan_def *chandef = mvif->ctx ?301&mvif->ctx->def : &mphy->chandef;302u8 nss = 0, mode = 0, band = chandef->chan->band;303int rateidx = 0, mcast_rate;304int offset = 0;305306if (!conf)307goto legacy;308309if (is_mt7921(mphy->dev)) {310rateidx = ffs(conf->basic_rates) - 1;311goto legacy;312}313314if (beacon) {315struct cfg80211_bitrate_mask *mask;316317mask = &conf->beacon_tx_rate;318319__bitrate_mask_check(he_mcs, HE_SU);320__bitrate_mask_check(vht_mcs, VHT);321__bitrate_mask_check(ht_mcs, HT);322323if (hweight32(mask->control[band].legacy) == 1) {324rateidx = ffs(mask->control[band].legacy) - 1;325goto legacy;326}327}328329mcast_rate = conf->mcast_rate[band];330if (mcast && mcast_rate > 0)331rateidx = mcast_rate - 1;332else333rateidx = ffs(conf->basic_rates) - 1;334335legacy:336if (band != NL80211_BAND_2GHZ)337offset = 4;338339/* pick the lowest rate for hidden nodes */340if (rateidx < 0)341rateidx = 0;342343rateidx += offset;344if (rateidx >= ARRAY_SIZE(mt76_rates))345rateidx = offset;346347rateidx = mt76_rates[rateidx].hw_value;348mode = rateidx >> 8;349rateidx &= GENMASK(7, 0);350out:351return FIELD_PREP(MT_TX_RATE_NSS, nss) |352FIELD_PREP(MT_TX_RATE_IDX, rateidx) |353FIELD_PREP(MT_TX_RATE_MODE, mode);354}355EXPORT_SYMBOL_GPL(mt76_connac2_mac_tx_rate_val);356357static void358mt76_connac2_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,359struct mt76_wcid *wcid)360{361u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;362u8 fc_type, fc_stype;363u16 ethertype;364bool wmm = false;365u32 val;366367if (wcid->sta) {368struct ieee80211_sta *sta;369370sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);371wmm = sta->wme;372}373374val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |375FIELD_PREP(MT_TXD1_TID, tid);376377ethertype = get_unaligned_be16(&skb->data[12]);378if (ethertype >= ETH_P_802_3_MIN)379val |= MT_TXD1_ETH_802_3;380381txwi[1] |= cpu_to_le32(val);382383fc_type = IEEE80211_FTYPE_DATA >> 2;384fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;385386val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |387FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);388389txwi[2] |= cpu_to_le32(val);390391val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |392FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);393394txwi[7] |= cpu_to_le32(val);395}396397static void398mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,399struct sk_buff *skb,400struct ieee80211_key_conf *key)401{402struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;403struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;404struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);405bool multicast = is_multicast_ether_addr(hdr->addr1);406u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;407__le16 fc = hdr->frame_control;408__le16 sc = hdr->seq_ctrl;409u8 fc_type, fc_stype;410u32 val;411412if (ieee80211_is_action(fc) &&413mgmt->u.action.category == WLAN_CATEGORY_BACK &&414mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {415u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);416417txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);418tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;419} else if (ieee80211_is_back_req(hdr->frame_control)) {420struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;421u16 control = le16_to_cpu(bar->control);422423tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);424}425426val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |427FIELD_PREP(MT_TXD1_HDR_INFO,428ieee80211_get_hdrlen_from_skb(skb) / 2) |429FIELD_PREP(MT_TXD1_TID, tid);430431txwi[1] |= cpu_to_le32(val);432433fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;434fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;435436val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |437FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |438FIELD_PREP(MT_TXD2_MULTICAST, multicast);439440if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&441key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {442val |= MT_TXD2_BIP;443txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);444}445446if (!ieee80211_is_data(fc) || multicast ||447info->flags & IEEE80211_TX_CTL_USE_MINRATE)448val |= MT_TXD2_FIX_RATE;449450if (ieee80211_has_morefrags(fc) && ieee80211_is_first_frag(sc))451val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_FIRST);452else if (ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc))453val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_MID);454else if (!ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc))455val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_LAST);456457txwi[2] |= cpu_to_le32(val);458459if (ieee80211_is_beacon(fc)) {460txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);461txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);462}463464if (info->flags & IEEE80211_TX_CTL_INJECTED) {465u16 seqno = le16_to_cpu(sc);466467if (ieee80211_is_back_req(hdr->frame_control)) {468struct ieee80211_bar *bar;469470bar = (struct ieee80211_bar *)skb->data;471seqno = le16_to_cpu(bar->start_seq_num);472}473474val = MT_TXD3_SN_VALID |475FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));476txwi[3] |= cpu_to_le32(val);477txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);478}479480if (mt76_is_mmio(dev)) {481val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |482FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);483txwi[7] |= cpu_to_le32(val);484} else {485val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |486FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);487txwi[8] |= cpu_to_le32(val);488}489}490491void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,492struct sk_buff *skb, struct mt76_wcid *wcid,493struct ieee80211_key_conf *key, int pid,494enum mt76_txq_id qid, u32 changed)495{496struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);497u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;498struct ieee80211_vif *vif = info->control.vif;499struct mt76_phy *mphy = &dev->phy;500u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0;501u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE;502bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;503bool beacon = !!(changed & (BSS_CHANGED_BEACON |504BSS_CHANGED_BEACON_ENABLED));505bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |506BSS_CHANGED_FILS_DISCOVERY));507bool amsdu_en = wcid->amsdu;508509if (vif) {510struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;511512omac_idx = mvif->omac_idx;513wmm_idx = mvif->wmm_idx;514band_idx = mvif->band_idx;515}516517if (phy_idx && dev->phys[MT_BAND1])518mphy = dev->phys[MT_BAND1];519520if (inband_disc) {521p_fmt = MT_TX_TYPE_FW;522q_idx = MT_LMAC_ALTX0;523} else if (beacon) {524p_fmt = MT_TX_TYPE_FW;525q_idx = MT_LMAC_BCN0;526} else if (qid >= MT_TXQ_PSD) {527p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;528q_idx = MT_LMAC_ALTX0;529} else {530p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;531q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +532mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));533534/* mt7915 WA only counts WED path */535if (is_mt7915(dev) && mtk_wed_device_active(&dev->mmio.wed))536wcid->stats.tx_packets++;537}538539val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |540FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |541FIELD_PREP(MT_TXD0_Q_IDX, q_idx);542txwi[0] = cpu_to_le32(val);543544val = MT_TXD1_LONG_FORMAT |545FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |546FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);547if (!is_mt7921(dev))548val |= MT_TXD1_VTA;549if (phy_idx || band_idx)550val |= MT_TXD1_TGID;551552txwi[1] = cpu_to_le32(val);553txwi[2] = 0;554555val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15);556if (!is_mt7921(dev))557val |= MT_TXD3_SW_POWER_MGMT;558if (key)559val |= MT_TXD3_PROTECT_FRAME;560if (info->flags & IEEE80211_TX_CTL_NO_ACK)561val |= MT_TXD3_NO_ACK;562563txwi[3] = cpu_to_le32(val);564txwi[4] = 0;565566val = FIELD_PREP(MT_TXD5_PID, pid);567if (pid >= MT_PACKET_ID_FIRST) {568val |= MT_TXD5_TX_STATUS_HOST;569amsdu_en = 0;570}571572txwi[5] = cpu_to_le32(val);573txwi[6] = 0;574txwi[7] = amsdu_en ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;575576if (is_8023)577mt76_connac2_mac_write_txwi_8023(txwi, skb, wcid);578else579mt76_connac2_mac_write_txwi_80211(dev, txwi, skb, key);580581if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {582/* Fixed rata is available just for 802.11 txd */583struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;584bool multicast = ieee80211_is_data(hdr->frame_control) &&585is_multicast_ether_addr(hdr->addr1);586u16 rate = mt76_connac2_mac_tx_rate_val(mphy, &vif->bss_conf, beacon,587multicast);588u32 val = MT_TXD6_FIXED_BW;589590/* hardware won't add HTC for mgmt/ctrl frame */591txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);592593val |= FIELD_PREP(MT_TXD6_TX_RATE, rate);594txwi[6] |= cpu_to_le32(val);595txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);596597if (!is_mt7921(dev)) {598u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);599600if (!spe_idx)601spe_idx = 24 + phy_idx;602txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx));603}604605txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);606}607}608EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi);609610bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,611__le32 *txs_data)612{613struct mt76_sta_stats *stats = &wcid->stats;614struct ieee80211_supported_band *sband;615struct mt76_phy *mphy;616struct rate_info rate = {};617bool cck = false;618u32 txrate, txs, mode, stbc;619620txs = le32_to_cpu(txs_data[0]);621622/* PPDU based reporting */623if (mtk_wed_device_active(&dev->mmio.wed) &&624FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {625stats->tx_bytes +=626le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) -627le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE);628stats->tx_failed +=629le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);630stats->tx_retries +=631le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT);632633if (wcid->sta) {634struct ieee80211_sta *sta;635u8 tid;636637sta = container_of((void *)wcid, struct ieee80211_sta,638drv_priv);639tid = FIELD_GET(MT_TXS0_TID, txs);640641ieee80211_refresh_tx_agg_session_timer(sta, tid);642}643}644645txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);646647rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);648rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;649stbc = FIELD_GET(MT_TX_RATE_STBC, txrate);650651if (stbc && rate.nss > 1)652rate.nss >>= 1;653654if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))655stats->tx_nss[rate.nss - 1]++;656if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))657stats->tx_mcs[rate.mcs]++;658659mode = FIELD_GET(MT_TX_RATE_MODE, txrate);660switch (mode) {661case MT_PHY_TYPE_CCK:662cck = true;663fallthrough;664case MT_PHY_TYPE_OFDM:665mphy = &dev->phy;666if (wcid->phy_idx == MT_BAND1 && dev->phys[MT_BAND1])667mphy = dev->phys[MT_BAND1];668669if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)670sband = &mphy->sband_5g.sband;671else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)672sband = &mphy->sband_6g.sband;673else674sband = &mphy->sband_2g.sband;675676rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);677rate.legacy = sband->bitrates[rate.mcs].bitrate;678break;679case MT_PHY_TYPE_HT:680case MT_PHY_TYPE_HT_GF:681if (rate.mcs > 31)682return false;683684rate.flags = RATE_INFO_FLAGS_MCS;685if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)686rate.flags |= RATE_INFO_FLAGS_SHORT_GI;687break;688case MT_PHY_TYPE_VHT:689if (rate.mcs > 9)690return false;691692rate.flags = RATE_INFO_FLAGS_VHT_MCS;693break;694case MT_PHY_TYPE_HE_SU:695case MT_PHY_TYPE_HE_EXT_SU:696case MT_PHY_TYPE_HE_TB:697case MT_PHY_TYPE_HE_MU:698if (rate.mcs > 11)699return false;700701rate.he_gi = wcid->rate.he_gi;702rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);703rate.flags = RATE_INFO_FLAGS_HE_MCS;704break;705default:706return false;707}708709stats->tx_mode[mode]++;710711switch (FIELD_GET(MT_TXS0_BW, txs)) {712case IEEE80211_STA_RX_BW_160:713rate.bw = RATE_INFO_BW_160;714stats->tx_bw[3]++;715break;716case IEEE80211_STA_RX_BW_80:717rate.bw = RATE_INFO_BW_80;718stats->tx_bw[2]++;719break;720case IEEE80211_STA_RX_BW_40:721rate.bw = RATE_INFO_BW_40;722stats->tx_bw[1]++;723break;724default:725rate.bw = RATE_INFO_BW_20;726stats->tx_bw[0]++;727break;728}729wcid->rate = rate;730731return true;732}733EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_txs);734735bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,736int pid, __le32 *txs_data)737{738struct sk_buff_head list;739struct sk_buff *skb;740741if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) == MT_TXS_PPDU_FMT)742return false;743744mt76_tx_status_lock(dev, &list);745skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);746if (skb) {747struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);748749if (!(le32_to_cpu(txs_data[0]) & MT_TXS0_ACK_ERROR_MASK))750info->flags |= IEEE80211_TX_STAT_ACK;751752info->status.ampdu_len = 1;753info->status.ampdu_ack_len =754!!(info->flags & IEEE80211_TX_STAT_ACK);755info->status.rates[0].idx = -1;756757mt76_connac2_mac_fill_txs(dev, wcid, txs_data);758mt76_tx_status_skb_done(dev, skb, &list);759}760mt76_tx_status_unlock(dev, &list);761762return !!skb;763}764EXPORT_SYMBOL_GPL(mt76_connac2_mac_add_txs_skb);765766static void767mt76_connac2_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,768struct ieee80211_radiotap_he *he,769__le32 *rxv)770{771u32 ru_h, ru_l;772u8 ru, offs = 0;773774ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L);775ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H);776ru = (u8)(ru_l | ru_h << 4);777778status->bw = RATE_INFO_BW_HE_RU;779780switch (ru) {781case 0 ... 36:782status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;783offs = ru;784break;785case 37 ... 52:786status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;787offs = ru - 37;788break;789case 53 ... 60:790status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;791offs = ru - 53;792break;793case 61 ... 64:794status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;795offs = ru - 61;796break;797case 65 ... 66:798status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;799offs = ru - 65;800break;801case 67:802status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;803break;804case 68:805status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;806break;807}808809he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);810he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |811le16_encode_bits(offs,812IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);813}814815static void816mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb,817__le32 *rxv)818{819struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;820static struct ieee80211_radiotap_he_mu mu_known = {821.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |822HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |823HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |824HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),825.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),826};827struct ieee80211_radiotap_he_mu *he_mu;828829if (is_mt7921(dev)) {830mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN);831mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN);832}833834status->flag |= RX_FLAG_RADIOTAP_HE_MU;835836he_mu = skb_push(skb, sizeof(mu_known));837memcpy(he_mu, &mu_known, sizeof(mu_known));838839#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)840841he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);842if (status->he_dcm)843he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);844845he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |846MU_PREP(FLAGS2_SIG_B_SYMS_USERS,847le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));848849he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);850851if (status->bw >= RATE_INFO_BW_40) {852he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);853he_mu->ru_ch2[0] =854le32_get_bits(rxv[3], MT_CRXV_HE_RU1);855}856857if (status->bw >= RATE_INFO_BW_80) {858he_mu->ru_ch1[1] =859le32_get_bits(rxv[3], MT_CRXV_HE_RU2);860he_mu->ru_ch2[1] =861le32_get_bits(rxv[3], MT_CRXV_HE_RU3);862}863}864865void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,866struct sk_buff *skb,867__le32 *rxv, u32 mode)868{869struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;870static const struct ieee80211_radiotap_he known = {871.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |872HE_BITS(DATA1_DATA_DCM_KNOWN) |873HE_BITS(DATA1_STBC_KNOWN) |874HE_BITS(DATA1_CODING_KNOWN) |875HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |876HE_BITS(DATA1_DOPPLER_KNOWN) |877HE_BITS(DATA1_SPTL_REUSE_KNOWN) |878HE_BITS(DATA1_BSS_COLOR_KNOWN),879.data2 = HE_BITS(DATA2_GI_KNOWN) |880HE_BITS(DATA2_TXBF_KNOWN) |881HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |882HE_BITS(DATA2_TXOP_KNOWN),883};884u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;885struct ieee80211_radiotap_he *he;886887status->flag |= RX_FLAG_RADIOTAP_HE;888889he = skb_push(skb, sizeof(known));890memcpy(he, &known, sizeof(known));891892he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |893HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);894he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);895he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |896le16_encode_bits(ltf_size,897IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);898if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)899he->data5 |= HE_BITS(DATA5_TXBF);900he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |901HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);902903switch (mode) {904case MT_PHY_TYPE_HE_SU:905he->data1 |= HE_BITS(DATA1_FORMAT_SU) |906HE_BITS(DATA1_UL_DL_KNOWN) |907HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |908HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);909910he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |911HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);912break;913case MT_PHY_TYPE_HE_EXT_SU:914he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |915HE_BITS(DATA1_UL_DL_KNOWN) |916HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);917918he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);919break;920case MT_PHY_TYPE_HE_MU:921he->data1 |= HE_BITS(DATA1_FORMAT_MU) |922HE_BITS(DATA1_UL_DL_KNOWN);923924he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);925he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);926927mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv);928mt76_connac2_mac_decode_he_mu_radiotap(dev, skb, rxv);929break;930case MT_PHY_TYPE_HE_TB:931he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |932HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |933HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |934HE_BITS(DATA1_SPTL_REUSE4_KNOWN);935936he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |937HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |938HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |939HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);940941mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv);942break;943default:944break;945}946}947EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap);948949/* The HW does not translate the mac header to 802.3 for mesh point */950int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,951struct sk_buff *skb, u16 hdr_offset)952{953struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;954struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_offset);955__le32 *rxd = (__le32 *)skb->data;956struct ieee80211_sta *sta;957struct ieee80211_hdr hdr;958u16 frame_control;959960if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=961MT_RXD3_NORMAL_U2M)962return -EINVAL;963964if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))965return -EINVAL;966967sta = container_of((void *)status->wcid, struct ieee80211_sta, drv_priv);968969/* store the info from RXD and ethhdr to avoid being overridden */970frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL);971hdr.frame_control = cpu_to_le16(frame_control);972hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL));973hdr.duration_id = 0;974975ether_addr_copy(hdr.addr1, vif->addr);976ether_addr_copy(hdr.addr2, sta->addr);977switch (frame_control & (IEEE80211_FCTL_TODS |978IEEE80211_FCTL_FROMDS)) {979case 0:980ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);981break;982case IEEE80211_FCTL_FROMDS:983ether_addr_copy(hdr.addr3, eth_hdr->h_source);984break;985case IEEE80211_FCTL_TODS:986ether_addr_copy(hdr.addr3, eth_hdr->h_dest);987break;988case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:989ether_addr_copy(hdr.addr3, eth_hdr->h_dest);990ether_addr_copy(hdr.addr4, eth_hdr->h_source);991break;992default:993return -EINVAL;994}995996skb_pull(skb, hdr_offset + sizeof(struct ethhdr) - 2);997if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||998eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))999ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);1000else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)1001ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);1002else1003skb_pull(skb, 2);10041005if (ieee80211_has_order(hdr.frame_control))1006memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9],1007IEEE80211_HT_CTL_LEN);1008if (ieee80211_is_data_qos(hdr.frame_control)) {1009__le16 qos_ctrl;10101011qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL));1012memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,1013IEEE80211_QOS_CTL_LEN);1014}10151016if (ieee80211_has_a4(hdr.frame_control))1017memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));1018else1019memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);10201021return 0;1022}1023EXPORT_SYMBOL_GPL(mt76_connac2_reverse_frag0_hdr_trans);10241025int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,1026struct mt76_rx_status *status,1027struct ieee80211_supported_band *sband,1028__le32 *rxv, u8 *mode)1029{1030u32 v0, v2;1031u8 stbc, gi, bw, dcm, nss;1032int i, idx;1033bool cck = false;10341035v0 = le32_to_cpu(rxv[0]);1036v2 = le32_to_cpu(rxv[2]);10371038idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0);1039nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;10401041if (!is_mt7915(dev)) {1042stbc = FIELD_GET(MT_PRXV_HT_STBC, v0);1043gi = FIELD_GET(MT_PRXV_HT_SGI, v0);1044*mode = FIELD_GET(MT_PRXV_TX_MODE, v0);1045if (is_mt7921(dev))1046dcm = !!(idx & MT_PRXV_TX_DCM);1047else1048dcm = FIELD_GET(MT_PRXV_DCM, v0);1049bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0);1050} else {1051stbc = FIELD_GET(MT_CRXV_HT_STBC, v2);1052gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2);1053*mode = FIELD_GET(MT_CRXV_TX_MODE, v2);1054dcm = !!(idx & GENMASK(3, 0) & MT_PRXV_TX_DCM);1055bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2);1056}10571058switch (*mode) {1059case MT_PHY_TYPE_CCK:1060cck = true;1061fallthrough;1062case MT_PHY_TYPE_OFDM:1063i = mt76_get_rate(dev, sband, i, cck);1064break;1065case MT_PHY_TYPE_HT_GF:1066case MT_PHY_TYPE_HT:1067status->encoding = RX_ENC_HT;1068if (gi)1069status->enc_flags |= RX_ENC_FLAG_SHORT_GI;1070if (i > 31)1071return -EINVAL;1072break;1073case MT_PHY_TYPE_VHT:1074status->nss = nss;1075status->encoding = RX_ENC_VHT;1076if (gi)1077status->enc_flags |= RX_ENC_FLAG_SHORT_GI;1078if (i > 11)1079return -EINVAL;1080break;1081case MT_PHY_TYPE_HE_MU:1082case MT_PHY_TYPE_HE_SU:1083case MT_PHY_TYPE_HE_EXT_SU:1084case MT_PHY_TYPE_HE_TB:1085status->nss = nss;1086status->encoding = RX_ENC_HE;1087i &= GENMASK(3, 0);10881089if (gi <= NL80211_RATE_INFO_HE_GI_3_2)1090status->he_gi = gi;10911092status->he_dcm = dcm;1093break;1094default:1095return -EINVAL;1096}1097status->rate_idx = i;10981099switch (bw) {1100case IEEE80211_STA_RX_BW_20:1101break;1102case IEEE80211_STA_RX_BW_40:1103if (*mode & MT_PHY_TYPE_HE_EXT_SU &&1104(idx & MT_PRXV_TX_ER_SU_106T)) {1105status->bw = RATE_INFO_BW_HE_RU;1106status->he_ru =1107NL80211_RATE_INFO_HE_RU_ALLOC_106;1108} else {1109status->bw = RATE_INFO_BW_40;1110}1111break;1112case IEEE80211_STA_RX_BW_80:1113status->bw = RATE_INFO_BW_80;1114break;1115case IEEE80211_STA_RX_BW_160:1116status->bw = RATE_INFO_BW_160;1117break;1118default:1119return -EINVAL;1120}11211122status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;1123if (*mode < MT_PHY_TYPE_HE_SU && gi)1124status->enc_flags |= RX_ENC_FLAG_SHORT_GI;11251126return 0;1127}1128EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_rx_rate);11291130void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)1131{1132struct mt76_wcid *wcid;1133u16 fc, tid;1134u32 val;11351136if (!sta ||1137!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))1138return;11391140tid = le32_get_bits(txwi[1], MT_TXD1_TID);1141if (tid >= 6) /* skip VO queue */1142return;11431144val = le32_to_cpu(txwi[2]);1145fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |1146FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;1147if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))1148return;11491150wcid = (struct mt76_wcid *)sta->drv_priv;1151if (!test_and_set_bit(tid, &wcid->ampdu_state))1152ieee80211_start_tx_ba_session(sta, tid, 0);1153}1154EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr);11551156void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,1157struct ieee80211_sta *sta,1158struct list_head *free_list)1159{1160struct mt76_wcid *wcid;1161__le32 *txwi;1162u16 wcid_idx;11631164mt76_connac_txp_skb_unmap(dev, t);1165if (!t->skb)1166goto out;11671168txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);1169if (sta) {1170wcid = (struct mt76_wcid *)sta->drv_priv;1171wcid_idx = wcid->idx;1172} else {1173wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);1174wcid = __mt76_wcid_ptr(dev, wcid_idx);11751176if (wcid && wcid->sta) {1177sta = container_of((void *)wcid, struct ieee80211_sta,1178drv_priv);1179mt76_wcid_add_poll(dev, wcid);1180}1181}11821183if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))1184mt76_connac2_tx_check_aggr(sta, txwi);11851186__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);1187out:1188t->skb = NULL;1189mt76_put_txwi(dev, t);1190}1191EXPORT_SYMBOL_GPL(mt76_connac2_txwi_free);11921193void mt76_connac2_tx_token_put(struct mt76_dev *dev)1194{1195struct mt76_txwi_cache *txwi;1196int id;11971198spin_lock_bh(&dev->token_lock);1199idr_for_each_entry(&dev->token, txwi, id) {1200mt76_connac2_txwi_free(dev, txwi, NULL, NULL);1201dev->token_count--;1202}1203spin_unlock_bh(&dev->token_lock);1204idr_destroy(&dev->token);1205}1206EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put);120712081209