Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7925/mac.c
48526 views
// SPDX-License-Identifier: ISC1/* Copyright (C) 2023 MediaTek Inc. */23#include <linux/devcoredump.h>4#include <linux/etherdevice.h>5#include <linux/timekeeping.h>6#include "mt7925.h"7#include "../dma.h"8#include "mac.h"9#include "mcu.h"1011bool mt7925_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask)12{13mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,14FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);1516return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,170, 5000);18}1920static void mt7925_mac_sta_poll(struct mt792x_dev *dev)21{22static const u8 ac_to_tid[] = {23[IEEE80211_AC_BE] = 0,24[IEEE80211_AC_BK] = 1,25[IEEE80211_AC_VI] = 4,26[IEEE80211_AC_VO] = 627};28struct ieee80211_sta *sta;29struct mt792x_sta *msta;30struct mt792x_link_sta *mlink;31u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];32LIST_HEAD(sta_poll_list);33struct rate_info *rate;34s8 rssi[4];35int i;3637spin_lock_bh(&dev->mt76.sta_poll_lock);38list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);39spin_unlock_bh(&dev->mt76.sta_poll_lock);4041while (true) {42bool clear = false;43u32 addr, val;44u16 idx;45u8 bw;4647if (list_empty(&sta_poll_list))48break;49mlink = list_first_entry(&sta_poll_list,50struct mt792x_link_sta, wcid.poll_list);51msta = mlink->sta;52spin_lock_bh(&dev->mt76.sta_poll_lock);53list_del_init(&mlink->wcid.poll_list);54spin_unlock_bh(&dev->mt76.sta_poll_lock);5556idx = mlink->wcid.idx;57addr = mt7925_mac_wtbl_lmac_addr(dev, idx, MT_WTBL_AC0_CTT_OFFSET);5859for (i = 0; i < IEEE80211_NUM_ACS; i++) {60u32 tx_last = mlink->airtime_ac[i];61u32 rx_last = mlink->airtime_ac[i + 4];6263mlink->airtime_ac[i] = mt76_rr(dev, addr);64mlink->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);6566tx_time[i] = mlink->airtime_ac[i] - tx_last;67rx_time[i] = mlink->airtime_ac[i + 4] - rx_last;6869if ((tx_last | rx_last) & BIT(30))70clear = true;7172addr += 8;73}7475if (clear) {76mt7925_mac_wtbl_update(dev, idx,77MT_WTBL_UPDATE_ADM_COUNT_CLEAR);78memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac));79}8081if (!mlink->wcid.sta)82continue;8384sta = container_of((void *)msta, struct ieee80211_sta,85drv_priv);86for (i = 0; i < IEEE80211_NUM_ACS; i++) {87u8 q = mt76_connac_lmac_mapping(i);88u32 tx_cur = tx_time[q];89u32 rx_cur = rx_time[q];90u8 tid = ac_to_tid[i];9192if (!tx_cur && !rx_cur)93continue;9495ieee80211_sta_register_airtime(sta, tid, tx_cur,96rx_cur);97}9899/* We don't support reading GI info from txs packets.100* For accurate tx status reporting and AQL improvement,101* we need to make sure that flags match so polling GI102* from per-sta counters directly.103*/104rate = &mlink->wcid.rate;105106switch (rate->bw) {107case RATE_INFO_BW_160:108bw = IEEE80211_STA_RX_BW_160;109break;110case RATE_INFO_BW_80:111bw = IEEE80211_STA_RX_BW_80;112break;113case RATE_INFO_BW_40:114bw = IEEE80211_STA_RX_BW_40;115break;116default:117bw = IEEE80211_STA_RX_BW_20;118break;119}120121addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 6);122val = mt76_rr(dev, addr);123if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {124addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 5);125val = mt76_rr(dev, addr);126rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);127} else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {128u8 offs = MT_WTBL_TXRX_RATE_G2_HE + 2 * bw;129130rate->he_gi = (val & (0x3 << offs)) >> offs;131} else if (rate->flags &132(RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {133if (val & BIT(MT_WTBL_TXRX_RATE_G2 + bw))134rate->flags |= RATE_INFO_FLAGS_SHORT_GI;135else136rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;137}138139/* get signal strength of resp frames (CTS/BA/ACK) */140addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 34);141val = mt76_rr(dev, addr);142143rssi[0] = to_rssi(GENMASK(7, 0), val);144rssi[1] = to_rssi(GENMASK(15, 8), val);145rssi[2] = to_rssi(GENMASK(23, 16), val);146rssi[3] = to_rssi(GENMASK(31, 14), val);147148mlink->ack_signal =149mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);150151ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal);152}153}154155void mt7925_mac_set_fixed_rate_table(struct mt792x_dev *dev,156u8 tbl_idx, u16 rate_idx)157{158u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;159160mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);161/* use wtbl spe idx */162mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);163mt76_wr(dev, MT_WTBL_ITCR, ctrl);164}165166/* The HW does not translate the mac header to 802.3 for mesh point */167static int mt7925_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)168{169struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;170struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);171struct mt792x_sta *msta = (struct mt792x_sta *)status->wcid;172__le32 *rxd = (__le32 *)skb->data;173struct ieee80211_sta *sta;174struct ieee80211_vif *vif;175struct ieee80211_hdr hdr;176u16 frame_control;177178if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=179MT_RXD3_NORMAL_U2M)180return -EINVAL;181182if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))183return -EINVAL;184185if (!msta || !msta->vif)186return -EINVAL;187188sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);189vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);190191/* store the info from RXD and ethhdr to avoid being overridden */192frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);193hdr.frame_control = cpu_to_le16(frame_control);194hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL));195hdr.duration_id = 0;196197ether_addr_copy(hdr.addr1, vif->addr);198ether_addr_copy(hdr.addr2, sta->addr);199switch (frame_control & (IEEE80211_FCTL_TODS |200IEEE80211_FCTL_FROMDS)) {201case 0:202ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);203break;204case IEEE80211_FCTL_FROMDS:205ether_addr_copy(hdr.addr3, eth_hdr->h_source);206break;207case IEEE80211_FCTL_TODS:208ether_addr_copy(hdr.addr3, eth_hdr->h_dest);209break;210case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:211ether_addr_copy(hdr.addr3, eth_hdr->h_dest);212ether_addr_copy(hdr.addr4, eth_hdr->h_source);213break;214default:215break;216}217218skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);219if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||220eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))221ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);222else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)223ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);224else225skb_pull(skb, 2);226227if (ieee80211_has_order(hdr.frame_control))228memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11],229IEEE80211_HT_CTL_LEN);230if (ieee80211_is_data_qos(hdr.frame_control)) {231__le16 qos_ctrl;232233qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL));234memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,235IEEE80211_QOS_CTL_LEN);236}237238if (ieee80211_has_a4(hdr.frame_control))239memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));240else241memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);242243return 0;244}245246static int247mt7925_mac_fill_rx_rate(struct mt792x_dev *dev,248struct mt76_rx_status *status,249struct ieee80211_supported_band *sband,250__le32 *rxv, u8 *mode)251{252u32 v0, v2;253u8 stbc, gi, bw, dcm, nss;254int i, idx;255bool cck = false;256257v0 = le32_to_cpu(rxv[0]);258v2 = le32_to_cpu(rxv[2]);259260idx = FIELD_GET(MT_PRXV_TX_RATE, v0);261i = idx;262nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;263264stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);265gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);266*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);267dcm = FIELD_GET(MT_PRXV_DCM, v2);268bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);269270switch (*mode) {271case MT_PHY_TYPE_CCK:272cck = true;273fallthrough;274case MT_PHY_TYPE_OFDM:275i = mt76_get_rate(&dev->mt76, sband, i, cck);276break;277case MT_PHY_TYPE_HT_GF:278case MT_PHY_TYPE_HT:279status->encoding = RX_ENC_HT;280if (gi)281status->enc_flags |= RX_ENC_FLAG_SHORT_GI;282if (i > 31)283return -EINVAL;284break;285case MT_PHY_TYPE_VHT:286status->nss = nss;287status->encoding = RX_ENC_VHT;288if (gi)289status->enc_flags |= RX_ENC_FLAG_SHORT_GI;290if (i > 11)291return -EINVAL;292break;293case MT_PHY_TYPE_HE_MU:294case MT_PHY_TYPE_HE_SU:295case MT_PHY_TYPE_HE_EXT_SU:296case MT_PHY_TYPE_HE_TB:297status->nss = nss;298status->encoding = RX_ENC_HE;299i &= GENMASK(3, 0);300301if (gi <= NL80211_RATE_INFO_HE_GI_3_2)302status->he_gi = gi;303304status->he_dcm = dcm;305break;306case MT_PHY_TYPE_EHT_SU:307case MT_PHY_TYPE_EHT_TRIG:308case MT_PHY_TYPE_EHT_MU:309status->nss = nss;310status->encoding = RX_ENC_EHT;311i &= GENMASK(3, 0);312313if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)314status->eht.gi = gi;315break;316default:317return -EINVAL;318}319status->rate_idx = i;320321switch (bw) {322case IEEE80211_STA_RX_BW_20:323break;324case IEEE80211_STA_RX_BW_40:325if (*mode & MT_PHY_TYPE_HE_EXT_SU &&326(idx & MT_PRXV_TX_ER_SU_106T)) {327status->bw = RATE_INFO_BW_HE_RU;328status->he_ru =329NL80211_RATE_INFO_HE_RU_ALLOC_106;330} else {331status->bw = RATE_INFO_BW_40;332}333break;334case IEEE80211_STA_RX_BW_80:335status->bw = RATE_INFO_BW_80;336break;337case IEEE80211_STA_RX_BW_160:338status->bw = RATE_INFO_BW_160;339break;340default:341return -EINVAL;342}343344status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;345if (*mode < MT_PHY_TYPE_HE_SU && gi)346status->enc_flags |= RX_ENC_FLAG_SHORT_GI;347348return 0;349}350351static int352mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)353{354u32 csum_mask = MT_RXD3_NORMAL_IP_SUM | MT_RXD3_NORMAL_UDP_TCP_SUM;355struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;356bool hdr_trans, unicast, insert_ccmp_hdr = false;357u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info;358u16 hdr_gap;359__le32 *rxv = NULL, *rxd = (__le32 *)skb->data;360struct mt76_phy *mphy = &dev->mt76.phy;361struct mt792x_phy *phy = &dev->phy;362struct ieee80211_supported_band *sband;363u32 csum_status = *(u32 *)skb->cb;364u32 rxd1 = le32_to_cpu(rxd[1]);365u32 rxd2 = le32_to_cpu(rxd[2]);366u32 rxd3 = le32_to_cpu(rxd[3]);367u32 rxd4 = le32_to_cpu(rxd[4]);368struct mt792x_link_sta *mlink;369u8 mode = 0; /* , band_idx; */370u16 seq_ctrl = 0;371__le16 fc = 0;372int idx;373374memset(status, 0, sizeof(*status));375376if (!test_bit(MT76_STATE_RUNNING, &mphy->state))377return -EINVAL;378379if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)380return -EINVAL;381382hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;383if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))384return -EINVAL;385386/* ICV error or CCMP/BIP/WPI MIC error */387if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)388status->flag |= RX_FLAG_ONLY_MONITOR;389390chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);391unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;392idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);393status->wcid = mt792x_rx_get_wcid(dev, idx, unicast);394395if (status->wcid) {396mlink = container_of(status->wcid, struct mt792x_link_sta, wcid);397mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);398}399400mt792x_get_status_freq_info(status, chfreq);401402switch (status->band) {403case NL80211_BAND_5GHZ:404sband = &mphy->sband_5g.sband;405break;406case NL80211_BAND_6GHZ:407sband = &mphy->sband_6g.sband;408break;409default:410sband = &mphy->sband_2g.sband;411break;412}413414if (!sband->channels)415return -EINVAL;416417if (mt76_is_mmio(&dev->mt76) && (rxd3 & csum_mask) == csum_mask &&418!(csum_status & (BIT(0) | BIT(2) | BIT(3))))419skb->ip_summed = CHECKSUM_UNNECESSARY;420421if (rxd3 & MT_RXD3_NORMAL_FCS_ERR)422status->flag |= RX_FLAG_FAILED_FCS_CRC;423424if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)425status->flag |= RX_FLAG_MMIC_ERROR;426427if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&428!(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {429status->flag |= RX_FLAG_DECRYPTED;430status->flag |= RX_FLAG_IV_STRIPPED;431status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;432}433434remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);435436if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)437return -EINVAL;438439rxd += 8;440if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {441u32 v0 = le32_to_cpu(rxd[0]);442u32 v2 = le32_to_cpu(rxd[2]);443444/* TODO: need to map rxd address */445fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0));446seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);447qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);448449rxd += 4;450if ((u8 *)rxd - skb->data >= skb->len)451return -EINVAL;452}453454if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {455u8 *data = (u8 *)rxd;456457if (status->flag & RX_FLAG_DECRYPTED) {458switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {459case MT_CIPHER_AES_CCMP:460case MT_CIPHER_CCMP_CCX:461case MT_CIPHER_CCMP_256:462insert_ccmp_hdr =463FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);464fallthrough;465case MT_CIPHER_TKIP:466case MT_CIPHER_TKIP_NO_MIC:467case MT_CIPHER_GCMP:468case MT_CIPHER_GCMP_256:469status->iv[0] = data[5];470status->iv[1] = data[4];471status->iv[2] = data[3];472status->iv[3] = data[2];473status->iv[4] = data[1];474status->iv[5] = data[0];475break;476default:477break;478}479}480rxd += 4;481if ((u8 *)rxd - skb->data >= skb->len)482return -EINVAL;483}484485if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {486status->timestamp = le32_to_cpu(rxd[0]);487status->flag |= RX_FLAG_MACTIME_START;488489if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {490status->flag |= RX_FLAG_AMPDU_DETAILS;491492/* all subframes of an A-MPDU have the same timestamp */493if (phy->rx_ampdu_ts != status->timestamp) {494if (!++phy->ampdu_ref)495phy->ampdu_ref++;496}497phy->rx_ampdu_ts = status->timestamp;498499status->ampdu_ref = phy->ampdu_ref;500}501502rxd += 4;503if ((u8 *)rxd - skb->data >= skb->len)504return -EINVAL;505}506507/* RXD Group 3 - P-RXV */508if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {509u32 v3;510int ret;511512rxv = rxd;513rxd += 4;514if ((u8 *)rxd - skb->data >= skb->len)515return -EINVAL;516517v3 = le32_to_cpu(rxv[3]);518519status->chains = mphy->antenna_mask;520status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3);521status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3);522status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3);523status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3);524525/* RXD Group 5 - C-RXV */526if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {527rxd += 24;528if ((u8 *)rxd - skb->data >= skb->len)529return -EINVAL;530}531532ret = mt7925_mac_fill_rx_rate(dev, status, sband, rxv, &mode);533if (ret < 0)534return ret;535}536537amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);538status->amsdu = !!amsdu_info;539if (status->amsdu) {540status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;541status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;542}543544hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;545if (hdr_trans && ieee80211_has_morefrags(fc)) {546if (mt7925_reverse_frag0_hdr_trans(skb, hdr_gap))547return -EINVAL;548hdr_trans = false;549} else {550int pad_start = 0;551552skb_pull(skb, hdr_gap);553if (!hdr_trans && status->amsdu) {554pad_start = ieee80211_get_hdrlen_from_skb(skb);555} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {556/* When header translation failure is indicated,557* the hardware will insert an extra 2-byte field558* containing the data length after the protocol559* type field.560*/561pad_start = 12;562if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)563pad_start += 4;564else565pad_start = 0;566}567568if (pad_start) {569memmove(skb->data + 2, skb->data, pad_start);570skb_pull(skb, 2);571}572}573574if (!hdr_trans) {575struct ieee80211_hdr *hdr;576577if (insert_ccmp_hdr) {578u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);579580mt76_insert_ccmp_hdr(skb, key_id);581}582583hdr = mt76_skb_get_hdr(skb);584fc = hdr->frame_control;585if (ieee80211_is_data_qos(fc)) {586seq_ctrl = le16_to_cpu(hdr->seq_ctrl);587qos_ctl = *ieee80211_get_qos_ctl(hdr);588}589skb_set_mac_header(skb, (unsigned char *)hdr - skb->data);590} else {591status->flag |= RX_FLAG_8023;592}593594mt792x_mac_assoc_rssi(dev, skb);595596if (rxv && !(status->flag & RX_FLAG_8023)) {597switch (status->encoding) {598case RX_ENC_EHT:599mt76_connac3_mac_decode_eht_radiotap(skb, rxv, mode);600break;601case RX_ENC_HE:602mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);603break;604default:605break;606}607}608609if (!status->wcid || !ieee80211_is_data_qos(fc))610return 0;611612status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);613status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);614status->qos_ctl = qos_ctl;615616return 0;617}618619static void620mt7925_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,621struct mt76_wcid *wcid)622{623u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;624u8 fc_type, fc_stype;625u16 ethertype;626bool wmm = false;627u32 val;628629if (wcid->sta) {630struct ieee80211_sta *sta;631632sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);633wmm = sta->wme;634}635636val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |637FIELD_PREP(MT_TXD1_TID, tid);638639ethertype = get_unaligned_be16(&skb->data[12]);640if (ethertype >= ETH_P_802_3_MIN)641val |= MT_TXD1_ETH_802_3;642643txwi[1] |= cpu_to_le32(val);644645fc_type = IEEE80211_FTYPE_DATA >> 2;646fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;647648val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |649FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);650651txwi[2] |= cpu_to_le32(val);652}653654static void655mt7925_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,656struct sk_buff *skb,657struct ieee80211_key_conf *key)658{659struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;660struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;661struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);662bool multicast = is_multicast_ether_addr(hdr->addr1);663u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;664__le16 fc = hdr->frame_control;665u8 fc_type, fc_stype;666u32 val;667668if (ieee80211_is_action(fc) &&669mgmt->u.action.category == WLAN_CATEGORY_BACK &&670mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)671tid = MT_TX_ADDBA;672else if (ieee80211_is_mgmt(hdr->frame_control))673tid = MT_TX_NORMAL;674675val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |676FIELD_PREP(MT_TXD1_HDR_INFO,677ieee80211_get_hdrlen_from_skb(skb) / 2) |678FIELD_PREP(MT_TXD1_TID, tid);679680if (!ieee80211_is_data(fc) || multicast ||681info->flags & IEEE80211_TX_CTL_USE_MINRATE)682val |= MT_TXD1_FIXED_RATE;683684if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&685key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {686val |= MT_TXD1_BIP;687txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);688}689690txwi[1] |= cpu_to_le32(val);691692fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;693fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;694695val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |696FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);697698txwi[2] |= cpu_to_le32(val);699700txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));701if (ieee80211_is_beacon(fc))702txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);703704if (info->flags & IEEE80211_TX_CTL_INJECTED) {705u16 seqno = le16_to_cpu(hdr->seq_ctrl);706707if (ieee80211_is_back_req(hdr->frame_control)) {708struct ieee80211_bar *bar;709710bar = (struct ieee80211_bar *)skb->data;711seqno = le16_to_cpu(bar->start_seq_num);712}713714val = MT_TXD3_SN_VALID |715FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));716txwi[3] |= cpu_to_le32(val);717txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);718}719}720721void722mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,723struct sk_buff *skb, struct mt76_wcid *wcid,724struct ieee80211_key_conf *key, int pid,725enum mt76_txq_id qid, u32 changed)726{727struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);728struct ieee80211_vif *vif = info->control.vif;729u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0;730u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE;731bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;732struct mt76_vif_link *mvif;733bool beacon = !!(changed & (BSS_CHANGED_BEACON |734BSS_CHANGED_BEACON_ENABLED));735bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |736BSS_CHANGED_FILS_DISCOVERY));737struct mt792x_bss_conf *mconf;738739mconf = vif ? mt792x_vif_to_link((struct mt792x_vif *)vif->drv_priv,740wcid->link_id) : NULL;741mvif = mconf ? (struct mt76_vif_link *)&mconf->mt76 : NULL;742743if (mvif) {744omac_idx = mvif->omac_idx;745wmm_idx = mvif->wmm_idx;746band_idx = mvif->band_idx;747}748749if (inband_disc) {750p_fmt = MT_TX_TYPE_FW;751q_idx = MT_LMAC_ALTX0;752} else if (beacon) {753p_fmt = MT_TX_TYPE_FW;754q_idx = MT_LMAC_BCN0;755} else if (qid >= MT_TXQ_PSD) {756p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;757q_idx = MT_LMAC_ALTX0;758} else {759p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;760q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +761mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));762763/* counting non-offloading skbs */764wcid->stats.tx_bytes += skb->len;765wcid->stats.tx_packets++;766}767768val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |769FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |770FIELD_PREP(MT_TXD0_Q_IDX, q_idx);771txwi[0] = cpu_to_le32(val);772773val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |774FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);775776if (band_idx)777val |= FIELD_PREP(MT_TXD1_TGID, band_idx);778779txwi[1] = cpu_to_le32(val);780txwi[2] = 0;781782val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15);783784if (key)785val |= MT_TXD3_PROTECT_FRAME;786if (info->flags & IEEE80211_TX_CTL_NO_ACK)787val |= MT_TXD3_NO_ACK;788if (wcid->amsdu)789val |= MT_TXD3_HW_AMSDU;790791txwi[3] = cpu_to_le32(val);792txwi[4] = 0;793794val = FIELD_PREP(MT_TXD5_PID, pid);795if (pid >= MT_PACKET_ID_FIRST) {796val |= MT_TXD5_TX_STATUS_HOST;797txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);798txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);799}800801txwi[5] = cpu_to_le32(val);802803val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1);804if (!ieee80211_vif_is_mld(vif) ||805(q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))806val |= MT_TXD6_DIS_MAT;807txwi[6] = cpu_to_le32(val);808txwi[7] = 0;809810if (is_8023)811mt7925_mac_write_txwi_8023(txwi, skb, wcid);812else813mt7925_mac_write_txwi_80211(dev, txwi, skb, key);814815if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {816struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;817bool mcast = ieee80211_is_data(hdr->frame_control) &&818is_multicast_ether_addr(hdr->addr1);819u8 idx = MT792x_BASIC_RATES_TBL;820821if (mvif) {822if (mcast && mvif->mcast_rates_idx)823idx = mvif->mcast_rates_idx;824else if (beacon && mvif->beacon_rates_idx)825idx = mvif->beacon_rates_idx;826else827idx = mvif->basic_rates_idx;828}829830txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));831txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);832}833}834EXPORT_SYMBOL_GPL(mt7925_mac_write_txwi);835836static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,837struct mt76_wcid *wcid)838{839struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);840struct ieee80211_link_sta *link_sta;841struct mt792x_link_sta *mlink;842struct mt792x_sta *msta;843bool is_8023;844u16 fc, tid;845846link_sta = rcu_dereference(sta->link[wcid->link_id]);847if (!link_sta)848return;849850if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))851return;852853tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;854is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;855856if (is_8023) {857fc = IEEE80211_FTYPE_DATA |858(sta->wme ? IEEE80211_STYPE_QOS_DATA :859IEEE80211_STYPE_DATA);860} else {861/* No need to get precise TID for Action/Management Frame,862* since it will not meet the following Frame Control863* condition anyway.864*/865866struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;867868fc = le16_to_cpu(hdr->frame_control) &869(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);870}871872if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))873return;874875msta = (struct mt792x_sta *)sta->drv_priv;876877if (sta->mlo && msta->deflink_id != IEEE80211_LINK_UNSPECIFIED)878mlink = rcu_dereference(msta->link[msta->deflink_id]);879else880mlink = &msta->deflink;881882if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state))883ieee80211_start_tx_ba_session(sta, tid, 0);884}885886static bool887mt7925_mac_add_txs_skb(struct mt792x_dev *dev, struct mt76_wcid *wcid,888int pid, __le32 *txs_data)889{890struct mt76_sta_stats *stats = &wcid->stats;891struct ieee80211_supported_band *sband;892struct mt76_dev *mdev = &dev->mt76;893struct mt76_phy *mphy;894struct ieee80211_tx_info *info;895struct sk_buff_head list;896struct rate_info rate = {};897struct sk_buff *skb;898bool cck = false;899u32 txrate, txs, mode, stbc;900901mt76_tx_status_lock(mdev, &list);902skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);903if (!skb)904goto out_no_skb;905906txs = le32_to_cpu(txs_data[0]);907908info = IEEE80211_SKB_CB(skb);909if (!(txs & MT_TXS0_ACK_ERROR_MASK))910info->flags |= IEEE80211_TX_STAT_ACK;911912info->status.ampdu_len = 1;913info->status.ampdu_ack_len = !!(info->flags &914IEEE80211_TX_STAT_ACK);915916info->status.rates[0].idx = -1;917918txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);919920rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);921rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;922stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);923924if (stbc && rate.nss > 1)925rate.nss >>= 1;926927if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))928stats->tx_nss[rate.nss - 1]++;929if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))930stats->tx_mcs[rate.mcs]++;931932mode = FIELD_GET(MT_TX_RATE_MODE, txrate);933switch (mode) {934case MT_PHY_TYPE_CCK:935cck = true;936fallthrough;937case MT_PHY_TYPE_OFDM:938mphy = mt76_dev_phy(mdev, wcid->phy_idx);939940if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)941sband = &mphy->sband_5g.sband;942else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)943sband = &mphy->sband_6g.sband;944else945sband = &mphy->sband_2g.sband;946947rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);948rate.legacy = sband->bitrates[rate.mcs].bitrate;949break;950case MT_PHY_TYPE_HT:951case MT_PHY_TYPE_HT_GF:952if (rate.mcs > 31)953goto out;954955rate.flags = RATE_INFO_FLAGS_MCS;956if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)957rate.flags |= RATE_INFO_FLAGS_SHORT_GI;958break;959case MT_PHY_TYPE_VHT:960if (rate.mcs > 9)961goto out;962963rate.flags = RATE_INFO_FLAGS_VHT_MCS;964break;965case MT_PHY_TYPE_HE_SU:966case MT_PHY_TYPE_HE_EXT_SU:967case MT_PHY_TYPE_HE_TB:968case MT_PHY_TYPE_HE_MU:969if (rate.mcs > 11)970goto out;971972rate.he_gi = wcid->rate.he_gi;973rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);974rate.flags = RATE_INFO_FLAGS_HE_MCS;975break;976case MT_PHY_TYPE_EHT_SU:977case MT_PHY_TYPE_EHT_TRIG:978case MT_PHY_TYPE_EHT_MU:979if (rate.mcs > 13)980goto out;981982rate.eht_gi = wcid->rate.eht_gi;983rate.flags = RATE_INFO_FLAGS_EHT_MCS;984break;985default:986goto out;987}988989stats->tx_mode[mode]++;990991switch (FIELD_GET(MT_TXS0_BW, txs)) {992case IEEE80211_STA_RX_BW_160:993rate.bw = RATE_INFO_BW_160;994stats->tx_bw[3]++;995break;996case IEEE80211_STA_RX_BW_80:997rate.bw = RATE_INFO_BW_80;998stats->tx_bw[2]++;999break;1000case IEEE80211_STA_RX_BW_40:1001rate.bw = RATE_INFO_BW_40;1002stats->tx_bw[1]++;1003break;1004default:1005rate.bw = RATE_INFO_BW_20;1006stats->tx_bw[0]++;1007break;1008}1009wcid->rate = rate;10101011out:1012mt76_tx_status_skb_done(mdev, skb, &list);10131014out_no_skb:1015mt76_tx_status_unlock(mdev, &list);10161017return !!skb;1018}10191020void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data)1021{1022struct mt792x_link_sta *mlink = NULL;1023struct mt76_wcid *wcid;1024__le32 *txs_data = data;1025u16 wcidx;1026u8 pid;10271028if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)1029return;10301031wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);1032pid = le32_get_bits(txs_data[3], MT_TXS3_PID);10331034if (pid < MT_PACKET_ID_FIRST)1035return;10361037if (wcidx >= MT792x_WTBL_SIZE)1038return;10391040rcu_read_lock();10411042wcid = mt76_wcid_ptr(dev, wcidx);1043if (!wcid)1044goto out;10451046mlink = container_of(wcid, struct mt792x_link_sta, wcid);10471048mt7925_mac_add_txs_skb(dev, wcid, pid, txs_data);1049if (!wcid->sta)1050goto out;10511052mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);10531054out:1055rcu_read_unlock();1056}10571058void mt7925_txwi_free(struct mt792x_dev *dev, struct mt76_txwi_cache *t,1059struct ieee80211_sta *sta, struct mt76_wcid *wcid,1060struct list_head *free_list)1061{1062struct mt76_dev *mdev = &dev->mt76;1063__le32 *txwi;1064u16 wcid_idx;10651066mt76_connac_txp_skb_unmap(mdev, t);1067if (!t->skb)1068goto out;10691070txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);1071if (sta) {1072if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))1073mt7925_tx_check_aggr(sta, t->skb, wcid);10741075wcid_idx = wcid->idx;1076} else {1077wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);1078}10791080__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);1081out:1082t->skb = NULL;1083mt76_put_txwi(mdev, t);1084}1085EXPORT_SYMBOL_GPL(mt7925_txwi_free);10861087static void1088mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len)1089{1090__le32 *tx_free = (__le32 *)data, *cur_info;1091struct mt76_dev *mdev = &dev->mt76;1092struct mt76_txwi_cache *txwi;1093struct ieee80211_sta *sta = NULL;1094struct mt76_wcid *wcid = NULL;1095LIST_HEAD(free_list);1096struct sk_buff *skb, *tmp;1097#if defined(__linux__)1098void *end = data + len;1099#elif defined(__FreeBSD__)1100void *end = (u8 *)data + len;1101#endif1102bool wake = false;1103u16 total, count = 0;11041105/* clean DMA queues and unmap buffers first */1106mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);1107mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);11081109if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4))1110return;11111112total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);1113for (cur_info = &tx_free[2]; count < total; cur_info++) {1114u32 msdu, info;1115u8 i;11161117if (WARN_ON_ONCE((void *)cur_info >= end))1118return;1119/* 1'b1: new wcid pair.1120* 1'b0: msdu_id with the same 'wcid pair' as above.1121*/1122info = le32_to_cpu(*cur_info);1123if (info & MT_TXFREE_INFO_PAIR) {1124struct mt792x_link_sta *mlink;1125u16 idx;11261127idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);1128wcid = mt76_wcid_ptr(dev, idx);1129sta = wcid_to_sta(wcid);1130if (!sta)1131continue;11321133mlink = container_of(wcid, struct mt792x_link_sta, wcid);1134mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);1135continue;1136}11371138if (info & MT_TXFREE_INFO_HEADER) {1139if (wcid) {1140wcid->stats.tx_retries +=1141FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1;1142wcid->stats.tx_failed +=1143!!FIELD_GET(MT_TXFREE_INFO_STAT, info);1144}1145continue;1146}11471148for (i = 0; i < 2; i++) {1149msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID;1150if (msdu == MT_TXFREE_INFO_MSDU_ID)1151continue;11521153count++;1154txwi = mt76_token_release(mdev, msdu, &wake);1155if (!txwi)1156continue;11571158mt7925_txwi_free(dev, txwi, sta, wcid, &free_list);1159}1160}11611162mt7925_mac_sta_poll(dev);11631164if (wake)1165mt76_set_tx_blocked(&dev->mt76, false);11661167mt76_worker_schedule(&dev->mt76.tx_worker);11681169list_for_each_entry_safe(skb, tmp, &free_list, list) {1170skb_list_del_init(skb);1171napi_consume_skb(skb, 1);1172}1173}11741175bool mt7925_rx_check(struct mt76_dev *mdev, void *data, int len)1176{1177struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);1178__le32 *rxd = (__le32 *)data;1179__le32 *end = (__le32 *)&rxd[len / 4];1180enum rx_pkt_type type;11811182type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);1183if (type != PKT_TYPE_NORMAL) {1184u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);11851186if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==1187MT_RXD0_SW_PKT_TYPE_FRAME))1188return true;1189}11901191switch (type) {1192case PKT_TYPE_TXRX_NOTIFY:1193/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */1194mt7925_mac_tx_free(dev, data, len); /* mmio */1195return false;1196case PKT_TYPE_TXS:1197for (rxd += 4; rxd + 12 <= end; rxd += 12)1198mt7925_mac_add_txs(dev, rxd);1199return false;1200default:1201return true;1202}1203}1204EXPORT_SYMBOL_GPL(mt7925_rx_check);12051206void mt7925_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,1207struct sk_buff *skb, u32 *info)1208{1209struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);1210__le32 *rxd = (__le32 *)skb->data;1211__le32 *end = (__le32 *)&skb->data[skb->len];1212enum rx_pkt_type type;1213u16 flag;12141215type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);1216flag = le32_get_bits(rxd[0], MT_RXD0_PKT_FLAG);1217if (type != PKT_TYPE_NORMAL) {1218u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);12191220if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==1221MT_RXD0_SW_PKT_TYPE_FRAME))1222type = PKT_TYPE_NORMAL;1223}12241225if (type == PKT_TYPE_RX_EVENT && flag == 0x1)1226type = PKT_TYPE_NORMAL_MCU;12271228switch (type) {1229case PKT_TYPE_TXRX_NOTIFY:1230/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */1231mt7925_mac_tx_free(dev, skb->data, skb->len);1232napi_consume_skb(skb, 1);1233break;1234case PKT_TYPE_RX_EVENT:1235mt7925_mcu_rx_event(dev, skb);1236break;1237case PKT_TYPE_TXS:1238for (rxd += 2; rxd + 8 <= end; rxd += 8)1239mt7925_mac_add_txs(dev, rxd);1240dev_kfree_skb(skb);1241break;1242case PKT_TYPE_NORMAL_MCU:1243case PKT_TYPE_NORMAL:1244if (!mt7925_mac_fill_rx(dev, skb)) {1245mt76_rx(&dev->mt76, q, skb);1246return;1247}1248fallthrough;1249default:1250dev_kfree_skb(skb);1251break;1252}1253}1254EXPORT_SYMBOL_GPL(mt7925_queue_rx_skb);12551256static void1257mt7925_vif_connect_iter(void *priv, u8 *mac,1258struct ieee80211_vif *vif)1259{1260struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1261unsigned long valid = ieee80211_vif_is_mld(vif) ?1262mvif->valid_links : BIT(0);1263struct mt792x_dev *dev = mvif->phy->dev;1264struct ieee80211_hw *hw = mt76_hw(dev);1265struct ieee80211_bss_conf *bss_conf;1266struct mt792x_bss_conf *mconf;1267int i;12681269if (vif->type == NL80211_IFTYPE_STATION)1270ieee80211_disconnect(vif, true);12711272for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {1273bss_conf = mt792x_vif_to_bss_conf(vif, i);1274mconf = mt792x_vif_to_link(mvif, i);12751276mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76,1277&mvif->sta.deflink.wcid, true);1278mt7925_mcu_set_tx(dev, bss_conf);1279}12801281if (vif->type == NL80211_IFTYPE_AP) {1282mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid,1283true, NULL);1284mt7925_mcu_sta_update(dev, NULL, vif, true,1285MT76_STA_INFO_STATE_NONE);1286mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true);1287}1288}12891290/* system error recovery */1291void mt7925_mac_reset_work(struct work_struct *work)1292{1293struct mt792x_dev *dev = container_of(work, struct mt792x_dev,1294reset_work);1295struct ieee80211_hw *hw = mt76_hw(dev);1296struct mt76_connac_pm *pm = &dev->pm;1297int i, ret;12981299dev_dbg(dev->mt76.dev, "chip reset\n");1300dev->hw_full_reset = true;1301ieee80211_stop_queues(hw);13021303cancel_delayed_work_sync(&dev->mphy.mac_work);1304cancel_delayed_work_sync(&pm->ps_work);1305cancel_work_sync(&pm->wake_work);1306dev->sar_inited = false;13071308for (i = 0; i < 10; i++) {1309mutex_lock(&dev->mt76.mutex);1310ret = mt792x_dev_reset(dev);1311mutex_unlock(&dev->mt76.mutex);13121313if (!ret)1314break;1315}13161317if (i == 10)1318dev_err(dev->mt76.dev, "chip reset failed\n");13191320if (test_and_clear_bit(MT76_HW_SCANNING, &dev->mphy.state)) {1321struct cfg80211_scan_info info = {1322.aborted = true,1323};13241325ieee80211_scan_completed(dev->mphy.hw, &info);1326}13271328dev->hw_full_reset = false;1329pm->suspended = false;1330ieee80211_wake_queues(hw);1331ieee80211_iterate_active_interfaces(hw,1332IEEE80211_IFACE_ITER_RESUME_ALL,1333mt7925_vif_connect_iter, NULL);1334mt76_connac_power_save_sched(&dev->mt76.phy, pm);1335}13361337void mt7925_coredump_work(struct work_struct *work)1338{1339struct mt792x_dev *dev;1340char *dump, *data;13411342dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev,1343coredump.work.work);13441345if (time_is_after_jiffies(dev->coredump.last_activity +13464 * MT76_CONNAC_COREDUMP_TIMEOUT)) {1347queue_delayed_work(dev->mt76.wq, &dev->coredump.work,1348MT76_CONNAC_COREDUMP_TIMEOUT);1349return;1350}13511352dump = vzalloc(MT76_CONNAC_COREDUMP_SZ);1353data = dump;13541355while (true) {1356struct sk_buff *skb;13571358spin_lock_bh(&dev->mt76.lock);1359skb = __skb_dequeue(&dev->coredump.msg_list);1360spin_unlock_bh(&dev->mt76.lock);13611362if (!skb)1363break;13641365skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 8);1366if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {1367dev_kfree_skb(skb);1368continue;1369}13701371memcpy(data, skb->data, skb->len);1372data += skb->len;13731374dev_kfree_skb(skb);1375}13761377if (dump)1378dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,1379GFP_KERNEL);13801381mt792x_reset(&dev->mt76);1382}13831384/* usb_sdio */1385static void1386mt7925_usb_sdio_write_txwi(struct mt792x_dev *dev, struct mt76_wcid *wcid,1387enum mt76_txq_id qid, struct ieee80211_sta *sta,1388struct ieee80211_key_conf *key, int pid,1389struct sk_buff *skb)1390{1391__le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE);13921393memset(txwi, 0, MT_SDIO_TXD_SIZE);1394mt7925_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, qid, 0);1395skb_push(skb, MT_SDIO_TXD_SIZE);1396}13971398int mt7925_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,1399enum mt76_txq_id qid, struct mt76_wcid *wcid,1400struct ieee80211_sta *sta,1401struct mt76_tx_info *tx_info)1402{1403struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);1404struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);1405struct ieee80211_key_conf *key = info->control.hw_key;1406struct sk_buff *skb = tx_info->skb;1407int err, pad, pktid;14081409if (unlikely(tx_info->skb->len <= ETH_HLEN))1410return -EINVAL;14111412if (!wcid)1413wcid = &dev->mt76.global_wcid;14141415if (sta) {1416struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;14171418if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) {1419info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;1420msta->deflink.last_txs = jiffies;1421}1422}14231424pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb);1425mt7925_usb_sdio_write_txwi(dev, wcid, qid, sta, key, pktid, skb);14261427mt792x_skb_add_usb_sdio_hdr(dev, skb, 0);1428pad = round_up(skb->len, 4) - skb->len;1429if (mt76_is_usb(mdev))1430pad += 4;14311432err = mt76_skb_adjust_pad(skb, pad);1433if (err)1434/* Release pktid in case of error. */1435idr_remove(&wcid->pktid, pktid);14361437return err;1438}1439EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_prepare_skb);14401441void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,1442struct mt76_queue_entry *e)1443{1444__le32 *txwi = (__le32 *)(e->skb->data + MT_SDIO_HDR_SIZE);1445unsigned int headroom = MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;1446struct ieee80211_sta *sta;1447struct mt76_wcid *wcid;1448u16 idx;14491450idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);1451wcid = __mt76_wcid_ptr(mdev, idx);1452sta = wcid_to_sta(wcid);14531454if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))1455mt7925_tx_check_aggr(sta, e->skb, wcid);14561457skb_pull(e->skb, headroom);1458mt76_tx_complete_skb(mdev, e->wcid, e->skb);1459}1460EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_complete_skb);14611462bool mt7925_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)1463{1464struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);14651466mt792x_mutex_acquire(dev);1467mt7925_mac_sta_poll(dev);1468mt792x_mutex_release(dev);14691470return false;1471}1472EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_status_data);14731474#if IS_ENABLED(CONFIG_IPV6)1475void mt7925_set_ipv6_ns_work(struct work_struct *work)1476{1477struct mt792x_dev *dev = container_of(work, struct mt792x_dev,1478ipv6_ns_work);1479struct sk_buff *skb;1480int ret = 0;14811482do {1483skb = skb_dequeue(&dev->ipv6_ns_list);14841485if (!skb)1486break;14871488mt792x_mutex_acquire(dev);1489ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,1490MCU_UNI_CMD(OFFLOAD), true);1491mt792x_mutex_release(dev);14921493} while (!ret);14941495if (ret)1496skb_queue_purge(&dev->ipv6_ns_list);1497}1498#endif149915001501