Path: blob/main/sys/contrib/dev/mediatek/mt76/mt76_connac_mac.c
107740 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/* 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{299u8 nss = 0, mode = 0, band = NL80211_BAND_2GHZ;300int rateidx = 0, offset = 0, mcast_rate;301struct cfg80211_chan_def *chandef;302struct mt76_vif_link *mvif;303304if (!conf)305goto legacy;306307mvif = mt76_vif_conf_link(mphy->dev, conf->vif, conf);308chandef = mvif->ctx ? &mvif->ctx->def : &mphy->chandef;309band = chandef->chan->band;310311if (is_mt7921(mphy->dev)) {312rateidx = ffs(conf->basic_rates) - 1;313goto legacy;314}315316if (beacon) {317struct cfg80211_bitrate_mask *mask;318319mask = &conf->beacon_tx_rate;320321__bitrate_mask_check(he_mcs, HE_SU);322__bitrate_mask_check(vht_mcs, VHT);323__bitrate_mask_check(ht_mcs, HT);324325if (hweight32(mask->control[band].legacy) == 1) {326rateidx = ffs(mask->control[band].legacy) - 1;327goto legacy;328}329}330331mcast_rate = conf->mcast_rate[band];332if (mcast && mcast_rate > 0)333rateidx = mcast_rate - 1;334else335rateidx = ffs(conf->basic_rates) - 1;336337legacy:338if (band != NL80211_BAND_2GHZ)339offset = 4;340341/* pick the lowest rate for hidden nodes */342if (rateidx < 0)343rateidx = 0;344345rateidx += offset;346if (rateidx >= ARRAY_SIZE(mt76_rates))347rateidx = offset;348349rateidx = mt76_rates[rateidx].hw_value;350mode = rateidx >> 8;351rateidx &= GENMASK(7, 0);352out:353return FIELD_PREP(MT_TX_RATE_NSS, nss) |354FIELD_PREP(MT_TX_RATE_IDX, rateidx) |355FIELD_PREP(MT_TX_RATE_MODE, mode);356}357EXPORT_SYMBOL_GPL(mt76_connac2_mac_tx_rate_val);358359static void360mt76_connac2_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,361struct mt76_wcid *wcid)362{363u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;364u8 fc_type, fc_stype;365u16 ethertype;366bool wmm = false;367u32 val;368369if (wcid->sta) {370struct ieee80211_sta *sta;371372sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);373wmm = sta->wme;374}375376val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |377FIELD_PREP(MT_TXD1_TID, tid);378379ethertype = get_unaligned_be16(&skb->data[12]);380if (ethertype >= ETH_P_802_3_MIN)381val |= MT_TXD1_ETH_802_3;382383txwi[1] |= cpu_to_le32(val);384385fc_type = IEEE80211_FTYPE_DATA >> 2;386fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;387388val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |389FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);390391txwi[2] |= cpu_to_le32(val);392393val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |394FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);395396txwi[7] |= cpu_to_le32(val);397}398399static void400mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,401struct sk_buff *skb,402struct ieee80211_key_conf *key)403{404struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;405struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;406struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);407bool multicast = is_multicast_ether_addr(hdr->addr1);408u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;409__le16 fc = hdr->frame_control;410__le16 sc = hdr->seq_ctrl;411u8 fc_type, fc_stype;412u32 val;413414if (ieee80211_is_action(fc) &&415mgmt->u.action.category == WLAN_CATEGORY_BACK &&416mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {417u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);418419txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);420tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;421} else if (ieee80211_is_back_req(hdr->frame_control)) {422struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;423u16 control = le16_to_cpu(bar->control);424425tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);426}427428val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |429FIELD_PREP(MT_TXD1_HDR_INFO,430ieee80211_get_hdrlen_from_skb(skb) / 2) |431FIELD_PREP(MT_TXD1_TID, tid);432433txwi[1] |= cpu_to_le32(val);434435fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;436fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;437438val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |439FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |440FIELD_PREP(MT_TXD2_MULTICAST, multicast);441442if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&443key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {444val |= MT_TXD2_BIP;445txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);446}447448if (!ieee80211_is_data(fc) || multicast ||449info->flags & IEEE80211_TX_CTL_USE_MINRATE)450val |= MT_TXD2_FIX_RATE;451452if (ieee80211_has_morefrags(fc) && ieee80211_is_first_frag(sc))453val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_FIRST);454else if (ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc))455val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_MID);456else if (!ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc))457val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_LAST);458459txwi[2] |= cpu_to_le32(val);460461if (ieee80211_is_beacon(fc)) {462txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);463txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);464}465466if (info->flags & IEEE80211_TX_CTL_INJECTED) {467u16 seqno = le16_to_cpu(sc);468469if (ieee80211_is_back_req(hdr->frame_control)) {470struct ieee80211_bar *bar;471472bar = (struct ieee80211_bar *)skb->data;473seqno = le16_to_cpu(bar->start_seq_num);474}475476val = MT_TXD3_SN_VALID |477FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));478txwi[3] |= cpu_to_le32(val);479txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);480}481482if (mt76_is_mmio(dev)) {483val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |484FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);485txwi[7] |= cpu_to_le32(val);486} else {487val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |488FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);489txwi[8] |= cpu_to_le32(val);490}491}492493void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,494struct sk_buff *skb, struct mt76_wcid *wcid,495struct ieee80211_key_conf *key, int pid,496enum mt76_txq_id qid, u32 changed)497{498struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);499u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;500struct ieee80211_vif *vif = info->control.vif;501struct mt76_phy *mphy = &dev->phy;502u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0;503u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE;504bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;505bool beacon = !!(changed & (BSS_CHANGED_BEACON |506BSS_CHANGED_BEACON_ENABLED));507bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |508BSS_CHANGED_FILS_DISCOVERY));509bool amsdu_en = wcid->amsdu;510511if (vif) {512struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;513514omac_idx = mvif->omac_idx;515wmm_idx = mvif->wmm_idx;516band_idx = mvif->band_idx;517}518519if (phy_idx && dev->phys[MT_BAND1])520mphy = dev->phys[MT_BAND1];521522if (inband_disc) {523p_fmt = MT_TX_TYPE_FW;524q_idx = MT_LMAC_ALTX0;525} else if (beacon) {526p_fmt = MT_TX_TYPE_FW;527q_idx = MT_LMAC_BCN0;528} else if (qid >= MT_TXQ_PSD) {529p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;530q_idx = MT_LMAC_ALTX0;531} else {532p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;533q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +534mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));535536/* mt7915 WA only counts WED path */537if (is_mt7915(dev) && mtk_wed_device_active(&dev->mmio.wed))538wcid->stats.tx_packets++;539}540541val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |542FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |543FIELD_PREP(MT_TXD0_Q_IDX, q_idx);544txwi[0] = cpu_to_le32(val);545546val = MT_TXD1_LONG_FORMAT |547FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |548FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);549if (!is_mt7921(dev))550val |= MT_TXD1_VTA;551if (phy_idx || band_idx)552val |= MT_TXD1_TGID;553554txwi[1] = cpu_to_le32(val);555txwi[2] = 0;556557val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15);558if (!is_mt7921(dev))559val |= MT_TXD3_SW_POWER_MGMT;560if (key)561val |= MT_TXD3_PROTECT_FRAME;562if (info->flags & IEEE80211_TX_CTL_NO_ACK)563val |= MT_TXD3_NO_ACK;564565txwi[3] = cpu_to_le32(val);566txwi[4] = 0;567568val = FIELD_PREP(MT_TXD5_PID, pid);569if (pid >= MT_PACKET_ID_FIRST) {570val |= MT_TXD5_TX_STATUS_HOST;571amsdu_en = 0;572}573574txwi[5] = cpu_to_le32(val);575txwi[6] = 0;576txwi[7] = amsdu_en ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;577578if (is_8023)579mt76_connac2_mac_write_txwi_8023(txwi, skb, wcid);580else581mt76_connac2_mac_write_txwi_80211(dev, txwi, skb, key);582583if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {584/* Fixed rata is available just for 802.11 txd */585struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;586bool multicast = ieee80211_is_data(hdr->frame_control) &&587is_multicast_ether_addr(hdr->addr1);588u16 rate = mt76_connac2_mac_tx_rate_val(mphy,589vif ? &vif->bss_conf : NULL,590beacon, multicast);591u32 val = MT_TXD6_FIXED_BW;592593/* hardware won't add HTC for mgmt/ctrl frame */594txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);595596val |= FIELD_PREP(MT_TXD6_TX_RATE, rate);597txwi[6] |= cpu_to_le32(val);598txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);599600if (!is_mt7921(dev)) {601u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);602603if (!spe_idx)604spe_idx = 24 + phy_idx;605txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx));606}607608txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);609}610}611EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi);612613bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,614__le32 *txs_data)615{616struct mt76_sta_stats *stats = &wcid->stats;617struct ieee80211_supported_band *sband;618struct mt76_phy *mphy;619struct rate_info rate = {};620bool cck = false;621u32 txrate, txs, mode, stbc;622623txs = le32_to_cpu(txs_data[0]);624625/* PPDU based reporting */626if (mtk_wed_device_active(&dev->mmio.wed) &&627FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {628stats->tx_bytes +=629le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) -630le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE);631stats->tx_failed +=632le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);633stats->tx_retries +=634le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT);635636if (wcid->sta) {637struct ieee80211_sta *sta;638u8 tid;639640sta = container_of((void *)wcid, struct ieee80211_sta,641drv_priv);642tid = FIELD_GET(MT_TXS0_TID, txs);643644ieee80211_refresh_tx_agg_session_timer(sta, tid);645}646}647648txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);649650rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);651rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;652stbc = FIELD_GET(MT_TX_RATE_STBC, txrate);653654if (stbc && rate.nss > 1)655rate.nss >>= 1;656657if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))658stats->tx_nss[rate.nss - 1]++;659if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))660stats->tx_mcs[rate.mcs]++;661662mode = FIELD_GET(MT_TX_RATE_MODE, txrate);663switch (mode) {664case MT_PHY_TYPE_CCK:665cck = true;666fallthrough;667case MT_PHY_TYPE_OFDM:668mphy = &dev->phy;669if (wcid->phy_idx == MT_BAND1 && dev->phys[MT_BAND1])670mphy = dev->phys[MT_BAND1];671672if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)673sband = &mphy->sband_5g.sband;674else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)675sband = &mphy->sband_6g.sband;676else677sband = &mphy->sband_2g.sband;678679rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);680rate.legacy = sband->bitrates[rate.mcs].bitrate;681break;682case MT_PHY_TYPE_HT:683case MT_PHY_TYPE_HT_GF:684if (rate.mcs > 31)685return false;686687rate.flags = RATE_INFO_FLAGS_MCS;688if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)689rate.flags |= RATE_INFO_FLAGS_SHORT_GI;690break;691case MT_PHY_TYPE_VHT:692if (rate.mcs > 9)693return false;694695rate.flags = RATE_INFO_FLAGS_VHT_MCS;696break;697case MT_PHY_TYPE_HE_SU:698case MT_PHY_TYPE_HE_EXT_SU:699case MT_PHY_TYPE_HE_TB:700case MT_PHY_TYPE_HE_MU:701if (rate.mcs > 11)702return false;703704rate.he_gi = wcid->rate.he_gi;705rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);706rate.flags = RATE_INFO_FLAGS_HE_MCS;707break;708default:709return false;710}711712stats->tx_mode[mode]++;713714switch (FIELD_GET(MT_TXS0_BW, txs)) {715case IEEE80211_STA_RX_BW_160:716rate.bw = RATE_INFO_BW_160;717stats->tx_bw[3]++;718break;719case IEEE80211_STA_RX_BW_80:720rate.bw = RATE_INFO_BW_80;721stats->tx_bw[2]++;722break;723case IEEE80211_STA_RX_BW_40:724rate.bw = RATE_INFO_BW_40;725stats->tx_bw[1]++;726break;727default:728rate.bw = RATE_INFO_BW_20;729stats->tx_bw[0]++;730break;731}732wcid->rate = rate;733734return true;735}736EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_txs);737738bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,739int pid, __le32 *txs_data)740{741struct sk_buff_head list;742struct sk_buff *skb;743744if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) == MT_TXS_PPDU_FMT)745return false;746747mt76_tx_status_lock(dev, &list);748skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);749if (skb) {750struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);751752if (!(le32_to_cpu(txs_data[0]) & MT_TXS0_ACK_ERROR_MASK))753info->flags |= IEEE80211_TX_STAT_ACK;754755info->status.ampdu_len = 1;756info->status.ampdu_ack_len =757!!(info->flags & IEEE80211_TX_STAT_ACK);758info->status.rates[0].idx = -1;759760mt76_connac2_mac_fill_txs(dev, wcid, txs_data);761mt76_tx_status_skb_done(dev, skb, &list);762}763mt76_tx_status_unlock(dev, &list);764765return !!skb;766}767EXPORT_SYMBOL_GPL(mt76_connac2_mac_add_txs_skb);768769static void770mt76_connac2_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,771struct ieee80211_radiotap_he *he,772__le32 *rxv)773{774u32 ru_h, ru_l;775u8 ru, offs = 0;776777ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L);778ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H);779ru = (u8)(ru_l | ru_h << 4);780781status->bw = RATE_INFO_BW_HE_RU;782783switch (ru) {784case 0 ... 36:785status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;786offs = ru;787break;788case 37 ... 52:789status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;790offs = ru - 37;791break;792case 53 ... 60:793status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;794offs = ru - 53;795break;796case 61 ... 64:797status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;798offs = ru - 61;799break;800case 65 ... 66:801status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;802offs = ru - 65;803break;804case 67:805status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;806break;807case 68:808status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;809break;810}811812he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);813he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |814le16_encode_bits(offs,815IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);816}817818static void819mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb,820__le32 *rxv)821{822struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;823static struct ieee80211_radiotap_he_mu mu_known = {824.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |825HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |826HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |827HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),828.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),829};830struct ieee80211_radiotap_he_mu *he_mu;831832if (is_mt7921(dev)) {833mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN);834mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN);835}836837status->flag |= RX_FLAG_RADIOTAP_HE_MU;838839he_mu = skb_push(skb, sizeof(mu_known));840memcpy(he_mu, &mu_known, sizeof(mu_known));841842#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)843844he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);845if (status->he_dcm)846he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);847848he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |849MU_PREP(FLAGS2_SIG_B_SYMS_USERS,850le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));851852he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);853854if (status->bw >= RATE_INFO_BW_40) {855he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);856he_mu->ru_ch2[0] =857le32_get_bits(rxv[3], MT_CRXV_HE_RU1);858}859860if (status->bw >= RATE_INFO_BW_80) {861he_mu->ru_ch1[1] =862le32_get_bits(rxv[3], MT_CRXV_HE_RU2);863he_mu->ru_ch2[1] =864le32_get_bits(rxv[3], MT_CRXV_HE_RU3);865}866}867868void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,869struct sk_buff *skb,870__le32 *rxv, u32 mode)871{872struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;873static const struct ieee80211_radiotap_he known = {874.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |875HE_BITS(DATA1_DATA_DCM_KNOWN) |876HE_BITS(DATA1_STBC_KNOWN) |877HE_BITS(DATA1_CODING_KNOWN) |878HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |879HE_BITS(DATA1_DOPPLER_KNOWN) |880HE_BITS(DATA1_SPTL_REUSE_KNOWN) |881HE_BITS(DATA1_BSS_COLOR_KNOWN),882.data2 = HE_BITS(DATA2_GI_KNOWN) |883HE_BITS(DATA2_TXBF_KNOWN) |884HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |885HE_BITS(DATA2_TXOP_KNOWN),886};887u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;888struct ieee80211_radiotap_he *he;889890status->flag |= RX_FLAG_RADIOTAP_HE;891892he = skb_push(skb, sizeof(known));893memcpy(he, &known, sizeof(known));894895he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |896HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);897he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);898he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |899le16_encode_bits(ltf_size,900IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);901if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)902he->data5 |= HE_BITS(DATA5_TXBF);903he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |904HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);905906switch (mode) {907case MT_PHY_TYPE_HE_SU:908he->data1 |= HE_BITS(DATA1_FORMAT_SU) |909HE_BITS(DATA1_UL_DL_KNOWN) |910HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |911HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);912913he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |914HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);915break;916case MT_PHY_TYPE_HE_EXT_SU:917he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |918HE_BITS(DATA1_UL_DL_KNOWN) |919HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);920921he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);922break;923case MT_PHY_TYPE_HE_MU:924he->data1 |= HE_BITS(DATA1_FORMAT_MU) |925HE_BITS(DATA1_UL_DL_KNOWN);926927he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);928he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);929930mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv);931mt76_connac2_mac_decode_he_mu_radiotap(dev, skb, rxv);932break;933case MT_PHY_TYPE_HE_TB:934he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |935HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |936HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |937HE_BITS(DATA1_SPTL_REUSE4_KNOWN);938939he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |940HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |941HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |942HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);943944mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv);945break;946default:947break;948}949}950EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap);951952/* The HW does not translate the mac header to 802.3 for mesh point */953int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,954struct sk_buff *skb, u16 hdr_offset)955{956struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;957struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_offset);958__le32 *rxd = (__le32 *)skb->data;959struct ieee80211_sta *sta;960struct ieee80211_hdr hdr;961u16 frame_control;962963if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=964MT_RXD3_NORMAL_U2M)965return -EINVAL;966967if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))968return -EINVAL;969970sta = container_of((void *)status->wcid, struct ieee80211_sta, drv_priv);971972/* store the info from RXD and ethhdr to avoid being overridden */973frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL);974hdr.frame_control = cpu_to_le16(frame_control);975hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL));976hdr.duration_id = 0;977978ether_addr_copy(hdr.addr1, vif->addr);979ether_addr_copy(hdr.addr2, sta->addr);980switch (frame_control & (IEEE80211_FCTL_TODS |981IEEE80211_FCTL_FROMDS)) {982case 0:983ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);984break;985case IEEE80211_FCTL_FROMDS:986ether_addr_copy(hdr.addr3, eth_hdr->h_source);987break;988case IEEE80211_FCTL_TODS:989ether_addr_copy(hdr.addr3, eth_hdr->h_dest);990break;991case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:992ether_addr_copy(hdr.addr3, eth_hdr->h_dest);993ether_addr_copy(hdr.addr4, eth_hdr->h_source);994break;995default:996return -EINVAL;997}998999skb_pull(skb, hdr_offset + sizeof(struct ethhdr) - 2);1000if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||1001eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))1002ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);1003else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)1004ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);1005else1006skb_pull(skb, 2);10071008if (ieee80211_has_order(hdr.frame_control))1009memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9],1010IEEE80211_HT_CTL_LEN);1011if (ieee80211_is_data_qos(hdr.frame_control)) {1012__le16 qos_ctrl;10131014qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL));1015memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,1016IEEE80211_QOS_CTL_LEN);1017}10181019if (ieee80211_has_a4(hdr.frame_control))1020memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));1021else1022memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);10231024return 0;1025}1026EXPORT_SYMBOL_GPL(mt76_connac2_reverse_frag0_hdr_trans);10271028int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,1029struct mt76_rx_status *status,1030struct ieee80211_supported_band *sband,1031__le32 *rxv, u8 *mode)1032{1033u32 v0, v2;1034u8 stbc, gi, bw, dcm, nss;1035int i, idx;1036bool cck = false;10371038v0 = le32_to_cpu(rxv[0]);1039v2 = le32_to_cpu(rxv[2]);10401041idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0);1042nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;10431044if (!is_mt7915(dev)) {1045stbc = FIELD_GET(MT_PRXV_HT_STBC, v0);1046gi = FIELD_GET(MT_PRXV_HT_SGI, v0);1047*mode = FIELD_GET(MT_PRXV_TX_MODE, v0);1048if (is_mt7921(dev))1049dcm = !!(idx & MT_PRXV_TX_DCM);1050else1051dcm = FIELD_GET(MT_PRXV_DCM, v0);1052bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0);1053} else {1054stbc = FIELD_GET(MT_CRXV_HT_STBC, v2);1055gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2);1056*mode = FIELD_GET(MT_CRXV_TX_MODE, v2);1057dcm = !!(idx & GENMASK(3, 0) & MT_PRXV_TX_DCM);1058bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2);1059}10601061switch (*mode) {1062case MT_PHY_TYPE_CCK:1063cck = true;1064fallthrough;1065case MT_PHY_TYPE_OFDM:1066i = mt76_get_rate(dev, sband, i, cck);1067break;1068case MT_PHY_TYPE_HT_GF:1069case MT_PHY_TYPE_HT:1070status->encoding = RX_ENC_HT;1071if (gi)1072status->enc_flags |= RX_ENC_FLAG_SHORT_GI;1073if (i > 31)1074return -EINVAL;1075break;1076case MT_PHY_TYPE_VHT:1077status->nss = nss;1078status->encoding = RX_ENC_VHT;1079if (gi)1080status->enc_flags |= RX_ENC_FLAG_SHORT_GI;1081if (i > 11)1082return -EINVAL;1083break;1084case MT_PHY_TYPE_HE_MU:1085case MT_PHY_TYPE_HE_SU:1086case MT_PHY_TYPE_HE_EXT_SU:1087case MT_PHY_TYPE_HE_TB:1088status->nss = nss;1089status->encoding = RX_ENC_HE;1090i &= GENMASK(3, 0);10911092if (gi <= NL80211_RATE_INFO_HE_GI_3_2)1093status->he_gi = gi;10941095status->he_dcm = dcm;1096break;1097default:1098return -EINVAL;1099}1100status->rate_idx = i;11011102switch (bw) {1103case IEEE80211_STA_RX_BW_20:1104break;1105case IEEE80211_STA_RX_BW_40:1106if (*mode & MT_PHY_TYPE_HE_EXT_SU &&1107(idx & MT_PRXV_TX_ER_SU_106T)) {1108status->bw = RATE_INFO_BW_HE_RU;1109status->he_ru =1110NL80211_RATE_INFO_HE_RU_ALLOC_106;1111} else {1112status->bw = RATE_INFO_BW_40;1113}1114break;1115case IEEE80211_STA_RX_BW_80:1116status->bw = RATE_INFO_BW_80;1117break;1118case IEEE80211_STA_RX_BW_160:1119status->bw = RATE_INFO_BW_160;1120break;1121default:1122return -EINVAL;1123}11241125status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;1126if (*mode < MT_PHY_TYPE_HE_SU && gi)1127status->enc_flags |= RX_ENC_FLAG_SHORT_GI;11281129return 0;1130}1131EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_rx_rate);11321133void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)1134{1135struct mt76_wcid *wcid;1136u16 fc, tid;1137u32 val;11381139if (!sta ||1140!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))1141return;11421143tid = le32_get_bits(txwi[1], MT_TXD1_TID);1144if (tid >= 6) /* skip VO queue */1145return;11461147val = le32_to_cpu(txwi[2]);1148fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |1149FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;1150if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))1151return;11521153wcid = (struct mt76_wcid *)sta->drv_priv;1154if (!test_and_set_bit(tid, &wcid->ampdu_state))1155ieee80211_start_tx_ba_session(sta, tid, 0);1156}1157EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr);11581159void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,1160struct ieee80211_sta *sta,1161struct list_head *free_list)1162{1163struct mt76_wcid *wcid;1164__le32 *txwi;1165u16 wcid_idx;11661167mt76_connac_txp_skb_unmap(dev, t);1168if (!t->skb)1169goto out;11701171txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);1172if (sta) {1173wcid = (struct mt76_wcid *)sta->drv_priv;1174wcid_idx = wcid->idx;1175} else {1176wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);1177wcid = __mt76_wcid_ptr(dev, wcid_idx);11781179if (wcid && wcid->sta) {1180sta = container_of((void *)wcid, struct ieee80211_sta,1181drv_priv);1182mt76_wcid_add_poll(dev, wcid);1183}1184}11851186if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))1187mt76_connac2_tx_check_aggr(sta, txwi);11881189__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);1190out:1191t->skb = NULL;1192mt76_put_txwi(dev, t);1193}1194EXPORT_SYMBOL_GPL(mt76_connac2_txwi_free);11951196void mt76_connac2_tx_token_put(struct mt76_dev *dev)1197{1198struct mt76_txwi_cache *txwi;1199int id;12001201spin_lock_bh(&dev->token_lock);1202idr_for_each_entry(&dev->token, txwi, id) {1203mt76_connac2_txwi_free(dev, txwi, NULL, NULL);1204dev->token_count--;1205}1206spin_unlock_bh(&dev->token_lock);1207idr_destroy(&dev->token);1208}1209EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put);121012111212