198686cd2SShayne Chen // SPDX-License-Identifier: ISC
298686cd2SShayne Chen /*
398686cd2SShayne Chen * Copyright (C) 2022 MediaTek Inc.
498686cd2SShayne Chen */
598686cd2SShayne Chen
698686cd2SShayne Chen #include <linux/etherdevice.h>
798686cd2SShayne Chen #include <linux/timekeeping.h>
8878161d5SRyder Lee #include "coredump.h"
998686cd2SShayne Chen #include "mt7996.h"
1098686cd2SShayne Chen #include "../dma.h"
1198686cd2SShayne Chen #include "mac.h"
1298686cd2SShayne Chen #include "mcu.h"
1398686cd2SShayne Chen
14ea5d99d0SRyder Lee #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
1598686cd2SShayne Chen
1698686cd2SShayne Chen static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
1798686cd2SShayne Chen .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
1898686cd2SShayne Chen .radar_pattern = {
1998686cd2SShayne Chen [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 },
2098686cd2SShayne Chen [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 },
2198686cd2SShayne Chen [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 },
2298686cd2SShayne Chen [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 },
2398686cd2SShayne Chen [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 },
2498686cd2SShayne Chen [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 },
2598686cd2SShayne Chen [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 },
2698686cd2SShayne Chen [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 },
2798686cd2SShayne Chen },
2898686cd2SShayne Chen };
2998686cd2SShayne Chen
3098686cd2SShayne Chen static const struct mt7996_dfs_radar_spec fcc_radar_specs = {
3198686cd2SShayne Chen .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
3298686cd2SShayne Chen .radar_pattern = {
3398686cd2SShayne Chen [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 },
3498686cd2SShayne Chen [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 },
3598686cd2SShayne Chen [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 },
3698686cd2SShayne Chen [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 },
3798686cd2SShayne Chen [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 },
3898686cd2SShayne Chen },
3998686cd2SShayne Chen };
4098686cd2SShayne Chen
4198686cd2SShayne Chen static const struct mt7996_dfs_radar_spec jp_radar_specs = {
4298686cd2SShayne Chen .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
4398686cd2SShayne Chen .radar_pattern = {
4498686cd2SShayne Chen [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 },
4598686cd2SShayne Chen [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 },
4698686cd2SShayne Chen [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 },
4798686cd2SShayne Chen [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 },
4898686cd2SShayne Chen [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 },
4998686cd2SShayne Chen [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 },
5098686cd2SShayne Chen [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 },
5198686cd2SShayne Chen [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 },
5298686cd2SShayne Chen },
5398686cd2SShayne Chen };
5498686cd2SShayne Chen
mt7996_rx_get_wcid(struct mt7996_dev * dev,u16 idx,bool unicast)5598686cd2SShayne Chen static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
5698686cd2SShayne Chen u16 idx, bool unicast)
5798686cd2SShayne Chen {
5898686cd2SShayne Chen struct mt7996_sta *sta;
5998686cd2SShayne Chen struct mt76_wcid *wcid;
6098686cd2SShayne Chen
6198686cd2SShayne Chen if (idx >= ARRAY_SIZE(dev->mt76.wcid))
6298686cd2SShayne Chen return NULL;
6398686cd2SShayne Chen
6498686cd2SShayne Chen wcid = rcu_dereference(dev->mt76.wcid[idx]);
6598686cd2SShayne Chen if (unicast || !wcid)
6698686cd2SShayne Chen return wcid;
6798686cd2SShayne Chen
6898686cd2SShayne Chen if (!wcid->sta)
6998686cd2SShayne Chen return NULL;
7098686cd2SShayne Chen
7198686cd2SShayne Chen sta = container_of(wcid, struct mt7996_sta, wcid);
7298686cd2SShayne Chen if (!sta->vif)
7398686cd2SShayne Chen return NULL;
7498686cd2SShayne Chen
7598686cd2SShayne Chen return &sta->vif->sta.wcid;
7698686cd2SShayne Chen }
7798686cd2SShayne Chen
mt7996_mac_wtbl_update(struct mt7996_dev * dev,int idx,u32 mask)7898686cd2SShayne Chen bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
7998686cd2SShayne Chen {
8098686cd2SShayne Chen mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
8198686cd2SShayne Chen FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
8298686cd2SShayne Chen
8398686cd2SShayne Chen return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
8498686cd2SShayne Chen 0, 5000);
8598686cd2SShayne Chen }
8698686cd2SShayne Chen
mt7996_mac_wtbl_lmac_addr(struct mt7996_dev * dev,u16 wcid,u8 dw)8798686cd2SShayne Chen u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw)
8898686cd2SShayne Chen {
8998686cd2SShayne Chen mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
9098686cd2SShayne Chen FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
9198686cd2SShayne Chen
9298686cd2SShayne Chen return MT_WTBL_LMAC_OFFS(wcid, dw);
9398686cd2SShayne Chen }
9498686cd2SShayne Chen
mt7996_mac_sta_poll(struct mt7996_dev * dev)9598686cd2SShayne Chen static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
9698686cd2SShayne Chen {
9798686cd2SShayne Chen static const u8 ac_to_tid[] = {
9898686cd2SShayne Chen [IEEE80211_AC_BE] = 0,
9998686cd2SShayne Chen [IEEE80211_AC_BK] = 1,
10098686cd2SShayne Chen [IEEE80211_AC_VI] = 4,
10198686cd2SShayne Chen [IEEE80211_AC_VO] = 6
10298686cd2SShayne Chen };
10398686cd2SShayne Chen struct ieee80211_sta *sta;
10498686cd2SShayne Chen struct mt7996_sta *msta;
10598686cd2SShayne Chen struct rate_info *rate;
10698686cd2SShayne Chen u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
10798686cd2SShayne Chen LIST_HEAD(sta_poll_list);
10898686cd2SShayne Chen int i;
10998686cd2SShayne Chen
110ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock);
111ea0f3867SLorenzo Bianconi list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
112ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock);
11398686cd2SShayne Chen
11498686cd2SShayne Chen rcu_read_lock();
11598686cd2SShayne Chen
11698686cd2SShayne Chen while (true) {
11798686cd2SShayne Chen bool clear = false;
11898686cd2SShayne Chen u32 addr, val;
11998686cd2SShayne Chen u16 idx;
120ea5d99d0SRyder Lee s8 rssi[4];
12198686cd2SShayne Chen u8 bw;
12298686cd2SShayne Chen
123ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock);
12498686cd2SShayne Chen if (list_empty(&sta_poll_list)) {
125ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock);
12698686cd2SShayne Chen break;
12798686cd2SShayne Chen }
12898686cd2SShayne Chen msta = list_first_entry(&sta_poll_list,
129e3b0311fSLorenzo Bianconi struct mt7996_sta, wcid.poll_list);
130e3b0311fSLorenzo Bianconi list_del_init(&msta->wcid.poll_list);
131ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock);
13298686cd2SShayne Chen
13398686cd2SShayne Chen idx = msta->wcid.idx;
134ea5d99d0SRyder Lee
135ea5d99d0SRyder Lee /* refresh peer's airtime reporting */
13698686cd2SShayne Chen addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);
13798686cd2SShayne Chen
13898686cd2SShayne Chen for (i = 0; i < IEEE80211_NUM_ACS; i++) {
13998686cd2SShayne Chen u32 tx_last = msta->airtime_ac[i];
14098686cd2SShayne Chen u32 rx_last = msta->airtime_ac[i + 4];
14198686cd2SShayne Chen
14298686cd2SShayne Chen msta->airtime_ac[i] = mt76_rr(dev, addr);
14398686cd2SShayne Chen msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
14498686cd2SShayne Chen
14598686cd2SShayne Chen tx_time[i] = msta->airtime_ac[i] - tx_last;
14698686cd2SShayne Chen rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
14798686cd2SShayne Chen
14898686cd2SShayne Chen if ((tx_last | rx_last) & BIT(30))
14998686cd2SShayne Chen clear = true;
15098686cd2SShayne Chen
15198686cd2SShayne Chen addr += 8;
15298686cd2SShayne Chen }
15398686cd2SShayne Chen
15498686cd2SShayne Chen if (clear) {
15598686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx,
15698686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
15798686cd2SShayne Chen memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
15898686cd2SShayne Chen }
15998686cd2SShayne Chen
16098686cd2SShayne Chen if (!msta->wcid.sta)
16198686cd2SShayne Chen continue;
16298686cd2SShayne Chen
16398686cd2SShayne Chen sta = container_of((void *)msta, struct ieee80211_sta,
16498686cd2SShayne Chen drv_priv);
16598686cd2SShayne Chen for (i = 0; i < IEEE80211_NUM_ACS; i++) {
16698686cd2SShayne Chen u8 q = mt76_connac_lmac_mapping(i);
16798686cd2SShayne Chen u32 tx_cur = tx_time[q];
16898686cd2SShayne Chen u32 rx_cur = rx_time[q];
16998686cd2SShayne Chen u8 tid = ac_to_tid[i];
17098686cd2SShayne Chen
17198686cd2SShayne Chen if (!tx_cur && !rx_cur)
17298686cd2SShayne Chen continue;
17398686cd2SShayne Chen
17498686cd2SShayne Chen ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
17598686cd2SShayne Chen }
17698686cd2SShayne Chen
17798686cd2SShayne Chen /* We don't support reading GI info from txs packets.
17898686cd2SShayne Chen * For accurate tx status reporting and AQL improvement,
17998686cd2SShayne Chen * we need to make sure that flags match so polling GI
18098686cd2SShayne Chen * from per-sta counters directly.
18198686cd2SShayne Chen */
18298686cd2SShayne Chen rate = &msta->wcid.rate;
18398686cd2SShayne Chen
18498686cd2SShayne Chen switch (rate->bw) {
18580f5a31dSShayne Chen case RATE_INFO_BW_320:
18680f5a31dSShayne Chen bw = IEEE80211_STA_RX_BW_320;
18780f5a31dSShayne Chen break;
18898686cd2SShayne Chen case RATE_INFO_BW_160:
18998686cd2SShayne Chen bw = IEEE80211_STA_RX_BW_160;
19098686cd2SShayne Chen break;
19198686cd2SShayne Chen case RATE_INFO_BW_80:
19298686cd2SShayne Chen bw = IEEE80211_STA_RX_BW_80;
19398686cd2SShayne Chen break;
19498686cd2SShayne Chen case RATE_INFO_BW_40:
19598686cd2SShayne Chen bw = IEEE80211_STA_RX_BW_40;
19698686cd2SShayne Chen break;
19798686cd2SShayne Chen default:
19898686cd2SShayne Chen bw = IEEE80211_STA_RX_BW_20;
19998686cd2SShayne Chen break;
20098686cd2SShayne Chen }
20198686cd2SShayne Chen
20298686cd2SShayne Chen addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6);
20398686cd2SShayne Chen val = mt76_rr(dev, addr);
20480f5a31dSShayne Chen if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {
20580f5a31dSShayne Chen addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5);
20680f5a31dSShayne Chen val = mt76_rr(dev, addr);
20780f5a31dSShayne Chen rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);
20880f5a31dSShayne Chen } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
20998686cd2SShayne Chen u8 offs = 24 + 2 * bw;
21098686cd2SShayne Chen
21198686cd2SShayne Chen rate->he_gi = (val & (0x3 << offs)) >> offs;
21298686cd2SShayne Chen } else if (rate->flags &
21398686cd2SShayne Chen (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
21498686cd2SShayne Chen if (val & BIT(12 + bw))
21598686cd2SShayne Chen rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
21698686cd2SShayne Chen else
21798686cd2SShayne Chen rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
21898686cd2SShayne Chen }
219ea5d99d0SRyder Lee
220ea5d99d0SRyder Lee /* get signal strength of resp frames (CTS/BA/ACK) */
221ea5d99d0SRyder Lee addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
222ea5d99d0SRyder Lee val = mt76_rr(dev, addr);
223ea5d99d0SRyder Lee
224ea5d99d0SRyder Lee rssi[0] = to_rssi(GENMASK(7, 0), val);
225ea5d99d0SRyder Lee rssi[1] = to_rssi(GENMASK(15, 8), val);
226ea5d99d0SRyder Lee rssi[2] = to_rssi(GENMASK(23, 16), val);
227ea5d99d0SRyder Lee rssi[3] = to_rssi(GENMASK(31, 14), val);
228ea5d99d0SRyder Lee
229ea5d99d0SRyder Lee msta->ack_signal =
230ea5d99d0SRyder Lee mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
231ea5d99d0SRyder Lee
232ea5d99d0SRyder Lee ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
23398686cd2SShayne Chen }
23498686cd2SShayne Chen
23598686cd2SShayne Chen rcu_read_unlock();
23698686cd2SShayne Chen }
23798686cd2SShayne Chen
mt7996_mac_enable_rtscts(struct mt7996_dev * dev,struct ieee80211_vif * vif,bool enable)238d75e739bSRyder Lee void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
239d75e739bSRyder Lee struct ieee80211_vif *vif, bool enable)
240d75e739bSRyder Lee {
241d75e739bSRyder Lee struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
242d75e739bSRyder Lee u32 addr;
243d75e739bSRyder Lee
244d75e739bSRyder Lee addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
245d75e739bSRyder Lee if (enable)
246d75e739bSRyder Lee mt76_set(dev, addr, BIT(5));
247d75e739bSRyder Lee else
248d75e739bSRyder Lee mt76_clear(dev, addr, BIT(5));
249d75e739bSRyder Lee }
250d75e739bSRyder Lee
mt7996_mac_set_fixed_rate_table(struct mt7996_dev * dev,u8 tbl_idx,u16 rate_idx)25115ee62e7SRyder Lee void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
25215ee62e7SRyder Lee u8 tbl_idx, u16 rate_idx)
25315ee62e7SRyder Lee {
25415ee62e7SRyder Lee u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;
25515ee62e7SRyder Lee
25615ee62e7SRyder Lee mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);
25715ee62e7SRyder Lee /* use wtbl spe idx */
25815ee62e7SRyder Lee mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);
25915ee62e7SRyder Lee mt76_wr(dev, MT_WTBL_ITCR, ctrl);
26015ee62e7SRyder Lee }
26115ee62e7SRyder Lee
26298686cd2SShayne Chen /* The HW does not translate the mac header to 802.3 for mesh point */
mt7996_reverse_frag0_hdr_trans(struct sk_buff * skb,u16 hdr_gap)26398686cd2SShayne Chen static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
26498686cd2SShayne Chen {
26598686cd2SShayne Chen struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
26698686cd2SShayne Chen struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
26798686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid;
26898686cd2SShayne Chen __le32 *rxd = (__le32 *)skb->data;
26998686cd2SShayne Chen struct ieee80211_sta *sta;
27098686cd2SShayne Chen struct ieee80211_vif *vif;
27198686cd2SShayne Chen struct ieee80211_hdr hdr;
27298686cd2SShayne Chen u16 frame_control;
27398686cd2SShayne Chen
27498686cd2SShayne Chen if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
27598686cd2SShayne Chen MT_RXD3_NORMAL_U2M)
27698686cd2SShayne Chen return -EINVAL;
27798686cd2SShayne Chen
27898686cd2SShayne Chen if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
27998686cd2SShayne Chen return -EINVAL;
28098686cd2SShayne Chen
28198686cd2SShayne Chen if (!msta || !msta->vif)
28298686cd2SShayne Chen return -EINVAL;
28398686cd2SShayne Chen
28498686cd2SShayne Chen sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
28598686cd2SShayne Chen vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
28698686cd2SShayne Chen
28798686cd2SShayne Chen /* store the info from RXD and ethhdr to avoid being overridden */
28898686cd2SShayne Chen frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);
28998686cd2SShayne Chen hdr.frame_control = cpu_to_le16(frame_control);
29098686cd2SShayne Chen hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL));
29198686cd2SShayne Chen hdr.duration_id = 0;
29298686cd2SShayne Chen
29398686cd2SShayne Chen ether_addr_copy(hdr.addr1, vif->addr);
29498686cd2SShayne Chen ether_addr_copy(hdr.addr2, sta->addr);
29598686cd2SShayne Chen switch (frame_control & (IEEE80211_FCTL_TODS |
29698686cd2SShayne Chen IEEE80211_FCTL_FROMDS)) {
29798686cd2SShayne Chen case 0:
29898686cd2SShayne Chen ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
29998686cd2SShayne Chen break;
30098686cd2SShayne Chen case IEEE80211_FCTL_FROMDS:
30198686cd2SShayne Chen ether_addr_copy(hdr.addr3, eth_hdr->h_source);
30298686cd2SShayne Chen break;
30398686cd2SShayne Chen case IEEE80211_FCTL_TODS:
30498686cd2SShayne Chen ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
30598686cd2SShayne Chen break;
30698686cd2SShayne Chen case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:
30798686cd2SShayne Chen ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
30898686cd2SShayne Chen ether_addr_copy(hdr.addr4, eth_hdr->h_source);
30998686cd2SShayne Chen break;
31098686cd2SShayne Chen default:
311aed8d9b5SLorenzo Bianconi return -EINVAL;
31298686cd2SShayne Chen }
31398686cd2SShayne Chen
31498686cd2SShayne Chen skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);
31598686cd2SShayne Chen if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||
31698686cd2SShayne Chen eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))
31798686cd2SShayne Chen ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);
31898686cd2SShayne Chen else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)
31998686cd2SShayne Chen ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);
32098686cd2SShayne Chen else
32198686cd2SShayne Chen skb_pull(skb, 2);
32298686cd2SShayne Chen
32398686cd2SShayne Chen if (ieee80211_has_order(hdr.frame_control))
32498686cd2SShayne Chen memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11],
32598686cd2SShayne Chen IEEE80211_HT_CTL_LEN);
32698686cd2SShayne Chen if (ieee80211_is_data_qos(hdr.frame_control)) {
32798686cd2SShayne Chen __le16 qos_ctrl;
32898686cd2SShayne Chen
32998686cd2SShayne Chen qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL));
33098686cd2SShayne Chen memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,
33198686cd2SShayne Chen IEEE80211_QOS_CTL_LEN);
33298686cd2SShayne Chen }
33398686cd2SShayne Chen
33498686cd2SShayne Chen if (ieee80211_has_a4(hdr.frame_control))
33598686cd2SShayne Chen memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
33698686cd2SShayne Chen else
33798686cd2SShayne Chen memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);
33898686cd2SShayne Chen
33998686cd2SShayne Chen return 0;
34098686cd2SShayne Chen }
34198686cd2SShayne Chen
34298686cd2SShayne Chen static int
mt7996_mac_fill_rx_rate(struct mt7996_dev * dev,struct mt76_rx_status * status,struct ieee80211_supported_band * sband,__le32 * rxv,u8 * mode)34398686cd2SShayne Chen mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
34498686cd2SShayne Chen struct mt76_rx_status *status,
34598686cd2SShayne Chen struct ieee80211_supported_band *sband,
34698686cd2SShayne Chen __le32 *rxv, u8 *mode)
34798686cd2SShayne Chen {
34898686cd2SShayne Chen u32 v0, v2;
34998686cd2SShayne Chen u8 stbc, gi, bw, dcm, nss;
35098686cd2SShayne Chen int i, idx;
35198686cd2SShayne Chen bool cck = false;
35298686cd2SShayne Chen
35398686cd2SShayne Chen v0 = le32_to_cpu(rxv[0]);
35498686cd2SShayne Chen v2 = le32_to_cpu(rxv[2]);
35598686cd2SShayne Chen
35698686cd2SShayne Chen idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
35798686cd2SShayne Chen i = idx;
35898686cd2SShayne Chen nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
35998686cd2SShayne Chen
36098686cd2SShayne Chen stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
36198686cd2SShayne Chen gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
36298686cd2SShayne Chen *mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
36398686cd2SShayne Chen dcm = FIELD_GET(MT_PRXV_DCM, v2);
36498686cd2SShayne Chen bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
36598686cd2SShayne Chen
36698686cd2SShayne Chen switch (*mode) {
36798686cd2SShayne Chen case MT_PHY_TYPE_CCK:
36898686cd2SShayne Chen cck = true;
36998686cd2SShayne Chen fallthrough;
37098686cd2SShayne Chen case MT_PHY_TYPE_OFDM:
37198686cd2SShayne Chen i = mt76_get_rate(&dev->mt76, sband, i, cck);
37298686cd2SShayne Chen break;
37398686cd2SShayne Chen case MT_PHY_TYPE_HT_GF:
37498686cd2SShayne Chen case MT_PHY_TYPE_HT:
37598686cd2SShayne Chen status->encoding = RX_ENC_HT;
37698686cd2SShayne Chen if (gi)
37798686cd2SShayne Chen status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
37898686cd2SShayne Chen if (i > 31)
37998686cd2SShayne Chen return -EINVAL;
38098686cd2SShayne Chen break;
38198686cd2SShayne Chen case MT_PHY_TYPE_VHT:
38298686cd2SShayne Chen status->nss = nss;
38398686cd2SShayne Chen status->encoding = RX_ENC_VHT;
38498686cd2SShayne Chen if (gi)
38598686cd2SShayne Chen status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
38698686cd2SShayne Chen if (i > 11)
38798686cd2SShayne Chen return -EINVAL;
38898686cd2SShayne Chen break;
38998686cd2SShayne Chen case MT_PHY_TYPE_HE_MU:
39098686cd2SShayne Chen case MT_PHY_TYPE_HE_SU:
39198686cd2SShayne Chen case MT_PHY_TYPE_HE_EXT_SU:
39298686cd2SShayne Chen case MT_PHY_TYPE_HE_TB:
39398686cd2SShayne Chen status->nss = nss;
39498686cd2SShayne Chen status->encoding = RX_ENC_HE;
39598686cd2SShayne Chen i &= GENMASK(3, 0);
39698686cd2SShayne Chen
39798686cd2SShayne Chen if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
39898686cd2SShayne Chen status->he_gi = gi;
39998686cd2SShayne Chen
40098686cd2SShayne Chen status->he_dcm = dcm;
40198686cd2SShayne Chen break;
40280f5a31dSShayne Chen case MT_PHY_TYPE_EHT_SU:
40380f5a31dSShayne Chen case MT_PHY_TYPE_EHT_TRIG:
40480f5a31dSShayne Chen case MT_PHY_TYPE_EHT_MU:
40580f5a31dSShayne Chen status->nss = nss;
406021af945SShayne Chen status->encoding = RX_ENC_EHT;
407021af945SShayne Chen i &= GENMASK(3, 0);
408021af945SShayne Chen
409021af945SShayne Chen if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
410021af945SShayne Chen status->eht.gi = gi;
41180f5a31dSShayne Chen break;
41298686cd2SShayne Chen default:
41398686cd2SShayne Chen return -EINVAL;
41498686cd2SShayne Chen }
41598686cd2SShayne Chen status->rate_idx = i;
41698686cd2SShayne Chen
41798686cd2SShayne Chen switch (bw) {
41898686cd2SShayne Chen case IEEE80211_STA_RX_BW_20:
41998686cd2SShayne Chen break;
42098686cd2SShayne Chen case IEEE80211_STA_RX_BW_40:
42198686cd2SShayne Chen if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
42298686cd2SShayne Chen (idx & MT_PRXV_TX_ER_SU_106T)) {
42398686cd2SShayne Chen status->bw = RATE_INFO_BW_HE_RU;
42498686cd2SShayne Chen status->he_ru =
42598686cd2SShayne Chen NL80211_RATE_INFO_HE_RU_ALLOC_106;
42698686cd2SShayne Chen } else {
42798686cd2SShayne Chen status->bw = RATE_INFO_BW_40;
42898686cd2SShayne Chen }
42998686cd2SShayne Chen break;
43098686cd2SShayne Chen case IEEE80211_STA_RX_BW_80:
43198686cd2SShayne Chen status->bw = RATE_INFO_BW_80;
43298686cd2SShayne Chen break;
43398686cd2SShayne Chen case IEEE80211_STA_RX_BW_160:
43498686cd2SShayne Chen status->bw = RATE_INFO_BW_160;
43598686cd2SShayne Chen break;
436a4fcd1caSPeter Chiu /* rxv reports bw 320-1 and 320-2 separately */
43780f5a31dSShayne Chen case IEEE80211_STA_RX_BW_320:
438a4fcd1caSPeter Chiu case IEEE80211_STA_RX_BW_320 + 1:
43980f5a31dSShayne Chen status->bw = RATE_INFO_BW_320;
44080f5a31dSShayne Chen break;
44198686cd2SShayne Chen default:
44298686cd2SShayne Chen return -EINVAL;
44398686cd2SShayne Chen }
44498686cd2SShayne Chen
44598686cd2SShayne Chen status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
44698686cd2SShayne Chen if (*mode < MT_PHY_TYPE_HE_SU && gi)
44798686cd2SShayne Chen status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
44898686cd2SShayne Chen
44998686cd2SShayne Chen return 0;
45098686cd2SShayne Chen }
45198686cd2SShayne Chen
45298686cd2SShayne Chen static int
mt7996_mac_fill_rx(struct mt7996_dev * dev,struct sk_buff * skb)45398686cd2SShayne Chen mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
45498686cd2SShayne Chen {
45598686cd2SShayne Chen struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
45698686cd2SShayne Chen struct mt76_phy *mphy = &dev->mt76.phy;
45798686cd2SShayne Chen struct mt7996_phy *phy = &dev->phy;
45898686cd2SShayne Chen struct ieee80211_supported_band *sband;
45998686cd2SShayne Chen __le32 *rxd = (__le32 *)skb->data;
46098686cd2SShayne Chen __le32 *rxv = NULL;
46198686cd2SShayne Chen u32 rxd0 = le32_to_cpu(rxd[0]);
46298686cd2SShayne Chen u32 rxd1 = le32_to_cpu(rxd[1]);
46398686cd2SShayne Chen u32 rxd2 = le32_to_cpu(rxd[2]);
46498686cd2SShayne Chen u32 rxd3 = le32_to_cpu(rxd[3]);
46598686cd2SShayne Chen u32 rxd4 = le32_to_cpu(rxd[4]);
46698686cd2SShayne Chen u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
46798686cd2SShayne Chen u32 csum_status = *(u32 *)skb->cb;
46827db47abSRyder Lee u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP;
46927db47abSRyder Lee bool is_mesh = (rxd0 & mesh_mask) == mesh_mask;
47098686cd2SShayne Chen bool unicast, insert_ccmp_hdr = false;
47198686cd2SShayne Chen u8 remove_pad, amsdu_info, band_idx;
47298686cd2SShayne Chen u8 mode = 0, qos_ctl = 0;
47398686cd2SShayne Chen bool hdr_trans;
47498686cd2SShayne Chen u16 hdr_gap;
47598686cd2SShayne Chen u16 seq_ctrl = 0;
47698686cd2SShayne Chen __le16 fc = 0;
47798686cd2SShayne Chen int idx;
47898686cd2SShayne Chen
47998686cd2SShayne Chen memset(status, 0, sizeof(*status));
48098686cd2SShayne Chen
48198686cd2SShayne Chen band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1);
48298686cd2SShayne Chen mphy = dev->mt76.phys[band_idx];
48398686cd2SShayne Chen phy = mphy->priv;
48498686cd2SShayne Chen status->phy_idx = mphy->band_idx;
48598686cd2SShayne Chen
48698686cd2SShayne Chen if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
48798686cd2SShayne Chen return -EINVAL;
48898686cd2SShayne Chen
48998686cd2SShayne Chen if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
49098686cd2SShayne Chen return -EINVAL;
49198686cd2SShayne Chen
49298686cd2SShayne Chen hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
49398686cd2SShayne Chen if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
49498686cd2SShayne Chen return -EINVAL;
49598686cd2SShayne Chen
49698686cd2SShayne Chen /* ICV error or CCMP/BIP/WPI MIC error */
49798686cd2SShayne Chen if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
49898686cd2SShayne Chen status->flag |= RX_FLAG_ONLY_MONITOR;
49998686cd2SShayne Chen
50098686cd2SShayne Chen unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
50198686cd2SShayne Chen idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
50298686cd2SShayne Chen status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
50398686cd2SShayne Chen
50498686cd2SShayne Chen if (status->wcid) {
50598686cd2SShayne Chen struct mt7996_sta *msta;
50698686cd2SShayne Chen
50798686cd2SShayne Chen msta = container_of(status->wcid, struct mt7996_sta, wcid);
508ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock);
509e3b0311fSLorenzo Bianconi if (list_empty(&msta->wcid.poll_list))
510e3b0311fSLorenzo Bianconi list_add_tail(&msta->wcid.poll_list,
511ea0f3867SLorenzo Bianconi &dev->mt76.sta_poll_list);
512ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock);
51398686cd2SShayne Chen }
51498686cd2SShayne Chen
51598686cd2SShayne Chen status->freq = mphy->chandef.chan->center_freq;
51698686cd2SShayne Chen status->band = mphy->chandef.chan->band;
51798686cd2SShayne Chen if (status->band == NL80211_BAND_5GHZ)
51898686cd2SShayne Chen sband = &mphy->sband_5g.sband;
51998686cd2SShayne Chen else if (status->band == NL80211_BAND_6GHZ)
52098686cd2SShayne Chen sband = &mphy->sband_6g.sband;
52198686cd2SShayne Chen else
52298686cd2SShayne Chen sband = &mphy->sband_2g.sband;
52398686cd2SShayne Chen
52498686cd2SShayne Chen if (!sband->channels)
52598686cd2SShayne Chen return -EINVAL;
52698686cd2SShayne Chen
52798686cd2SShayne Chen if ((rxd0 & csum_mask) == csum_mask &&
52898686cd2SShayne Chen !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
52998686cd2SShayne Chen skb->ip_summed = CHECKSUM_UNNECESSARY;
53098686cd2SShayne Chen
53198686cd2SShayne Chen if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
53298686cd2SShayne Chen status->flag |= RX_FLAG_FAILED_FCS_CRC;
53398686cd2SShayne Chen
53498686cd2SShayne Chen if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
53598686cd2SShayne Chen status->flag |= RX_FLAG_MMIC_ERROR;
53698686cd2SShayne Chen
53798686cd2SShayne Chen if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
53898686cd2SShayne Chen !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
53998686cd2SShayne Chen status->flag |= RX_FLAG_DECRYPTED;
54098686cd2SShayne Chen status->flag |= RX_FLAG_IV_STRIPPED;
54198686cd2SShayne Chen status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
54298686cd2SShayne Chen }
54398686cd2SShayne Chen
54498686cd2SShayne Chen remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
54598686cd2SShayne Chen
54698686cd2SShayne Chen if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
54798686cd2SShayne Chen return -EINVAL;
54898686cd2SShayne Chen
54998686cd2SShayne Chen rxd += 8;
55098686cd2SShayne Chen if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
55198686cd2SShayne Chen u32 v0 = le32_to_cpu(rxd[0]);
55298686cd2SShayne Chen u32 v2 = le32_to_cpu(rxd[2]);
55398686cd2SShayne Chen
55498686cd2SShayne Chen fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0));
55598686cd2SShayne Chen qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);
55698686cd2SShayne Chen seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);
55798686cd2SShayne Chen
55898686cd2SShayne Chen rxd += 4;
55998686cd2SShayne Chen if ((u8 *)rxd - skb->data >= skb->len)
56098686cd2SShayne Chen return -EINVAL;
56198686cd2SShayne Chen }
56298686cd2SShayne Chen
56398686cd2SShayne Chen if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
56498686cd2SShayne Chen u8 *data = (u8 *)rxd;
56598686cd2SShayne Chen
56698686cd2SShayne Chen if (status->flag & RX_FLAG_DECRYPTED) {
56798686cd2SShayne Chen switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
56898686cd2SShayne Chen case MT_CIPHER_AES_CCMP:
56998686cd2SShayne Chen case MT_CIPHER_CCMP_CCX:
57098686cd2SShayne Chen case MT_CIPHER_CCMP_256:
57198686cd2SShayne Chen insert_ccmp_hdr =
57298686cd2SShayne Chen FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
57398686cd2SShayne Chen fallthrough;
57498686cd2SShayne Chen case MT_CIPHER_TKIP:
57598686cd2SShayne Chen case MT_CIPHER_TKIP_NO_MIC:
57698686cd2SShayne Chen case MT_CIPHER_GCMP:
57798686cd2SShayne Chen case MT_CIPHER_GCMP_256:
57898686cd2SShayne Chen status->iv[0] = data[5];
57998686cd2SShayne Chen status->iv[1] = data[4];
58098686cd2SShayne Chen status->iv[2] = data[3];
58198686cd2SShayne Chen status->iv[3] = data[2];
58298686cd2SShayne Chen status->iv[4] = data[1];
58398686cd2SShayne Chen status->iv[5] = data[0];
58498686cd2SShayne Chen break;
58598686cd2SShayne Chen default:
58698686cd2SShayne Chen break;
58798686cd2SShayne Chen }
58898686cd2SShayne Chen }
58998686cd2SShayne Chen rxd += 4;
59098686cd2SShayne Chen if ((u8 *)rxd - skb->data >= skb->len)
59198686cd2SShayne Chen return -EINVAL;
59298686cd2SShayne Chen }
59398686cd2SShayne Chen
59498686cd2SShayne Chen if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
59598686cd2SShayne Chen status->timestamp = le32_to_cpu(rxd[0]);
59698686cd2SShayne Chen status->flag |= RX_FLAG_MACTIME_START;
59798686cd2SShayne Chen
59898686cd2SShayne Chen if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
59998686cd2SShayne Chen status->flag |= RX_FLAG_AMPDU_DETAILS;
60098686cd2SShayne Chen
60198686cd2SShayne Chen /* all subframes of an A-MPDU have the same timestamp */
60298686cd2SShayne Chen if (phy->rx_ampdu_ts != status->timestamp) {
60398686cd2SShayne Chen if (!++phy->ampdu_ref)
60498686cd2SShayne Chen phy->ampdu_ref++;
60598686cd2SShayne Chen }
60698686cd2SShayne Chen phy->rx_ampdu_ts = status->timestamp;
60798686cd2SShayne Chen
60898686cd2SShayne Chen status->ampdu_ref = phy->ampdu_ref;
60998686cd2SShayne Chen }
61098686cd2SShayne Chen
61198686cd2SShayne Chen rxd += 4;
61298686cd2SShayne Chen if ((u8 *)rxd - skb->data >= skb->len)
61398686cd2SShayne Chen return -EINVAL;
61498686cd2SShayne Chen }
61598686cd2SShayne Chen
61698686cd2SShayne Chen /* RXD Group 3 - P-RXV */
61798686cd2SShayne Chen if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
61898686cd2SShayne Chen u32 v3;
61998686cd2SShayne Chen int ret;
62098686cd2SShayne Chen
62198686cd2SShayne Chen rxv = rxd;
62298686cd2SShayne Chen rxd += 4;
62398686cd2SShayne Chen if ((u8 *)rxd - skb->data >= skb->len)
62498686cd2SShayne Chen return -EINVAL;
62598686cd2SShayne Chen
62698686cd2SShayne Chen v3 = le32_to_cpu(rxv[3]);
62798686cd2SShayne Chen
62898686cd2SShayne Chen status->chains = mphy->antenna_mask;
62998686cd2SShayne Chen status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3);
63098686cd2SShayne Chen status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3);
63198686cd2SShayne Chen status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3);
63298686cd2SShayne Chen status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3);
63398686cd2SShayne Chen
63498686cd2SShayne Chen /* RXD Group 5 - C-RXV */
63598686cd2SShayne Chen if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
63698686cd2SShayne Chen rxd += 24;
63798686cd2SShayne Chen if ((u8 *)rxd - skb->data >= skb->len)
63898686cd2SShayne Chen return -EINVAL;
63998686cd2SShayne Chen }
64098686cd2SShayne Chen
64198686cd2SShayne Chen ret = mt7996_mac_fill_rx_rate(dev, status, sband, rxv, &mode);
64298686cd2SShayne Chen if (ret < 0)
64398686cd2SShayne Chen return ret;
64498686cd2SShayne Chen }
64598686cd2SShayne Chen
64698686cd2SShayne Chen amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
64798686cd2SShayne Chen status->amsdu = !!amsdu_info;
64898686cd2SShayne Chen if (status->amsdu) {
64998686cd2SShayne Chen status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
65098686cd2SShayne Chen status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
65198686cd2SShayne Chen }
65298686cd2SShayne Chen
65398686cd2SShayne Chen hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
65498686cd2SShayne Chen if (hdr_trans && ieee80211_has_morefrags(fc)) {
65598686cd2SShayne Chen if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
65698686cd2SShayne Chen return -EINVAL;
65798686cd2SShayne Chen hdr_trans = false;
65898686cd2SShayne Chen } else {
65998686cd2SShayne Chen int pad_start = 0;
66098686cd2SShayne Chen
66198686cd2SShayne Chen skb_pull(skb, hdr_gap);
66227db47abSRyder Lee if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) {
66398686cd2SShayne Chen pad_start = ieee80211_get_hdrlen_from_skb(skb);
664c55b4e78SRyder Lee } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
66598686cd2SShayne Chen /* When header translation failure is indicated,
66698686cd2SShayne Chen * the hardware will insert an extra 2-byte field
66798686cd2SShayne Chen * containing the data length after the protocol
668c55b4e78SRyder Lee * type field. This happens either when the LLC-SNAP
669c55b4e78SRyder Lee * pattern did not match, or if a VLAN header was
670c55b4e78SRyder Lee * detected.
67198686cd2SShayne Chen */
672c55b4e78SRyder Lee pad_start = 12;
673c55b4e78SRyder Lee if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
674c55b4e78SRyder Lee pad_start += 4;
675c55b4e78SRyder Lee else
676c55b4e78SRyder Lee pad_start = 0;
67798686cd2SShayne Chen }
67898686cd2SShayne Chen
67998686cd2SShayne Chen if (pad_start) {
68098686cd2SShayne Chen memmove(skb->data + 2, skb->data, pad_start);
68198686cd2SShayne Chen skb_pull(skb, 2);
68298686cd2SShayne Chen }
68398686cd2SShayne Chen }
68498686cd2SShayne Chen
68598686cd2SShayne Chen if (!hdr_trans) {
68698686cd2SShayne Chen struct ieee80211_hdr *hdr;
68798686cd2SShayne Chen
68898686cd2SShayne Chen if (insert_ccmp_hdr) {
68998686cd2SShayne Chen u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
69098686cd2SShayne Chen
69198686cd2SShayne Chen mt76_insert_ccmp_hdr(skb, key_id);
69298686cd2SShayne Chen }
69398686cd2SShayne Chen
69498686cd2SShayne Chen hdr = mt76_skb_get_hdr(skb);
69598686cd2SShayne Chen fc = hdr->frame_control;
69698686cd2SShayne Chen if (ieee80211_is_data_qos(fc)) {
69727db47abSRyder Lee u8 *qos = ieee80211_get_qos_ctl(hdr);
69827db47abSRyder Lee
69998686cd2SShayne Chen seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
70027db47abSRyder Lee qos_ctl = *qos;
70127db47abSRyder Lee
70227db47abSRyder Lee /* Mesh DA/SA/Length will be stripped after hardware
70327db47abSRyder Lee * de-amsdu, so here needs to clear amsdu present bit
70427db47abSRyder Lee * to mark it as a normal mesh frame.
70527db47abSRyder Lee */
70627db47abSRyder Lee if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
70727db47abSRyder Lee *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
70898686cd2SShayne Chen }
70998686cd2SShayne Chen } else {
71098686cd2SShayne Chen status->flag |= RX_FLAG_8023;
71198686cd2SShayne Chen }
71298686cd2SShayne Chen
71398686cd2SShayne Chen if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
71446d3304dSLorenzo Bianconi mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
71598686cd2SShayne Chen
71698686cd2SShayne Chen if (!status->wcid || !ieee80211_is_data_qos(fc))
71798686cd2SShayne Chen return 0;
71898686cd2SShayne Chen
71998686cd2SShayne Chen status->aggr = unicast &&
72098686cd2SShayne Chen !ieee80211_is_qos_nullfunc(fc);
72198686cd2SShayne Chen status->qos_ctl = qos_ctl;
72298686cd2SShayne Chen status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
72398686cd2SShayne Chen
72498686cd2SShayne Chen return 0;
72598686cd2SShayne Chen }
72698686cd2SShayne Chen
72798686cd2SShayne Chen static void
mt7996_mac_write_txwi_8023(struct mt7996_dev * dev,__le32 * txwi,struct sk_buff * skb,struct mt76_wcid * wcid)72898686cd2SShayne Chen mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
72998686cd2SShayne Chen struct sk_buff *skb, struct mt76_wcid *wcid)
73098686cd2SShayne Chen {
73198686cd2SShayne Chen u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
73298686cd2SShayne Chen u8 fc_type, fc_stype;
73398686cd2SShayne Chen u16 ethertype;
73498686cd2SShayne Chen bool wmm = false;
73598686cd2SShayne Chen u32 val;
73698686cd2SShayne Chen
73798686cd2SShayne Chen if (wcid->sta) {
73898686cd2SShayne Chen struct ieee80211_sta *sta;
73998686cd2SShayne Chen
74098686cd2SShayne Chen sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
74198686cd2SShayne Chen wmm = sta->wme;
74298686cd2SShayne Chen }
74398686cd2SShayne Chen
74498686cd2SShayne Chen val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
74598686cd2SShayne Chen FIELD_PREP(MT_TXD1_TID, tid);
74698686cd2SShayne Chen
74798686cd2SShayne Chen ethertype = get_unaligned_be16(&skb->data[12]);
74898686cd2SShayne Chen if (ethertype >= ETH_P_802_3_MIN)
74998686cd2SShayne Chen val |= MT_TXD1_ETH_802_3;
75098686cd2SShayne Chen
75198686cd2SShayne Chen txwi[1] |= cpu_to_le32(val);
75298686cd2SShayne Chen
75398686cd2SShayne Chen fc_type = IEEE80211_FTYPE_DATA >> 2;
75498686cd2SShayne Chen fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
75598686cd2SShayne Chen
75698686cd2SShayne Chen val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
75798686cd2SShayne Chen FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
75898686cd2SShayne Chen
75998686cd2SShayne Chen txwi[2] |= cpu_to_le32(val);
760*1152c2cdSPeter Chiu
761*1152c2cdSPeter Chiu if (wcid->amsdu)
762*1152c2cdSPeter Chiu txwi[3] |= cpu_to_le32(MT_TXD3_HW_AMSDU);
76398686cd2SShayne Chen }
76498686cd2SShayne Chen
76598686cd2SShayne Chen static void
mt7996_mac_write_txwi_80211(struct mt7996_dev * dev,__le32 * txwi,struct sk_buff * skb,struct ieee80211_key_conf * key)76698686cd2SShayne Chen mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
76798686cd2SShayne Chen struct sk_buff *skb, struct ieee80211_key_conf *key)
76898686cd2SShayne Chen {
76998686cd2SShayne Chen struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
77098686cd2SShayne Chen struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
77198686cd2SShayne Chen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
77298686cd2SShayne Chen bool multicast = is_multicast_ether_addr(hdr->addr1);
77398686cd2SShayne Chen u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
77498686cd2SShayne Chen __le16 fc = hdr->frame_control;
77598686cd2SShayne Chen u8 fc_type, fc_stype;
77698686cd2SShayne Chen u32 val;
77798686cd2SShayne Chen
77898686cd2SShayne Chen if (ieee80211_is_action(fc) &&
77998686cd2SShayne Chen mgmt->u.action.category == WLAN_CATEGORY_BACK &&
78098686cd2SShayne Chen mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
78198686cd2SShayne Chen tid = MT_TX_ADDBA;
78298686cd2SShayne Chen else if (ieee80211_is_mgmt(hdr->frame_control))
78398686cd2SShayne Chen tid = MT_TX_NORMAL;
78498686cd2SShayne Chen
78598686cd2SShayne Chen val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
78698686cd2SShayne Chen FIELD_PREP(MT_TXD1_HDR_INFO,
78798686cd2SShayne Chen ieee80211_get_hdrlen_from_skb(skb) / 2) |
78898686cd2SShayne Chen FIELD_PREP(MT_TXD1_TID, tid);
78998686cd2SShayne Chen
79098686cd2SShayne Chen if (!ieee80211_is_data(fc) || multicast ||
79198686cd2SShayne Chen info->flags & IEEE80211_TX_CTL_USE_MINRATE)
79298686cd2SShayne Chen val |= MT_TXD1_FIXED_RATE;
79398686cd2SShayne Chen
79498686cd2SShayne Chen if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
79598686cd2SShayne Chen key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
79698686cd2SShayne Chen val |= MT_TXD1_BIP;
79798686cd2SShayne Chen txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
79898686cd2SShayne Chen }
79998686cd2SShayne Chen
80098686cd2SShayne Chen txwi[1] |= cpu_to_le32(val);
80198686cd2SShayne Chen
80298686cd2SShayne Chen fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
80398686cd2SShayne Chen fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
80498686cd2SShayne Chen
80598686cd2SShayne Chen val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
80698686cd2SShayne Chen FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
80798686cd2SShayne Chen
80898686cd2SShayne Chen txwi[2] |= cpu_to_le32(val);
80998686cd2SShayne Chen
81098686cd2SShayne Chen txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
81198686cd2SShayne Chen if (ieee80211_is_beacon(fc)) {
81298686cd2SShayne Chen txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
81398686cd2SShayne Chen txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
81498686cd2SShayne Chen }
81598686cd2SShayne Chen
81698686cd2SShayne Chen if (info->flags & IEEE80211_TX_CTL_INJECTED) {
81798686cd2SShayne Chen u16 seqno = le16_to_cpu(hdr->seq_ctrl);
81898686cd2SShayne Chen
81998686cd2SShayne Chen if (ieee80211_is_back_req(hdr->frame_control)) {
82098686cd2SShayne Chen struct ieee80211_bar *bar;
82198686cd2SShayne Chen
82298686cd2SShayne Chen bar = (struct ieee80211_bar *)skb->data;
82398686cd2SShayne Chen seqno = le16_to_cpu(bar->start_seq_num);
82498686cd2SShayne Chen }
82598686cd2SShayne Chen
82698686cd2SShayne Chen val = MT_TXD3_SN_VALID |
82798686cd2SShayne Chen FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
82898686cd2SShayne Chen txwi[3] |= cpu_to_le32(val);
82998686cd2SShayne Chen txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
83098686cd2SShayne Chen }
83198686cd2SShayne Chen }
83298686cd2SShayne Chen
mt7996_mac_write_txwi(struct mt7996_dev * dev,__le32 * txwi,struct sk_buff * skb,struct mt76_wcid * wcid,struct ieee80211_key_conf * key,int pid,enum mt76_txq_id qid,u32 changed)83398686cd2SShayne Chen void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
834d0b6f86fSShayne Chen struct sk_buff *skb, struct mt76_wcid *wcid,
835d0b6f86fSShayne Chen struct ieee80211_key_conf *key, int pid,
836d0b6f86fSShayne Chen enum mt76_txq_id qid, u32 changed)
83798686cd2SShayne Chen {
83898686cd2SShayne Chen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
83998686cd2SShayne Chen struct ieee80211_vif *vif = info->control.vif;
84098686cd2SShayne Chen u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
84198686cd2SShayne Chen u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
84298686cd2SShayne Chen bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
8430cb065b9SLorenzo Bianconi struct mt76_vif *mvif;
84498686cd2SShayne Chen u16 tx_count = 15;
84598686cd2SShayne Chen u32 val;
84698686cd2SShayne Chen bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
84798686cd2SShayne Chen BSS_CHANGED_FILS_DISCOVERY));
848d0355945SMeiChia Chiu bool beacon = !!(changed & (BSS_CHANGED_BEACON |
849d0355945SMeiChia Chiu BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc);
85098686cd2SShayne Chen
8510cb065b9SLorenzo Bianconi mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
852ead44902SLorenzo Bianconi if (mvif) {
8530cb065b9SLorenzo Bianconi omac_idx = mvif->omac_idx;
8540cb065b9SLorenzo Bianconi wmm_idx = mvif->wmm_idx;
8550cb065b9SLorenzo Bianconi band_idx = mvif->band_idx;
85698686cd2SShayne Chen }
85798686cd2SShayne Chen
85898686cd2SShayne Chen if (inband_disc) {
85998686cd2SShayne Chen p_fmt = MT_TX_TYPE_FW;
86098686cd2SShayne Chen q_idx = MT_LMAC_ALTX0;
86198686cd2SShayne Chen } else if (beacon) {
86298686cd2SShayne Chen p_fmt = MT_TX_TYPE_FW;
86398686cd2SShayne Chen q_idx = MT_LMAC_BCN0;
864d0b6f86fSShayne Chen } else if (qid >= MT_TXQ_PSD) {
86598686cd2SShayne Chen p_fmt = MT_TX_TYPE_CT;
86698686cd2SShayne Chen q_idx = MT_LMAC_ALTX0;
86798686cd2SShayne Chen } else {
86898686cd2SShayne Chen p_fmt = MT_TX_TYPE_CT;
86998686cd2SShayne Chen q_idx = wmm_idx * MT7996_MAX_WMM_SETS +
87098686cd2SShayne Chen mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
87198686cd2SShayne Chen }
87298686cd2SShayne Chen
87398686cd2SShayne Chen val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
87498686cd2SShayne Chen FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
87598686cd2SShayne Chen FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
87698686cd2SShayne Chen txwi[0] = cpu_to_le32(val);
87798686cd2SShayne Chen
87898686cd2SShayne Chen val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
87998686cd2SShayne Chen FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
88098686cd2SShayne Chen
88198686cd2SShayne Chen if (band_idx)
88298686cd2SShayne Chen val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
88398686cd2SShayne Chen
88498686cd2SShayne Chen txwi[1] = cpu_to_le32(val);
88598686cd2SShayne Chen txwi[2] = 0;
88698686cd2SShayne Chen
88798686cd2SShayne Chen val = MT_TXD3_SW_POWER_MGMT |
88898686cd2SShayne Chen FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
88998686cd2SShayne Chen if (key)
89098686cd2SShayne Chen val |= MT_TXD3_PROTECT_FRAME;
89198686cd2SShayne Chen if (info->flags & IEEE80211_TX_CTL_NO_ACK)
89298686cd2SShayne Chen val |= MT_TXD3_NO_ACK;
89398686cd2SShayne Chen
89498686cd2SShayne Chen txwi[3] = cpu_to_le32(val);
89598686cd2SShayne Chen txwi[4] = 0;
89698686cd2SShayne Chen
89798686cd2SShayne Chen val = FIELD_PREP(MT_TXD5_PID, pid);
89898686cd2SShayne Chen if (pid >= MT_PACKET_ID_FIRST)
89998686cd2SShayne Chen val |= MT_TXD5_TX_STATUS_HOST;
90098686cd2SShayne Chen txwi[5] = cpu_to_le32(val);
90198686cd2SShayne Chen
90298686cd2SShayne Chen val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
90398686cd2SShayne Chen FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
90498686cd2SShayne Chen txwi[6] = cpu_to_le32(val);
90598686cd2SShayne Chen txwi[7] = 0;
90698686cd2SShayne Chen
90798686cd2SShayne Chen if (is_8023)
90898686cd2SShayne Chen mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid);
90998686cd2SShayne Chen else
91098686cd2SShayne Chen mt7996_mac_write_txwi_80211(dev, txwi, skb, key);
91198686cd2SShayne Chen
91298686cd2SShayne Chen if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
913ab0eec4bSRyder Lee struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
914ab0eec4bSRyder Lee bool mcast = ieee80211_is_data(hdr->frame_control) &&
915ab0eec4bSRyder Lee is_multicast_ether_addr(hdr->addr1);
916ead44902SLorenzo Bianconi u8 idx = MT7996_BASIC_RATES_TBL;
91798686cd2SShayne Chen
918ead44902SLorenzo Bianconi if (mvif) {
919ab0eec4bSRyder Lee if (mcast && mvif->mcast_rates_idx)
920ab0eec4bSRyder Lee idx = mvif->mcast_rates_idx;
921c2171b06SRyder Lee else if (beacon && mvif->beacon_rates_idx)
922c2171b06SRyder Lee idx = mvif->beacon_rates_idx;
923ead44902SLorenzo Bianconi else
924ead44902SLorenzo Bianconi idx = mvif->basic_rates_idx;
925ead44902SLorenzo Bianconi }
926ab0eec4bSRyder Lee
927cdc26ee8SRyder Lee txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
92898686cd2SShayne Chen txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
92998686cd2SShayne Chen }
93098686cd2SShayne Chen }
93198686cd2SShayne Chen
mt7996_tx_prepare_skb(struct mt76_dev * mdev,void * txwi_ptr,enum mt76_txq_id qid,struct mt76_wcid * wcid,struct ieee80211_sta * sta,struct mt76_tx_info * tx_info)93298686cd2SShayne Chen int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
93398686cd2SShayne Chen enum mt76_txq_id qid, struct mt76_wcid *wcid,
93498686cd2SShayne Chen struct ieee80211_sta *sta,
93598686cd2SShayne Chen struct mt76_tx_info *tx_info)
93698686cd2SShayne Chen {
93798686cd2SShayne Chen struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
93898686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
93998686cd2SShayne Chen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
94098686cd2SShayne Chen struct ieee80211_key_conf *key = info->control.hw_key;
94198686cd2SShayne Chen struct ieee80211_vif *vif = info->control.vif;
9423c38dfc1SLorenzo Bianconi struct mt76_connac_txp_common *txp;
94398686cd2SShayne Chen struct mt76_txwi_cache *t;
94498686cd2SShayne Chen int id, i, pid, nbuf = tx_info->nbuf - 1;
94598686cd2SShayne Chen bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
94698686cd2SShayne Chen u8 *txwi = (u8 *)txwi_ptr;
94798686cd2SShayne Chen
94898686cd2SShayne Chen if (unlikely(tx_info->skb->len <= ETH_HLEN))
94998686cd2SShayne Chen return -EINVAL;
95098686cd2SShayne Chen
95198686cd2SShayne Chen if (!wcid)
95298686cd2SShayne Chen wcid = &dev->mt76.global_wcid;
95398686cd2SShayne Chen
95498686cd2SShayne Chen if (sta) {
95598686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
95698686cd2SShayne Chen
95798686cd2SShayne Chen if (time_after(jiffies, msta->jiffies + HZ / 4)) {
95898686cd2SShayne Chen info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
95998686cd2SShayne Chen msta->jiffies = jiffies;
96098686cd2SShayne Chen }
96198686cd2SShayne Chen }
96298686cd2SShayne Chen
96398686cd2SShayne Chen t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
96498686cd2SShayne Chen t->skb = tx_info->skb;
96598686cd2SShayne Chen
96698686cd2SShayne Chen id = mt76_token_consume(mdev, &t);
96798686cd2SShayne Chen if (id < 0)
96898686cd2SShayne Chen return id;
96998686cd2SShayne Chen
97098686cd2SShayne Chen pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
971d0b6f86fSShayne Chen mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
972d0b6f86fSShayne Chen pid, qid, 0);
97398686cd2SShayne Chen
9743c38dfc1SLorenzo Bianconi txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
97598686cd2SShayne Chen for (i = 0; i < nbuf; i++) {
9763c38dfc1SLorenzo Bianconi txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
9773c38dfc1SLorenzo Bianconi txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
97898686cd2SShayne Chen }
9793c38dfc1SLorenzo Bianconi txp->fw.nbuf = nbuf;
98098686cd2SShayne Chen
9813b522cadSRyder Lee txp->fw.flags =
9823b522cadSRyder Lee cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD);
98398686cd2SShayne Chen
98498686cd2SShayne Chen if (!key)
9853c38dfc1SLorenzo Bianconi txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
98698686cd2SShayne Chen
98798686cd2SShayne Chen if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
9883c38dfc1SLorenzo Bianconi txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
98998686cd2SShayne Chen
99098686cd2SShayne Chen if (vif) {
99198686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
99298686cd2SShayne Chen
9933c38dfc1SLorenzo Bianconi txp->fw.bss_idx = mvif->mt76.idx;
99498686cd2SShayne Chen }
99598686cd2SShayne Chen
9963c38dfc1SLorenzo Bianconi txp->fw.token = cpu_to_le16(id);
9975ac5fbdcSPeter Chiu txp->fw.rept_wds_wcid = cpu_to_le16(sta ? wcid->idx : 0xfff);
9985ac5fbdcSPeter Chiu
999730be160SFelix Fietkau tx_info->skb = NULL;
100098686cd2SShayne Chen
100198686cd2SShayne Chen /* pass partial skb header to fw */
100298686cd2SShayne Chen tx_info->buf[1].len = MT_CT_PARSE_LEN;
100398686cd2SShayne Chen tx_info->buf[1].skip_unmap = true;
100498686cd2SShayne Chen tx_info->nbuf = MT_CT_DMA_BUF_NUM;
100598686cd2SShayne Chen
100698686cd2SShayne Chen return 0;
100798686cd2SShayne Chen }
100898686cd2SShayne Chen
100998686cd2SShayne Chen static void
mt7996_tx_check_aggr(struct ieee80211_sta * sta,__le32 * txwi)101098686cd2SShayne Chen mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
101198686cd2SShayne Chen {
101298686cd2SShayne Chen struct mt7996_sta *msta;
101398686cd2SShayne Chen u16 fc, tid;
101498686cd2SShayne Chen u32 val;
101598686cd2SShayne Chen
101698686cd2SShayne Chen if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
101798686cd2SShayne Chen return;
101898686cd2SShayne Chen
101998686cd2SShayne Chen tid = le32_get_bits(txwi[1], MT_TXD1_TID);
102098686cd2SShayne Chen if (tid >= 6) /* skip VO queue */
102198686cd2SShayne Chen return;
102298686cd2SShayne Chen
102398686cd2SShayne Chen val = le32_to_cpu(txwi[2]);
102498686cd2SShayne Chen fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
102598686cd2SShayne Chen FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
102698686cd2SShayne Chen if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
102798686cd2SShayne Chen return;
102898686cd2SShayne Chen
102998686cd2SShayne Chen msta = (struct mt7996_sta *)sta->drv_priv;
1030ef591d74SLorenzo Bianconi if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
103198686cd2SShayne Chen ieee80211_start_tx_ba_session(sta, tid, 0);
103298686cd2SShayne Chen }
103398686cd2SShayne Chen
103498686cd2SShayne Chen static void
mt7996_txwi_free(struct mt7996_dev * dev,struct mt76_txwi_cache * t,struct ieee80211_sta * sta,struct list_head * free_list)103598686cd2SShayne Chen mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
103698686cd2SShayne Chen struct ieee80211_sta *sta, struct list_head *free_list)
103798686cd2SShayne Chen {
103898686cd2SShayne Chen struct mt76_dev *mdev = &dev->mt76;
103998686cd2SShayne Chen struct mt76_wcid *wcid;
104098686cd2SShayne Chen __le32 *txwi;
104198686cd2SShayne Chen u16 wcid_idx;
104298686cd2SShayne Chen
104330495864SLorenzo Bianconi mt76_connac_txp_skb_unmap(mdev, t);
104498686cd2SShayne Chen if (!t->skb)
104598686cd2SShayne Chen goto out;
104698686cd2SShayne Chen
104798686cd2SShayne Chen txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
104898686cd2SShayne Chen if (sta) {
104998686cd2SShayne Chen wcid = (struct mt76_wcid *)sta->drv_priv;
105098686cd2SShayne Chen wcid_idx = wcid->idx;
105198686cd2SShayne Chen
105298686cd2SShayne Chen if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
105398686cd2SShayne Chen mt7996_tx_check_aggr(sta, txwi);
105498686cd2SShayne Chen } else {
10555ac5fbdcSPeter Chiu wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX);
105698686cd2SShayne Chen }
105798686cd2SShayne Chen
105898686cd2SShayne Chen __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
105998686cd2SShayne Chen
106098686cd2SShayne Chen out:
106198686cd2SShayne Chen t->skb = NULL;
106298686cd2SShayne Chen mt76_put_txwi(mdev, t);
106398686cd2SShayne Chen }
106498686cd2SShayne Chen
106598686cd2SShayne Chen static void
mt7996_mac_tx_free(struct mt7996_dev * dev,void * data,int len)106698686cd2SShayne Chen mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
106798686cd2SShayne Chen {
106898686cd2SShayne Chen __le32 *tx_free = (__le32 *)data, *cur_info;
106998686cd2SShayne Chen struct mt76_dev *mdev = &dev->mt76;
107098686cd2SShayne Chen struct mt76_phy *phy2 = mdev->phys[MT_BAND1];
107198686cd2SShayne Chen struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
107298686cd2SShayne Chen struct mt76_txwi_cache *txwi;
107398686cd2SShayne Chen struct ieee80211_sta *sta = NULL;
107498686cd2SShayne Chen LIST_HEAD(free_list);
107598686cd2SShayne Chen struct sk_buff *skb, *tmp;
107698686cd2SShayne Chen void *end = data + len;
107798686cd2SShayne Chen bool wake = false;
107898686cd2SShayne Chen u16 total, count = 0;
107998686cd2SShayne Chen
108098686cd2SShayne Chen /* clean DMA queues and unmap buffers first */
108198686cd2SShayne Chen mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
108298686cd2SShayne Chen mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
108398686cd2SShayne Chen if (phy2) {
108498686cd2SShayne Chen mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_PSD], false);
108598686cd2SShayne Chen mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_BE], false);
108698686cd2SShayne Chen }
108798686cd2SShayne Chen if (phy3) {
108898686cd2SShayne Chen mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_PSD], false);
108998686cd2SShayne Chen mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false);
109098686cd2SShayne Chen }
109198686cd2SShayne Chen
109298686cd2SShayne Chen if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4))
109398686cd2SShayne Chen return;
109498686cd2SShayne Chen
109598686cd2SShayne Chen total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);
109698686cd2SShayne Chen for (cur_info = &tx_free[2]; count < total; cur_info++) {
109798686cd2SShayne Chen u32 msdu, info;
109898686cd2SShayne Chen u8 i;
109998686cd2SShayne Chen
110098686cd2SShayne Chen if (WARN_ON_ONCE((void *)cur_info >= end))
110198686cd2SShayne Chen return;
110298686cd2SShayne Chen /* 1'b1: new wcid pair.
110398686cd2SShayne Chen * 1'b0: msdu_id with the same 'wcid pair' as above.
110498686cd2SShayne Chen */
110598686cd2SShayne Chen info = le32_to_cpu(*cur_info);
110698686cd2SShayne Chen if (info & MT_TXFREE_INFO_PAIR) {
110798686cd2SShayne Chen struct mt7996_sta *msta;
110898686cd2SShayne Chen struct mt76_wcid *wcid;
110998686cd2SShayne Chen u16 idx;
111098686cd2SShayne Chen
111198686cd2SShayne Chen idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
111298686cd2SShayne Chen wcid = rcu_dereference(dev->mt76.wcid[idx]);
111398686cd2SShayne Chen sta = wcid_to_sta(wcid);
111498686cd2SShayne Chen if (!sta)
111598686cd2SShayne Chen continue;
111698686cd2SShayne Chen
111798686cd2SShayne Chen msta = container_of(wcid, struct mt7996_sta, wcid);
1118ea0f3867SLorenzo Bianconi spin_lock_bh(&mdev->sta_poll_lock);
1119e3b0311fSLorenzo Bianconi if (list_empty(&msta->wcid.poll_list))
1120e3b0311fSLorenzo Bianconi list_add_tail(&msta->wcid.poll_list,
1121ea0f3867SLorenzo Bianconi &mdev->sta_poll_list);
1122ea0f3867SLorenzo Bianconi spin_unlock_bh(&mdev->sta_poll_lock);
112398686cd2SShayne Chen continue;
112498686cd2SShayne Chen }
112598686cd2SShayne Chen
112698686cd2SShayne Chen if (info & MT_TXFREE_INFO_HEADER)
112798686cd2SShayne Chen continue;
112898686cd2SShayne Chen
112998686cd2SShayne Chen for (i = 0; i < 2; i++) {
113098686cd2SShayne Chen msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID;
113198686cd2SShayne Chen if (msdu == MT_TXFREE_INFO_MSDU_ID)
113298686cd2SShayne Chen continue;
113398686cd2SShayne Chen
113498686cd2SShayne Chen count++;
113598686cd2SShayne Chen txwi = mt76_token_release(mdev, msdu, &wake);
113698686cd2SShayne Chen if (!txwi)
113798686cd2SShayne Chen continue;
113898686cd2SShayne Chen
113998686cd2SShayne Chen mt7996_txwi_free(dev, txwi, sta, &free_list);
114098686cd2SShayne Chen }
114198686cd2SShayne Chen }
114298686cd2SShayne Chen
114398686cd2SShayne Chen mt7996_mac_sta_poll(dev);
114498686cd2SShayne Chen
114598686cd2SShayne Chen if (wake)
114698686cd2SShayne Chen mt76_set_tx_blocked(&dev->mt76, false);
114798686cd2SShayne Chen
114898686cd2SShayne Chen mt76_worker_schedule(&dev->mt76.tx_worker);
114998686cd2SShayne Chen
115098686cd2SShayne Chen list_for_each_entry_safe(skb, tmp, &free_list, list) {
115198686cd2SShayne Chen skb_list_del_init(skb);
115298686cd2SShayne Chen napi_consume_skb(skb, 1);
115398686cd2SShayne Chen }
115498686cd2SShayne Chen }
115598686cd2SShayne Chen
115698686cd2SShayne Chen static bool
mt7996_mac_add_txs_skb(struct mt7996_dev * dev,struct mt76_wcid * wcid,int pid,__le32 * txs_data)1157d82e7c67SLorenzo Bianconi mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
1158d82e7c67SLorenzo Bianconi int pid, __le32 *txs_data)
115998686cd2SShayne Chen {
1160d82e7c67SLorenzo Bianconi struct mt76_sta_stats *stats = &wcid->stats;
116198686cd2SShayne Chen struct ieee80211_supported_band *sband;
116298686cd2SShayne Chen struct mt76_dev *mdev = &dev->mt76;
116398686cd2SShayne Chen struct mt76_phy *mphy;
116498686cd2SShayne Chen struct ieee80211_tx_info *info;
116598686cd2SShayne Chen struct sk_buff_head list;
116698686cd2SShayne Chen struct rate_info rate = {};
116798686cd2SShayne Chen struct sk_buff *skb;
116898686cd2SShayne Chen bool cck = false;
116998686cd2SShayne Chen u32 txrate, txs, mode, stbc;
117098686cd2SShayne Chen
117198686cd2SShayne Chen mt76_tx_status_lock(mdev, &list);
117298686cd2SShayne Chen skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
117398686cd2SShayne Chen if (!skb)
117498686cd2SShayne Chen goto out_no_skb;
117598686cd2SShayne Chen
117698686cd2SShayne Chen txs = le32_to_cpu(txs_data[0]);
117798686cd2SShayne Chen
117898686cd2SShayne Chen info = IEEE80211_SKB_CB(skb);
117998686cd2SShayne Chen if (!(txs & MT_TXS0_ACK_ERROR_MASK))
118098686cd2SShayne Chen info->flags |= IEEE80211_TX_STAT_ACK;
118198686cd2SShayne Chen
118298686cd2SShayne Chen info->status.ampdu_len = 1;
118398686cd2SShayne Chen info->status.ampdu_ack_len = !!(info->flags &
118498686cd2SShayne Chen IEEE80211_TX_STAT_ACK);
118598686cd2SShayne Chen
118698686cd2SShayne Chen info->status.rates[0].idx = -1;
118798686cd2SShayne Chen
118898686cd2SShayne Chen txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
118998686cd2SShayne Chen
119098686cd2SShayne Chen rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
119198686cd2SShayne Chen rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
119298686cd2SShayne Chen stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
119398686cd2SShayne Chen
119498686cd2SShayne Chen if (stbc && rate.nss > 1)
119598686cd2SShayne Chen rate.nss >>= 1;
119698686cd2SShayne Chen
119798686cd2SShayne Chen if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
119898686cd2SShayne Chen stats->tx_nss[rate.nss - 1]++;
119998686cd2SShayne Chen if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
120098686cd2SShayne Chen stats->tx_mcs[rate.mcs]++;
120198686cd2SShayne Chen
120298686cd2SShayne Chen mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
120398686cd2SShayne Chen switch (mode) {
120498686cd2SShayne Chen case MT_PHY_TYPE_CCK:
120598686cd2SShayne Chen cck = true;
120698686cd2SShayne Chen fallthrough;
120798686cd2SShayne Chen case MT_PHY_TYPE_OFDM:
120898686cd2SShayne Chen mphy = mt76_dev_phy(mdev, wcid->phy_idx);
120998686cd2SShayne Chen
121098686cd2SShayne Chen if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
121198686cd2SShayne Chen sband = &mphy->sband_5g.sband;
121298686cd2SShayne Chen else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
121398686cd2SShayne Chen sband = &mphy->sband_6g.sband;
121498686cd2SShayne Chen else
121598686cd2SShayne Chen sband = &mphy->sband_2g.sband;
121698686cd2SShayne Chen
121798686cd2SShayne Chen rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
121898686cd2SShayne Chen rate.legacy = sband->bitrates[rate.mcs].bitrate;
121998686cd2SShayne Chen break;
122098686cd2SShayne Chen case MT_PHY_TYPE_HT:
122198686cd2SShayne Chen case MT_PHY_TYPE_HT_GF:
122298686cd2SShayne Chen if (rate.mcs > 31)
122398686cd2SShayne Chen goto out;
122498686cd2SShayne Chen
122598686cd2SShayne Chen rate.flags = RATE_INFO_FLAGS_MCS;
122698686cd2SShayne Chen if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
122798686cd2SShayne Chen rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
122898686cd2SShayne Chen break;
122998686cd2SShayne Chen case MT_PHY_TYPE_VHT:
123098686cd2SShayne Chen if (rate.mcs > 9)
123198686cd2SShayne Chen goto out;
123298686cd2SShayne Chen
123398686cd2SShayne Chen rate.flags = RATE_INFO_FLAGS_VHT_MCS;
123498686cd2SShayne Chen break;
123598686cd2SShayne Chen case MT_PHY_TYPE_HE_SU:
123698686cd2SShayne Chen case MT_PHY_TYPE_HE_EXT_SU:
123798686cd2SShayne Chen case MT_PHY_TYPE_HE_TB:
123898686cd2SShayne Chen case MT_PHY_TYPE_HE_MU:
123998686cd2SShayne Chen if (rate.mcs > 11)
124098686cd2SShayne Chen goto out;
124198686cd2SShayne Chen
124298686cd2SShayne Chen rate.he_gi = wcid->rate.he_gi;
124398686cd2SShayne Chen rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
124498686cd2SShayne Chen rate.flags = RATE_INFO_FLAGS_HE_MCS;
124598686cd2SShayne Chen break;
124680f5a31dSShayne Chen case MT_PHY_TYPE_EHT_SU:
124780f5a31dSShayne Chen case MT_PHY_TYPE_EHT_TRIG:
124880f5a31dSShayne Chen case MT_PHY_TYPE_EHT_MU:
124980f5a31dSShayne Chen if (rate.mcs > 13)
125080f5a31dSShayne Chen goto out;
125180f5a31dSShayne Chen
125280f5a31dSShayne Chen rate.eht_gi = wcid->rate.eht_gi;
125380f5a31dSShayne Chen rate.flags = RATE_INFO_FLAGS_EHT_MCS;
125480f5a31dSShayne Chen break;
125598686cd2SShayne Chen default:
125698686cd2SShayne Chen goto out;
125798686cd2SShayne Chen }
125898686cd2SShayne Chen
125998686cd2SShayne Chen stats->tx_mode[mode]++;
126098686cd2SShayne Chen
126198686cd2SShayne Chen switch (FIELD_GET(MT_TXS0_BW, txs)) {
126280f5a31dSShayne Chen case IEEE80211_STA_RX_BW_320:
126380f5a31dSShayne Chen rate.bw = RATE_INFO_BW_320;
126480f5a31dSShayne Chen stats->tx_bw[4]++;
126580f5a31dSShayne Chen break;
126698686cd2SShayne Chen case IEEE80211_STA_RX_BW_160:
126798686cd2SShayne Chen rate.bw = RATE_INFO_BW_160;
126898686cd2SShayne Chen stats->tx_bw[3]++;
126998686cd2SShayne Chen break;
127098686cd2SShayne Chen case IEEE80211_STA_RX_BW_80:
127198686cd2SShayne Chen rate.bw = RATE_INFO_BW_80;
127298686cd2SShayne Chen stats->tx_bw[2]++;
127398686cd2SShayne Chen break;
127498686cd2SShayne Chen case IEEE80211_STA_RX_BW_40:
127598686cd2SShayne Chen rate.bw = RATE_INFO_BW_40;
127698686cd2SShayne Chen stats->tx_bw[1]++;
127798686cd2SShayne Chen break;
127898686cd2SShayne Chen default:
127998686cd2SShayne Chen rate.bw = RATE_INFO_BW_20;
128098686cd2SShayne Chen stats->tx_bw[0]++;
128198686cd2SShayne Chen break;
128298686cd2SShayne Chen }
128398686cd2SShayne Chen wcid->rate = rate;
128498686cd2SShayne Chen
128598686cd2SShayne Chen out:
128698686cd2SShayne Chen mt76_tx_status_skb_done(mdev, skb, &list);
128798686cd2SShayne Chen
128898686cd2SShayne Chen out_no_skb:
128998686cd2SShayne Chen mt76_tx_status_unlock(mdev, &list);
129098686cd2SShayne Chen
129198686cd2SShayne Chen return !!skb;
129298686cd2SShayne Chen }
129398686cd2SShayne Chen
mt7996_mac_add_txs(struct mt7996_dev * dev,void * data)129498686cd2SShayne Chen static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
129598686cd2SShayne Chen {
129698686cd2SShayne Chen struct mt7996_sta *msta = NULL;
129798686cd2SShayne Chen struct mt76_wcid *wcid;
129898686cd2SShayne Chen __le32 *txs_data = data;
129998686cd2SShayne Chen u16 wcidx;
130098686cd2SShayne Chen u8 pid;
130198686cd2SShayne Chen
130298686cd2SShayne Chen if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
130398686cd2SShayne Chen return;
130498686cd2SShayne Chen
130598686cd2SShayne Chen wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
130698686cd2SShayne Chen pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
130798686cd2SShayne Chen
130898686cd2SShayne Chen if (pid < MT_PACKET_ID_FIRST)
130998686cd2SShayne Chen return;
131098686cd2SShayne Chen
131143482540SShayne Chen if (wcidx >= mt7996_wtbl_size(dev))
131298686cd2SShayne Chen return;
131398686cd2SShayne Chen
131498686cd2SShayne Chen rcu_read_lock();
131598686cd2SShayne Chen
131698686cd2SShayne Chen wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
131798686cd2SShayne Chen if (!wcid)
131898686cd2SShayne Chen goto out;
131998686cd2SShayne Chen
132098686cd2SShayne Chen msta = container_of(wcid, struct mt7996_sta, wcid);
132198686cd2SShayne Chen
1322d82e7c67SLorenzo Bianconi mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
132398686cd2SShayne Chen
132498686cd2SShayne Chen if (!wcid->sta)
132598686cd2SShayne Chen goto out;
132698686cd2SShayne Chen
1327ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock);
1328e3b0311fSLorenzo Bianconi if (list_empty(&msta->wcid.poll_list))
1329e3b0311fSLorenzo Bianconi list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
1330ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock);
133198686cd2SShayne Chen
133298686cd2SShayne Chen out:
133398686cd2SShayne Chen rcu_read_unlock();
133498686cd2SShayne Chen }
133598686cd2SShayne Chen
mt7996_rx_check(struct mt76_dev * mdev,void * data,int len)133698686cd2SShayne Chen bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)
133798686cd2SShayne Chen {
133898686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
133998686cd2SShayne Chen __le32 *rxd = (__le32 *)data;
134098686cd2SShayne Chen __le32 *end = (__le32 *)&rxd[len / 4];
134198686cd2SShayne Chen enum rx_pkt_type type;
134298686cd2SShayne Chen
134398686cd2SShayne Chen type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
134498686cd2SShayne Chen if (type != PKT_TYPE_NORMAL) {
134598686cd2SShayne Chen u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
134698686cd2SShayne Chen
134798686cd2SShayne Chen if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
134898686cd2SShayne Chen MT_RXD0_SW_PKT_TYPE_FRAME))
134998686cd2SShayne Chen return true;
135098686cd2SShayne Chen }
135198686cd2SShayne Chen
135298686cd2SShayne Chen switch (type) {
135398686cd2SShayne Chen case PKT_TYPE_TXRX_NOTIFY:
135498686cd2SShayne Chen mt7996_mac_tx_free(dev, data, len);
135598686cd2SShayne Chen return false;
135698686cd2SShayne Chen case PKT_TYPE_TXS:
135798686cd2SShayne Chen for (rxd += 4; rxd + 8 <= end; rxd += 8)
135898686cd2SShayne Chen mt7996_mac_add_txs(dev, rxd);
135998686cd2SShayne Chen return false;
136098686cd2SShayne Chen case PKT_TYPE_RX_FW_MONITOR:
136198686cd2SShayne Chen mt7996_debugfs_rx_fw_monitor(dev, data, len);
136298686cd2SShayne Chen return false;
136398686cd2SShayne Chen default:
136498686cd2SShayne Chen return true;
136598686cd2SShayne Chen }
136698686cd2SShayne Chen }
136798686cd2SShayne Chen
mt7996_queue_rx_skb(struct mt76_dev * mdev,enum mt76_rxq_id q,struct sk_buff * skb,u32 * info)136898686cd2SShayne Chen void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
136998686cd2SShayne Chen struct sk_buff *skb, u32 *info)
137098686cd2SShayne Chen {
137198686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
137298686cd2SShayne Chen __le32 *rxd = (__le32 *)skb->data;
137398686cd2SShayne Chen __le32 *end = (__le32 *)&skb->data[skb->len];
137498686cd2SShayne Chen enum rx_pkt_type type;
137598686cd2SShayne Chen
137698686cd2SShayne Chen type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
137798686cd2SShayne Chen if (type != PKT_TYPE_NORMAL) {
137898686cd2SShayne Chen u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
137998686cd2SShayne Chen
138098686cd2SShayne Chen if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
138198686cd2SShayne Chen MT_RXD0_SW_PKT_TYPE_FRAME))
138298686cd2SShayne Chen type = PKT_TYPE_NORMAL;
138398686cd2SShayne Chen }
138498686cd2SShayne Chen
138598686cd2SShayne Chen switch (type) {
138698686cd2SShayne Chen case PKT_TYPE_TXRX_NOTIFY:
138798686cd2SShayne Chen mt7996_mac_tx_free(dev, skb->data, skb->len);
138898686cd2SShayne Chen napi_consume_skb(skb, 1);
138998686cd2SShayne Chen break;
139098686cd2SShayne Chen case PKT_TYPE_RX_EVENT:
139198686cd2SShayne Chen mt7996_mcu_rx_event(dev, skb);
139298686cd2SShayne Chen break;
139398686cd2SShayne Chen case PKT_TYPE_TXS:
139498686cd2SShayne Chen for (rxd += 4; rxd + 8 <= end; rxd += 8)
139598686cd2SShayne Chen mt7996_mac_add_txs(dev, rxd);
139698686cd2SShayne Chen dev_kfree_skb(skb);
139798686cd2SShayne Chen break;
139898686cd2SShayne Chen case PKT_TYPE_RX_FW_MONITOR:
139998686cd2SShayne Chen mt7996_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
140098686cd2SShayne Chen dev_kfree_skb(skb);
140198686cd2SShayne Chen break;
140298686cd2SShayne Chen case PKT_TYPE_NORMAL:
140398686cd2SShayne Chen if (!mt7996_mac_fill_rx(dev, skb)) {
140498686cd2SShayne Chen mt76_rx(&dev->mt76, q, skb);
140598686cd2SShayne Chen return;
140698686cd2SShayne Chen }
140798686cd2SShayne Chen fallthrough;
140898686cd2SShayne Chen default:
140998686cd2SShayne Chen dev_kfree_skb(skb);
141098686cd2SShayne Chen break;
141198686cd2SShayne Chen }
141298686cd2SShayne Chen }
141398686cd2SShayne Chen
mt7996_mac_cca_stats_reset(struct mt7996_phy * phy)141498686cd2SShayne Chen void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
141598686cd2SShayne Chen {
141698686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
141798686cd2SShayne Chen u32 reg = MT_WF_PHYRX_BAND_RX_CTRL1(phy->mt76->band_idx);
141898686cd2SShayne Chen
141998686cd2SShayne Chen mt76_clear(dev, reg, MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN);
142098686cd2SShayne Chen mt76_set(dev, reg, BIT(11) | BIT(9));
142198686cd2SShayne Chen }
142298686cd2SShayne Chen
mt7996_mac_reset_counters(struct mt7996_phy * phy)142398686cd2SShayne Chen void mt7996_mac_reset_counters(struct mt7996_phy *phy)
142498686cd2SShayne Chen {
142598686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
142698686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx;
142798686cd2SShayne Chen int i;
142898686cd2SShayne Chen
142998686cd2SShayne Chen for (i = 0; i < 16; i++)
143098686cd2SShayne Chen mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
143198686cd2SShayne Chen
143298686cd2SShayne Chen phy->mt76->survey_time = ktime_get_boottime();
143398686cd2SShayne Chen
143498686cd2SShayne Chen memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
143598686cd2SShayne Chen
143698686cd2SShayne Chen /* reset airtime counters */
143798686cd2SShayne Chen mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band_idx),
143898686cd2SShayne Chen MT_WF_RMAC_MIB_RXTIME_CLR);
143998686cd2SShayne Chen
144098686cd2SShayne Chen mt7996_mcu_get_chan_mib_info(phy, true);
144198686cd2SShayne Chen }
144298686cd2SShayne Chen
mt7996_mac_set_coverage_class(struct mt7996_phy * phy)144383a10ae2SPeter Chiu void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
144498686cd2SShayne Chen {
144598686cd2SShayne Chen s16 coverage_class = phy->coverage_class;
144698686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
144798686cd2SShayne Chen struct mt7996_phy *phy2 = mt7996_phy2(dev);
144898686cd2SShayne Chen struct mt7996_phy *phy3 = mt7996_phy3(dev);
144983a10ae2SPeter Chiu u32 reg_offset;
145098686cd2SShayne Chen u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
145198686cd2SShayne Chen FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
145298686cd2SShayne Chen u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
145398686cd2SShayne Chen FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
145498686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx;
145598686cd2SShayne Chen int offset;
145698686cd2SShayne Chen
145798686cd2SShayne Chen if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
145898686cd2SShayne Chen return;
145998686cd2SShayne Chen
146098686cd2SShayne Chen if (phy2)
146198686cd2SShayne Chen coverage_class = max_t(s16, dev->phy.coverage_class,
146298686cd2SShayne Chen phy2->coverage_class);
146398686cd2SShayne Chen
146498686cd2SShayne Chen if (phy3)
146598686cd2SShayne Chen coverage_class = max_t(s16, coverage_class,
146698686cd2SShayne Chen phy3->coverage_class);
146798686cd2SShayne Chen
146898686cd2SShayne Chen offset = 3 * coverage_class;
146998686cd2SShayne Chen reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
147098686cd2SShayne Chen FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
147198686cd2SShayne Chen
147298686cd2SShayne Chen mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
147398686cd2SShayne Chen mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
147498686cd2SShayne Chen }
147598686cd2SShayne Chen
mt7996_mac_enable_nf(struct mt7996_dev * dev,u8 band)147698686cd2SShayne Chen void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
147798686cd2SShayne Chen {
147898686cd2SShayne Chen mt76_set(dev, MT_WF_PHYRX_CSD_BAND_RXTD12(band),
147998686cd2SShayne Chen MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY |
148098686cd2SShayne Chen MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR);
148198686cd2SShayne Chen
148298686cd2SShayne Chen mt76_set(dev, MT_WF_PHYRX_BAND_RX_CTRL1(band),
148398686cd2SShayne Chen FIELD_PREP(MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN, 0x5));
148498686cd2SShayne Chen }
148598686cd2SShayne Chen
148698686cd2SShayne Chen static u8
mt7996_phy_get_nf(struct mt7996_phy * phy,u8 band_idx)148798686cd2SShayne Chen mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx)
148898686cd2SShayne Chen {
148998686cd2SShayne Chen static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
149098686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
149198686cd2SShayne Chen u32 val, sum = 0, n = 0;
149298686cd2SShayne Chen int ant, i;
149398686cd2SShayne Chen
149498686cd2SShayne Chen for (ant = 0; ant < hweight8(phy->mt76->antenna_mask); ant++) {
149598686cd2SShayne Chen u32 reg = MT_WF_PHYRX_CSD_IRPI(band_idx, ant);
149698686cd2SShayne Chen
149798686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
149898686cd2SShayne Chen val = mt76_rr(dev, reg);
149998686cd2SShayne Chen sum += val * nf_power[i];
150098686cd2SShayne Chen n += val;
150198686cd2SShayne Chen }
150298686cd2SShayne Chen }
150398686cd2SShayne Chen
150498686cd2SShayne Chen return n ? sum / n : 0;
150598686cd2SShayne Chen }
150698686cd2SShayne Chen
mt7996_update_channel(struct mt76_phy * mphy)150798686cd2SShayne Chen void mt7996_update_channel(struct mt76_phy *mphy)
150898686cd2SShayne Chen {
150998686cd2SShayne Chen struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv;
151098686cd2SShayne Chen struct mt76_channel_state *state = mphy->chan_state;
151198686cd2SShayne Chen int nf;
151298686cd2SShayne Chen
151398686cd2SShayne Chen mt7996_mcu_get_chan_mib_info(phy, false);
151498686cd2SShayne Chen
151598686cd2SShayne Chen nf = mt7996_phy_get_nf(phy, mphy->band_idx);
151698686cd2SShayne Chen if (!phy->noise)
151798686cd2SShayne Chen phy->noise = nf << 4;
151898686cd2SShayne Chen else if (nf)
151998686cd2SShayne Chen phy->noise += nf - (phy->noise >> 4);
152098686cd2SShayne Chen
152198686cd2SShayne Chen state->noise = -(phy->noise >> 4);
152298686cd2SShayne Chen }
152398686cd2SShayne Chen
152498686cd2SShayne Chen static bool
mt7996_wait_reset_state(struct mt7996_dev * dev,u32 state)152598686cd2SShayne Chen mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
152698686cd2SShayne Chen {
152798686cd2SShayne Chen bool ret;
152898686cd2SShayne Chen
152998686cd2SShayne Chen ret = wait_event_timeout(dev->reset_wait,
153027015b6fSBo Jiao (READ_ONCE(dev->recovery.state) & state),
153198686cd2SShayne Chen MT7996_RESET_TIMEOUT);
153298686cd2SShayne Chen
153398686cd2SShayne Chen WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
153498686cd2SShayne Chen return ret;
153598686cd2SShayne Chen }
153698686cd2SShayne Chen
153798686cd2SShayne Chen static void
mt7996_update_vif_beacon(void * priv,u8 * mac,struct ieee80211_vif * vif)153898686cd2SShayne Chen mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
153998686cd2SShayne Chen {
154098686cd2SShayne Chen struct ieee80211_hw *hw = priv;
154198686cd2SShayne Chen
154298686cd2SShayne Chen switch (vif->type) {
154398686cd2SShayne Chen case NL80211_IFTYPE_MESH_POINT:
154498686cd2SShayne Chen case NL80211_IFTYPE_ADHOC:
154598686cd2SShayne Chen case NL80211_IFTYPE_AP:
154698686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
154798686cd2SShayne Chen break;
154898686cd2SShayne Chen default:
154998686cd2SShayne Chen break;
155098686cd2SShayne Chen }
155198686cd2SShayne Chen }
155298686cd2SShayne Chen
155398686cd2SShayne Chen static void
mt7996_update_beacons(struct mt7996_dev * dev)155498686cd2SShayne Chen mt7996_update_beacons(struct mt7996_dev *dev)
155598686cd2SShayne Chen {
155698686cd2SShayne Chen struct mt76_phy *phy2, *phy3;
155798686cd2SShayne Chen
155898686cd2SShayne Chen ieee80211_iterate_active_interfaces(dev->mt76.hw,
155998686cd2SShayne Chen IEEE80211_IFACE_ITER_RESUME_ALL,
156098686cd2SShayne Chen mt7996_update_vif_beacon, dev->mt76.hw);
156198686cd2SShayne Chen
156298686cd2SShayne Chen phy2 = dev->mt76.phys[MT_BAND1];
156398686cd2SShayne Chen if (!phy2)
156498686cd2SShayne Chen return;
156598686cd2SShayne Chen
156698686cd2SShayne Chen ieee80211_iterate_active_interfaces(phy2->hw,
156798686cd2SShayne Chen IEEE80211_IFACE_ITER_RESUME_ALL,
156898686cd2SShayne Chen mt7996_update_vif_beacon, phy2->hw);
156998686cd2SShayne Chen
157098686cd2SShayne Chen phy3 = dev->mt76.phys[MT_BAND2];
157198686cd2SShayne Chen if (!phy3)
157298686cd2SShayne Chen return;
157398686cd2SShayne Chen
157498686cd2SShayne Chen ieee80211_iterate_active_interfaces(phy3->hw,
157598686cd2SShayne Chen IEEE80211_IFACE_ITER_RESUME_ALL,
157698686cd2SShayne Chen mt7996_update_vif_beacon, phy3->hw);
157798686cd2SShayne Chen }
157898686cd2SShayne Chen
mt7996_tx_token_put(struct mt7996_dev * dev)157998686cd2SShayne Chen void mt7996_tx_token_put(struct mt7996_dev *dev)
158098686cd2SShayne Chen {
158198686cd2SShayne Chen struct mt76_txwi_cache *txwi;
158298686cd2SShayne Chen int id;
158398686cd2SShayne Chen
158498686cd2SShayne Chen spin_lock_bh(&dev->mt76.token_lock);
158598686cd2SShayne Chen idr_for_each_entry(&dev->mt76.token, txwi, id) {
158698686cd2SShayne Chen mt7996_txwi_free(dev, txwi, NULL, NULL);
158798686cd2SShayne Chen dev->mt76.token_count--;
158898686cd2SShayne Chen }
158998686cd2SShayne Chen spin_unlock_bh(&dev->mt76.token_lock);
159098686cd2SShayne Chen idr_destroy(&dev->mt76.token);
159198686cd2SShayne Chen }
159298686cd2SShayne Chen
159327015b6fSBo Jiao static int
mt7996_mac_restart(struct mt7996_dev * dev)159427015b6fSBo Jiao mt7996_mac_restart(struct mt7996_dev *dev)
159527015b6fSBo Jiao {
159627015b6fSBo Jiao struct mt7996_phy *phy2, *phy3;
159727015b6fSBo Jiao struct mt76_dev *mdev = &dev->mt76;
159827015b6fSBo Jiao int i, ret;
159927015b6fSBo Jiao
160027015b6fSBo Jiao phy2 = mt7996_phy2(dev);
160127015b6fSBo Jiao phy3 = mt7996_phy3(dev);
160227015b6fSBo Jiao
160327015b6fSBo Jiao if (dev->hif2) {
160427015b6fSBo Jiao mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
160527015b6fSBo Jiao mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
160627015b6fSBo Jiao }
160727015b6fSBo Jiao
160827015b6fSBo Jiao if (dev_is_pci(mdev->dev)) {
160927015b6fSBo Jiao mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
161027015b6fSBo Jiao if (dev->hif2)
161127015b6fSBo Jiao mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
161227015b6fSBo Jiao }
161327015b6fSBo Jiao
161427015b6fSBo Jiao set_bit(MT76_RESET, &dev->mphy.state);
161527015b6fSBo Jiao set_bit(MT76_MCU_RESET, &dev->mphy.state);
161627015b6fSBo Jiao wake_up(&dev->mt76.mcu.wait);
161727015b6fSBo Jiao if (phy2) {
161827015b6fSBo Jiao set_bit(MT76_RESET, &phy2->mt76->state);
161927015b6fSBo Jiao set_bit(MT76_MCU_RESET, &phy2->mt76->state);
162027015b6fSBo Jiao }
162127015b6fSBo Jiao if (phy3) {
162227015b6fSBo Jiao set_bit(MT76_RESET, &phy3->mt76->state);
162327015b6fSBo Jiao set_bit(MT76_MCU_RESET, &phy3->mt76->state);
162427015b6fSBo Jiao }
162527015b6fSBo Jiao
162627015b6fSBo Jiao /* lock/unlock all queues to ensure that no tx is pending */
162727015b6fSBo Jiao mt76_txq_schedule_all(&dev->mphy);
162827015b6fSBo Jiao if (phy2)
162927015b6fSBo Jiao mt76_txq_schedule_all(phy2->mt76);
163027015b6fSBo Jiao if (phy3)
163127015b6fSBo Jiao mt76_txq_schedule_all(phy3->mt76);
163227015b6fSBo Jiao
163327015b6fSBo Jiao /* disable all tx/rx napi */
163427015b6fSBo Jiao mt76_worker_disable(&dev->mt76.tx_worker);
163527015b6fSBo Jiao mt76_for_each_q_rx(mdev, i) {
163627015b6fSBo Jiao if (mdev->q_rx[i].ndesc)
163727015b6fSBo Jiao napi_disable(&dev->mt76.napi[i]);
163827015b6fSBo Jiao }
163927015b6fSBo Jiao napi_disable(&dev->mt76.tx_napi);
164027015b6fSBo Jiao
164127015b6fSBo Jiao /* token reinit */
164227015b6fSBo Jiao mt7996_tx_token_put(dev);
164327015b6fSBo Jiao idr_init(&dev->mt76.token);
164427015b6fSBo Jiao
164527015b6fSBo Jiao mt7996_dma_reset(dev, true);
164627015b6fSBo Jiao
164727015b6fSBo Jiao local_bh_disable();
164827015b6fSBo Jiao mt76_for_each_q_rx(mdev, i) {
164927015b6fSBo Jiao if (mdev->q_rx[i].ndesc) {
165027015b6fSBo Jiao napi_enable(&dev->mt76.napi[i]);
165127015b6fSBo Jiao napi_schedule(&dev->mt76.napi[i]);
165227015b6fSBo Jiao }
165327015b6fSBo Jiao }
165427015b6fSBo Jiao local_bh_enable();
165527015b6fSBo Jiao clear_bit(MT76_MCU_RESET, &dev->mphy.state);
165627015b6fSBo Jiao clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
165727015b6fSBo Jiao
165827015b6fSBo Jiao mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
165927015b6fSBo Jiao mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
166027015b6fSBo Jiao if (dev->hif2) {
166127015b6fSBo Jiao mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
166227015b6fSBo Jiao mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
166327015b6fSBo Jiao }
166427015b6fSBo Jiao if (dev_is_pci(mdev->dev)) {
166527015b6fSBo Jiao mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
166627015b6fSBo Jiao if (dev->hif2)
166727015b6fSBo Jiao mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
166827015b6fSBo Jiao }
166927015b6fSBo Jiao
167027015b6fSBo Jiao /* load firmware */
167127015b6fSBo Jiao ret = mt7996_mcu_init_firmware(dev);
167227015b6fSBo Jiao if (ret)
167327015b6fSBo Jiao goto out;
167427015b6fSBo Jiao
167527015b6fSBo Jiao /* set the necessary init items */
167627015b6fSBo Jiao ret = mt7996_mcu_set_eeprom(dev);
167727015b6fSBo Jiao if (ret)
167827015b6fSBo Jiao goto out;
167927015b6fSBo Jiao
168027015b6fSBo Jiao mt7996_mac_init(dev);
168127015b6fSBo Jiao mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
168227015b6fSBo Jiao mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
168327015b6fSBo Jiao mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
168427015b6fSBo Jiao ret = mt7996_txbf_init(dev);
168527015b6fSBo Jiao
168627015b6fSBo Jiao if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
168727015b6fSBo Jiao ret = mt7996_run(dev->mphy.hw);
168827015b6fSBo Jiao if (ret)
168927015b6fSBo Jiao goto out;
169027015b6fSBo Jiao }
169127015b6fSBo Jiao
169227015b6fSBo Jiao if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
169327015b6fSBo Jiao ret = mt7996_run(phy2->mt76->hw);
169427015b6fSBo Jiao if (ret)
169527015b6fSBo Jiao goto out;
169627015b6fSBo Jiao }
169727015b6fSBo Jiao
169827015b6fSBo Jiao if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
169927015b6fSBo Jiao ret = mt7996_run(phy3->mt76->hw);
170027015b6fSBo Jiao if (ret)
170127015b6fSBo Jiao goto out;
170227015b6fSBo Jiao }
170327015b6fSBo Jiao
170427015b6fSBo Jiao out:
170527015b6fSBo Jiao /* reset done */
170627015b6fSBo Jiao clear_bit(MT76_RESET, &dev->mphy.state);
170727015b6fSBo Jiao if (phy2)
170827015b6fSBo Jiao clear_bit(MT76_RESET, &phy2->mt76->state);
170927015b6fSBo Jiao if (phy3)
171027015b6fSBo Jiao clear_bit(MT76_RESET, &phy3->mt76->state);
171127015b6fSBo Jiao
171227015b6fSBo Jiao local_bh_disable();
171327015b6fSBo Jiao napi_enable(&dev->mt76.tx_napi);
171427015b6fSBo Jiao napi_schedule(&dev->mt76.tx_napi);
171527015b6fSBo Jiao local_bh_enable();
171627015b6fSBo Jiao
171727015b6fSBo Jiao mt76_worker_enable(&dev->mt76.tx_worker);
171827015b6fSBo Jiao return ret;
171927015b6fSBo Jiao }
172027015b6fSBo Jiao
172127015b6fSBo Jiao static void
mt7996_mac_full_reset(struct mt7996_dev * dev)172227015b6fSBo Jiao mt7996_mac_full_reset(struct mt7996_dev *dev)
172327015b6fSBo Jiao {
172427015b6fSBo Jiao struct mt7996_phy *phy2, *phy3;
172527015b6fSBo Jiao int i;
172627015b6fSBo Jiao
172727015b6fSBo Jiao phy2 = mt7996_phy2(dev);
172827015b6fSBo Jiao phy3 = mt7996_phy3(dev);
172927015b6fSBo Jiao dev->recovery.hw_full_reset = true;
173027015b6fSBo Jiao
173127015b6fSBo Jiao wake_up(&dev->mt76.mcu.wait);
173227015b6fSBo Jiao ieee80211_stop_queues(mt76_hw(dev));
173327015b6fSBo Jiao if (phy2)
173427015b6fSBo Jiao ieee80211_stop_queues(phy2->mt76->hw);
173527015b6fSBo Jiao if (phy3)
173627015b6fSBo Jiao ieee80211_stop_queues(phy3->mt76->hw);
173727015b6fSBo Jiao
173827015b6fSBo Jiao cancel_delayed_work_sync(&dev->mphy.mac_work);
173927015b6fSBo Jiao if (phy2)
174027015b6fSBo Jiao cancel_delayed_work_sync(&phy2->mt76->mac_work);
174127015b6fSBo Jiao if (phy3)
174227015b6fSBo Jiao cancel_delayed_work_sync(&phy3->mt76->mac_work);
174327015b6fSBo Jiao
174427015b6fSBo Jiao mutex_lock(&dev->mt76.mutex);
174527015b6fSBo Jiao for (i = 0; i < 10; i++) {
174627015b6fSBo Jiao if (!mt7996_mac_restart(dev))
174727015b6fSBo Jiao break;
174827015b6fSBo Jiao }
174927015b6fSBo Jiao mutex_unlock(&dev->mt76.mutex);
175027015b6fSBo Jiao
175127015b6fSBo Jiao if (i == 10)
175227015b6fSBo Jiao dev_err(dev->mt76.dev, "chip full reset failed\n");
175327015b6fSBo Jiao
175427015b6fSBo Jiao ieee80211_restart_hw(mt76_hw(dev));
175527015b6fSBo Jiao if (phy2)
175627015b6fSBo Jiao ieee80211_restart_hw(phy2->mt76->hw);
175727015b6fSBo Jiao if (phy3)
175827015b6fSBo Jiao ieee80211_restart_hw(phy3->mt76->hw);
175927015b6fSBo Jiao
176027015b6fSBo Jiao ieee80211_wake_queues(mt76_hw(dev));
176127015b6fSBo Jiao if (phy2)
176227015b6fSBo Jiao ieee80211_wake_queues(phy2->mt76->hw);
176327015b6fSBo Jiao if (phy3)
176427015b6fSBo Jiao ieee80211_wake_queues(phy3->mt76->hw);
176527015b6fSBo Jiao
176627015b6fSBo Jiao dev->recovery.hw_full_reset = false;
176727015b6fSBo Jiao ieee80211_queue_delayed_work(mt76_hw(dev),
176827015b6fSBo Jiao &dev->mphy.mac_work,
176927015b6fSBo Jiao MT7996_WATCHDOG_TIME);
177027015b6fSBo Jiao if (phy2)
177127015b6fSBo Jiao ieee80211_queue_delayed_work(phy2->mt76->hw,
177227015b6fSBo Jiao &phy2->mt76->mac_work,
177327015b6fSBo Jiao MT7996_WATCHDOG_TIME);
177427015b6fSBo Jiao if (phy3)
177527015b6fSBo Jiao ieee80211_queue_delayed_work(phy3->mt76->hw,
177627015b6fSBo Jiao &phy3->mt76->mac_work,
177727015b6fSBo Jiao MT7996_WATCHDOG_TIME);
177827015b6fSBo Jiao }
177927015b6fSBo Jiao
mt7996_mac_reset_work(struct work_struct * work)178098686cd2SShayne Chen void mt7996_mac_reset_work(struct work_struct *work)
178198686cd2SShayne Chen {
178298686cd2SShayne Chen struct mt7996_phy *phy2, *phy3;
178398686cd2SShayne Chen struct mt7996_dev *dev;
178498686cd2SShayne Chen int i;
178598686cd2SShayne Chen
178698686cd2SShayne Chen dev = container_of(work, struct mt7996_dev, reset_work);
178798686cd2SShayne Chen phy2 = mt7996_phy2(dev);
178898686cd2SShayne Chen phy3 = mt7996_phy3(dev);
178998686cd2SShayne Chen
179027015b6fSBo Jiao /* chip full reset */
179127015b6fSBo Jiao if (dev->recovery.restart) {
179227015b6fSBo Jiao /* disable WA/WM WDT */
179327015b6fSBo Jiao mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
179427015b6fSBo Jiao MT_MCU_CMD_WDT_MASK);
179527015b6fSBo Jiao
179627015b6fSBo Jiao if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
179727015b6fSBo Jiao dev->recovery.wa_reset_count++;
179827015b6fSBo Jiao else
179927015b6fSBo Jiao dev->recovery.wm_reset_count++;
180027015b6fSBo Jiao
180127015b6fSBo Jiao mt7996_mac_full_reset(dev);
180227015b6fSBo Jiao
180327015b6fSBo Jiao /* enable mcu irq */
180427015b6fSBo Jiao mt7996_irq_enable(dev, MT_INT_MCU_CMD);
180527015b6fSBo Jiao mt7996_irq_disable(dev, 0);
180627015b6fSBo Jiao
180727015b6fSBo Jiao /* enable WA/WM WDT */
180827015b6fSBo Jiao mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
180927015b6fSBo Jiao
181027015b6fSBo Jiao dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
181127015b6fSBo Jiao dev->recovery.restart = false;
181227015b6fSBo Jiao return;
181327015b6fSBo Jiao }
181427015b6fSBo Jiao
181527015b6fSBo Jiao if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
181698686cd2SShayne Chen return;
181798686cd2SShayne Chen
181827015b6fSBo Jiao dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
181927015b6fSBo Jiao wiphy_name(dev->mt76.hw->wiphy));
182098686cd2SShayne Chen ieee80211_stop_queues(mt76_hw(dev));
182198686cd2SShayne Chen if (phy2)
182298686cd2SShayne Chen ieee80211_stop_queues(phy2->mt76->hw);
182398686cd2SShayne Chen if (phy3)
182498686cd2SShayne Chen ieee80211_stop_queues(phy3->mt76->hw);
182598686cd2SShayne Chen
182698686cd2SShayne Chen set_bit(MT76_RESET, &dev->mphy.state);
182798686cd2SShayne Chen set_bit(MT76_MCU_RESET, &dev->mphy.state);
182898686cd2SShayne Chen wake_up(&dev->mt76.mcu.wait);
182998686cd2SShayne Chen cancel_delayed_work_sync(&dev->mphy.mac_work);
183098686cd2SShayne Chen if (phy2) {
183198686cd2SShayne Chen set_bit(MT76_RESET, &phy2->mt76->state);
183298686cd2SShayne Chen cancel_delayed_work_sync(&phy2->mt76->mac_work);
183398686cd2SShayne Chen }
183498686cd2SShayne Chen if (phy3) {
183598686cd2SShayne Chen set_bit(MT76_RESET, &phy3->mt76->state);
183698686cd2SShayne Chen cancel_delayed_work_sync(&phy3->mt76->mac_work);
183798686cd2SShayne Chen }
183898686cd2SShayne Chen mt76_worker_disable(&dev->mt76.tx_worker);
183998686cd2SShayne Chen mt76_for_each_q_rx(&dev->mt76, i)
184098686cd2SShayne Chen napi_disable(&dev->mt76.napi[i]);
184198686cd2SShayne Chen napi_disable(&dev->mt76.tx_napi);
184298686cd2SShayne Chen
184398686cd2SShayne Chen mutex_lock(&dev->mt76.mutex);
184498686cd2SShayne Chen
184598686cd2SShayne Chen mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
184698686cd2SShayne Chen
184798686cd2SShayne Chen if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
184827015b6fSBo Jiao mt7996_dma_reset(dev, false);
184998686cd2SShayne Chen
185098686cd2SShayne Chen mt7996_tx_token_put(dev);
185198686cd2SShayne Chen idr_init(&dev->mt76.token);
185298686cd2SShayne Chen
185398686cd2SShayne Chen mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
185498686cd2SShayne Chen mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
185598686cd2SShayne Chen }
185698686cd2SShayne Chen
18578e8c09c7SBo Jiao mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
18588e8c09c7SBo Jiao mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
18598e8c09c7SBo Jiao
18608e8c09c7SBo Jiao /* enable DMA Tx/Tx and interrupt */
18618e8c09c7SBo Jiao mt7996_dma_start(dev, false);
18628e8c09c7SBo Jiao
186398686cd2SShayne Chen clear_bit(MT76_MCU_RESET, &dev->mphy.state);
186498686cd2SShayne Chen clear_bit(MT76_RESET, &dev->mphy.state);
186598686cd2SShayne Chen if (phy2)
186698686cd2SShayne Chen clear_bit(MT76_RESET, &phy2->mt76->state);
186798686cd2SShayne Chen if (phy3)
186898686cd2SShayne Chen clear_bit(MT76_RESET, &phy3->mt76->state);
186998686cd2SShayne Chen
187098686cd2SShayne Chen local_bh_disable();
187198686cd2SShayne Chen mt76_for_each_q_rx(&dev->mt76, i) {
187298686cd2SShayne Chen napi_enable(&dev->mt76.napi[i]);
187398686cd2SShayne Chen napi_schedule(&dev->mt76.napi[i]);
187498686cd2SShayne Chen }
187598686cd2SShayne Chen local_bh_enable();
187698686cd2SShayne Chen
1877ec193b41SLorenzo Bianconi tasklet_schedule(&dev->mt76.irq_tasklet);
187898686cd2SShayne Chen
187998686cd2SShayne Chen mt76_worker_enable(&dev->mt76.tx_worker);
188098686cd2SShayne Chen
188198686cd2SShayne Chen local_bh_disable();
188298686cd2SShayne Chen napi_enable(&dev->mt76.tx_napi);
188398686cd2SShayne Chen napi_schedule(&dev->mt76.tx_napi);
188498686cd2SShayne Chen local_bh_enable();
188598686cd2SShayne Chen
188698686cd2SShayne Chen ieee80211_wake_queues(mt76_hw(dev));
188798686cd2SShayne Chen if (phy2)
188898686cd2SShayne Chen ieee80211_wake_queues(phy2->mt76->hw);
188998686cd2SShayne Chen if (phy3)
189098686cd2SShayne Chen ieee80211_wake_queues(phy3->mt76->hw);
189198686cd2SShayne Chen
189298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex);
189398686cd2SShayne Chen
189498686cd2SShayne Chen mt7996_update_beacons(dev);
189598686cd2SShayne Chen
189698686cd2SShayne Chen ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
189798686cd2SShayne Chen MT7996_WATCHDOG_TIME);
189898686cd2SShayne Chen if (phy2)
189998686cd2SShayne Chen ieee80211_queue_delayed_work(phy2->mt76->hw,
190098686cd2SShayne Chen &phy2->mt76->mac_work,
190198686cd2SShayne Chen MT7996_WATCHDOG_TIME);
190298686cd2SShayne Chen if (phy3)
190398686cd2SShayne Chen ieee80211_queue_delayed_work(phy3->mt76->hw,
190498686cd2SShayne Chen &phy3->mt76->mac_work,
190598686cd2SShayne Chen MT7996_WATCHDOG_TIME);
190627015b6fSBo Jiao dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.",
190727015b6fSBo Jiao wiphy_name(dev->mt76.hw->wiphy));
190827015b6fSBo Jiao }
190927015b6fSBo Jiao
1910878161d5SRyder Lee /* firmware coredump */
mt7996_mac_dump_work(struct work_struct * work)1911878161d5SRyder Lee void mt7996_mac_dump_work(struct work_struct *work)
1912878161d5SRyder Lee {
1913878161d5SRyder Lee const struct mt7996_mem_region *mem_region;
1914878161d5SRyder Lee struct mt7996_crash_data *crash_data;
1915878161d5SRyder Lee struct mt7996_dev *dev;
1916878161d5SRyder Lee struct mt7996_mem_hdr *hdr;
1917878161d5SRyder Lee size_t buf_len;
1918878161d5SRyder Lee int i;
1919878161d5SRyder Lee u32 num;
1920878161d5SRyder Lee u8 *buf;
1921878161d5SRyder Lee
1922878161d5SRyder Lee dev = container_of(work, struct mt7996_dev, dump_work);
1923878161d5SRyder Lee
1924878161d5SRyder Lee mutex_lock(&dev->dump_mutex);
1925878161d5SRyder Lee
1926878161d5SRyder Lee crash_data = mt7996_coredump_new(dev);
1927878161d5SRyder Lee if (!crash_data) {
1928878161d5SRyder Lee mutex_unlock(&dev->dump_mutex);
1929878161d5SRyder Lee goto skip_coredump;
1930878161d5SRyder Lee }
1931878161d5SRyder Lee
1932878161d5SRyder Lee mem_region = mt7996_coredump_get_mem_layout(dev, &num);
1933878161d5SRyder Lee if (!mem_region || !crash_data->memdump_buf_len) {
1934878161d5SRyder Lee mutex_unlock(&dev->dump_mutex);
1935878161d5SRyder Lee goto skip_memdump;
1936878161d5SRyder Lee }
1937878161d5SRyder Lee
1938878161d5SRyder Lee buf = crash_data->memdump_buf;
1939878161d5SRyder Lee buf_len = crash_data->memdump_buf_len;
1940878161d5SRyder Lee
1941878161d5SRyder Lee /* dumping memory content... */
1942878161d5SRyder Lee memset(buf, 0, buf_len);
1943878161d5SRyder Lee for (i = 0; i < num; i++) {
1944878161d5SRyder Lee if (mem_region->len > buf_len) {
1945878161d5SRyder Lee dev_warn(dev->mt76.dev, "%s len %zu is too large\n",
1946878161d5SRyder Lee mem_region->name, mem_region->len);
1947878161d5SRyder Lee break;
1948878161d5SRyder Lee }
1949878161d5SRyder Lee
1950878161d5SRyder Lee /* reserve space for the header */
1951878161d5SRyder Lee hdr = (void *)buf;
1952878161d5SRyder Lee buf += sizeof(*hdr);
1953878161d5SRyder Lee buf_len -= sizeof(*hdr);
1954878161d5SRyder Lee
1955878161d5SRyder Lee mt7996_memcpy_fromio(dev, buf, mem_region->start,
1956878161d5SRyder Lee mem_region->len);
1957878161d5SRyder Lee
1958878161d5SRyder Lee hdr->start = mem_region->start;
1959878161d5SRyder Lee hdr->len = mem_region->len;
1960878161d5SRyder Lee
1961878161d5SRyder Lee if (!mem_region->len)
1962878161d5SRyder Lee /* note: the header remains, just with zero length */
1963878161d5SRyder Lee break;
1964878161d5SRyder Lee
1965878161d5SRyder Lee buf += mem_region->len;
1966878161d5SRyder Lee buf_len -= mem_region->len;
1967878161d5SRyder Lee
1968878161d5SRyder Lee mem_region++;
1969878161d5SRyder Lee }
1970878161d5SRyder Lee
1971878161d5SRyder Lee mutex_unlock(&dev->dump_mutex);
1972878161d5SRyder Lee
1973878161d5SRyder Lee skip_memdump:
1974878161d5SRyder Lee mt7996_coredump_submit(dev);
1975878161d5SRyder Lee skip_coredump:
1976878161d5SRyder Lee queue_work(dev->mt76.wq, &dev->reset_work);
1977878161d5SRyder Lee }
1978878161d5SRyder Lee
mt7996_reset(struct mt7996_dev * dev)197927015b6fSBo Jiao void mt7996_reset(struct mt7996_dev *dev)
198027015b6fSBo Jiao {
198127015b6fSBo Jiao if (!dev->recovery.hw_init_done)
198227015b6fSBo Jiao return;
198327015b6fSBo Jiao
198427015b6fSBo Jiao if (dev->recovery.hw_full_reset)
198527015b6fSBo Jiao return;
198627015b6fSBo Jiao
198727015b6fSBo Jiao /* wm/wa exception: do full recovery */
198827015b6fSBo Jiao if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
198927015b6fSBo Jiao dev->recovery.restart = true;
199027015b6fSBo Jiao dev_info(dev->mt76.dev,
199127015b6fSBo Jiao "%s indicated firmware crash, attempting recovery\n",
199227015b6fSBo Jiao wiphy_name(dev->mt76.hw->wiphy));
199327015b6fSBo Jiao
199427015b6fSBo Jiao mt7996_irq_disable(dev, MT_INT_MCU_CMD);
1995878161d5SRyder Lee queue_work(dev->mt76.wq, &dev->dump_work);
199627015b6fSBo Jiao return;
199727015b6fSBo Jiao }
199827015b6fSBo Jiao
199927015b6fSBo Jiao queue_work(dev->mt76.wq, &dev->reset_work);
200027015b6fSBo Jiao wake_up(&dev->reset_wait);
200198686cd2SShayne Chen }
200298686cd2SShayne Chen
mt7996_mac_update_stats(struct mt7996_phy * phy)200398686cd2SShayne Chen void mt7996_mac_update_stats(struct mt7996_phy *phy)
200498686cd2SShayne Chen {
200598214484SLorenzo Bianconi struct mt76_mib_stats *mib = &phy->mib;
200698686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
200798686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx;
200898686cd2SShayne Chen u32 cnt;
200998686cd2SShayne Chen int i;
201098686cd2SShayne Chen
201198686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR1(band_idx));
201298686cd2SShayne Chen mib->fcs_err_cnt += cnt;
201398686cd2SShayne Chen
201498686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR33(band_idx));
201598686cd2SShayne Chen mib->rx_fifo_full_cnt += cnt;
201698686cd2SShayne Chen
201798686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR31(band_idx));
201898686cd2SShayne Chen mib->rx_mpdu_cnt += cnt;
201998686cd2SShayne Chen
202098686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_SDR6(band_idx));
202198686cd2SShayne Chen mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
202298686cd2SShayne Chen
202398686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RVSR0(band_idx));
202498686cd2SShayne Chen mib->rx_vector_mismatch_cnt += cnt;
202598686cd2SShayne Chen
202698686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR35(band_idx));
202798686cd2SShayne Chen mib->rx_delimiter_fail_cnt += cnt;
202898686cd2SShayne Chen
202998686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR36(band_idx));
203098686cd2SShayne Chen mib->rx_len_mismatch_cnt += cnt;
203198686cd2SShayne Chen
203298686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR0(band_idx));
203398686cd2SShayne Chen mib->tx_ampdu_cnt += cnt;
203498686cd2SShayne Chen
203598686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR2(band_idx));
203698686cd2SShayne Chen mib->tx_stop_q_empty_cnt += cnt;
203798686cd2SShayne Chen
203898686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR3(band_idx));
203998686cd2SShayne Chen mib->tx_mpdu_attempts_cnt += cnt;
204098686cd2SShayne Chen
204198686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR4(band_idx));
204298686cd2SShayne Chen mib->tx_mpdu_success_cnt += cnt;
204398686cd2SShayne Chen
204498686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR27(band_idx));
204598686cd2SShayne Chen mib->rx_ampdu_cnt += cnt;
204698686cd2SShayne Chen
204798686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR28(band_idx));
204898686cd2SShayne Chen mib->rx_ampdu_bytes_cnt += cnt;
204998686cd2SShayne Chen
205098686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR29(band_idx));
205198686cd2SShayne Chen mib->rx_ampdu_valid_subframe_cnt += cnt;
205298686cd2SShayne Chen
205398686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RSCR30(band_idx));
205498686cd2SShayne Chen mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
205598686cd2SShayne Chen
205698686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_SDR27(band_idx));
205798686cd2SShayne Chen mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT, cnt);
205898686cd2SShayne Chen
205998686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_SDR28(band_idx));
206098686cd2SShayne Chen mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT, cnt);
206198686cd2SShayne Chen
206298686cd2SShayne Chen cnt = mt76_rr(dev, MT_UMIB_RPDCR(band_idx));
206398686cd2SShayne Chen mib->rx_pfdrop_cnt += cnt;
206498686cd2SShayne Chen
206598686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_RVSR1(band_idx));
206698686cd2SShayne Chen mib->rx_vec_queue_overflow_drop_cnt += cnt;
206798686cd2SShayne Chen
206898686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR1(band_idx));
206998686cd2SShayne Chen mib->rx_ba_cnt += cnt;
207098686cd2SShayne Chen
207198686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR0(band_idx));
207298686cd2SShayne Chen mib->tx_bf_ebf_ppdu_cnt += cnt;
207398686cd2SShayne Chen
207498686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR1(band_idx));
207598686cd2SShayne Chen mib->tx_bf_ibf_ppdu_cnt += cnt;
207698686cd2SShayne Chen
207798686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR2(band_idx));
207898686cd2SShayne Chen mib->tx_mu_bf_cnt += cnt;
207998686cd2SShayne Chen
208098686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR5(band_idx));
208198686cd2SShayne Chen mib->tx_mu_mpdu_cnt += cnt;
208298686cd2SShayne Chen
208398686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR6(band_idx));
208498686cd2SShayne Chen mib->tx_mu_acked_mpdu_cnt += cnt;
208598686cd2SShayne Chen
208698686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_TSCR7(band_idx));
208798686cd2SShayne Chen mib->tx_su_acked_mpdu_cnt += cnt;
208898686cd2SShayne Chen
208998686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR3(band_idx));
209098686cd2SShayne Chen mib->tx_bf_rx_fb_ht_cnt += cnt;
209198686cd2SShayne Chen mib->tx_bf_rx_fb_all_cnt += cnt;
209298686cd2SShayne Chen
209398686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR4(band_idx));
209498686cd2SShayne Chen mib->tx_bf_rx_fb_vht_cnt += cnt;
209598686cd2SShayne Chen mib->tx_bf_rx_fb_all_cnt += cnt;
209698686cd2SShayne Chen
209798686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR5(band_idx));
209898686cd2SShayne Chen mib->tx_bf_rx_fb_he_cnt += cnt;
209998686cd2SShayne Chen mib->tx_bf_rx_fb_all_cnt += cnt;
210098686cd2SShayne Chen
210198686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR6(band_idx));
210298686cd2SShayne Chen mib->tx_bf_rx_fb_eht_cnt += cnt;
210398686cd2SShayne Chen mib->tx_bf_rx_fb_all_cnt += cnt;
210498686cd2SShayne Chen
210598686cd2SShayne Chen cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(band_idx));
210698686cd2SShayne Chen mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt);
210798686cd2SShayne Chen mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt);
210898686cd2SShayne Chen mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt);
210998686cd2SShayne Chen
211098686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR7(band_idx));
211198686cd2SShayne Chen mib->tx_bf_fb_trig_cnt += cnt;
211298686cd2SShayne Chen
211398686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BSCR17(band_idx));
211498686cd2SShayne Chen mib->tx_bf_fb_cpl_cnt += cnt;
211598686cd2SShayne Chen
211698686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
211798686cd2SShayne Chen cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
211898686cd2SShayne Chen mib->tx_amsdu[i] += cnt;
211998686cd2SShayne Chen mib->tx_amsdu_cnt += cnt;
212098686cd2SShayne Chen }
212198686cd2SShayne Chen
212298686cd2SShayne Chen /* rts count */
212398686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BTSCR5(band_idx));
212498686cd2SShayne Chen mib->rts_cnt += cnt;
212598686cd2SShayne Chen
212698686cd2SShayne Chen /* rts retry count */
212798686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BTSCR6(band_idx));
212898686cd2SShayne Chen mib->rts_retries_cnt += cnt;
212998686cd2SShayne Chen
213098686cd2SShayne Chen /* ba miss count */
213198686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BTSCR0(band_idx));
213298686cd2SShayne Chen mib->ba_miss_cnt += cnt;
213398686cd2SShayne Chen
213498686cd2SShayne Chen /* ack fail count */
213598686cd2SShayne Chen cnt = mt76_rr(dev, MT_MIB_BFTFCR(band_idx));
213698686cd2SShayne Chen mib->ack_fail_cnt += cnt;
213798686cd2SShayne Chen
213898686cd2SShayne Chen for (i = 0; i < 16; i++) {
213998686cd2SShayne Chen cnt = mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
214098686cd2SShayne Chen phy->mt76->aggr_stats[i] += cnt;
214198686cd2SShayne Chen }
214298686cd2SShayne Chen }
214398686cd2SShayne Chen
mt7996_mac_sta_rc_work(struct work_struct * work)214498686cd2SShayne Chen void mt7996_mac_sta_rc_work(struct work_struct *work)
214598686cd2SShayne Chen {
214698686cd2SShayne Chen struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
214798686cd2SShayne Chen struct ieee80211_sta *sta;
214898686cd2SShayne Chen struct ieee80211_vif *vif;
214998686cd2SShayne Chen struct mt7996_sta *msta;
215098686cd2SShayne Chen u32 changed;
215198686cd2SShayne Chen LIST_HEAD(list);
215298686cd2SShayne Chen
2153ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock);
215498686cd2SShayne Chen list_splice_init(&dev->sta_rc_list, &list);
215598686cd2SShayne Chen
215698686cd2SShayne Chen while (!list_empty(&list)) {
215798686cd2SShayne Chen msta = list_first_entry(&list, struct mt7996_sta, rc_list);
215898686cd2SShayne Chen list_del_init(&msta->rc_list);
215998686cd2SShayne Chen changed = msta->changed;
216098686cd2SShayne Chen msta->changed = 0;
2161ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock);
216298686cd2SShayne Chen
216398686cd2SShayne Chen sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
216498686cd2SShayne Chen vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
216598686cd2SShayne Chen
216698686cd2SShayne Chen if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
216798686cd2SShayne Chen IEEE80211_RC_NSS_CHANGED |
216898686cd2SShayne Chen IEEE80211_RC_BW_CHANGED))
216998686cd2SShayne Chen mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
217098686cd2SShayne Chen
217198686cd2SShayne Chen /* TODO: smps change */
217298686cd2SShayne Chen
2173ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock);
217498686cd2SShayne Chen }
217598686cd2SShayne Chen
2176ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock);
217798686cd2SShayne Chen }
217898686cd2SShayne Chen
mt7996_mac_work(struct work_struct * work)217998686cd2SShayne Chen void mt7996_mac_work(struct work_struct *work)
218098686cd2SShayne Chen {
218198686cd2SShayne Chen struct mt7996_phy *phy;
218298686cd2SShayne Chen struct mt76_phy *mphy;
218398686cd2SShayne Chen
218498686cd2SShayne Chen mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
218598686cd2SShayne Chen mac_work.work);
218698686cd2SShayne Chen phy = mphy->priv;
218798686cd2SShayne Chen
218898686cd2SShayne Chen mutex_lock(&mphy->dev->mutex);
218998686cd2SShayne Chen
219098686cd2SShayne Chen mt76_update_survey(mphy);
219198686cd2SShayne Chen if (++mphy->mac_work_count == 5) {
219298686cd2SShayne Chen mphy->mac_work_count = 0;
219398686cd2SShayne Chen
219498686cd2SShayne Chen mt7996_mac_update_stats(phy);
219598686cd2SShayne Chen }
219698686cd2SShayne Chen
219798686cd2SShayne Chen mutex_unlock(&mphy->dev->mutex);
219898686cd2SShayne Chen
219998686cd2SShayne Chen mt76_tx_status_check(mphy->dev, false);
220098686cd2SShayne Chen
220198686cd2SShayne Chen ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
220298686cd2SShayne Chen MT7996_WATCHDOG_TIME);
220398686cd2SShayne Chen }
220498686cd2SShayne Chen
mt7996_dfs_stop_radar_detector(struct mt7996_phy * phy)220598686cd2SShayne Chen static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
220698686cd2SShayne Chen {
220798686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
220898686cd2SShayne Chen
220998686cd2SShayne Chen if (phy->rdd_state & BIT(0))
221098686cd2SShayne Chen mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0,
221198686cd2SShayne Chen MT_RX_SEL0, 0);
221298686cd2SShayne Chen if (phy->rdd_state & BIT(1))
221398686cd2SShayne Chen mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1,
221498686cd2SShayne Chen MT_RX_SEL0, 0);
221598686cd2SShayne Chen }
221698686cd2SShayne Chen
mt7996_dfs_start_rdd(struct mt7996_dev * dev,int chain)221798686cd2SShayne Chen static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)
221898686cd2SShayne Chen {
221998686cd2SShayne Chen int err, region;
222098686cd2SShayne Chen
222198686cd2SShayne Chen switch (dev->mt76.region) {
222298686cd2SShayne Chen case NL80211_DFS_ETSI:
222398686cd2SShayne Chen region = 0;
222498686cd2SShayne Chen break;
222598686cd2SShayne Chen case NL80211_DFS_JP:
222698686cd2SShayne Chen region = 2;
222798686cd2SShayne Chen break;
222898686cd2SShayne Chen case NL80211_DFS_FCC:
222998686cd2SShayne Chen default:
223098686cd2SShayne Chen region = 1;
223198686cd2SShayne Chen break;
223298686cd2SShayne Chen }
223398686cd2SShayne Chen
223498686cd2SShayne Chen err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain,
223598686cd2SShayne Chen MT_RX_SEL0, region);
223698686cd2SShayne Chen if (err < 0)
223798686cd2SShayne Chen return err;
223898686cd2SShayne Chen
223998686cd2SShayne Chen return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
224098686cd2SShayne Chen MT_RX_SEL0, 1);
224198686cd2SShayne Chen }
224298686cd2SShayne Chen
mt7996_dfs_start_radar_detector(struct mt7996_phy * phy)224398686cd2SShayne Chen static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
224498686cd2SShayne Chen {
224598686cd2SShayne Chen struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
224698686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
224798686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx;
224898686cd2SShayne Chen int err;
224998686cd2SShayne Chen
225098686cd2SShayne Chen /* start CAC */
225198686cd2SShayne Chen err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx,
225298686cd2SShayne Chen MT_RX_SEL0, 0);
225398686cd2SShayne Chen if (err < 0)
225498686cd2SShayne Chen return err;
225598686cd2SShayne Chen
225698686cd2SShayne Chen err = mt7996_dfs_start_rdd(dev, band_idx);
225798686cd2SShayne Chen if (err < 0)
225898686cd2SShayne Chen return err;
225998686cd2SShayne Chen
226098686cd2SShayne Chen phy->rdd_state |= BIT(band_idx);
226198686cd2SShayne Chen
226298686cd2SShayne Chen if (chandef->width == NL80211_CHAN_WIDTH_160 ||
226398686cd2SShayne Chen chandef->width == NL80211_CHAN_WIDTH_80P80) {
226498686cd2SShayne Chen err = mt7996_dfs_start_rdd(dev, 1);
226598686cd2SShayne Chen if (err < 0)
226698686cd2SShayne Chen return err;
226798686cd2SShayne Chen
226898686cd2SShayne Chen phy->rdd_state |= BIT(1);
226998686cd2SShayne Chen }
227098686cd2SShayne Chen
227198686cd2SShayne Chen return 0;
227298686cd2SShayne Chen }
227398686cd2SShayne Chen
227498686cd2SShayne Chen static int
mt7996_dfs_init_radar_specs(struct mt7996_phy * phy)227598686cd2SShayne Chen mt7996_dfs_init_radar_specs(struct mt7996_phy *phy)
227698686cd2SShayne Chen {
227798686cd2SShayne Chen const struct mt7996_dfs_radar_spec *radar_specs;
227898686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
227998686cd2SShayne Chen int err, i;
228098686cd2SShayne Chen
228198686cd2SShayne Chen switch (dev->mt76.region) {
228298686cd2SShayne Chen case NL80211_DFS_FCC:
228398686cd2SShayne Chen radar_specs = &fcc_radar_specs;
228498686cd2SShayne Chen err = mt7996_mcu_set_fcc5_lpn(dev, 8);
228598686cd2SShayne Chen if (err < 0)
228698686cd2SShayne Chen return err;
228798686cd2SShayne Chen break;
228898686cd2SShayne Chen case NL80211_DFS_ETSI:
228998686cd2SShayne Chen radar_specs = &etsi_radar_specs;
229098686cd2SShayne Chen break;
229198686cd2SShayne Chen case NL80211_DFS_JP:
229298686cd2SShayne Chen radar_specs = &jp_radar_specs;
229398686cd2SShayne Chen break;
229498686cd2SShayne Chen default:
229598686cd2SShayne Chen return -EINVAL;
229698686cd2SShayne Chen }
229798686cd2SShayne Chen
229898686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
229998686cd2SShayne Chen err = mt7996_mcu_set_radar_th(dev, i,
230098686cd2SShayne Chen &radar_specs->radar_pattern[i]);
230198686cd2SShayne Chen if (err < 0)
230298686cd2SShayne Chen return err;
230398686cd2SShayne Chen }
230498686cd2SShayne Chen
230598686cd2SShayne Chen return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
230698686cd2SShayne Chen }
230798686cd2SShayne Chen
mt7996_dfs_init_radar_detector(struct mt7996_phy * phy)230898686cd2SShayne Chen int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
230998686cd2SShayne Chen {
231098686cd2SShayne Chen struct mt7996_dev *dev = phy->dev;
231198686cd2SShayne Chen enum mt76_dfs_state dfs_state, prev_state;
231298686cd2SShayne Chen int err;
231398686cd2SShayne Chen
231498686cd2SShayne Chen prev_state = phy->mt76->dfs_state;
231598686cd2SShayne Chen dfs_state = mt76_phy_dfs_state(phy->mt76);
231698686cd2SShayne Chen
231798686cd2SShayne Chen if (prev_state == dfs_state)
231898686cd2SShayne Chen return 0;
231998686cd2SShayne Chen
232098686cd2SShayne Chen if (prev_state == MT_DFS_STATE_UNKNOWN)
232198686cd2SShayne Chen mt7996_dfs_stop_radar_detector(phy);
232298686cd2SShayne Chen
232398686cd2SShayne Chen if (dfs_state == MT_DFS_STATE_DISABLED)
232498686cd2SShayne Chen goto stop;
232598686cd2SShayne Chen
232698686cd2SShayne Chen if (prev_state <= MT_DFS_STATE_DISABLED) {
232798686cd2SShayne Chen err = mt7996_dfs_init_radar_specs(phy);
232898686cd2SShayne Chen if (err < 0)
232998686cd2SShayne Chen return err;
233098686cd2SShayne Chen
233198686cd2SShayne Chen err = mt7996_dfs_start_radar_detector(phy);
233298686cd2SShayne Chen if (err < 0)
233398686cd2SShayne Chen return err;
233498686cd2SShayne Chen
233598686cd2SShayne Chen phy->mt76->dfs_state = MT_DFS_STATE_CAC;
233698686cd2SShayne Chen }
233798686cd2SShayne Chen
233898686cd2SShayne Chen if (dfs_state == MT_DFS_STATE_CAC)
233998686cd2SShayne Chen return 0;
234098686cd2SShayne Chen
234198686cd2SShayne Chen err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END,
234298686cd2SShayne Chen phy->mt76->band_idx, MT_RX_SEL0, 0);
234398686cd2SShayne Chen if (err < 0) {
234498686cd2SShayne Chen phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
234598686cd2SShayne Chen return err;
234698686cd2SShayne Chen }
234798686cd2SShayne Chen
234898686cd2SShayne Chen phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
234998686cd2SShayne Chen return 0;
235098686cd2SShayne Chen
235198686cd2SShayne Chen stop:
235298686cd2SShayne Chen err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START,
235398686cd2SShayne Chen phy->mt76->band_idx, MT_RX_SEL0, 0);
235498686cd2SShayne Chen if (err < 0)
235598686cd2SShayne Chen return err;
235698686cd2SShayne Chen
235798686cd2SShayne Chen mt7996_dfs_stop_radar_detector(phy);
235898686cd2SShayne Chen phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
235998686cd2SShayne Chen
236098686cd2SShayne Chen return 0;
236198686cd2SShayne Chen }
236298686cd2SShayne Chen
236398686cd2SShayne Chen static int
mt7996_mac_twt_duration_align(int duration)236498686cd2SShayne Chen mt7996_mac_twt_duration_align(int duration)
236598686cd2SShayne Chen {
236698686cd2SShayne Chen return duration << 8;
236798686cd2SShayne Chen }
236898686cd2SShayne Chen
236998686cd2SShayne Chen static u64
mt7996_mac_twt_sched_list_add(struct mt7996_dev * dev,struct mt7996_twt_flow * flow)237098686cd2SShayne Chen mt7996_mac_twt_sched_list_add(struct mt7996_dev *dev,
237198686cd2SShayne Chen struct mt7996_twt_flow *flow)
237298686cd2SShayne Chen {
237398686cd2SShayne Chen struct mt7996_twt_flow *iter, *iter_next;
237498686cd2SShayne Chen u32 duration = flow->duration << 8;
237598686cd2SShayne Chen u64 start_tsf;
237698686cd2SShayne Chen
237798686cd2SShayne Chen iter = list_first_entry_or_null(&dev->twt_list,
237898686cd2SShayne Chen struct mt7996_twt_flow, list);
237998686cd2SShayne Chen if (!iter || !iter->sched || iter->start_tsf > duration) {
238098686cd2SShayne Chen /* add flow as first entry in the list */
238198686cd2SShayne Chen list_add(&flow->list, &dev->twt_list);
238298686cd2SShayne Chen return 0;
238398686cd2SShayne Chen }
238498686cd2SShayne Chen
238598686cd2SShayne Chen list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
238698686cd2SShayne Chen start_tsf = iter->start_tsf +
238798686cd2SShayne Chen mt7996_mac_twt_duration_align(iter->duration);
238898686cd2SShayne Chen if (list_is_last(&iter->list, &dev->twt_list))
238998686cd2SShayne Chen break;
239098686cd2SShayne Chen
239198686cd2SShayne Chen if (!iter_next->sched ||
239298686cd2SShayne Chen iter_next->start_tsf > start_tsf + duration) {
239398686cd2SShayne Chen list_add(&flow->list, &iter->list);
239498686cd2SShayne Chen goto out;
239598686cd2SShayne Chen }
239698686cd2SShayne Chen }
239798686cd2SShayne Chen
239898686cd2SShayne Chen /* add flow as last entry in the list */
239998686cd2SShayne Chen list_add_tail(&flow->list, &dev->twt_list);
240098686cd2SShayne Chen out:
240198686cd2SShayne Chen return start_tsf;
240298686cd2SShayne Chen }
240398686cd2SShayne Chen
mt7996_mac_check_twt_req(struct ieee80211_twt_setup * twt)240498686cd2SShayne Chen static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)
240598686cd2SShayne Chen {
240698686cd2SShayne Chen struct ieee80211_twt_params *twt_agrt;
240798686cd2SShayne Chen u64 interval, duration;
240898686cd2SShayne Chen u16 mantissa;
240998686cd2SShayne Chen u8 exp;
241098686cd2SShayne Chen
241198686cd2SShayne Chen /* only individual agreement supported */
241298686cd2SShayne Chen if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
241398686cd2SShayne Chen return -EOPNOTSUPP;
241498686cd2SShayne Chen
241598686cd2SShayne Chen /* only 256us unit supported */
241698686cd2SShayne Chen if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
241798686cd2SShayne Chen return -EOPNOTSUPP;
241898686cd2SShayne Chen
241998686cd2SShayne Chen twt_agrt = (struct ieee80211_twt_params *)twt->params;
242098686cd2SShayne Chen
242198686cd2SShayne Chen /* explicit agreement not supported */
242298686cd2SShayne Chen if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
242398686cd2SShayne Chen return -EOPNOTSUPP;
242498686cd2SShayne Chen
242598686cd2SShayne Chen exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
242698686cd2SShayne Chen le16_to_cpu(twt_agrt->req_type));
242798686cd2SShayne Chen mantissa = le16_to_cpu(twt_agrt->mantissa);
242898686cd2SShayne Chen duration = twt_agrt->min_twt_dur << 8;
242998686cd2SShayne Chen
243098686cd2SShayne Chen interval = (u64)mantissa << exp;
243198686cd2SShayne Chen if (interval < duration)
243298686cd2SShayne Chen return -EOPNOTSUPP;
243398686cd2SShayne Chen
243498686cd2SShayne Chen return 0;
243598686cd2SShayne Chen }
243698686cd2SShayne Chen
2437e6ed68cbSPeter Chiu static bool
mt7996_mac_twt_param_equal(struct mt7996_sta * msta,struct ieee80211_twt_params * twt_agrt)2438e6ed68cbSPeter Chiu mt7996_mac_twt_param_equal(struct mt7996_sta *msta,
2439e6ed68cbSPeter Chiu struct ieee80211_twt_params *twt_agrt)
2440e6ed68cbSPeter Chiu {
2441e6ed68cbSPeter Chiu u16 type = le16_to_cpu(twt_agrt->req_type);
2442e6ed68cbSPeter Chiu u8 exp;
2443e6ed68cbSPeter Chiu int i;
2444e6ed68cbSPeter Chiu
2445e6ed68cbSPeter Chiu exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type);
2446e6ed68cbSPeter Chiu for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) {
2447e6ed68cbSPeter Chiu struct mt7996_twt_flow *f;
2448e6ed68cbSPeter Chiu
2449e6ed68cbSPeter Chiu if (!(msta->twt.flowid_mask & BIT(i)))
2450e6ed68cbSPeter Chiu continue;
2451e6ed68cbSPeter Chiu
2452e6ed68cbSPeter Chiu f = &msta->twt.flow[i];
2453e6ed68cbSPeter Chiu if (f->duration == twt_agrt->min_twt_dur &&
2454e6ed68cbSPeter Chiu f->mantissa == twt_agrt->mantissa &&
2455e6ed68cbSPeter Chiu f->exp == exp &&
2456e6ed68cbSPeter Chiu f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) &&
2457e6ed68cbSPeter Chiu f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) &&
2458e6ed68cbSPeter Chiu f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER))
2459e6ed68cbSPeter Chiu return true;
2460e6ed68cbSPeter Chiu }
2461e6ed68cbSPeter Chiu
2462e6ed68cbSPeter Chiu return false;
2463e6ed68cbSPeter Chiu }
2464e6ed68cbSPeter Chiu
mt7996_mac_add_twt_setup(struct ieee80211_hw * hw,struct ieee80211_sta * sta,struct ieee80211_twt_setup * twt)246598686cd2SShayne Chen void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
246698686cd2SShayne Chen struct ieee80211_sta *sta,
246798686cd2SShayne Chen struct ieee80211_twt_setup *twt)
246898686cd2SShayne Chen {
246998686cd2SShayne Chen enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
247098686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
247198686cd2SShayne Chen struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
247298686cd2SShayne Chen u16 req_type = le16_to_cpu(twt_agrt->req_type);
247398686cd2SShayne Chen enum ieee80211_twt_setup_cmd sta_setup_cmd;
247498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw);
247598686cd2SShayne Chen struct mt7996_twt_flow *flow;
2476e6ed68cbSPeter Chiu u8 flowid, table_id, exp;
247798686cd2SShayne Chen
247898686cd2SShayne Chen if (mt7996_mac_check_twt_req(twt))
247998686cd2SShayne Chen goto out;
248098686cd2SShayne Chen
248198686cd2SShayne Chen mutex_lock(&dev->mt76.mutex);
248298686cd2SShayne Chen
248398686cd2SShayne Chen if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)
248498686cd2SShayne Chen goto unlock;
248598686cd2SShayne Chen
248698686cd2SShayne Chen if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
248798686cd2SShayne Chen goto unlock;
248898686cd2SShayne Chen
2489e6ed68cbSPeter Chiu if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) {
2490e6ed68cbSPeter Chiu setup_cmd = TWT_SETUP_CMD_DICTATE;
2491e6ed68cbSPeter Chiu twt_agrt->min_twt_dur = MT7996_MIN_TWT_DUR;
2492e6ed68cbSPeter Chiu goto unlock;
2493e6ed68cbSPeter Chiu }
2494e6ed68cbSPeter Chiu
2495e6ed68cbSPeter Chiu if (mt7996_mac_twt_param_equal(msta, twt_agrt))
2496e6ed68cbSPeter Chiu goto unlock;
2497e6ed68cbSPeter Chiu
249898686cd2SShayne Chen flowid = ffs(~msta->twt.flowid_mask) - 1;
2499e6ed68cbSPeter Chiu twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID);
2500e6ed68cbSPeter Chiu twt_agrt->req_type |= le16_encode_bits(flowid,
250198686cd2SShayne Chen IEEE80211_TWT_REQTYPE_FLOWID);
250298686cd2SShayne Chen
250398686cd2SShayne Chen table_id = ffs(~dev->twt.table_mask) - 1;
250498686cd2SShayne Chen exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
250598686cd2SShayne Chen sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
250698686cd2SShayne Chen
250798686cd2SShayne Chen flow = &msta->twt.flow[flowid];
250898686cd2SShayne Chen memset(flow, 0, sizeof(*flow));
250998686cd2SShayne Chen INIT_LIST_HEAD(&flow->list);
251098686cd2SShayne Chen flow->wcid = msta->wcid.idx;
251198686cd2SShayne Chen flow->table_id = table_id;
251298686cd2SShayne Chen flow->id = flowid;
251398686cd2SShayne Chen flow->duration = twt_agrt->min_twt_dur;
251498686cd2SShayne Chen flow->mantissa = twt_agrt->mantissa;
251598686cd2SShayne Chen flow->exp = exp;
251698686cd2SShayne Chen flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
251798686cd2SShayne Chen flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
251898686cd2SShayne Chen flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
251998686cd2SShayne Chen
252098686cd2SShayne Chen if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
252198686cd2SShayne Chen sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
252298686cd2SShayne Chen u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
252398686cd2SShayne Chen u64 flow_tsf, curr_tsf;
252498686cd2SShayne Chen u32 rem;
252598686cd2SShayne Chen
252698686cd2SShayne Chen flow->sched = true;
252798686cd2SShayne Chen flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
252898686cd2SShayne Chen curr_tsf = __mt7996_get_tsf(hw, msta->vif);
252998686cd2SShayne Chen div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
253098686cd2SShayne Chen flow_tsf = curr_tsf + interval - rem;
253198686cd2SShayne Chen twt_agrt->twt = cpu_to_le64(flow_tsf);
253298686cd2SShayne Chen } else {
253398686cd2SShayne Chen list_add_tail(&flow->list, &dev->twt_list);
253498686cd2SShayne Chen }
253598686cd2SShayne Chen flow->tsf = le64_to_cpu(twt_agrt->twt);
253698686cd2SShayne Chen
253798686cd2SShayne Chen if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
253898686cd2SShayne Chen goto unlock;
253998686cd2SShayne Chen
254098686cd2SShayne Chen setup_cmd = TWT_SETUP_CMD_ACCEPT;
254198686cd2SShayne Chen dev->twt.table_mask |= BIT(table_id);
254298686cd2SShayne Chen msta->twt.flowid_mask |= BIT(flowid);
254398686cd2SShayne Chen dev->twt.n_agrt++;
254498686cd2SShayne Chen
254598686cd2SShayne Chen unlock:
254698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex);
254798686cd2SShayne Chen out:
2548e6ed68cbSPeter Chiu twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD);
2549e6ed68cbSPeter Chiu twt_agrt->req_type |=
2550e6ed68cbSPeter Chiu le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD);
2551e6ed68cbSPeter Chiu twt->control = twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED;
255298686cd2SShayne Chen }
255398686cd2SShayne Chen
mt7996_mac_twt_teardown_flow(struct mt7996_dev * dev,struct mt7996_sta * msta,u8 flowid)255498686cd2SShayne Chen void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
255598686cd2SShayne Chen struct mt7996_sta *msta,
255698686cd2SShayne Chen u8 flowid)
255798686cd2SShayne Chen {
255898686cd2SShayne Chen struct mt7996_twt_flow *flow;
255998686cd2SShayne Chen
256098686cd2SShayne Chen lockdep_assert_held(&dev->mt76.mutex);
256198686cd2SShayne Chen
256298686cd2SShayne Chen if (flowid >= ARRAY_SIZE(msta->twt.flow))
256398686cd2SShayne Chen return;
256498686cd2SShayne Chen
256598686cd2SShayne Chen if (!(msta->twt.flowid_mask & BIT(flowid)))
256698686cd2SShayne Chen return;
256798686cd2SShayne Chen
256898686cd2SShayne Chen flow = &msta->twt.flow[flowid];
256998686cd2SShayne Chen if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow,
257098686cd2SShayne Chen MCU_TWT_AGRT_DELETE))
257198686cd2SShayne Chen return;
257298686cd2SShayne Chen
257398686cd2SShayne Chen list_del_init(&flow->list);
257498686cd2SShayne Chen msta->twt.flowid_mask &= ~BIT(flowid);
257598686cd2SShayne Chen dev->twt.table_mask &= ~BIT(flow->table_id);
257698686cd2SShayne Chen dev->twt.n_agrt--;
257798686cd2SShayne Chen }
2578