Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7925/mac.c
106465 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/* 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 "regd.h"9#include "mac.h"10#include "mcu.h"1112bool mt7925_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask)13{14mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,15FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);1617return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,180, 5000);19}2021static void mt7925_mac_sta_poll(struct mt792x_dev *dev)22{23static const u8 ac_to_tid[] = {24[IEEE80211_AC_BE] = 0,25[IEEE80211_AC_BK] = 1,26[IEEE80211_AC_VI] = 4,27[IEEE80211_AC_VO] = 628};29struct ieee80211_sta *sta;30struct mt792x_sta *msta;31struct mt792x_link_sta *mlink;32u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];33LIST_HEAD(sta_poll_list);34struct rate_info *rate;35s8 rssi[4];36int i;3738spin_lock_bh(&dev->mt76.sta_poll_lock);39list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);40spin_unlock_bh(&dev->mt76.sta_poll_lock);4142while (true) {43bool clear = false;44u32 addr, val;45u16 idx;46u8 bw;4748if (list_empty(&sta_poll_list))49break;50mlink = list_first_entry(&sta_poll_list,51struct mt792x_link_sta, wcid.poll_list);52msta = mlink->sta;53spin_lock_bh(&dev->mt76.sta_poll_lock);54list_del_init(&mlink->wcid.poll_list);55spin_unlock_bh(&dev->mt76.sta_poll_lock);5657idx = mlink->wcid.idx;58addr = mt7925_mac_wtbl_lmac_addr(dev, idx, MT_WTBL_AC0_CTT_OFFSET);5960for (i = 0; i < IEEE80211_NUM_ACS; i++) {61u32 tx_last = mlink->airtime_ac[i];62u32 rx_last = mlink->airtime_ac[i + 4];6364mlink->airtime_ac[i] = mt76_rr(dev, addr);65mlink->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);6667tx_time[i] = mlink->airtime_ac[i] - tx_last;68rx_time[i] = mlink->airtime_ac[i + 4] - rx_last;6970if ((tx_last | rx_last) & BIT(30))71clear = true;7273addr += 8;74}7576if (clear) {77mt7925_mac_wtbl_update(dev, idx,78MT_WTBL_UPDATE_ADM_COUNT_CLEAR);79memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac));80}8182if (!mlink->wcid.sta)83continue;8485sta = container_of((void *)msta, struct ieee80211_sta,86drv_priv);87for (i = 0; i < IEEE80211_NUM_ACS; i++) {88u8 q = mt76_connac_lmac_mapping(i);89u32 tx_cur = tx_time[q];90u32 rx_cur = rx_time[q];91u8 tid = ac_to_tid[i];9293if (!tx_cur && !rx_cur)94continue;9596ieee80211_sta_register_airtime(sta, tid, tx_cur,97rx_cur);98}99100/* We don't support reading GI info from txs packets.101* For accurate tx status reporting and AQL improvement,102* we need to make sure that flags match so polling GI103* from per-sta counters directly.104*/105rate = &mlink->wcid.rate;106107switch (rate->bw) {108case RATE_INFO_BW_160:109bw = IEEE80211_STA_RX_BW_160;110break;111case RATE_INFO_BW_80:112bw = IEEE80211_STA_RX_BW_80;113break;114case RATE_INFO_BW_40:115bw = IEEE80211_STA_RX_BW_40;116break;117default:118bw = IEEE80211_STA_RX_BW_20;119break;120}121122addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 6);123val = mt76_rr(dev, addr);124if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {125addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 5);126val = mt76_rr(dev, addr);127rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);128} else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {129u8 offs = MT_WTBL_TXRX_RATE_G2_HE + 2 * bw;130131rate->he_gi = (val & (0x3 << offs)) >> offs;132} else if (rate->flags &133(RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {134if (val & BIT(MT_WTBL_TXRX_RATE_G2 + bw))135rate->flags |= RATE_INFO_FLAGS_SHORT_GI;136else137rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;138}139140/* get signal strength of resp frames (CTS/BA/ACK) */141addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 34);142val = mt76_rr(dev, addr);143144rssi[0] = to_rssi(GENMASK(7, 0), val);145rssi[1] = to_rssi(GENMASK(15, 8), val);146rssi[2] = to_rssi(GENMASK(23, 16), val);147rssi[3] = to_rssi(GENMASK(31, 14), val);148149mlink->ack_signal =150mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);151152ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal);153}154}155156void mt7925_mac_set_fixed_rate_table(struct mt792x_dev *dev,157u8 tbl_idx, u16 rate_idx)158{159u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;160161mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);162/* use wtbl spe idx */163mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);164mt76_wr(dev, MT_WTBL_ITCR, ctrl);165}166167/* The HW does not translate the mac header to 802.3 for mesh point */168static int mt7925_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)169{170struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;171struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);172struct mt792x_sta *msta = (struct mt792x_sta *)status->wcid;173__le32 *rxd = (__le32 *)skb->data;174struct ieee80211_sta *sta;175struct ieee80211_vif *vif;176struct ieee80211_hdr hdr;177u16 frame_control;178179if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=180MT_RXD3_NORMAL_U2M)181return -EINVAL;182183if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))184return -EINVAL;185186if (!msta || !msta->vif)187return -EINVAL;188189sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);190vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);191192/* store the info from RXD and ethhdr to avoid being overridden */193frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);194hdr.frame_control = cpu_to_le16(frame_control);195hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL));196hdr.duration_id = 0;197198ether_addr_copy(hdr.addr1, vif->addr);199ether_addr_copy(hdr.addr2, sta->addr);200switch (frame_control & (IEEE80211_FCTL_TODS |201IEEE80211_FCTL_FROMDS)) {202case 0:203ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);204break;205case IEEE80211_FCTL_FROMDS:206ether_addr_copy(hdr.addr3, eth_hdr->h_source);207break;208case IEEE80211_FCTL_TODS:209ether_addr_copy(hdr.addr3, eth_hdr->h_dest);210break;211case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:212ether_addr_copy(hdr.addr3, eth_hdr->h_dest);213ether_addr_copy(hdr.addr4, eth_hdr->h_source);214break;215default:216break;217}218219skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);220if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||221eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))222ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);223else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)224ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);225else226skb_pull(skb, 2);227228if (ieee80211_has_order(hdr.frame_control))229memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11],230IEEE80211_HT_CTL_LEN);231if (ieee80211_is_data_qos(hdr.frame_control)) {232__le16 qos_ctrl;233234qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL));235memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,236IEEE80211_QOS_CTL_LEN);237}238239if (ieee80211_has_a4(hdr.frame_control))240memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));241else242memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);243244return 0;245}246247static int248mt7925_mac_fill_rx_rate(struct mt792x_dev *dev,249struct mt76_rx_status *status,250struct ieee80211_supported_band *sband,251__le32 *rxv, u8 *mode)252{253u32 v0, v2;254u8 stbc, gi, bw, dcm, nss;255int i, idx;256bool cck = false;257258v0 = le32_to_cpu(rxv[0]);259v2 = le32_to_cpu(rxv[2]);260261idx = FIELD_GET(MT_PRXV_TX_RATE, v0);262i = idx;263nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;264265stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);266gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);267*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);268dcm = FIELD_GET(MT_PRXV_DCM, v2);269bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);270271switch (*mode) {272case MT_PHY_TYPE_CCK:273cck = true;274fallthrough;275case MT_PHY_TYPE_OFDM:276i = mt76_get_rate(&dev->mt76, sband, i, cck);277break;278case MT_PHY_TYPE_HT_GF:279case MT_PHY_TYPE_HT:280status->encoding = RX_ENC_HT;281if (gi)282status->enc_flags |= RX_ENC_FLAG_SHORT_GI;283if (i > 31)284return -EINVAL;285break;286case MT_PHY_TYPE_VHT:287status->nss = nss;288status->encoding = RX_ENC_VHT;289if (gi)290status->enc_flags |= RX_ENC_FLAG_SHORT_GI;291if (i > 11)292return -EINVAL;293break;294case MT_PHY_TYPE_HE_MU:295case MT_PHY_TYPE_HE_SU:296case MT_PHY_TYPE_HE_EXT_SU:297case MT_PHY_TYPE_HE_TB:298status->nss = nss;299status->encoding = RX_ENC_HE;300i &= GENMASK(3, 0);301302if (gi <= NL80211_RATE_INFO_HE_GI_3_2)303status->he_gi = gi;304305status->he_dcm = dcm;306break;307case MT_PHY_TYPE_EHT_SU:308case MT_PHY_TYPE_EHT_TRIG:309case MT_PHY_TYPE_EHT_MU:310status->nss = nss;311status->encoding = RX_ENC_EHT;312i &= GENMASK(3, 0);313314if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)315status->eht.gi = gi;316break;317default:318return -EINVAL;319}320status->rate_idx = i;321322switch (bw) {323case IEEE80211_STA_RX_BW_20:324break;325case IEEE80211_STA_RX_BW_40:326if (*mode & MT_PHY_TYPE_HE_EXT_SU &&327(idx & MT_PRXV_TX_ER_SU_106T)) {328status->bw = RATE_INFO_BW_HE_RU;329status->he_ru =330NL80211_RATE_INFO_HE_RU_ALLOC_106;331} else {332status->bw = RATE_INFO_BW_40;333}334break;335case IEEE80211_STA_RX_BW_80:336status->bw = RATE_INFO_BW_80;337break;338case IEEE80211_STA_RX_BW_160:339status->bw = RATE_INFO_BW_160;340break;341default:342return -EINVAL;343}344345status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;346if (*mode < MT_PHY_TYPE_HE_SU && gi)347status->enc_flags |= RX_ENC_FLAG_SHORT_GI;348349return 0;350}351352static int353mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)354{355u32 csum_mask = MT_RXD3_NORMAL_IP_SUM | MT_RXD3_NORMAL_UDP_TCP_SUM;356struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;357bool hdr_trans, unicast, insert_ccmp_hdr = false;358u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info;359u16 hdr_gap;360__le32 *rxv = NULL, *rxd = (__le32 *)skb->data;361struct mt76_phy *mphy = &dev->mt76.phy;362struct mt792x_phy *phy = &dev->phy;363struct ieee80211_supported_band *sband;364u32 csum_status = *(u32 *)skb->cb;365u32 rxd1 = le32_to_cpu(rxd[1]);366u32 rxd2 = le32_to_cpu(rxd[2]);367u32 rxd3 = le32_to_cpu(rxd[3]);368u32 rxd4 = le32_to_cpu(rxd[4]);369struct mt792x_link_sta *mlink;370u8 mode = 0; /* , band_idx; */371u16 seq_ctrl = 0;372__le16 fc = 0;373int idx;374375memset(status, 0, sizeof(*status));376377if (!test_bit(MT76_STATE_RUNNING, &mphy->state))378return -EINVAL;379380if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)381return -EINVAL;382383hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;384if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))385return -EINVAL;386387/* ICV error or CCMP/BIP/WPI MIC error */388if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)389status->flag |= RX_FLAG_ONLY_MONITOR;390391chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);392unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;393idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);394status->wcid = mt792x_rx_get_wcid(dev, idx, unicast);395396if (status->wcid) {397mlink = container_of(status->wcid, struct mt792x_link_sta, wcid);398mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);399}400401mt792x_get_status_freq_info(status, chfreq);402403switch (status->band) {404case NL80211_BAND_5GHZ:405sband = &mphy->sband_5g.sband;406break;407case NL80211_BAND_6GHZ:408sband = &mphy->sband_6g.sband;409break;410default:411sband = &mphy->sband_2g.sband;412break;413}414415if (!sband->channels)416return -EINVAL;417418if (mt76_is_mmio(&dev->mt76) && (rxd3 & csum_mask) == csum_mask &&419!(csum_status & (BIT(0) | BIT(2) | BIT(3))))420skb->ip_summed = CHECKSUM_UNNECESSARY;421422if (rxd3 & MT_RXD3_NORMAL_FCS_ERR)423status->flag |= RX_FLAG_FAILED_FCS_CRC;424425if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)426status->flag |= RX_FLAG_MMIC_ERROR;427428if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&429!(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {430status->flag |= RX_FLAG_DECRYPTED;431status->flag |= RX_FLAG_IV_STRIPPED;432status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;433}434435remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);436437if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)438return -EINVAL;439440rxd += 8;441if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {442u32 v0 = le32_to_cpu(rxd[0]);443u32 v2 = le32_to_cpu(rxd[2]);444445/* TODO: need to map rxd address */446fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0));447seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);448qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);449450rxd += 4;451if ((u8 *)rxd - skb->data >= skb->len)452return -EINVAL;453}454455if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {456u8 *data = (u8 *)rxd;457458if (status->flag & RX_FLAG_DECRYPTED) {459switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {460case MT_CIPHER_AES_CCMP:461case MT_CIPHER_CCMP_CCX:462case MT_CIPHER_CCMP_256:463insert_ccmp_hdr =464FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);465fallthrough;466case MT_CIPHER_TKIP:467case MT_CIPHER_TKIP_NO_MIC:468case MT_CIPHER_GCMP:469case MT_CIPHER_GCMP_256:470status->iv[0] = data[5];471status->iv[1] = data[4];472status->iv[2] = data[3];473status->iv[3] = data[2];474status->iv[4] = data[1];475status->iv[5] = data[0];476break;477default:478break;479}480}481rxd += 4;482if ((u8 *)rxd - skb->data >= skb->len)483return -EINVAL;484}485486if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {487status->timestamp = le32_to_cpu(rxd[0]);488status->flag |= RX_FLAG_MACTIME_START;489490if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {491status->flag |= RX_FLAG_AMPDU_DETAILS;492493/* all subframes of an A-MPDU have the same timestamp */494if (phy->rx_ampdu_ts != status->timestamp) {495if (!++phy->ampdu_ref)496phy->ampdu_ref++;497}498phy->rx_ampdu_ts = status->timestamp;499500status->ampdu_ref = phy->ampdu_ref;501}502503rxd += 4;504if ((u8 *)rxd - skb->data >= skb->len)505return -EINVAL;506}507508/* RXD Group 3 - P-RXV */509if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {510u32 v3;511int ret;512513rxv = rxd;514rxd += 4;515if ((u8 *)rxd - skb->data >= skb->len)516return -EINVAL;517518v3 = le32_to_cpu(rxv[3]);519520status->chains = mphy->antenna_mask;521status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3);522status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3);523status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3);524status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3);525526/* RXD Group 5 - C-RXV */527if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {528rxd += 24;529if ((u8 *)rxd - skb->data >= skb->len)530return -EINVAL;531}532533ret = mt7925_mac_fill_rx_rate(dev, status, sband, rxv, &mode);534if (ret < 0)535return ret;536}537538amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);539status->amsdu = !!amsdu_info;540if (status->amsdu) {541status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;542status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;543}544545hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;546if (hdr_trans && ieee80211_has_morefrags(fc)) {547if (mt7925_reverse_frag0_hdr_trans(skb, hdr_gap))548return -EINVAL;549hdr_trans = false;550} else {551int pad_start = 0;552553skb_pull(skb, hdr_gap);554if (!hdr_trans && status->amsdu) {555pad_start = ieee80211_get_hdrlen_from_skb(skb);556} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {557/* When header translation failure is indicated,558* the hardware will insert an extra 2-byte field559* containing the data length after the protocol560* type field.561*/562pad_start = 12;563if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)564pad_start += 4;565else566pad_start = 0;567}568569if (pad_start) {570memmove(skb->data + 2, skb->data, pad_start);571skb_pull(skb, 2);572}573}574575if (!hdr_trans) {576struct ieee80211_hdr *hdr;577578if (insert_ccmp_hdr) {579u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);580581mt76_insert_ccmp_hdr(skb, key_id);582}583584hdr = mt76_skb_get_hdr(skb);585fc = hdr->frame_control;586if (ieee80211_is_data_qos(fc)) {587seq_ctrl = le16_to_cpu(hdr->seq_ctrl);588qos_ctl = *ieee80211_get_qos_ctl(hdr);589}590skb_set_mac_header(skb, (unsigned char *)hdr - skb->data);591} else {592status->flag |= RX_FLAG_8023;593}594595mt792x_mac_assoc_rssi(dev, skb);596597if (rxv && !(status->flag & RX_FLAG_8023)) {598switch (status->encoding) {599case RX_ENC_EHT:600mt76_connac3_mac_decode_eht_radiotap(skb, rxv, mode);601break;602case RX_ENC_HE:603mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);604break;605default:606break;607}608}609610if (!status->wcid || !ieee80211_is_data_qos(fc))611return 0;612613status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);614status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);615status->qos_ctl = qos_ctl;616617return 0;618}619620static void621mt7925_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,622struct mt76_wcid *wcid)623{624u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;625u8 fc_type, fc_stype;626u16 ethertype;627bool wmm = false;628u32 val;629630if (wcid->sta) {631struct ieee80211_sta *sta;632633sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);634wmm = sta->wme;635}636637val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |638FIELD_PREP(MT_TXD1_TID, tid);639640ethertype = get_unaligned_be16(&skb->data[12]);641if (ethertype >= ETH_P_802_3_MIN)642val |= MT_TXD1_ETH_802_3;643644txwi[1] |= cpu_to_le32(val);645646fc_type = IEEE80211_FTYPE_DATA >> 2;647fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;648649val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |650FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);651652txwi[2] |= cpu_to_le32(val);653}654655static void656mt7925_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,657struct sk_buff *skb,658struct ieee80211_key_conf *key)659{660struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;661struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;662struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);663bool multicast = is_multicast_ether_addr(hdr->addr1);664u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;665__le16 fc = hdr->frame_control;666u8 fc_type, fc_stype;667u32 val;668669if (ieee80211_is_action(fc) &&670mgmt->u.action.category == WLAN_CATEGORY_BACK &&671mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)672tid = MT_TX_ADDBA;673else if (ieee80211_is_mgmt(hdr->frame_control))674tid = MT_TX_NORMAL;675676val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |677FIELD_PREP(MT_TXD1_HDR_INFO,678ieee80211_get_hdrlen_from_skb(skb) / 2) |679FIELD_PREP(MT_TXD1_TID, tid);680681if (!ieee80211_is_data(fc) || multicast ||682info->flags & IEEE80211_TX_CTL_USE_MINRATE)683val |= MT_TXD1_FIXED_RATE;684685if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&686key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {687val |= MT_TXD1_BIP;688txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);689}690691txwi[1] |= cpu_to_le32(val);692693fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;694fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;695696val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |697FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);698699txwi[2] |= cpu_to_le32(val);700701txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));702if (ieee80211_is_beacon(fc))703txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);704705if (info->flags & IEEE80211_TX_CTL_INJECTED) {706u16 seqno = le16_to_cpu(hdr->seq_ctrl);707708if (ieee80211_is_back_req(hdr->frame_control)) {709struct ieee80211_bar *bar;710711bar = (struct ieee80211_bar *)skb->data;712seqno = le16_to_cpu(bar->start_seq_num);713}714715val = MT_TXD3_SN_VALID |716FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));717txwi[3] |= cpu_to_le32(val);718txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);719}720}721722void723mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,724struct sk_buff *skb, struct mt76_wcid *wcid,725struct ieee80211_key_conf *key, int pid,726enum mt76_txq_id qid, u32 changed)727{728struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);729struct ieee80211_vif *vif = info->control.vif;730u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0;731u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE;732bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;733struct mt76_vif_link *mvif;734bool beacon = !!(changed & (BSS_CHANGED_BEACON |735BSS_CHANGED_BEACON_ENABLED));736bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |737BSS_CHANGED_FILS_DISCOVERY));738struct mt792x_bss_conf *mconf;739740mconf = vif ? mt792x_vif_to_link((struct mt792x_vif *)vif->drv_priv,741wcid->link_id) : NULL;742mvif = mconf ? (struct mt76_vif_link *)&mconf->mt76 : NULL;743744if (mvif) {745omac_idx = mvif->omac_idx;746wmm_idx = mvif->wmm_idx;747band_idx = mvif->band_idx;748}749750if (inband_disc) {751p_fmt = MT_TX_TYPE_FW;752q_idx = MT_LMAC_ALTX0;753} else if (beacon) {754p_fmt = MT_TX_TYPE_FW;755q_idx = MT_LMAC_BCN0;756} else if (qid >= MT_TXQ_PSD) {757p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;758q_idx = MT_LMAC_ALTX0;759} else {760p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;761q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +762mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));763764/* counting non-offloading skbs */765wcid->stats.tx_bytes += skb->len;766wcid->stats.tx_packets++;767}768769val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |770FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |771FIELD_PREP(MT_TXD0_Q_IDX, q_idx);772txwi[0] = cpu_to_le32(val);773774val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |775FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);776777if (band_idx)778val |= FIELD_PREP(MT_TXD1_TGID, band_idx);779780txwi[1] = cpu_to_le32(val);781txwi[2] = 0;782783val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15);784785if (key)786val |= MT_TXD3_PROTECT_FRAME;787if (info->flags & IEEE80211_TX_CTL_NO_ACK)788val |= MT_TXD3_NO_ACK;789if (wcid->amsdu)790val |= MT_TXD3_HW_AMSDU;791792txwi[3] = cpu_to_le32(val);793txwi[4] = 0;794795val = FIELD_PREP(MT_TXD5_PID, pid);796if (pid >= MT_PACKET_ID_FIRST) {797val |= MT_TXD5_TX_STATUS_HOST;798txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);799txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);800}801802txwi[5] = cpu_to_le32(val);803804val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1);805if (!ieee80211_vif_is_mld(vif) ||806(q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))807val |= MT_TXD6_DIS_MAT;808txwi[6] = cpu_to_le32(val);809txwi[7] = 0;810811if (is_8023)812mt7925_mac_write_txwi_8023(txwi, skb, wcid);813else814mt7925_mac_write_txwi_80211(dev, txwi, skb, key);815816if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {817struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;818bool mcast = ieee80211_is_data(hdr->frame_control) &&819is_multicast_ether_addr(hdr->addr1);820u8 idx = MT792x_BASIC_RATES_TBL;821822if (mvif) {823if (mcast && mvif->mcast_rates_idx)824idx = mvif->mcast_rates_idx;825else if (beacon && mvif->beacon_rates_idx)826idx = mvif->beacon_rates_idx;827else828idx = mvif->basic_rates_idx;829}830831txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));832txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);833}834}835EXPORT_SYMBOL_GPL(mt7925_mac_write_txwi);836837static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,838struct mt76_wcid *wcid)839{840struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);841struct ieee80211_link_sta *link_sta;842struct mt792x_link_sta *mlink;843struct mt792x_sta *msta;844bool is_8023;845u16 fc, tid;846847link_sta = rcu_dereference(sta->link[wcid->link_id]);848if (!link_sta)849return;850851if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))852return;853854tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;855is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;856857if (is_8023) {858fc = IEEE80211_FTYPE_DATA |859(sta->wme ? IEEE80211_STYPE_QOS_DATA :860IEEE80211_STYPE_DATA);861} else {862/* No need to get precise TID for Action/Management Frame,863* since it will not meet the following Frame Control864* condition anyway.865*/866867struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;868869fc = le16_to_cpu(hdr->frame_control) &870(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);871}872873if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))874return;875876msta = (struct mt792x_sta *)sta->drv_priv;877878if (sta->mlo && msta->deflink_id != IEEE80211_LINK_UNSPECIFIED)879mlink = rcu_dereference(msta->link[msta->deflink_id]);880else881mlink = &msta->deflink;882883if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state))884ieee80211_start_tx_ba_session(sta, tid, 0);885}886887static bool888mt7925_mac_add_txs_skb(struct mt792x_dev *dev, struct mt76_wcid *wcid,889int pid, __le32 *txs_data)890{891struct mt76_sta_stats *stats = &wcid->stats;892struct ieee80211_supported_band *sband;893struct mt76_dev *mdev = &dev->mt76;894struct mt76_phy *mphy;895struct ieee80211_tx_info *info;896struct sk_buff_head list;897struct rate_info rate = {};898struct sk_buff *skb;899bool cck = false;900u32 txrate, txs, mode, stbc;901902mt76_tx_status_lock(mdev, &list);903skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);904if (!skb)905goto out_no_skb;906907txs = le32_to_cpu(txs_data[0]);908909info = IEEE80211_SKB_CB(skb);910if (!(txs & MT_TXS0_ACK_ERROR_MASK))911info->flags |= IEEE80211_TX_STAT_ACK;912913info->status.ampdu_len = 1;914info->status.ampdu_ack_len = !!(info->flags &915IEEE80211_TX_STAT_ACK);916917info->status.rates[0].idx = -1;918919txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);920921rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);922rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;923stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);924925if (stbc && rate.nss > 1)926rate.nss >>= 1;927928if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))929stats->tx_nss[rate.nss - 1]++;930if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))931stats->tx_mcs[rate.mcs]++;932933mode = FIELD_GET(MT_TX_RATE_MODE, txrate);934switch (mode) {935case MT_PHY_TYPE_CCK:936cck = true;937fallthrough;938case MT_PHY_TYPE_OFDM:939mphy = mt76_dev_phy(mdev, wcid->phy_idx);940941if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)942sband = &mphy->sband_5g.sband;943else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)944sband = &mphy->sband_6g.sband;945else946sband = &mphy->sband_2g.sband;947948rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);949rate.legacy = sband->bitrates[rate.mcs].bitrate;950break;951case MT_PHY_TYPE_HT:952case MT_PHY_TYPE_HT_GF:953if (rate.mcs > 31)954goto out;955956rate.flags = RATE_INFO_FLAGS_MCS;957if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)958rate.flags |= RATE_INFO_FLAGS_SHORT_GI;959break;960case MT_PHY_TYPE_VHT:961if (rate.mcs > 9)962goto out;963964rate.flags = RATE_INFO_FLAGS_VHT_MCS;965break;966case MT_PHY_TYPE_HE_SU:967case MT_PHY_TYPE_HE_EXT_SU:968case MT_PHY_TYPE_HE_TB:969case MT_PHY_TYPE_HE_MU:970if (rate.mcs > 11)971goto out;972973rate.he_gi = wcid->rate.he_gi;974rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);975rate.flags = RATE_INFO_FLAGS_HE_MCS;976break;977case MT_PHY_TYPE_EHT_SU:978case MT_PHY_TYPE_EHT_TRIG:979case MT_PHY_TYPE_EHT_MU:980if (rate.mcs > 13)981goto out;982983rate.eht_gi = wcid->rate.eht_gi;984rate.flags = RATE_INFO_FLAGS_EHT_MCS;985break;986default:987goto out;988}989990stats->tx_mode[mode]++;991992switch (FIELD_GET(MT_TXS0_BW, txs)) {993case IEEE80211_STA_RX_BW_160:994rate.bw = RATE_INFO_BW_160;995stats->tx_bw[3]++;996break;997case IEEE80211_STA_RX_BW_80:998rate.bw = RATE_INFO_BW_80;999stats->tx_bw[2]++;1000break;1001case IEEE80211_STA_RX_BW_40:1002rate.bw = RATE_INFO_BW_40;1003stats->tx_bw[1]++;1004break;1005default:1006rate.bw = RATE_INFO_BW_20;1007stats->tx_bw[0]++;1008break;1009}1010wcid->rate = rate;10111012out:1013mt76_tx_status_skb_done(mdev, skb, &list);10141015out_no_skb:1016mt76_tx_status_unlock(mdev, &list);10171018return !!skb;1019}10201021void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data)1022{1023struct mt792x_link_sta *mlink = NULL;1024struct mt76_wcid *wcid;1025__le32 *txs_data = data;1026u16 wcidx;1027u8 pid;10281029if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)1030return;10311032wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);1033pid = le32_get_bits(txs_data[3], MT_TXS3_PID);10341035if (pid < MT_PACKET_ID_FIRST)1036return;10371038if (wcidx >= MT792x_WTBL_SIZE)1039return;10401041rcu_read_lock();10421043wcid = mt76_wcid_ptr(dev, wcidx);1044if (!wcid)1045goto out;10461047mlink = container_of(wcid, struct mt792x_link_sta, wcid);10481049mt7925_mac_add_txs_skb(dev, wcid, pid, txs_data);1050if (!wcid->sta)1051goto out;10521053mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);10541055out:1056rcu_read_unlock();1057}10581059void mt7925_txwi_free(struct mt792x_dev *dev, struct mt76_txwi_cache *t,1060struct ieee80211_sta *sta, struct mt76_wcid *wcid,1061struct list_head *free_list)1062{1063struct mt76_dev *mdev = &dev->mt76;1064__le32 *txwi;1065u16 wcid_idx;10661067mt76_connac_txp_skb_unmap(mdev, t);1068if (!t->skb)1069goto out;10701071txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);1072if (sta) {1073if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))1074mt7925_tx_check_aggr(sta, t->skb, wcid);10751076wcid_idx = wcid->idx;1077} else {1078wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);1079}10801081__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);1082out:1083t->skb = NULL;1084mt76_put_txwi(mdev, t);1085}1086EXPORT_SYMBOL_GPL(mt7925_txwi_free);10871088static void1089mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len)1090{1091__le32 *tx_free = (__le32 *)data, *cur_info;1092struct mt76_dev *mdev = &dev->mt76;1093struct mt76_txwi_cache *txwi;1094struct ieee80211_sta *sta = NULL;1095struct mt76_wcid *wcid = NULL;1096LIST_HEAD(free_list);1097struct sk_buff *skb, *tmp;1098#if defined(__linux__)1099void *end = data + len;1100#elif defined(__FreeBSD__)1101void *end = (u8 *)data + len;1102#endif1103bool wake = false;1104u16 total, count = 0;11051106/* clean DMA queues and unmap buffers first */1107mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);1108mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);11091110if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4))1111return;11121113total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);1114for (cur_info = &tx_free[2]; count < total; cur_info++) {1115u32 msdu, info;1116u8 i;11171118if (WARN_ON_ONCE((void *)cur_info >= end))1119return;1120/* 1'b1: new wcid pair.1121* 1'b0: msdu_id with the same 'wcid pair' as above.1122*/1123info = le32_to_cpu(*cur_info);1124if (info & MT_TXFREE_INFO_PAIR) {1125struct mt792x_link_sta *mlink;1126u16 idx;11271128idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);1129wcid = mt76_wcid_ptr(dev, idx);1130sta = wcid_to_sta(wcid);1131if (!sta)1132continue;11331134mlink = container_of(wcid, struct mt792x_link_sta, wcid);1135mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);1136continue;1137}11381139if (info & MT_TXFREE_INFO_HEADER) {1140if (wcid) {1141wcid->stats.tx_retries +=1142FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1;1143wcid->stats.tx_failed +=1144!!FIELD_GET(MT_TXFREE_INFO_STAT, info);1145}1146continue;1147}11481149for (i = 0; i < 2; i++) {1150msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID;1151if (msdu == MT_TXFREE_INFO_MSDU_ID)1152continue;11531154count++;1155txwi = mt76_token_release(mdev, msdu, &wake);1156if (!txwi)1157continue;11581159mt7925_txwi_free(dev, txwi, sta, wcid, &free_list);1160}1161}11621163mt7925_mac_sta_poll(dev);11641165if (wake)1166mt76_set_tx_blocked(&dev->mt76, false);11671168mt76_worker_schedule(&dev->mt76.tx_worker);11691170list_for_each_entry_safe(skb, tmp, &free_list, list) {1171skb_list_del_init(skb);1172napi_consume_skb(skb, 1);1173}1174}11751176bool mt7925_rx_check(struct mt76_dev *mdev, void *data, int len)1177{1178struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);1179__le32 *rxd = (__le32 *)data;1180__le32 *end = (__le32 *)&rxd[len / 4];1181enum rx_pkt_type type;11821183type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);1184if (type != PKT_TYPE_NORMAL) {1185u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);11861187if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==1188MT_RXD0_SW_PKT_TYPE_FRAME))1189return true;1190}11911192switch (type) {1193case PKT_TYPE_TXRX_NOTIFY:1194/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */1195mt7925_mac_tx_free(dev, data, len); /* mmio */1196return false;1197case PKT_TYPE_TXS:1198for (rxd += 4; rxd + 12 <= end; rxd += 12)1199mt7925_mac_add_txs(dev, rxd);1200return false;1201default:1202return true;1203}1204}1205EXPORT_SYMBOL_GPL(mt7925_rx_check);12061207void mt7925_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,1208struct sk_buff *skb, u32 *info)1209{1210struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);1211__le32 *rxd = (__le32 *)skb->data;1212__le32 *end = (__le32 *)&skb->data[skb->len];1213enum rx_pkt_type type;1214u16 flag;12151216type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);1217flag = le32_get_bits(rxd[0], MT_RXD0_PKT_FLAG);1218if (type != PKT_TYPE_NORMAL) {1219u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);12201221if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==1222MT_RXD0_SW_PKT_TYPE_FRAME))1223type = PKT_TYPE_NORMAL;1224}12251226if (type == PKT_TYPE_RX_EVENT && flag == 0x1)1227type = PKT_TYPE_NORMAL_MCU;12281229switch (type) {1230case PKT_TYPE_TXRX_NOTIFY:1231/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */1232mt7925_mac_tx_free(dev, skb->data, skb->len);1233napi_consume_skb(skb, 1);1234break;1235case PKT_TYPE_RX_EVENT:1236mt7925_mcu_rx_event(dev, skb);1237break;1238case PKT_TYPE_TXS:1239for (rxd += 2; rxd + 8 <= end; rxd += 8)1240mt7925_mac_add_txs(dev, rxd);1241dev_kfree_skb(skb);1242break;1243case PKT_TYPE_NORMAL_MCU:1244case PKT_TYPE_NORMAL:1245if (!mt7925_mac_fill_rx(dev, skb)) {1246mt76_rx(&dev->mt76, q, skb);1247return;1248}1249fallthrough;1250default:1251dev_kfree_skb(skb);1252break;1253}1254}1255EXPORT_SYMBOL_GPL(mt7925_queue_rx_skb);12561257static void1258mt7925_vif_connect_iter(void *priv, u8 *mac,1259struct ieee80211_vif *vif)1260{1261struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1262unsigned long valid = ieee80211_vif_is_mld(vif) ?1263mvif->valid_links : BIT(0);1264struct mt792x_dev *dev = mvif->phy->dev;1265struct ieee80211_hw *hw = mt76_hw(dev);1266struct ieee80211_bss_conf *bss_conf;1267struct mt792x_bss_conf *mconf;1268int i;12691270if (vif->type == NL80211_IFTYPE_STATION)1271ieee80211_disconnect(vif, true);12721273for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {1274bss_conf = mt792x_vif_to_bss_conf(vif, i);1275mconf = mt792x_vif_to_link(mvif, i);12761277mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76,1278&mvif->sta.deflink.wcid, true);1279mt7925_mcu_set_tx(dev, bss_conf);1280}12811282if (vif->type == NL80211_IFTYPE_AP) {1283mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid,1284true, NULL);1285mt7925_mcu_sta_update(dev, NULL, vif, true,1286MT76_STA_INFO_STATE_NONE);1287mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true);1288}1289}12901291/* system error recovery */1292void mt7925_mac_reset_work(struct work_struct *work)1293{1294struct mt792x_dev *dev = container_of(work, struct mt792x_dev,1295reset_work);1296struct ieee80211_hw *hw = mt76_hw(dev);1297struct mt76_connac_pm *pm = &dev->pm;1298int i, ret;12991300dev_dbg(dev->mt76.dev, "chip reset\n");1301dev->hw_full_reset = true;1302ieee80211_stop_queues(hw);13031304cancel_delayed_work_sync(&dev->mphy.mac_work);1305cancel_delayed_work_sync(&pm->ps_work);1306cancel_work_sync(&pm->wake_work);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);13351336mt7925_regd_change(&dev->phy, "00");1337}13381339void mt7925_coredump_work(struct work_struct *work)1340{1341struct mt792x_dev *dev;1342char *dump, *data;13431344dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev,1345coredump.work.work);13461347if (time_is_after_jiffies(dev->coredump.last_activity +13484 * MT76_CONNAC_COREDUMP_TIMEOUT)) {1349queue_delayed_work(dev->mt76.wq, &dev->coredump.work,1350MT76_CONNAC_COREDUMP_TIMEOUT);1351return;1352}13531354dump = vzalloc(MT76_CONNAC_COREDUMP_SZ);1355data = dump;13561357while (true) {1358struct sk_buff *skb;13591360spin_lock_bh(&dev->mt76.lock);1361skb = __skb_dequeue(&dev->coredump.msg_list);1362spin_unlock_bh(&dev->mt76.lock);13631364if (!skb)1365break;13661367skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 8);1368if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {1369dev_kfree_skb(skb);1370continue;1371}13721373memcpy(data, skb->data, skb->len);1374data += skb->len;13751376dev_kfree_skb(skb);1377}13781379if (dump)1380dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,1381GFP_KERNEL);13821383mt792x_reset(&dev->mt76);1384}13851386/* usb_sdio */1387static void1388mt7925_usb_sdio_write_txwi(struct mt792x_dev *dev, struct mt76_wcid *wcid,1389enum mt76_txq_id qid, struct ieee80211_sta *sta,1390struct ieee80211_key_conf *key, int pid,1391struct sk_buff *skb)1392{1393__le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE);13941395memset(txwi, 0, MT_SDIO_TXD_SIZE);1396mt7925_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, qid, 0);1397skb_push(skb, MT_SDIO_TXD_SIZE);1398}13991400int mt7925_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,1401enum mt76_txq_id qid, struct mt76_wcid *wcid,1402struct ieee80211_sta *sta,1403struct mt76_tx_info *tx_info)1404{1405struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);1406struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);1407struct ieee80211_key_conf *key = info->control.hw_key;1408struct sk_buff *skb = tx_info->skb;1409int err, pad, pktid;14101411if (unlikely(tx_info->skb->len <= ETH_HLEN))1412return -EINVAL;14131414if (!wcid)1415wcid = &dev->mt76.global_wcid;14161417if (sta) {1418struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;14191420if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) {1421info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;1422msta->deflink.last_txs = jiffies;1423}1424}14251426pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb);1427mt7925_usb_sdio_write_txwi(dev, wcid, qid, sta, key, pktid, skb);14281429mt792x_skb_add_usb_sdio_hdr(dev, skb, 0);1430pad = round_up(skb->len, 4) - skb->len;1431if (mt76_is_usb(mdev))1432pad += 4;14331434err = mt76_skb_adjust_pad(skb, pad);1435if (err)1436/* Release pktid in case of error. */1437idr_remove(&wcid->pktid, pktid);14381439return err;1440}1441EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_prepare_skb);14421443void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,1444struct mt76_queue_entry *e)1445{1446__le32 *txwi = (__le32 *)(e->skb->data + MT_SDIO_HDR_SIZE);1447unsigned int headroom = MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;1448struct ieee80211_sta *sta;1449struct mt76_wcid *wcid;1450u16 idx;14511452idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);1453wcid = __mt76_wcid_ptr(mdev, idx);1454sta = wcid_to_sta(wcid);14551456if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))1457mt7925_tx_check_aggr(sta, e->skb, wcid);14581459skb_pull(e->skb, headroom);1460mt76_tx_complete_skb(mdev, e->wcid, e->skb);1461}1462EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_complete_skb);14631464bool mt7925_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)1465{1466struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);14671468mt792x_mutex_acquire(dev);1469mt7925_mac_sta_poll(dev);1470mt792x_mutex_release(dev);14711472return false;1473}1474EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_status_data);14751476#if IS_ENABLED(CONFIG_IPV6)1477void mt7925_set_ipv6_ns_work(struct work_struct *work)1478{1479struct mt792x_dev *dev = container_of(work, struct mt792x_dev,1480ipv6_ns_work);1481struct sk_buff *skb;1482int ret = 0;14831484do {1485skb = skb_dequeue(&dev->ipv6_ns_list);14861487if (!skb)1488break;14891490mt792x_mutex_acquire(dev);1491ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,1492MCU_UNI_CMD(OFFLOAD), true);1493mt792x_mutex_release(dev);14941495} while (!ret);14961497if (ret)1498skb_queue_purge(&dev->ipv6_ns_list);1499}1500#endif150115021503