162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022 MediaTek Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/etherdevice.h> 762306a36Sopenharmony_ci#include <linux/timekeeping.h> 862306a36Sopenharmony_ci#include "coredump.h" 962306a36Sopenharmony_ci#include "mt7996.h" 1062306a36Sopenharmony_ci#include "../dma.h" 1162306a36Sopenharmony_ci#include "mac.h" 1262306a36Sopenharmony_ci#include "mcu.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic const struct mt7996_dfs_radar_spec etsi_radar_specs = { 1762306a36Sopenharmony_ci .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, 1862306a36Sopenharmony_ci .radar_pattern = { 1962306a36Sopenharmony_ci [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, 2062306a36Sopenharmony_ci [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, 2162306a36Sopenharmony_ci [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, 2262306a36Sopenharmony_ci [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, 2362306a36Sopenharmony_ci [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, 2462306a36Sopenharmony_ci [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, 2562306a36Sopenharmony_ci [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, 2662306a36Sopenharmony_ci [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, 2762306a36Sopenharmony_ci }, 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const struct mt7996_dfs_radar_spec fcc_radar_specs = { 3162306a36Sopenharmony_ci .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, 3262306a36Sopenharmony_ci .radar_pattern = { 3362306a36Sopenharmony_ci [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, 3462306a36Sopenharmony_ci [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, 3562306a36Sopenharmony_ci [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, 3662306a36Sopenharmony_ci [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, 3762306a36Sopenharmony_ci [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, 3862306a36Sopenharmony_ci }, 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic const struct mt7996_dfs_radar_spec jp_radar_specs = { 4262306a36Sopenharmony_ci .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, 4362306a36Sopenharmony_ci .radar_pattern = { 4462306a36Sopenharmony_ci [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, 4562306a36Sopenharmony_ci [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, 4662306a36Sopenharmony_ci [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, 4762306a36Sopenharmony_ci [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, 4862306a36Sopenharmony_ci [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, 4962306a36Sopenharmony_ci [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, 5062306a36Sopenharmony_ci [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, 5162306a36Sopenharmony_ci [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, 5662306a36Sopenharmony_ci u16 idx, bool unicast) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct mt7996_sta *sta; 5962306a36Sopenharmony_ci struct mt76_wcid *wcid; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (idx >= ARRAY_SIZE(dev->mt76.wcid)) 6262306a36Sopenharmony_ci return NULL; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 6562306a36Sopenharmony_ci if (unicast || !wcid) 6662306a36Sopenharmony_ci return wcid; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (!wcid->sta) 6962306a36Sopenharmony_ci return NULL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci sta = container_of(wcid, struct mt7996_sta, wcid); 7262306a36Sopenharmony_ci if (!sta->vif) 7362306a36Sopenharmony_ci return NULL; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return &sta->vif->sta.wcid; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cibool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, 8162306a36Sopenharmony_ci FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 8462306a36Sopenharmony_ci 0, 5000); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciu32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci mt76_wr(dev, MT_WTBLON_TOP_WDUCR, 9062306a36Sopenharmony_ci FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return MT_WTBL_LMAC_OFFS(wcid, dw); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void mt7996_mac_sta_poll(struct mt7996_dev *dev) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci static const u8 ac_to_tid[] = { 9862306a36Sopenharmony_ci [IEEE80211_AC_BE] = 0, 9962306a36Sopenharmony_ci [IEEE80211_AC_BK] = 1, 10062306a36Sopenharmony_ci [IEEE80211_AC_VI] = 4, 10162306a36Sopenharmony_ci [IEEE80211_AC_VO] = 6 10262306a36Sopenharmony_ci }; 10362306a36Sopenharmony_ci struct ieee80211_sta *sta; 10462306a36Sopenharmony_ci struct mt7996_sta *msta; 10562306a36Sopenharmony_ci struct rate_info *rate; 10662306a36Sopenharmony_ci u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; 10762306a36Sopenharmony_ci LIST_HEAD(sta_poll_list); 10862306a36Sopenharmony_ci int i; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 11162306a36Sopenharmony_ci list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); 11262306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci rcu_read_lock(); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci while (true) { 11762306a36Sopenharmony_ci bool clear = false; 11862306a36Sopenharmony_ci u32 addr, val; 11962306a36Sopenharmony_ci u16 idx; 12062306a36Sopenharmony_ci s8 rssi[4]; 12162306a36Sopenharmony_ci u8 bw; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 12462306a36Sopenharmony_ci if (list_empty(&sta_poll_list)) { 12562306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci msta = list_first_entry(&sta_poll_list, 12962306a36Sopenharmony_ci struct mt7996_sta, wcid.poll_list); 13062306a36Sopenharmony_ci list_del_init(&msta->wcid.poll_list); 13162306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci idx = msta->wcid.idx; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* refresh peer's airtime reporting */ 13662306a36Sopenharmony_ci addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 13962306a36Sopenharmony_ci u32 tx_last = msta->airtime_ac[i]; 14062306a36Sopenharmony_ci u32 rx_last = msta->airtime_ac[i + 4]; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci msta->airtime_ac[i] = mt76_rr(dev, addr); 14362306a36Sopenharmony_ci msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci tx_time[i] = msta->airtime_ac[i] - tx_last; 14662306a36Sopenharmony_ci rx_time[i] = msta->airtime_ac[i + 4] - rx_last; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if ((tx_last | rx_last) & BIT(30)) 14962306a36Sopenharmony_ci clear = true; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci addr += 8; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (clear) { 15562306a36Sopenharmony_ci mt7996_mac_wtbl_update(dev, idx, 15662306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 15762306a36Sopenharmony_ci memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (!msta->wcid.sta) 16162306a36Sopenharmony_ci continue; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, 16462306a36Sopenharmony_ci drv_priv); 16562306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 16662306a36Sopenharmony_ci u8 q = mt76_connac_lmac_mapping(i); 16762306a36Sopenharmony_ci u32 tx_cur = tx_time[q]; 16862306a36Sopenharmony_ci u32 rx_cur = rx_time[q]; 16962306a36Sopenharmony_ci u8 tid = ac_to_tid[i]; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!tx_cur && !rx_cur) 17262306a36Sopenharmony_ci continue; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* We don't support reading GI info from txs packets. 17862306a36Sopenharmony_ci * For accurate tx status reporting and AQL improvement, 17962306a36Sopenharmony_ci * we need to make sure that flags match so polling GI 18062306a36Sopenharmony_ci * from per-sta counters directly. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci rate = &msta->wcid.rate; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci switch (rate->bw) { 18562306a36Sopenharmony_ci case RATE_INFO_BW_320: 18662306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_320; 18762306a36Sopenharmony_ci break; 18862306a36Sopenharmony_ci case RATE_INFO_BW_160: 18962306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_160; 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci case RATE_INFO_BW_80: 19262306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_80; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci case RATE_INFO_BW_40: 19562306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_40; 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_20; 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6); 20362306a36Sopenharmony_ci val = mt76_rr(dev, addr); 20462306a36Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) { 20562306a36Sopenharmony_ci addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5); 20662306a36Sopenharmony_ci val = mt76_rr(dev, addr); 20762306a36Sopenharmony_ci rate->eht_gi = FIELD_GET(GENMASK(25, 24), val); 20862306a36Sopenharmony_ci } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { 20962306a36Sopenharmony_ci u8 offs = 24 + 2 * bw; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci rate->he_gi = (val & (0x3 << offs)) >> offs; 21262306a36Sopenharmony_ci } else if (rate->flags & 21362306a36Sopenharmony_ci (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) { 21462306a36Sopenharmony_ci if (val & BIT(12 + bw)) 21562306a36Sopenharmony_ci rate->flags |= RATE_INFO_FLAGS_SHORT_GI; 21662306a36Sopenharmony_ci else 21762306a36Sopenharmony_ci rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* get signal strength of resp frames (CTS/BA/ACK) */ 22162306a36Sopenharmony_ci addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34); 22262306a36Sopenharmony_ci val = mt76_rr(dev, addr); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci rssi[0] = to_rssi(GENMASK(7, 0), val); 22562306a36Sopenharmony_ci rssi[1] = to_rssi(GENMASK(15, 8), val); 22662306a36Sopenharmony_ci rssi[2] = to_rssi(GENMASK(23, 16), val); 22762306a36Sopenharmony_ci rssi[3] = to_rssi(GENMASK(31, 14), val); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci msta->ack_signal = 23062306a36Sopenharmony_ci mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci rcu_read_unlock(); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_civoid mt7996_mac_enable_rtscts(struct mt7996_dev *dev, 23962306a36Sopenharmony_ci struct ieee80211_vif *vif, bool enable) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 24262306a36Sopenharmony_ci u32 addr; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); 24562306a36Sopenharmony_ci if (enable) 24662306a36Sopenharmony_ci mt76_set(dev, addr, BIT(5)); 24762306a36Sopenharmony_ci else 24862306a36Sopenharmony_ci mt76_clear(dev, addr, BIT(5)); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_civoid mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, 25262306a36Sopenharmony_ci u8 tbl_idx, u16 rate_idx) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); 25762306a36Sopenharmony_ci /* use wtbl spe idx */ 25862306a36Sopenharmony_ci mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); 25962306a36Sopenharmony_ci mt76_wr(dev, MT_WTBL_ITCR, ctrl); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* The HW does not translate the mac header to 802.3 for mesh point */ 26362306a36Sopenharmony_cistatic int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 26662306a36Sopenharmony_ci struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap); 26762306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid; 26862306a36Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 26962306a36Sopenharmony_ci struct ieee80211_sta *sta; 27062306a36Sopenharmony_ci struct ieee80211_vif *vif; 27162306a36Sopenharmony_ci struct ieee80211_hdr hdr; 27262306a36Sopenharmony_ci u16 frame_control; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) != 27562306a36Sopenharmony_ci MT_RXD3_NORMAL_U2M) 27662306a36Sopenharmony_ci return -EINVAL; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4)) 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (!msta || !msta->vif) 28262306a36Sopenharmony_ci return -EINVAL; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); 28562306a36Sopenharmony_ci vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* store the info from RXD and ethhdr to avoid being overridden */ 28862306a36Sopenharmony_ci frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL); 28962306a36Sopenharmony_ci hdr.frame_control = cpu_to_le16(frame_control); 29062306a36Sopenharmony_ci hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL)); 29162306a36Sopenharmony_ci hdr.duration_id = 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci ether_addr_copy(hdr.addr1, vif->addr); 29462306a36Sopenharmony_ci ether_addr_copy(hdr.addr2, sta->addr); 29562306a36Sopenharmony_ci switch (frame_control & (IEEE80211_FCTL_TODS | 29662306a36Sopenharmony_ci IEEE80211_FCTL_FROMDS)) { 29762306a36Sopenharmony_ci case 0: 29862306a36Sopenharmony_ci ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci case IEEE80211_FCTL_FROMDS: 30162306a36Sopenharmony_ci ether_addr_copy(hdr.addr3, eth_hdr->h_source); 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci case IEEE80211_FCTL_TODS: 30462306a36Sopenharmony_ci ether_addr_copy(hdr.addr3, eth_hdr->h_dest); 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: 30762306a36Sopenharmony_ci ether_addr_copy(hdr.addr3, eth_hdr->h_dest); 30862306a36Sopenharmony_ci ether_addr_copy(hdr.addr4, eth_hdr->h_source); 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci default: 31162306a36Sopenharmony_ci return -EINVAL; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2); 31562306a36Sopenharmony_ci if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || 31662306a36Sopenharmony_ci eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) 31762306a36Sopenharmony_ci ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); 31862306a36Sopenharmony_ci else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) 31962306a36Sopenharmony_ci ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); 32062306a36Sopenharmony_ci else 32162306a36Sopenharmony_ci skb_pull(skb, 2); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (ieee80211_has_order(hdr.frame_control)) 32462306a36Sopenharmony_ci memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11], 32562306a36Sopenharmony_ci IEEE80211_HT_CTL_LEN); 32662306a36Sopenharmony_ci if (ieee80211_is_data_qos(hdr.frame_control)) { 32762306a36Sopenharmony_ci __le16 qos_ctrl; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL)); 33062306a36Sopenharmony_ci memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, 33162306a36Sopenharmony_ci IEEE80211_QOS_CTL_LEN); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (ieee80211_has_a4(hdr.frame_control)) 33562306a36Sopenharmony_ci memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int 34362306a36Sopenharmony_cimt7996_mac_fill_rx_rate(struct mt7996_dev *dev, 34462306a36Sopenharmony_ci struct mt76_rx_status *status, 34562306a36Sopenharmony_ci struct ieee80211_supported_band *sband, 34662306a36Sopenharmony_ci __le32 *rxv, u8 *mode) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci u32 v0, v2; 34962306a36Sopenharmony_ci u8 stbc, gi, bw, dcm, nss; 35062306a36Sopenharmony_ci int i, idx; 35162306a36Sopenharmony_ci bool cck = false; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci v0 = le32_to_cpu(rxv[0]); 35462306a36Sopenharmony_ci v2 = le32_to_cpu(rxv[2]); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci idx = FIELD_GET(MT_PRXV_TX_RATE, v0); 35762306a36Sopenharmony_ci i = idx; 35862306a36Sopenharmony_ci nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci stbc = FIELD_GET(MT_PRXV_HT_STBC, v2); 36162306a36Sopenharmony_ci gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2); 36262306a36Sopenharmony_ci *mode = FIELD_GET(MT_PRXV_TX_MODE, v2); 36362306a36Sopenharmony_ci dcm = FIELD_GET(MT_PRXV_DCM, v2); 36462306a36Sopenharmony_ci bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci switch (*mode) { 36762306a36Sopenharmony_ci case MT_PHY_TYPE_CCK: 36862306a36Sopenharmony_ci cck = true; 36962306a36Sopenharmony_ci fallthrough; 37062306a36Sopenharmony_ci case MT_PHY_TYPE_OFDM: 37162306a36Sopenharmony_ci i = mt76_get_rate(&dev->mt76, sband, i, cck); 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 37462306a36Sopenharmony_ci case MT_PHY_TYPE_HT: 37562306a36Sopenharmony_ci status->encoding = RX_ENC_HT; 37662306a36Sopenharmony_ci if (gi) 37762306a36Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 37862306a36Sopenharmony_ci if (i > 31) 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci case MT_PHY_TYPE_VHT: 38262306a36Sopenharmony_ci status->nss = nss; 38362306a36Sopenharmony_ci status->encoding = RX_ENC_VHT; 38462306a36Sopenharmony_ci if (gi) 38562306a36Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 38662306a36Sopenharmony_ci if (i > 11) 38762306a36Sopenharmony_ci return -EINVAL; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci case MT_PHY_TYPE_HE_MU: 39062306a36Sopenharmony_ci case MT_PHY_TYPE_HE_SU: 39162306a36Sopenharmony_ci case MT_PHY_TYPE_HE_EXT_SU: 39262306a36Sopenharmony_ci case MT_PHY_TYPE_HE_TB: 39362306a36Sopenharmony_ci status->nss = nss; 39462306a36Sopenharmony_ci status->encoding = RX_ENC_HE; 39562306a36Sopenharmony_ci i &= GENMASK(3, 0); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (gi <= NL80211_RATE_INFO_HE_GI_3_2) 39862306a36Sopenharmony_ci status->he_gi = gi; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci status->he_dcm = dcm; 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci case MT_PHY_TYPE_EHT_SU: 40362306a36Sopenharmony_ci case MT_PHY_TYPE_EHT_TRIG: 40462306a36Sopenharmony_ci case MT_PHY_TYPE_EHT_MU: 40562306a36Sopenharmony_ci status->nss = nss; 40662306a36Sopenharmony_ci status->encoding = RX_ENC_EHT; 40762306a36Sopenharmony_ci i &= GENMASK(3, 0); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (gi <= NL80211_RATE_INFO_EHT_GI_3_2) 41062306a36Sopenharmony_ci status->eht.gi = gi; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci default: 41362306a36Sopenharmony_ci return -EINVAL; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci status->rate_idx = i; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci switch (bw) { 41862306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_20: 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_40: 42162306a36Sopenharmony_ci if (*mode & MT_PHY_TYPE_HE_EXT_SU && 42262306a36Sopenharmony_ci (idx & MT_PRXV_TX_ER_SU_106T)) { 42362306a36Sopenharmony_ci status->bw = RATE_INFO_BW_HE_RU; 42462306a36Sopenharmony_ci status->he_ru = 42562306a36Sopenharmony_ci NL80211_RATE_INFO_HE_RU_ALLOC_106; 42662306a36Sopenharmony_ci } else { 42762306a36Sopenharmony_ci status->bw = RATE_INFO_BW_40; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_80: 43162306a36Sopenharmony_ci status->bw = RATE_INFO_BW_80; 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 43462306a36Sopenharmony_ci status->bw = RATE_INFO_BW_160; 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci /* rxv reports bw 320-1 and 320-2 separately */ 43762306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_320: 43862306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_320 + 1: 43962306a36Sopenharmony_ci status->bw = RATE_INFO_BW_320; 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; 44662306a36Sopenharmony_ci if (*mode < MT_PHY_TYPE_HE_SU && gi) 44762306a36Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int 45362306a36Sopenharmony_cimt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 45662306a36Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 45762306a36Sopenharmony_ci struct mt7996_phy *phy = &dev->phy; 45862306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 45962306a36Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 46062306a36Sopenharmony_ci __le32 *rxv = NULL; 46162306a36Sopenharmony_ci u32 rxd0 = le32_to_cpu(rxd[0]); 46262306a36Sopenharmony_ci u32 rxd1 = le32_to_cpu(rxd[1]); 46362306a36Sopenharmony_ci u32 rxd2 = le32_to_cpu(rxd[2]); 46462306a36Sopenharmony_ci u32 rxd3 = le32_to_cpu(rxd[3]); 46562306a36Sopenharmony_ci u32 rxd4 = le32_to_cpu(rxd[4]); 46662306a36Sopenharmony_ci u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; 46762306a36Sopenharmony_ci u32 csum_status = *(u32 *)skb->cb; 46862306a36Sopenharmony_ci u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP; 46962306a36Sopenharmony_ci bool is_mesh = (rxd0 & mesh_mask) == mesh_mask; 47062306a36Sopenharmony_ci bool unicast, insert_ccmp_hdr = false; 47162306a36Sopenharmony_ci u8 remove_pad, amsdu_info, band_idx; 47262306a36Sopenharmony_ci u8 mode = 0, qos_ctl = 0; 47362306a36Sopenharmony_ci bool hdr_trans; 47462306a36Sopenharmony_ci u16 hdr_gap; 47562306a36Sopenharmony_ci u16 seq_ctrl = 0; 47662306a36Sopenharmony_ci __le16 fc = 0; 47762306a36Sopenharmony_ci int idx; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci memset(status, 0, sizeof(*status)); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1); 48262306a36Sopenharmony_ci mphy = dev->mt76.phys[band_idx]; 48362306a36Sopenharmony_ci phy = mphy->priv; 48462306a36Sopenharmony_ci status->phy_idx = mphy->band_idx; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) 48762306a36Sopenharmony_ci return -EINVAL; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) 49062306a36Sopenharmony_ci return -EINVAL; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; 49362306a36Sopenharmony_ci if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM)) 49462306a36Sopenharmony_ci return -EINVAL; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* ICV error or CCMP/BIP/WPI MIC error */ 49762306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) 49862306a36Sopenharmony_ci status->flag |= RX_FLAG_ONLY_MONITOR; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; 50162306a36Sopenharmony_ci idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); 50262306a36Sopenharmony_ci status->wcid = mt7996_rx_get_wcid(dev, idx, unicast); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (status->wcid) { 50562306a36Sopenharmony_ci struct mt7996_sta *msta; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci msta = container_of(status->wcid, struct mt7996_sta, wcid); 50862306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 50962306a36Sopenharmony_ci if (list_empty(&msta->wcid.poll_list)) 51062306a36Sopenharmony_ci list_add_tail(&msta->wcid.poll_list, 51162306a36Sopenharmony_ci &dev->mt76.sta_poll_list); 51262306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci status->freq = mphy->chandef.chan->center_freq; 51662306a36Sopenharmony_ci status->band = mphy->chandef.chan->band; 51762306a36Sopenharmony_ci if (status->band == NL80211_BAND_5GHZ) 51862306a36Sopenharmony_ci sband = &mphy->sband_5g.sband; 51962306a36Sopenharmony_ci else if (status->band == NL80211_BAND_6GHZ) 52062306a36Sopenharmony_ci sband = &mphy->sband_6g.sband; 52162306a36Sopenharmony_ci else 52262306a36Sopenharmony_ci sband = &mphy->sband_2g.sband; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!sband->channels) 52562306a36Sopenharmony_ci return -EINVAL; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if ((rxd0 & csum_mask) == csum_mask && 52862306a36Sopenharmony_ci !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) 52962306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) 53262306a36Sopenharmony_ci status->flag |= RX_FLAG_FAILED_FCS_CRC; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) 53562306a36Sopenharmony_ci status->flag |= RX_FLAG_MMIC_ERROR; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && 53862306a36Sopenharmony_ci !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { 53962306a36Sopenharmony_ci status->flag |= RX_FLAG_DECRYPTED; 54062306a36Sopenharmony_ci status->flag |= RX_FLAG_IV_STRIPPED; 54162306a36Sopenharmony_ci status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) 54762306a36Sopenharmony_ci return -EINVAL; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci rxd += 8; 55062306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { 55162306a36Sopenharmony_ci u32 v0 = le32_to_cpu(rxd[0]); 55262306a36Sopenharmony_ci u32 v2 = le32_to_cpu(rxd[2]); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0)); 55562306a36Sopenharmony_ci qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2); 55662306a36Sopenharmony_ci seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci rxd += 4; 55962306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 56062306a36Sopenharmony_ci return -EINVAL; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { 56462306a36Sopenharmony_ci u8 *data = (u8 *)rxd; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) { 56762306a36Sopenharmony_ci switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { 56862306a36Sopenharmony_ci case MT_CIPHER_AES_CCMP: 56962306a36Sopenharmony_ci case MT_CIPHER_CCMP_CCX: 57062306a36Sopenharmony_ci case MT_CIPHER_CCMP_256: 57162306a36Sopenharmony_ci insert_ccmp_hdr = 57262306a36Sopenharmony_ci FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); 57362306a36Sopenharmony_ci fallthrough; 57462306a36Sopenharmony_ci case MT_CIPHER_TKIP: 57562306a36Sopenharmony_ci case MT_CIPHER_TKIP_NO_MIC: 57662306a36Sopenharmony_ci case MT_CIPHER_GCMP: 57762306a36Sopenharmony_ci case MT_CIPHER_GCMP_256: 57862306a36Sopenharmony_ci status->iv[0] = data[5]; 57962306a36Sopenharmony_ci status->iv[1] = data[4]; 58062306a36Sopenharmony_ci status->iv[2] = data[3]; 58162306a36Sopenharmony_ci status->iv[3] = data[2]; 58262306a36Sopenharmony_ci status->iv[4] = data[1]; 58362306a36Sopenharmony_ci status->iv[5] = data[0]; 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci default: 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci rxd += 4; 59062306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 59162306a36Sopenharmony_ci return -EINVAL; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { 59562306a36Sopenharmony_ci status->timestamp = le32_to_cpu(rxd[0]); 59662306a36Sopenharmony_ci status->flag |= RX_FLAG_MACTIME_START; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { 59962306a36Sopenharmony_ci status->flag |= RX_FLAG_AMPDU_DETAILS; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* all subframes of an A-MPDU have the same timestamp */ 60262306a36Sopenharmony_ci if (phy->rx_ampdu_ts != status->timestamp) { 60362306a36Sopenharmony_ci if (!++phy->ampdu_ref) 60462306a36Sopenharmony_ci phy->ampdu_ref++; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci phy->rx_ampdu_ts = status->timestamp; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci status->ampdu_ref = phy->ampdu_ref; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci rxd += 4; 61262306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 61362306a36Sopenharmony_ci return -EINVAL; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* RXD Group 3 - P-RXV */ 61762306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { 61862306a36Sopenharmony_ci u32 v3; 61962306a36Sopenharmony_ci int ret; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci rxv = rxd; 62262306a36Sopenharmony_ci rxd += 4; 62362306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 62462306a36Sopenharmony_ci return -EINVAL; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci v3 = le32_to_cpu(rxv[3]); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci status->chains = mphy->antenna_mask; 62962306a36Sopenharmony_ci status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3); 63062306a36Sopenharmony_ci status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3); 63162306a36Sopenharmony_ci status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3); 63262306a36Sopenharmony_ci status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* RXD Group 5 - C-RXV */ 63562306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { 63662306a36Sopenharmony_ci rxd += 24; 63762306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 63862306a36Sopenharmony_ci return -EINVAL; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci ret = mt7996_mac_fill_rx_rate(dev, status, sband, rxv, &mode); 64262306a36Sopenharmony_ci if (ret < 0) 64362306a36Sopenharmony_ci return ret; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); 64762306a36Sopenharmony_ci status->amsdu = !!amsdu_info; 64862306a36Sopenharmony_ci if (status->amsdu) { 64962306a36Sopenharmony_ci status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; 65062306a36Sopenharmony_ci status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; 65462306a36Sopenharmony_ci if (hdr_trans && ieee80211_has_morefrags(fc)) { 65562306a36Sopenharmony_ci if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap)) 65662306a36Sopenharmony_ci return -EINVAL; 65762306a36Sopenharmony_ci hdr_trans = false; 65862306a36Sopenharmony_ci } else { 65962306a36Sopenharmony_ci int pad_start = 0; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci skb_pull(skb, hdr_gap); 66262306a36Sopenharmony_ci if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) { 66362306a36Sopenharmony_ci pad_start = ieee80211_get_hdrlen_from_skb(skb); 66462306a36Sopenharmony_ci } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) { 66562306a36Sopenharmony_ci /* When header translation failure is indicated, 66662306a36Sopenharmony_ci * the hardware will insert an extra 2-byte field 66762306a36Sopenharmony_ci * containing the data length after the protocol 66862306a36Sopenharmony_ci * type field. This happens either when the LLC-SNAP 66962306a36Sopenharmony_ci * pattern did not match, or if a VLAN header was 67062306a36Sopenharmony_ci * detected. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_ci pad_start = 12; 67362306a36Sopenharmony_ci if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) 67462306a36Sopenharmony_ci pad_start += 4; 67562306a36Sopenharmony_ci else 67662306a36Sopenharmony_ci pad_start = 0; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (pad_start) { 68062306a36Sopenharmony_ci memmove(skb->data + 2, skb->data, pad_start); 68162306a36Sopenharmony_ci skb_pull(skb, 2); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (!hdr_trans) { 68662306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (insert_ccmp_hdr) { 68962306a36Sopenharmony_ci u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci mt76_insert_ccmp_hdr(skb, key_id); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci hdr = mt76_skb_get_hdr(skb); 69562306a36Sopenharmony_ci fc = hdr->frame_control; 69662306a36Sopenharmony_ci if (ieee80211_is_data_qos(fc)) { 69762306a36Sopenharmony_ci u8 *qos = ieee80211_get_qos_ctl(hdr); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci seq_ctrl = le16_to_cpu(hdr->seq_ctrl); 70062306a36Sopenharmony_ci qos_ctl = *qos; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* Mesh DA/SA/Length will be stripped after hardware 70362306a36Sopenharmony_ci * de-amsdu, so here needs to clear amsdu present bit 70462306a36Sopenharmony_ci * to mark it as a normal mesh frame. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci if (ieee80211_has_a4(fc) && is_mesh && status->amsdu) 70762306a36Sopenharmony_ci *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci } else { 71062306a36Sopenharmony_ci status->flag |= RX_FLAG_8023; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) 71462306a36Sopenharmony_ci mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (!status->wcid || !ieee80211_is_data_qos(fc)) 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci status->aggr = unicast && 72062306a36Sopenharmony_ci !ieee80211_is_qos_nullfunc(fc); 72162306a36Sopenharmony_ci status->qos_ctl = qos_ctl; 72262306a36Sopenharmony_ci status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return 0; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic void 72862306a36Sopenharmony_cimt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi, 72962306a36Sopenharmony_ci struct sk_buff *skb, struct mt76_wcid *wcid) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; 73262306a36Sopenharmony_ci u8 fc_type, fc_stype; 73362306a36Sopenharmony_ci u16 ethertype; 73462306a36Sopenharmony_ci bool wmm = false; 73562306a36Sopenharmony_ci u32 val; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (wcid->sta) { 73862306a36Sopenharmony_ci struct ieee80211_sta *sta; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 74162306a36Sopenharmony_ci wmm = sta->wme; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | 74562306a36Sopenharmony_ci FIELD_PREP(MT_TXD1_TID, tid); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci ethertype = get_unaligned_be16(&skb->data[12]); 74862306a36Sopenharmony_ci if (ethertype >= ETH_P_802_3_MIN) 74962306a36Sopenharmony_ci val |= MT_TXD1_ETH_802_3; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci txwi[1] |= cpu_to_le32(val); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci fc_type = IEEE80211_FTYPE_DATA >> 2; 75462306a36Sopenharmony_ci fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | 75762306a36Sopenharmony_ci FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci txwi[2] |= cpu_to_le32(val); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void 76362306a36Sopenharmony_cimt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, 76462306a36Sopenharmony_ci struct sk_buff *skb, struct ieee80211_key_conf *key) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 76762306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 76862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 76962306a36Sopenharmony_ci bool multicast = is_multicast_ether_addr(hdr->addr1); 77062306a36Sopenharmony_ci u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; 77162306a36Sopenharmony_ci __le16 fc = hdr->frame_control; 77262306a36Sopenharmony_ci u8 fc_type, fc_stype; 77362306a36Sopenharmony_ci u32 val; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (ieee80211_is_action(fc) && 77662306a36Sopenharmony_ci mgmt->u.action.category == WLAN_CATEGORY_BACK && 77762306a36Sopenharmony_ci mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) 77862306a36Sopenharmony_ci tid = MT_TX_ADDBA; 77962306a36Sopenharmony_ci else if (ieee80211_is_mgmt(hdr->frame_control)) 78062306a36Sopenharmony_ci tid = MT_TX_NORMAL; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | 78362306a36Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_INFO, 78462306a36Sopenharmony_ci ieee80211_get_hdrlen_from_skb(skb) / 2) | 78562306a36Sopenharmony_ci FIELD_PREP(MT_TXD1_TID, tid); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (!ieee80211_is_data(fc) || multicast || 78862306a36Sopenharmony_ci info->flags & IEEE80211_TX_CTL_USE_MINRATE) 78962306a36Sopenharmony_ci val |= MT_TXD1_FIXED_RATE; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && 79262306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { 79362306a36Sopenharmony_ci val |= MT_TXD1_BIP; 79462306a36Sopenharmony_ci txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci txwi[1] |= cpu_to_le32(val); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; 80062306a36Sopenharmony_ci fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | 80362306a36Sopenharmony_ci FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci txwi[2] |= cpu_to_le32(val); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast)); 80862306a36Sopenharmony_ci if (ieee80211_is_beacon(fc)) { 80962306a36Sopenharmony_ci txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT); 81062306a36Sopenharmony_ci txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_INJECTED) { 81462306a36Sopenharmony_ci u16 seqno = le16_to_cpu(hdr->seq_ctrl); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (ieee80211_is_back_req(hdr->frame_control)) { 81762306a36Sopenharmony_ci struct ieee80211_bar *bar; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci bar = (struct ieee80211_bar *)skb->data; 82062306a36Sopenharmony_ci seqno = le16_to_cpu(bar->start_seq_num); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci val = MT_TXD3_SN_VALID | 82462306a36Sopenharmony_ci FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); 82562306a36Sopenharmony_ci txwi[3] |= cpu_to_le32(val); 82662306a36Sopenharmony_ci txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_civoid mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, 83162306a36Sopenharmony_ci struct sk_buff *skb, struct mt76_wcid *wcid, 83262306a36Sopenharmony_ci struct ieee80211_key_conf *key, int pid, 83362306a36Sopenharmony_ci enum mt76_txq_id qid, u32 changed) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 83662306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 83762306a36Sopenharmony_ci u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; 83862306a36Sopenharmony_ci u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; 83962306a36Sopenharmony_ci bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; 84062306a36Sopenharmony_ci struct mt76_vif *mvif; 84162306a36Sopenharmony_ci u16 tx_count = 15; 84262306a36Sopenharmony_ci u32 val; 84362306a36Sopenharmony_ci bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | 84462306a36Sopenharmony_ci BSS_CHANGED_FILS_DISCOVERY)); 84562306a36Sopenharmony_ci bool beacon = !!(changed & (BSS_CHANGED_BEACON | 84662306a36Sopenharmony_ci BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL; 84962306a36Sopenharmony_ci if (mvif) { 85062306a36Sopenharmony_ci omac_idx = mvif->omac_idx; 85162306a36Sopenharmony_ci wmm_idx = mvif->wmm_idx; 85262306a36Sopenharmony_ci band_idx = mvif->band_idx; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (inband_disc) { 85662306a36Sopenharmony_ci p_fmt = MT_TX_TYPE_FW; 85762306a36Sopenharmony_ci q_idx = MT_LMAC_ALTX0; 85862306a36Sopenharmony_ci } else if (beacon) { 85962306a36Sopenharmony_ci p_fmt = MT_TX_TYPE_FW; 86062306a36Sopenharmony_ci q_idx = MT_LMAC_BCN0; 86162306a36Sopenharmony_ci } else if (qid >= MT_TXQ_PSD) { 86262306a36Sopenharmony_ci p_fmt = MT_TX_TYPE_CT; 86362306a36Sopenharmony_ci q_idx = MT_LMAC_ALTX0; 86462306a36Sopenharmony_ci } else { 86562306a36Sopenharmony_ci p_fmt = MT_TX_TYPE_CT; 86662306a36Sopenharmony_ci q_idx = wmm_idx * MT7996_MAX_WMM_SETS + 86762306a36Sopenharmony_ci mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | 87162306a36Sopenharmony_ci FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | 87262306a36Sopenharmony_ci FIELD_PREP(MT_TXD0_Q_IDX, q_idx); 87362306a36Sopenharmony_ci txwi[0] = cpu_to_le32(val); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | 87662306a36Sopenharmony_ci FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (band_idx) 87962306a36Sopenharmony_ci val |= FIELD_PREP(MT_TXD1_TGID, band_idx); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci txwi[1] = cpu_to_le32(val); 88262306a36Sopenharmony_ci txwi[2] = 0; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci val = MT_TXD3_SW_POWER_MGMT | 88562306a36Sopenharmony_ci FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); 88662306a36Sopenharmony_ci if (key) 88762306a36Sopenharmony_ci val |= MT_TXD3_PROTECT_FRAME; 88862306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_ACK) 88962306a36Sopenharmony_ci val |= MT_TXD3_NO_ACK; 89062306a36Sopenharmony_ci if (wcid->amsdu) 89162306a36Sopenharmony_ci val |= MT_TXD3_HW_AMSDU; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci txwi[3] = cpu_to_le32(val); 89462306a36Sopenharmony_ci txwi[4] = 0; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD5_PID, pid); 89762306a36Sopenharmony_ci if (pid >= MT_PACKET_ID_FIRST) 89862306a36Sopenharmony_ci val |= MT_TXD5_TX_STATUS_HOST; 89962306a36Sopenharmony_ci txwi[5] = cpu_to_le32(val); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci val = MT_TXD6_DIS_MAT | MT_TXD6_DAS | 90262306a36Sopenharmony_ci FIELD_PREP(MT_TXD6_MSDU_CNT, 1); 90362306a36Sopenharmony_ci txwi[6] = cpu_to_le32(val); 90462306a36Sopenharmony_ci txwi[7] = 0; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (is_8023) 90762306a36Sopenharmony_ci mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid); 90862306a36Sopenharmony_ci else 90962306a36Sopenharmony_ci mt7996_mac_write_txwi_80211(dev, txwi, skb, key); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) { 91262306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 91362306a36Sopenharmony_ci bool mcast = ieee80211_is_data(hdr->frame_control) && 91462306a36Sopenharmony_ci is_multicast_ether_addr(hdr->addr1); 91562306a36Sopenharmony_ci u8 idx = MT7996_BASIC_RATES_TBL; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (mvif) { 91862306a36Sopenharmony_ci if (mcast && mvif->mcast_rates_idx) 91962306a36Sopenharmony_ci idx = mvif->mcast_rates_idx; 92062306a36Sopenharmony_ci else if (beacon && mvif->beacon_rates_idx) 92162306a36Sopenharmony_ci idx = mvif->beacon_rates_idx; 92262306a36Sopenharmony_ci else 92362306a36Sopenharmony_ci idx = mvif->basic_rates_idx; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); 92762306a36Sopenharmony_ci txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ciint mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, 93262306a36Sopenharmony_ci enum mt76_txq_id qid, struct mt76_wcid *wcid, 93362306a36Sopenharmony_ci struct ieee80211_sta *sta, 93462306a36Sopenharmony_ci struct mt76_tx_info *tx_info) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; 93762306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 93862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); 93962306a36Sopenharmony_ci struct ieee80211_key_conf *key = info->control.hw_key; 94062306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 94162306a36Sopenharmony_ci struct mt76_connac_txp_common *txp; 94262306a36Sopenharmony_ci struct mt76_txwi_cache *t; 94362306a36Sopenharmony_ci int id, i, pid, nbuf = tx_info->nbuf - 1; 94462306a36Sopenharmony_ci bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; 94562306a36Sopenharmony_ci u8 *txwi = (u8 *)txwi_ptr; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (unlikely(tx_info->skb->len <= ETH_HLEN)) 94862306a36Sopenharmony_ci return -EINVAL; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (!wcid) 95162306a36Sopenharmony_ci wcid = &dev->mt76.global_wcid; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (sta) { 95462306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (time_after(jiffies, msta->jiffies + HZ / 4)) { 95762306a36Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; 95862306a36Sopenharmony_ci msta->jiffies = jiffies; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); 96362306a36Sopenharmony_ci t->skb = tx_info->skb; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci id = mt76_token_consume(mdev, &t); 96662306a36Sopenharmony_ci if (id < 0) 96762306a36Sopenharmony_ci return id; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); 97062306a36Sopenharmony_ci mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, 97162306a36Sopenharmony_ci pid, qid, 0); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE); 97462306a36Sopenharmony_ci for (i = 0; i < nbuf; i++) { 97562306a36Sopenharmony_ci txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); 97662306a36Sopenharmony_ci txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci txp->fw.nbuf = nbuf; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci txp->fw.flags = 98162306a36Sopenharmony_ci cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (!key) 98462306a36Sopenharmony_ci txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control)) 98762306a36Sopenharmony_ci txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (vif) { 99062306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci txp->fw.bss_idx = mvif->mt76.idx; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci txp->fw.token = cpu_to_le16(id); 99662306a36Sopenharmony_ci txp->fw.rept_wds_wcid = cpu_to_le16(sta ? wcid->idx : 0xfff); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci tx_info->skb = NULL; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* pass partial skb header to fw */ 100162306a36Sopenharmony_ci tx_info->buf[1].len = MT_CT_PARSE_LEN; 100262306a36Sopenharmony_ci tx_info->buf[1].skip_unmap = true; 100362306a36Sopenharmony_ci tx_info->nbuf = MT_CT_DMA_BUF_NUM; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci return 0; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic void 100962306a36Sopenharmony_cimt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct mt7996_sta *msta; 101262306a36Sopenharmony_ci u16 fc, tid; 101362306a36Sopenharmony_ci u32 val; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) 101662306a36Sopenharmony_ci return; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci tid = le32_get_bits(txwi[1], MT_TXD1_TID); 101962306a36Sopenharmony_ci if (tid >= 6) /* skip VO queue */ 102062306a36Sopenharmony_ci return; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci val = le32_to_cpu(txwi[2]); 102362306a36Sopenharmony_ci fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 | 102462306a36Sopenharmony_ci FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4; 102562306a36Sopenharmony_ci if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) 102662306a36Sopenharmony_ci return; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci msta = (struct mt7996_sta *)sta->drv_priv; 102962306a36Sopenharmony_ci if (!test_and_set_bit(tid, &msta->wcid.ampdu_state)) 103062306a36Sopenharmony_ci ieee80211_start_tx_ba_session(sta, tid, 0); 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic void 103462306a36Sopenharmony_cimt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t, 103562306a36Sopenharmony_ci struct ieee80211_sta *sta, struct list_head *free_list) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 103862306a36Sopenharmony_ci struct mt76_wcid *wcid; 103962306a36Sopenharmony_ci __le32 *txwi; 104062306a36Sopenharmony_ci u16 wcid_idx; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci mt76_connac_txp_skb_unmap(mdev, t); 104362306a36Sopenharmony_ci if (!t->skb) 104462306a36Sopenharmony_ci goto out; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); 104762306a36Sopenharmony_ci if (sta) { 104862306a36Sopenharmony_ci wcid = (struct mt76_wcid *)sta->drv_priv; 104962306a36Sopenharmony_ci wcid_idx = wcid->idx; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) 105262306a36Sopenharmony_ci mt7996_tx_check_aggr(sta, txwi); 105362306a36Sopenharmony_ci } else { 105462306a36Sopenharmony_ci wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX); 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ciout: 106062306a36Sopenharmony_ci t->skb = NULL; 106162306a36Sopenharmony_ci mt76_put_txwi(mdev, t); 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic void 106562306a36Sopenharmony_cimt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci __le32 *tx_free = (__le32 *)data, *cur_info; 106862306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 106962306a36Sopenharmony_ci struct mt76_phy *phy2 = mdev->phys[MT_BAND1]; 107062306a36Sopenharmony_ci struct mt76_phy *phy3 = mdev->phys[MT_BAND2]; 107162306a36Sopenharmony_ci struct mt76_txwi_cache *txwi; 107262306a36Sopenharmony_ci struct ieee80211_sta *sta = NULL; 107362306a36Sopenharmony_ci LIST_HEAD(free_list); 107462306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 107562306a36Sopenharmony_ci void *end = data + len; 107662306a36Sopenharmony_ci bool wake = false; 107762306a36Sopenharmony_ci u16 total, count = 0; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* clean DMA queues and unmap buffers first */ 108062306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); 108162306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false); 108262306a36Sopenharmony_ci if (phy2) { 108362306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_PSD], false); 108462306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_BE], false); 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci if (phy3) { 108762306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_PSD], false); 108862306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false); 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4)) 109262306a36Sopenharmony_ci return; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT); 109562306a36Sopenharmony_ci for (cur_info = &tx_free[2]; count < total; cur_info++) { 109662306a36Sopenharmony_ci u32 msdu, info; 109762306a36Sopenharmony_ci u8 i; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (WARN_ON_ONCE((void *)cur_info >= end)) 110062306a36Sopenharmony_ci return; 110162306a36Sopenharmony_ci /* 1'b1: new wcid pair. 110262306a36Sopenharmony_ci * 1'b0: msdu_id with the same 'wcid pair' as above. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ci info = le32_to_cpu(*cur_info); 110562306a36Sopenharmony_ci if (info & MT_TXFREE_INFO_PAIR) { 110662306a36Sopenharmony_ci struct mt7996_sta *msta; 110762306a36Sopenharmony_ci struct mt76_wcid *wcid; 110862306a36Sopenharmony_ci u16 idx; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); 111162306a36Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 111262306a36Sopenharmony_ci sta = wcid_to_sta(wcid); 111362306a36Sopenharmony_ci if (!sta) 111462306a36Sopenharmony_ci continue; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci msta = container_of(wcid, struct mt7996_sta, wcid); 111762306a36Sopenharmony_ci spin_lock_bh(&mdev->sta_poll_lock); 111862306a36Sopenharmony_ci if (list_empty(&msta->wcid.poll_list)) 111962306a36Sopenharmony_ci list_add_tail(&msta->wcid.poll_list, 112062306a36Sopenharmony_ci &mdev->sta_poll_list); 112162306a36Sopenharmony_ci spin_unlock_bh(&mdev->sta_poll_lock); 112262306a36Sopenharmony_ci continue; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (info & MT_TXFREE_INFO_HEADER) 112662306a36Sopenharmony_ci continue; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 112962306a36Sopenharmony_ci msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID; 113062306a36Sopenharmony_ci if (msdu == MT_TXFREE_INFO_MSDU_ID) 113162306a36Sopenharmony_ci continue; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci count++; 113462306a36Sopenharmony_ci txwi = mt76_token_release(mdev, msdu, &wake); 113562306a36Sopenharmony_ci if (!txwi) 113662306a36Sopenharmony_ci continue; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci mt7996_txwi_free(dev, txwi, sta, &free_list); 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci mt7996_mac_sta_poll(dev); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (wake) 114562306a36Sopenharmony_ci mt76_set_tx_blocked(&dev->mt76, false); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci mt76_worker_schedule(&dev->mt76.tx_worker); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci list_for_each_entry_safe(skb, tmp, &free_list, list) { 115062306a36Sopenharmony_ci skb_list_del_init(skb); 115162306a36Sopenharmony_ci napi_consume_skb(skb, 1); 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic bool 115662306a36Sopenharmony_cimt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, 115762306a36Sopenharmony_ci int pid, __le32 *txs_data) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci struct mt76_sta_stats *stats = &wcid->stats; 116062306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 116162306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 116262306a36Sopenharmony_ci struct mt76_phy *mphy; 116362306a36Sopenharmony_ci struct ieee80211_tx_info *info; 116462306a36Sopenharmony_ci struct sk_buff_head list; 116562306a36Sopenharmony_ci struct rate_info rate = {}; 116662306a36Sopenharmony_ci struct sk_buff *skb; 116762306a36Sopenharmony_ci bool cck = false; 116862306a36Sopenharmony_ci u32 txrate, txs, mode, stbc; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci mt76_tx_status_lock(mdev, &list); 117162306a36Sopenharmony_ci skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); 117262306a36Sopenharmony_ci if (!skb) 117362306a36Sopenharmony_ci goto out_no_skb; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci txs = le32_to_cpu(txs_data[0]); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 117862306a36Sopenharmony_ci if (!(txs & MT_TXS0_ACK_ERROR_MASK)) 117962306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci info->status.ampdu_len = 1; 118262306a36Sopenharmony_ci info->status.ampdu_ack_len = !!(info->flags & 118362306a36Sopenharmony_ci IEEE80211_TX_STAT_ACK); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci info->status.rates[0].idx = -1; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci txrate = FIELD_GET(MT_TXS0_TX_RATE, txs); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); 119062306a36Sopenharmony_ci rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; 119162306a36Sopenharmony_ci stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (stbc && rate.nss > 1) 119462306a36Sopenharmony_ci rate.nss >>= 1; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss)) 119762306a36Sopenharmony_ci stats->tx_nss[rate.nss - 1]++; 119862306a36Sopenharmony_ci if (rate.mcs < ARRAY_SIZE(stats->tx_mcs)) 119962306a36Sopenharmony_ci stats->tx_mcs[rate.mcs]++; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci mode = FIELD_GET(MT_TX_RATE_MODE, txrate); 120262306a36Sopenharmony_ci switch (mode) { 120362306a36Sopenharmony_ci case MT_PHY_TYPE_CCK: 120462306a36Sopenharmony_ci cck = true; 120562306a36Sopenharmony_ci fallthrough; 120662306a36Sopenharmony_ci case MT_PHY_TYPE_OFDM: 120762306a36Sopenharmony_ci mphy = mt76_dev_phy(mdev, wcid->phy_idx); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 121062306a36Sopenharmony_ci sband = &mphy->sband_5g.sband; 121162306a36Sopenharmony_ci else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) 121262306a36Sopenharmony_ci sband = &mphy->sband_6g.sband; 121362306a36Sopenharmony_ci else 121462306a36Sopenharmony_ci sband = &mphy->sband_2g.sband; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck); 121762306a36Sopenharmony_ci rate.legacy = sband->bitrates[rate.mcs].bitrate; 121862306a36Sopenharmony_ci break; 121962306a36Sopenharmony_ci case MT_PHY_TYPE_HT: 122062306a36Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 122162306a36Sopenharmony_ci if (rate.mcs > 31) 122262306a36Sopenharmony_ci goto out; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci rate.flags = RATE_INFO_FLAGS_MCS; 122562306a36Sopenharmony_ci if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) 122662306a36Sopenharmony_ci rate.flags |= RATE_INFO_FLAGS_SHORT_GI; 122762306a36Sopenharmony_ci break; 122862306a36Sopenharmony_ci case MT_PHY_TYPE_VHT: 122962306a36Sopenharmony_ci if (rate.mcs > 9) 123062306a36Sopenharmony_ci goto out; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci rate.flags = RATE_INFO_FLAGS_VHT_MCS; 123362306a36Sopenharmony_ci break; 123462306a36Sopenharmony_ci case MT_PHY_TYPE_HE_SU: 123562306a36Sopenharmony_ci case MT_PHY_TYPE_HE_EXT_SU: 123662306a36Sopenharmony_ci case MT_PHY_TYPE_HE_TB: 123762306a36Sopenharmony_ci case MT_PHY_TYPE_HE_MU: 123862306a36Sopenharmony_ci if (rate.mcs > 11) 123962306a36Sopenharmony_ci goto out; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci rate.he_gi = wcid->rate.he_gi; 124262306a36Sopenharmony_ci rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); 124362306a36Sopenharmony_ci rate.flags = RATE_INFO_FLAGS_HE_MCS; 124462306a36Sopenharmony_ci break; 124562306a36Sopenharmony_ci case MT_PHY_TYPE_EHT_SU: 124662306a36Sopenharmony_ci case MT_PHY_TYPE_EHT_TRIG: 124762306a36Sopenharmony_ci case MT_PHY_TYPE_EHT_MU: 124862306a36Sopenharmony_ci if (rate.mcs > 13) 124962306a36Sopenharmony_ci goto out; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci rate.eht_gi = wcid->rate.eht_gi; 125262306a36Sopenharmony_ci rate.flags = RATE_INFO_FLAGS_EHT_MCS; 125362306a36Sopenharmony_ci break; 125462306a36Sopenharmony_ci default: 125562306a36Sopenharmony_ci goto out; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci stats->tx_mode[mode]++; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci switch (FIELD_GET(MT_TXS0_BW, txs)) { 126162306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_320: 126262306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_320; 126362306a36Sopenharmony_ci stats->tx_bw[4]++; 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 126662306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_160; 126762306a36Sopenharmony_ci stats->tx_bw[3]++; 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_80: 127062306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_80; 127162306a36Sopenharmony_ci stats->tx_bw[2]++; 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_40: 127462306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_40; 127562306a36Sopenharmony_ci stats->tx_bw[1]++; 127662306a36Sopenharmony_ci break; 127762306a36Sopenharmony_ci default: 127862306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_20; 127962306a36Sopenharmony_ci stats->tx_bw[0]++; 128062306a36Sopenharmony_ci break; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci wcid->rate = rate; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ciout: 128562306a36Sopenharmony_ci mt76_tx_status_skb_done(mdev, skb, &list); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ciout_no_skb: 128862306a36Sopenharmony_ci mt76_tx_status_unlock(mdev, &list); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci return !!skb; 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cistatic void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci struct mt7996_sta *msta = NULL; 129662306a36Sopenharmony_ci struct mt76_wcid *wcid; 129762306a36Sopenharmony_ci __le32 *txs_data = data; 129862306a36Sopenharmony_ci u16 wcidx; 129962306a36Sopenharmony_ci u8 pid; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1) 130262306a36Sopenharmony_ci return; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); 130562306a36Sopenharmony_ci pid = le32_get_bits(txs_data[3], MT_TXS3_PID); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (pid < MT_PACKET_ID_FIRST) 130862306a36Sopenharmony_ci return; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (wcidx >= mt7996_wtbl_size(dev)) 131162306a36Sopenharmony_ci return; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci rcu_read_lock(); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[wcidx]); 131662306a36Sopenharmony_ci if (!wcid) 131762306a36Sopenharmony_ci goto out; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci msta = container_of(wcid, struct mt7996_sta, wcid); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (!wcid->sta) 132462306a36Sopenharmony_ci goto out; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 132762306a36Sopenharmony_ci if (list_empty(&msta->wcid.poll_list)) 132862306a36Sopenharmony_ci list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); 132962306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ciout: 133262306a36Sopenharmony_ci rcu_read_unlock(); 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cibool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 133862306a36Sopenharmony_ci __le32 *rxd = (__le32 *)data; 133962306a36Sopenharmony_ci __le32 *end = (__le32 *)&rxd[len / 4]; 134062306a36Sopenharmony_ci enum rx_pkt_type type; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); 134362306a36Sopenharmony_ci if (type != PKT_TYPE_NORMAL) { 134462306a36Sopenharmony_ci u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) == 134762306a36Sopenharmony_ci MT_RXD0_SW_PKT_TYPE_FRAME)) 134862306a36Sopenharmony_ci return true; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci switch (type) { 135262306a36Sopenharmony_ci case PKT_TYPE_TXRX_NOTIFY: 135362306a36Sopenharmony_ci mt7996_mac_tx_free(dev, data, len); 135462306a36Sopenharmony_ci return false; 135562306a36Sopenharmony_ci case PKT_TYPE_TXS: 135662306a36Sopenharmony_ci for (rxd += 4; rxd + 8 <= end; rxd += 8) 135762306a36Sopenharmony_ci mt7996_mac_add_txs(dev, rxd); 135862306a36Sopenharmony_ci return false; 135962306a36Sopenharmony_ci case PKT_TYPE_RX_FW_MONITOR: 136062306a36Sopenharmony_ci mt7996_debugfs_rx_fw_monitor(dev, data, len); 136162306a36Sopenharmony_ci return false; 136262306a36Sopenharmony_ci default: 136362306a36Sopenharmony_ci return true; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_civoid mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, 136862306a36Sopenharmony_ci struct sk_buff *skb, u32 *info) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 137162306a36Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 137262306a36Sopenharmony_ci __le32 *end = (__le32 *)&skb->data[skb->len]; 137362306a36Sopenharmony_ci enum rx_pkt_type type; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); 137662306a36Sopenharmony_ci if (type != PKT_TYPE_NORMAL) { 137762306a36Sopenharmony_ci u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) == 138062306a36Sopenharmony_ci MT_RXD0_SW_PKT_TYPE_FRAME)) 138162306a36Sopenharmony_ci type = PKT_TYPE_NORMAL; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci switch (type) { 138562306a36Sopenharmony_ci case PKT_TYPE_TXRX_NOTIFY: 138662306a36Sopenharmony_ci mt7996_mac_tx_free(dev, skb->data, skb->len); 138762306a36Sopenharmony_ci napi_consume_skb(skb, 1); 138862306a36Sopenharmony_ci break; 138962306a36Sopenharmony_ci case PKT_TYPE_RX_EVENT: 139062306a36Sopenharmony_ci mt7996_mcu_rx_event(dev, skb); 139162306a36Sopenharmony_ci break; 139262306a36Sopenharmony_ci case PKT_TYPE_TXS: 139362306a36Sopenharmony_ci for (rxd += 4; rxd + 8 <= end; rxd += 8) 139462306a36Sopenharmony_ci mt7996_mac_add_txs(dev, rxd); 139562306a36Sopenharmony_ci dev_kfree_skb(skb); 139662306a36Sopenharmony_ci break; 139762306a36Sopenharmony_ci case PKT_TYPE_RX_FW_MONITOR: 139862306a36Sopenharmony_ci mt7996_debugfs_rx_fw_monitor(dev, skb->data, skb->len); 139962306a36Sopenharmony_ci dev_kfree_skb(skb); 140062306a36Sopenharmony_ci break; 140162306a36Sopenharmony_ci case PKT_TYPE_NORMAL: 140262306a36Sopenharmony_ci if (!mt7996_mac_fill_rx(dev, skb)) { 140362306a36Sopenharmony_ci mt76_rx(&dev->mt76, q, skb); 140462306a36Sopenharmony_ci return; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci fallthrough; 140762306a36Sopenharmony_ci default: 140862306a36Sopenharmony_ci dev_kfree_skb(skb); 140962306a36Sopenharmony_ci break; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_civoid mt7996_mac_cca_stats_reset(struct mt7996_phy *phy) 141462306a36Sopenharmony_ci{ 141562306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 141662306a36Sopenharmony_ci u32 reg = MT_WF_PHYRX_BAND_RX_CTRL1(phy->mt76->band_idx); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci mt76_clear(dev, reg, MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN); 141962306a36Sopenharmony_ci mt76_set(dev, reg, BIT(11) | BIT(9)); 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_civoid mt7996_mac_reset_counters(struct mt7996_phy *phy) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 142562306a36Sopenharmony_ci u8 band_idx = phy->mt76->band_idx; 142662306a36Sopenharmony_ci int i; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci for (i = 0; i < 16; i++) 142962306a36Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i)); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci phy->mt76->survey_time = ktime_get_boottime(); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* reset airtime counters */ 143662306a36Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band_idx), 143762306a36Sopenharmony_ci MT_WF_RMAC_MIB_RXTIME_CLR); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci mt7996_mcu_get_chan_mib_info(phy, true); 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_civoid mt7996_mac_set_coverage_class(struct mt7996_phy *phy) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci s16 coverage_class = phy->coverage_class; 144562306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 144662306a36Sopenharmony_ci struct mt7996_phy *phy2 = mt7996_phy2(dev); 144762306a36Sopenharmony_ci struct mt7996_phy *phy3 = mt7996_phy3(dev); 144862306a36Sopenharmony_ci u32 reg_offset; 144962306a36Sopenharmony_ci u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | 145062306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); 145162306a36Sopenharmony_ci u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | 145262306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); 145362306a36Sopenharmony_ci u8 band_idx = phy->mt76->band_idx; 145462306a36Sopenharmony_ci int offset; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 145762306a36Sopenharmony_ci return; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci if (phy2) 146062306a36Sopenharmony_ci coverage_class = max_t(s16, dev->phy.coverage_class, 146162306a36Sopenharmony_ci phy2->coverage_class); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (phy3) 146462306a36Sopenharmony_ci coverage_class = max_t(s16, coverage_class, 146562306a36Sopenharmony_ci phy3->coverage_class); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci offset = 3 * coverage_class; 146862306a36Sopenharmony_ci reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | 146962306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset); 147262306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset); 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_civoid mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci mt76_set(dev, MT_WF_PHYRX_CSD_BAND_RXTD12(band), 147862306a36Sopenharmony_ci MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY | 147962306a36Sopenharmony_ci MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci mt76_set(dev, MT_WF_PHYRX_BAND_RX_CTRL1(band), 148262306a36Sopenharmony_ci FIELD_PREP(MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN, 0x5)); 148362306a36Sopenharmony_ci} 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_cistatic u8 148662306a36Sopenharmony_cimt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 }; 148962306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 149062306a36Sopenharmony_ci u32 val, sum = 0, n = 0; 149162306a36Sopenharmony_ci int ant, i; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci for (ant = 0; ant < hweight8(phy->mt76->antenna_mask); ant++) { 149462306a36Sopenharmony_ci u32 reg = MT_WF_PHYRX_CSD_IRPI(band_idx, ant); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { 149762306a36Sopenharmony_ci val = mt76_rr(dev, reg); 149862306a36Sopenharmony_ci sum += val * nf_power[i]; 149962306a36Sopenharmony_ci n += val; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci return n ? sum / n : 0; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_civoid mt7996_update_channel(struct mt76_phy *mphy) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv; 150962306a36Sopenharmony_ci struct mt76_channel_state *state = mphy->chan_state; 151062306a36Sopenharmony_ci int nf; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci mt7996_mcu_get_chan_mib_info(phy, false); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci nf = mt7996_phy_get_nf(phy, mphy->band_idx); 151562306a36Sopenharmony_ci if (!phy->noise) 151662306a36Sopenharmony_ci phy->noise = nf << 4; 151762306a36Sopenharmony_ci else if (nf) 151862306a36Sopenharmony_ci phy->noise += nf - (phy->noise >> 4); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci state->noise = -(phy->noise >> 4); 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic bool 152462306a36Sopenharmony_cimt7996_wait_reset_state(struct mt7996_dev *dev, u32 state) 152562306a36Sopenharmony_ci{ 152662306a36Sopenharmony_ci bool ret; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci ret = wait_event_timeout(dev->reset_wait, 152962306a36Sopenharmony_ci (READ_ONCE(dev->recovery.state) & state), 153062306a36Sopenharmony_ci MT7996_RESET_TIMEOUT); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); 153362306a36Sopenharmony_ci return ret; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic void 153762306a36Sopenharmony_cimt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci struct ieee80211_hw *hw = priv; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci switch (vif->type) { 154262306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 154362306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 154462306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 154562306a36Sopenharmony_ci mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon); 154662306a36Sopenharmony_ci break; 154762306a36Sopenharmony_ci default: 154862306a36Sopenharmony_ci break; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_cistatic void 155362306a36Sopenharmony_cimt7996_update_beacons(struct mt7996_dev *dev) 155462306a36Sopenharmony_ci{ 155562306a36Sopenharmony_ci struct mt76_phy *phy2, *phy3; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci ieee80211_iterate_active_interfaces(dev->mt76.hw, 155862306a36Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 155962306a36Sopenharmony_ci mt7996_update_vif_beacon, dev->mt76.hw); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci phy2 = dev->mt76.phys[MT_BAND1]; 156262306a36Sopenharmony_ci if (!phy2) 156362306a36Sopenharmony_ci return; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci ieee80211_iterate_active_interfaces(phy2->hw, 156662306a36Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 156762306a36Sopenharmony_ci mt7996_update_vif_beacon, phy2->hw); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci phy3 = dev->mt76.phys[MT_BAND2]; 157062306a36Sopenharmony_ci if (!phy3) 157162306a36Sopenharmony_ci return; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci ieee80211_iterate_active_interfaces(phy3->hw, 157462306a36Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 157562306a36Sopenharmony_ci mt7996_update_vif_beacon, phy3->hw); 157662306a36Sopenharmony_ci} 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_civoid mt7996_tx_token_put(struct mt7996_dev *dev) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci struct mt76_txwi_cache *txwi; 158162306a36Sopenharmony_ci int id; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.token_lock); 158462306a36Sopenharmony_ci idr_for_each_entry(&dev->mt76.token, txwi, id) { 158562306a36Sopenharmony_ci mt7996_txwi_free(dev, txwi, NULL, NULL); 158662306a36Sopenharmony_ci dev->mt76.token_count--; 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.token_lock); 158962306a36Sopenharmony_ci idr_destroy(&dev->mt76.token); 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_cistatic int 159362306a36Sopenharmony_cimt7996_mac_restart(struct mt7996_dev *dev) 159462306a36Sopenharmony_ci{ 159562306a36Sopenharmony_ci struct mt7996_phy *phy2, *phy3; 159662306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 159762306a36Sopenharmony_ci int i, ret; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci phy2 = mt7996_phy2(dev); 160062306a36Sopenharmony_ci phy3 = mt7996_phy3(dev); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (dev->hif2) { 160362306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); 160462306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (dev_is_pci(mdev->dev)) { 160862306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); 160962306a36Sopenharmony_ci if (dev->hif2) 161062306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0); 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 161462306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &dev->mphy.state); 161562306a36Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 161662306a36Sopenharmony_ci if (phy2) { 161762306a36Sopenharmony_ci set_bit(MT76_RESET, &phy2->mt76->state); 161862306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &phy2->mt76->state); 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci if (phy3) { 162162306a36Sopenharmony_ci set_bit(MT76_RESET, &phy3->mt76->state); 162262306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &phy3->mt76->state); 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci /* lock/unlock all queues to ensure that no tx is pending */ 162662306a36Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 162762306a36Sopenharmony_ci if (phy2) 162862306a36Sopenharmony_ci mt76_txq_schedule_all(phy2->mt76); 162962306a36Sopenharmony_ci if (phy3) 163062306a36Sopenharmony_ci mt76_txq_schedule_all(phy3->mt76); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci /* disable all tx/rx napi */ 163362306a36Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 163462306a36Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 163562306a36Sopenharmony_ci if (mdev->q_rx[i].ndesc) 163662306a36Sopenharmony_ci napi_disable(&dev->mt76.napi[i]); 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci napi_disable(&dev->mt76.tx_napi); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci /* token reinit */ 164162306a36Sopenharmony_ci mt7996_tx_token_put(dev); 164262306a36Sopenharmony_ci idr_init(&dev->mt76.token); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci mt7996_dma_reset(dev, true); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci local_bh_disable(); 164762306a36Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 164862306a36Sopenharmony_ci if (mdev->q_rx[i].ndesc) { 164962306a36Sopenharmony_ci napi_enable(&dev->mt76.napi[i]); 165062306a36Sopenharmony_ci napi_schedule(&dev->mt76.napi[i]); 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci local_bh_enable(); 165462306a36Sopenharmony_ci clear_bit(MT76_MCU_RESET, &dev->mphy.state); 165562306a36Sopenharmony_ci clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); 165862306a36Sopenharmony_ci mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); 165962306a36Sopenharmony_ci if (dev->hif2) { 166062306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask); 166162306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci if (dev_is_pci(mdev->dev)) { 166462306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); 166562306a36Sopenharmony_ci if (dev->hif2) 166662306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci /* load firmware */ 167062306a36Sopenharmony_ci ret = mt7996_mcu_init_firmware(dev); 167162306a36Sopenharmony_ci if (ret) 167262306a36Sopenharmony_ci goto out; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci /* set the necessary init items */ 167562306a36Sopenharmony_ci ret = mt7996_mcu_set_eeprom(dev); 167662306a36Sopenharmony_ci if (ret) 167762306a36Sopenharmony_ci goto out; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci mt7996_mac_init(dev); 168062306a36Sopenharmony_ci mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); 168162306a36Sopenharmony_ci mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); 168262306a36Sopenharmony_ci mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); 168362306a36Sopenharmony_ci ret = mt7996_txbf_init(dev); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { 168662306a36Sopenharmony_ci ret = mt7996_run(dev->mphy.hw); 168762306a36Sopenharmony_ci if (ret) 168862306a36Sopenharmony_ci goto out; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) { 169262306a36Sopenharmony_ci ret = mt7996_run(phy2->mt76->hw); 169362306a36Sopenharmony_ci if (ret) 169462306a36Sopenharmony_ci goto out; 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) { 169862306a36Sopenharmony_ci ret = mt7996_run(phy3->mt76->hw); 169962306a36Sopenharmony_ci if (ret) 170062306a36Sopenharmony_ci goto out; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ciout: 170462306a36Sopenharmony_ci /* reset done */ 170562306a36Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 170662306a36Sopenharmony_ci if (phy2) 170762306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy2->mt76->state); 170862306a36Sopenharmony_ci if (phy3) 170962306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy3->mt76->state); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci local_bh_disable(); 171262306a36Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 171362306a36Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 171462306a36Sopenharmony_ci local_bh_enable(); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 171762306a36Sopenharmony_ci return ret; 171862306a36Sopenharmony_ci} 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_cistatic void 172162306a36Sopenharmony_cimt7996_mac_full_reset(struct mt7996_dev *dev) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci struct mt7996_phy *phy2, *phy3; 172462306a36Sopenharmony_ci int i; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci phy2 = mt7996_phy2(dev); 172762306a36Sopenharmony_ci phy3 = mt7996_phy3(dev); 172862306a36Sopenharmony_ci dev->recovery.hw_full_reset = true; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 173162306a36Sopenharmony_ci ieee80211_stop_queues(mt76_hw(dev)); 173262306a36Sopenharmony_ci if (phy2) 173362306a36Sopenharmony_ci ieee80211_stop_queues(phy2->mt76->hw); 173462306a36Sopenharmony_ci if (phy3) 173562306a36Sopenharmony_ci ieee80211_stop_queues(phy3->mt76->hw); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->mphy.mac_work); 173862306a36Sopenharmony_ci if (phy2) 173962306a36Sopenharmony_ci cancel_delayed_work_sync(&phy2->mt76->mac_work); 174062306a36Sopenharmony_ci if (phy3) 174162306a36Sopenharmony_ci cancel_delayed_work_sync(&phy3->mt76->mac_work); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 174462306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 174562306a36Sopenharmony_ci if (!mt7996_mac_restart(dev)) 174662306a36Sopenharmony_ci break; 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (i == 10) 175162306a36Sopenharmony_ci dev_err(dev->mt76.dev, "chip full reset failed\n"); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci ieee80211_restart_hw(mt76_hw(dev)); 175462306a36Sopenharmony_ci if (phy2) 175562306a36Sopenharmony_ci ieee80211_restart_hw(phy2->mt76->hw); 175662306a36Sopenharmony_ci if (phy3) 175762306a36Sopenharmony_ci ieee80211_restart_hw(phy3->mt76->hw); 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci ieee80211_wake_queues(mt76_hw(dev)); 176062306a36Sopenharmony_ci if (phy2) 176162306a36Sopenharmony_ci ieee80211_wake_queues(phy2->mt76->hw); 176262306a36Sopenharmony_ci if (phy3) 176362306a36Sopenharmony_ci ieee80211_wake_queues(phy3->mt76->hw); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci dev->recovery.hw_full_reset = false; 176662306a36Sopenharmony_ci ieee80211_queue_delayed_work(mt76_hw(dev), 176762306a36Sopenharmony_ci &dev->mphy.mac_work, 176862306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 176962306a36Sopenharmony_ci if (phy2) 177062306a36Sopenharmony_ci ieee80211_queue_delayed_work(phy2->mt76->hw, 177162306a36Sopenharmony_ci &phy2->mt76->mac_work, 177262306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 177362306a36Sopenharmony_ci if (phy3) 177462306a36Sopenharmony_ci ieee80211_queue_delayed_work(phy3->mt76->hw, 177562306a36Sopenharmony_ci &phy3->mt76->mac_work, 177662306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 177762306a36Sopenharmony_ci} 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_civoid mt7996_mac_reset_work(struct work_struct *work) 178062306a36Sopenharmony_ci{ 178162306a36Sopenharmony_ci struct mt7996_phy *phy2, *phy3; 178262306a36Sopenharmony_ci struct mt7996_dev *dev; 178362306a36Sopenharmony_ci int i; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci dev = container_of(work, struct mt7996_dev, reset_work); 178662306a36Sopenharmony_ci phy2 = mt7996_phy2(dev); 178762306a36Sopenharmony_ci phy3 = mt7996_phy3(dev); 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* chip full reset */ 179062306a36Sopenharmony_ci if (dev->recovery.restart) { 179162306a36Sopenharmony_ci /* disable WA/WM WDT */ 179262306a36Sopenharmony_ci mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA, 179362306a36Sopenharmony_ci MT_MCU_CMD_WDT_MASK); 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT) 179662306a36Sopenharmony_ci dev->recovery.wa_reset_count++; 179762306a36Sopenharmony_ci else 179862306a36Sopenharmony_ci dev->recovery.wm_reset_count++; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci mt7996_mac_full_reset(dev); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci /* enable mcu irq */ 180362306a36Sopenharmony_ci mt7996_irq_enable(dev, MT_INT_MCU_CMD); 180462306a36Sopenharmony_ci mt7996_irq_disable(dev, 0); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci /* enable WA/WM WDT */ 180762306a36Sopenharmony_ci mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci dev->recovery.state = MT_MCU_CMD_NORMAL_STATE; 181062306a36Sopenharmony_ci dev->recovery.restart = false; 181162306a36Sopenharmony_ci return; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) 181562306a36Sopenharmony_ci return; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.", 181862306a36Sopenharmony_ci wiphy_name(dev->mt76.hw->wiphy)); 181962306a36Sopenharmony_ci ieee80211_stop_queues(mt76_hw(dev)); 182062306a36Sopenharmony_ci if (phy2) 182162306a36Sopenharmony_ci ieee80211_stop_queues(phy2->mt76->hw); 182262306a36Sopenharmony_ci if (phy3) 182362306a36Sopenharmony_ci ieee80211_stop_queues(phy3->mt76->hw); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 182662306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &dev->mphy.state); 182762306a36Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 182862306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->mphy.mac_work); 182962306a36Sopenharmony_ci if (phy2) { 183062306a36Sopenharmony_ci set_bit(MT76_RESET, &phy2->mt76->state); 183162306a36Sopenharmony_ci cancel_delayed_work_sync(&phy2->mt76->mac_work); 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci if (phy3) { 183462306a36Sopenharmony_ci set_bit(MT76_RESET, &phy3->mt76->state); 183562306a36Sopenharmony_ci cancel_delayed_work_sync(&phy3->mt76->mac_work); 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 183862306a36Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) 183962306a36Sopenharmony_ci napi_disable(&dev->mt76.napi[i]); 184062306a36Sopenharmony_ci napi_disable(&dev->mt76.tx_napi); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { 184762306a36Sopenharmony_ci mt7996_dma_reset(dev, false); 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci mt7996_tx_token_put(dev); 185062306a36Sopenharmony_ci idr_init(&dev->mt76.token); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); 185362306a36Sopenharmony_ci mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); 185762306a36Sopenharmony_ci mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci /* enable DMA Tx/Tx and interrupt */ 186062306a36Sopenharmony_ci mt7996_dma_start(dev, false); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci clear_bit(MT76_MCU_RESET, &dev->mphy.state); 186362306a36Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 186462306a36Sopenharmony_ci if (phy2) 186562306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy2->mt76->state); 186662306a36Sopenharmony_ci if (phy3) 186762306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy3->mt76->state); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci local_bh_disable(); 187062306a36Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) { 187162306a36Sopenharmony_ci napi_enable(&dev->mt76.napi[i]); 187262306a36Sopenharmony_ci napi_schedule(&dev->mt76.napi[i]); 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci local_bh_enable(); 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci tasklet_schedule(&dev->mt76.irq_tasklet); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci local_bh_disable(); 188162306a36Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 188262306a36Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 188362306a36Sopenharmony_ci local_bh_enable(); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci ieee80211_wake_queues(mt76_hw(dev)); 188662306a36Sopenharmony_ci if (phy2) 188762306a36Sopenharmony_ci ieee80211_wake_queues(phy2->mt76->hw); 188862306a36Sopenharmony_ci if (phy3) 188962306a36Sopenharmony_ci ieee80211_wake_queues(phy3->mt76->hw); 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci mt7996_update_beacons(dev); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, 189662306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 189762306a36Sopenharmony_ci if (phy2) 189862306a36Sopenharmony_ci ieee80211_queue_delayed_work(phy2->mt76->hw, 189962306a36Sopenharmony_ci &phy2->mt76->mac_work, 190062306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 190162306a36Sopenharmony_ci if (phy3) 190262306a36Sopenharmony_ci ieee80211_queue_delayed_work(phy3->mt76->hw, 190362306a36Sopenharmony_ci &phy3->mt76->mac_work, 190462306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 190562306a36Sopenharmony_ci dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.", 190662306a36Sopenharmony_ci wiphy_name(dev->mt76.hw->wiphy)); 190762306a36Sopenharmony_ci} 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci/* firmware coredump */ 191062306a36Sopenharmony_civoid mt7996_mac_dump_work(struct work_struct *work) 191162306a36Sopenharmony_ci{ 191262306a36Sopenharmony_ci const struct mt7996_mem_region *mem_region; 191362306a36Sopenharmony_ci struct mt7996_crash_data *crash_data; 191462306a36Sopenharmony_ci struct mt7996_dev *dev; 191562306a36Sopenharmony_ci struct mt7996_mem_hdr *hdr; 191662306a36Sopenharmony_ci size_t buf_len; 191762306a36Sopenharmony_ci int i; 191862306a36Sopenharmony_ci u32 num; 191962306a36Sopenharmony_ci u8 *buf; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci dev = container_of(work, struct mt7996_dev, dump_work); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci mutex_lock(&dev->dump_mutex); 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci crash_data = mt7996_coredump_new(dev); 192662306a36Sopenharmony_ci if (!crash_data) { 192762306a36Sopenharmony_ci mutex_unlock(&dev->dump_mutex); 192862306a36Sopenharmony_ci goto skip_coredump; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci mem_region = mt7996_coredump_get_mem_layout(dev, &num); 193262306a36Sopenharmony_ci if (!mem_region || !crash_data->memdump_buf_len) { 193362306a36Sopenharmony_ci mutex_unlock(&dev->dump_mutex); 193462306a36Sopenharmony_ci goto skip_memdump; 193562306a36Sopenharmony_ci } 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci buf = crash_data->memdump_buf; 193862306a36Sopenharmony_ci buf_len = crash_data->memdump_buf_len; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci /* dumping memory content... */ 194162306a36Sopenharmony_ci memset(buf, 0, buf_len); 194262306a36Sopenharmony_ci for (i = 0; i < num; i++) { 194362306a36Sopenharmony_ci if (mem_region->len > buf_len) { 194462306a36Sopenharmony_ci dev_warn(dev->mt76.dev, "%s len %zu is too large\n", 194562306a36Sopenharmony_ci mem_region->name, mem_region->len); 194662306a36Sopenharmony_ci break; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci /* reserve space for the header */ 195062306a36Sopenharmony_ci hdr = (void *)buf; 195162306a36Sopenharmony_ci buf += sizeof(*hdr); 195262306a36Sopenharmony_ci buf_len -= sizeof(*hdr); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci mt7996_memcpy_fromio(dev, buf, mem_region->start, 195562306a36Sopenharmony_ci mem_region->len); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci hdr->start = mem_region->start; 195862306a36Sopenharmony_ci hdr->len = mem_region->len; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci if (!mem_region->len) 196162306a36Sopenharmony_ci /* note: the header remains, just with zero length */ 196262306a36Sopenharmony_ci break; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci buf += mem_region->len; 196562306a36Sopenharmony_ci buf_len -= mem_region->len; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci mem_region++; 196862306a36Sopenharmony_ci } 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci mutex_unlock(&dev->dump_mutex); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ciskip_memdump: 197362306a36Sopenharmony_ci mt7996_coredump_submit(dev); 197462306a36Sopenharmony_ciskip_coredump: 197562306a36Sopenharmony_ci queue_work(dev->mt76.wq, &dev->reset_work); 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_civoid mt7996_reset(struct mt7996_dev *dev) 197962306a36Sopenharmony_ci{ 198062306a36Sopenharmony_ci if (!dev->recovery.hw_init_done) 198162306a36Sopenharmony_ci return; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci if (dev->recovery.hw_full_reset) 198462306a36Sopenharmony_ci return; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci /* wm/wa exception: do full recovery */ 198762306a36Sopenharmony_ci if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) { 198862306a36Sopenharmony_ci dev->recovery.restart = true; 198962306a36Sopenharmony_ci dev_info(dev->mt76.dev, 199062306a36Sopenharmony_ci "%s indicated firmware crash, attempting recovery\n", 199162306a36Sopenharmony_ci wiphy_name(dev->mt76.hw->wiphy)); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci mt7996_irq_disable(dev, MT_INT_MCU_CMD); 199462306a36Sopenharmony_ci queue_work(dev->mt76.wq, &dev->dump_work); 199562306a36Sopenharmony_ci return; 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci queue_work(dev->mt76.wq, &dev->reset_work); 199962306a36Sopenharmony_ci wake_up(&dev->reset_wait); 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_civoid mt7996_mac_update_stats(struct mt7996_phy *phy) 200362306a36Sopenharmony_ci{ 200462306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 200562306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 200662306a36Sopenharmony_ci u8 band_idx = phy->mt76->band_idx; 200762306a36Sopenharmony_ci u32 cnt; 200862306a36Sopenharmony_ci int i; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR1(band_idx)); 201162306a36Sopenharmony_ci mib->fcs_err_cnt += cnt; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR33(band_idx)); 201462306a36Sopenharmony_ci mib->rx_fifo_full_cnt += cnt; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR31(band_idx)); 201762306a36Sopenharmony_ci mib->rx_mpdu_cnt += cnt; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR6(band_idx)); 202062306a36Sopenharmony_ci mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RVSR0(band_idx)); 202362306a36Sopenharmony_ci mib->rx_vector_mismatch_cnt += cnt; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR35(band_idx)); 202662306a36Sopenharmony_ci mib->rx_delimiter_fail_cnt += cnt; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR36(band_idx)); 202962306a36Sopenharmony_ci mib->rx_len_mismatch_cnt += cnt; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR0(band_idx)); 203262306a36Sopenharmony_ci mib->tx_ampdu_cnt += cnt; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR2(band_idx)); 203562306a36Sopenharmony_ci mib->tx_stop_q_empty_cnt += cnt; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR3(band_idx)); 203862306a36Sopenharmony_ci mib->tx_mpdu_attempts_cnt += cnt; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR4(band_idx)); 204162306a36Sopenharmony_ci mib->tx_mpdu_success_cnt += cnt; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR27(band_idx)); 204462306a36Sopenharmony_ci mib->rx_ampdu_cnt += cnt; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR28(band_idx)); 204762306a36Sopenharmony_ci mib->rx_ampdu_bytes_cnt += cnt; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR29(band_idx)); 205062306a36Sopenharmony_ci mib->rx_ampdu_valid_subframe_cnt += cnt; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RSCR30(band_idx)); 205362306a36Sopenharmony_ci mib->rx_ampdu_valid_subframe_bytes_cnt += cnt; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR27(band_idx)); 205662306a36Sopenharmony_ci mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT, cnt); 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR28(band_idx)); 205962306a36Sopenharmony_ci mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT, cnt); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_UMIB_RPDCR(band_idx)); 206262306a36Sopenharmony_ci mib->rx_pfdrop_cnt += cnt; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_RVSR1(band_idx)); 206562306a36Sopenharmony_ci mib->rx_vec_queue_overflow_drop_cnt += cnt; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR1(band_idx)); 206862306a36Sopenharmony_ci mib->rx_ba_cnt += cnt; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR0(band_idx)); 207162306a36Sopenharmony_ci mib->tx_bf_ebf_ppdu_cnt += cnt; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR1(band_idx)); 207462306a36Sopenharmony_ci mib->tx_bf_ibf_ppdu_cnt += cnt; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR2(band_idx)); 207762306a36Sopenharmony_ci mib->tx_mu_bf_cnt += cnt; 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR5(band_idx)); 208062306a36Sopenharmony_ci mib->tx_mu_mpdu_cnt += cnt; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR6(band_idx)); 208362306a36Sopenharmony_ci mib->tx_mu_acked_mpdu_cnt += cnt; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_TSCR7(band_idx)); 208662306a36Sopenharmony_ci mib->tx_su_acked_mpdu_cnt += cnt; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR3(band_idx)); 208962306a36Sopenharmony_ci mib->tx_bf_rx_fb_ht_cnt += cnt; 209062306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += cnt; 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR4(band_idx)); 209362306a36Sopenharmony_ci mib->tx_bf_rx_fb_vht_cnt += cnt; 209462306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += cnt; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR5(band_idx)); 209762306a36Sopenharmony_ci mib->tx_bf_rx_fb_he_cnt += cnt; 209862306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += cnt; 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR6(band_idx)); 210162306a36Sopenharmony_ci mib->tx_bf_rx_fb_eht_cnt += cnt; 210262306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += cnt; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(band_idx)); 210562306a36Sopenharmony_ci mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt); 210662306a36Sopenharmony_ci mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt); 210762306a36Sopenharmony_ci mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt); 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR7(band_idx)); 211062306a36Sopenharmony_ci mib->tx_bf_fb_trig_cnt += cnt; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BSCR17(band_idx)); 211362306a36Sopenharmony_ci mib->tx_bf_fb_cpl_cnt += cnt; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { 211662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); 211762306a36Sopenharmony_ci mib->tx_amsdu[i] += cnt; 211862306a36Sopenharmony_ci mib->tx_amsdu_cnt += cnt; 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci /* rts count */ 212262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BTSCR5(band_idx)); 212362306a36Sopenharmony_ci mib->rts_cnt += cnt; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci /* rts retry count */ 212662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BTSCR6(band_idx)); 212762306a36Sopenharmony_ci mib->rts_retries_cnt += cnt; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci /* ba miss count */ 213062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BTSCR0(band_idx)); 213162306a36Sopenharmony_ci mib->ba_miss_cnt += cnt; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci /* ack fail count */ 213462306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BFTFCR(band_idx)); 213562306a36Sopenharmony_ci mib->ack_fail_cnt += cnt; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 213862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i)); 213962306a36Sopenharmony_ci phy->mt76->aggr_stats[i] += cnt; 214062306a36Sopenharmony_ci } 214162306a36Sopenharmony_ci} 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_civoid mt7996_mac_sta_rc_work(struct work_struct *work) 214462306a36Sopenharmony_ci{ 214562306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work); 214662306a36Sopenharmony_ci struct ieee80211_sta *sta; 214762306a36Sopenharmony_ci struct ieee80211_vif *vif; 214862306a36Sopenharmony_ci struct mt7996_sta *msta; 214962306a36Sopenharmony_ci u32 changed; 215062306a36Sopenharmony_ci LIST_HEAD(list); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 215362306a36Sopenharmony_ci list_splice_init(&dev->sta_rc_list, &list); 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci while (!list_empty(&list)) { 215662306a36Sopenharmony_ci msta = list_first_entry(&list, struct mt7996_sta, rc_list); 215762306a36Sopenharmony_ci list_del_init(&msta->rc_list); 215862306a36Sopenharmony_ci changed = msta->changed; 215962306a36Sopenharmony_ci msta->changed = 0; 216062306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); 216362306a36Sopenharmony_ci vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED | 216662306a36Sopenharmony_ci IEEE80211_RC_NSS_CHANGED | 216762306a36Sopenharmony_ci IEEE80211_RC_BW_CHANGED)) 216862306a36Sopenharmony_ci mt7996_mcu_add_rate_ctrl(dev, vif, sta, true); 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci /* TODO: smps change */ 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 217662306a36Sopenharmony_ci} 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_civoid mt7996_mac_work(struct work_struct *work) 217962306a36Sopenharmony_ci{ 218062306a36Sopenharmony_ci struct mt7996_phy *phy; 218162306a36Sopenharmony_ci struct mt76_phy *mphy; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, 218462306a36Sopenharmony_ci mac_work.work); 218562306a36Sopenharmony_ci phy = mphy->priv; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci mutex_lock(&mphy->dev->mutex); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci mt76_update_survey(mphy); 219062306a36Sopenharmony_ci if (++mphy->mac_work_count == 5) { 219162306a36Sopenharmony_ci mphy->mac_work_count = 0; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci mt7996_mac_update_stats(phy); 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci mutex_unlock(&mphy->dev->mutex); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci mt76_tx_status_check(mphy->dev, false); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, 220162306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 220262306a36Sopenharmony_ci} 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_cistatic void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy) 220562306a36Sopenharmony_ci{ 220662306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci if (phy->rdd_state & BIT(0)) 220962306a36Sopenharmony_ci mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0, 221062306a36Sopenharmony_ci MT_RX_SEL0, 0); 221162306a36Sopenharmony_ci if (phy->rdd_state & BIT(1)) 221262306a36Sopenharmony_ci mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1, 221362306a36Sopenharmony_ci MT_RX_SEL0, 0); 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_cistatic int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain) 221762306a36Sopenharmony_ci{ 221862306a36Sopenharmony_ci int err, region; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci switch (dev->mt76.region) { 222162306a36Sopenharmony_ci case NL80211_DFS_ETSI: 222262306a36Sopenharmony_ci region = 0; 222362306a36Sopenharmony_ci break; 222462306a36Sopenharmony_ci case NL80211_DFS_JP: 222562306a36Sopenharmony_ci region = 2; 222662306a36Sopenharmony_ci break; 222762306a36Sopenharmony_ci case NL80211_DFS_FCC: 222862306a36Sopenharmony_ci default: 222962306a36Sopenharmony_ci region = 1; 223062306a36Sopenharmony_ci break; 223162306a36Sopenharmony_ci } 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain, 223462306a36Sopenharmony_ci MT_RX_SEL0, region); 223562306a36Sopenharmony_ci if (err < 0) 223662306a36Sopenharmony_ci return err; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, 223962306a36Sopenharmony_ci MT_RX_SEL0, 1); 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_cistatic int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) 224362306a36Sopenharmony_ci{ 224462306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 224562306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 224662306a36Sopenharmony_ci u8 band_idx = phy->mt76->band_idx; 224762306a36Sopenharmony_ci int err; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci /* start CAC */ 225062306a36Sopenharmony_ci err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx, 225162306a36Sopenharmony_ci MT_RX_SEL0, 0); 225262306a36Sopenharmony_ci if (err < 0) 225362306a36Sopenharmony_ci return err; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci err = mt7996_dfs_start_rdd(dev, band_idx); 225662306a36Sopenharmony_ci if (err < 0) 225762306a36Sopenharmony_ci return err; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci phy->rdd_state |= BIT(band_idx); 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_160 || 226262306a36Sopenharmony_ci chandef->width == NL80211_CHAN_WIDTH_80P80) { 226362306a36Sopenharmony_ci err = mt7996_dfs_start_rdd(dev, 1); 226462306a36Sopenharmony_ci if (err < 0) 226562306a36Sopenharmony_ci return err; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci phy->rdd_state |= BIT(1); 226862306a36Sopenharmony_ci } 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci return 0; 227162306a36Sopenharmony_ci} 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_cistatic int 227462306a36Sopenharmony_cimt7996_dfs_init_radar_specs(struct mt7996_phy *phy) 227562306a36Sopenharmony_ci{ 227662306a36Sopenharmony_ci const struct mt7996_dfs_radar_spec *radar_specs; 227762306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 227862306a36Sopenharmony_ci int err, i; 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci switch (dev->mt76.region) { 228162306a36Sopenharmony_ci case NL80211_DFS_FCC: 228262306a36Sopenharmony_ci radar_specs = &fcc_radar_specs; 228362306a36Sopenharmony_ci err = mt7996_mcu_set_fcc5_lpn(dev, 8); 228462306a36Sopenharmony_ci if (err < 0) 228562306a36Sopenharmony_ci return err; 228662306a36Sopenharmony_ci break; 228762306a36Sopenharmony_ci case NL80211_DFS_ETSI: 228862306a36Sopenharmony_ci radar_specs = &etsi_radar_specs; 228962306a36Sopenharmony_ci break; 229062306a36Sopenharmony_ci case NL80211_DFS_JP: 229162306a36Sopenharmony_ci radar_specs = &jp_radar_specs; 229262306a36Sopenharmony_ci break; 229362306a36Sopenharmony_ci default: 229462306a36Sopenharmony_ci return -EINVAL; 229562306a36Sopenharmony_ci } 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { 229862306a36Sopenharmony_ci err = mt7996_mcu_set_radar_th(dev, i, 229962306a36Sopenharmony_ci &radar_specs->radar_pattern[i]); 230062306a36Sopenharmony_ci if (err < 0) 230162306a36Sopenharmony_ci return err; 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th); 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ciint mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) 230862306a36Sopenharmony_ci{ 230962306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 231062306a36Sopenharmony_ci enum mt76_dfs_state dfs_state, prev_state; 231162306a36Sopenharmony_ci int err; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci prev_state = phy->mt76->dfs_state; 231462306a36Sopenharmony_ci dfs_state = mt76_phy_dfs_state(phy->mt76); 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci if (prev_state == dfs_state) 231762306a36Sopenharmony_ci return 0; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci if (prev_state == MT_DFS_STATE_UNKNOWN) 232062306a36Sopenharmony_ci mt7996_dfs_stop_radar_detector(phy); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci if (dfs_state == MT_DFS_STATE_DISABLED) 232362306a36Sopenharmony_ci goto stop; 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci if (prev_state <= MT_DFS_STATE_DISABLED) { 232662306a36Sopenharmony_ci err = mt7996_dfs_init_radar_specs(phy); 232762306a36Sopenharmony_ci if (err < 0) 232862306a36Sopenharmony_ci return err; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci err = mt7996_dfs_start_radar_detector(phy); 233162306a36Sopenharmony_ci if (err < 0) 233262306a36Sopenharmony_ci return err; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_CAC; 233562306a36Sopenharmony_ci } 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci if (dfs_state == MT_DFS_STATE_CAC) 233862306a36Sopenharmony_ci return 0; 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END, 234162306a36Sopenharmony_ci phy->mt76->band_idx, MT_RX_SEL0, 0); 234262306a36Sopenharmony_ci if (err < 0) { 234362306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; 234462306a36Sopenharmony_ci return err; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE; 234862306a36Sopenharmony_ci return 0; 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_cistop: 235162306a36Sopenharmony_ci err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START, 235262306a36Sopenharmony_ci phy->mt76->band_idx, MT_RX_SEL0, 0); 235362306a36Sopenharmony_ci if (err < 0) 235462306a36Sopenharmony_ci return err; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci mt7996_dfs_stop_radar_detector(phy); 235762306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_DISABLED; 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci return 0; 236062306a36Sopenharmony_ci} 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_cistatic int 236362306a36Sopenharmony_cimt7996_mac_twt_duration_align(int duration) 236462306a36Sopenharmony_ci{ 236562306a36Sopenharmony_ci return duration << 8; 236662306a36Sopenharmony_ci} 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_cistatic u64 236962306a36Sopenharmony_cimt7996_mac_twt_sched_list_add(struct mt7996_dev *dev, 237062306a36Sopenharmony_ci struct mt7996_twt_flow *flow) 237162306a36Sopenharmony_ci{ 237262306a36Sopenharmony_ci struct mt7996_twt_flow *iter, *iter_next; 237362306a36Sopenharmony_ci u32 duration = flow->duration << 8; 237462306a36Sopenharmony_ci u64 start_tsf; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci iter = list_first_entry_or_null(&dev->twt_list, 237762306a36Sopenharmony_ci struct mt7996_twt_flow, list); 237862306a36Sopenharmony_ci if (!iter || !iter->sched || iter->start_tsf > duration) { 237962306a36Sopenharmony_ci /* add flow as first entry in the list */ 238062306a36Sopenharmony_ci list_add(&flow->list, &dev->twt_list); 238162306a36Sopenharmony_ci return 0; 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) { 238562306a36Sopenharmony_ci start_tsf = iter->start_tsf + 238662306a36Sopenharmony_ci mt7996_mac_twt_duration_align(iter->duration); 238762306a36Sopenharmony_ci if (list_is_last(&iter->list, &dev->twt_list)) 238862306a36Sopenharmony_ci break; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci if (!iter_next->sched || 239162306a36Sopenharmony_ci iter_next->start_tsf > start_tsf + duration) { 239262306a36Sopenharmony_ci list_add(&flow->list, &iter->list); 239362306a36Sopenharmony_ci goto out; 239462306a36Sopenharmony_ci } 239562306a36Sopenharmony_ci } 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci /* add flow as last entry in the list */ 239862306a36Sopenharmony_ci list_add_tail(&flow->list, &dev->twt_list); 239962306a36Sopenharmony_ciout: 240062306a36Sopenharmony_ci return start_tsf; 240162306a36Sopenharmony_ci} 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_cistatic int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt) 240462306a36Sopenharmony_ci{ 240562306a36Sopenharmony_ci struct ieee80211_twt_params *twt_agrt; 240662306a36Sopenharmony_ci u64 interval, duration; 240762306a36Sopenharmony_ci u16 mantissa; 240862306a36Sopenharmony_ci u8 exp; 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci /* only individual agreement supported */ 241162306a36Sopenharmony_ci if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) 241262306a36Sopenharmony_ci return -EOPNOTSUPP; 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci /* only 256us unit supported */ 241562306a36Sopenharmony_ci if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) 241662306a36Sopenharmony_ci return -EOPNOTSUPP; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci twt_agrt = (struct ieee80211_twt_params *)twt->params; 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci /* explicit agreement not supported */ 242162306a36Sopenharmony_ci if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT))) 242262306a36Sopenharmony_ci return -EOPNOTSUPP; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, 242562306a36Sopenharmony_ci le16_to_cpu(twt_agrt->req_type)); 242662306a36Sopenharmony_ci mantissa = le16_to_cpu(twt_agrt->mantissa); 242762306a36Sopenharmony_ci duration = twt_agrt->min_twt_dur << 8; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci interval = (u64)mantissa << exp; 243062306a36Sopenharmony_ci if (interval < duration) 243162306a36Sopenharmony_ci return -EOPNOTSUPP; 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci return 0; 243462306a36Sopenharmony_ci} 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_cistatic bool 243762306a36Sopenharmony_cimt7996_mac_twt_param_equal(struct mt7996_sta *msta, 243862306a36Sopenharmony_ci struct ieee80211_twt_params *twt_agrt) 243962306a36Sopenharmony_ci{ 244062306a36Sopenharmony_ci u16 type = le16_to_cpu(twt_agrt->req_type); 244162306a36Sopenharmony_ci u8 exp; 244262306a36Sopenharmony_ci int i; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type); 244562306a36Sopenharmony_ci for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) { 244662306a36Sopenharmony_ci struct mt7996_twt_flow *f; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci if (!(msta->twt.flowid_mask & BIT(i))) 244962306a36Sopenharmony_ci continue; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci f = &msta->twt.flow[i]; 245262306a36Sopenharmony_ci if (f->duration == twt_agrt->min_twt_dur && 245362306a36Sopenharmony_ci f->mantissa == twt_agrt->mantissa && 245462306a36Sopenharmony_ci f->exp == exp && 245562306a36Sopenharmony_ci f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) && 245662306a36Sopenharmony_ci f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) && 245762306a36Sopenharmony_ci f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER)) 245862306a36Sopenharmony_ci return true; 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci return false; 246262306a36Sopenharmony_ci} 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_civoid mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, 246562306a36Sopenharmony_ci struct ieee80211_sta *sta, 246662306a36Sopenharmony_ci struct ieee80211_twt_setup *twt) 246762306a36Sopenharmony_ci{ 246862306a36Sopenharmony_ci enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT; 246962306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 247062306a36Sopenharmony_ci struct ieee80211_twt_params *twt_agrt = (void *)twt->params; 247162306a36Sopenharmony_ci u16 req_type = le16_to_cpu(twt_agrt->req_type); 247262306a36Sopenharmony_ci enum ieee80211_twt_setup_cmd sta_setup_cmd; 247362306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 247462306a36Sopenharmony_ci struct mt7996_twt_flow *flow; 247562306a36Sopenharmony_ci u8 flowid, table_id, exp; 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci if (mt7996_mac_check_twt_req(twt)) 247862306a36Sopenharmony_ci goto out; 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT) 248362306a36Sopenharmony_ci goto unlock; 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) 248662306a36Sopenharmony_ci goto unlock; 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) { 248962306a36Sopenharmony_ci setup_cmd = TWT_SETUP_CMD_DICTATE; 249062306a36Sopenharmony_ci twt_agrt->min_twt_dur = MT7996_MIN_TWT_DUR; 249162306a36Sopenharmony_ci goto unlock; 249262306a36Sopenharmony_ci } 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci if (mt7996_mac_twt_param_equal(msta, twt_agrt)) 249562306a36Sopenharmony_ci goto unlock; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci flowid = ffs(~msta->twt.flowid_mask) - 1; 249862306a36Sopenharmony_ci twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID); 249962306a36Sopenharmony_ci twt_agrt->req_type |= le16_encode_bits(flowid, 250062306a36Sopenharmony_ci IEEE80211_TWT_REQTYPE_FLOWID); 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci table_id = ffs(~dev->twt.table_mask) - 1; 250362306a36Sopenharmony_ci exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type); 250462306a36Sopenharmony_ci sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci flow = &msta->twt.flow[flowid]; 250762306a36Sopenharmony_ci memset(flow, 0, sizeof(*flow)); 250862306a36Sopenharmony_ci INIT_LIST_HEAD(&flow->list); 250962306a36Sopenharmony_ci flow->wcid = msta->wcid.idx; 251062306a36Sopenharmony_ci flow->table_id = table_id; 251162306a36Sopenharmony_ci flow->id = flowid; 251262306a36Sopenharmony_ci flow->duration = twt_agrt->min_twt_dur; 251362306a36Sopenharmony_ci flow->mantissa = twt_agrt->mantissa; 251462306a36Sopenharmony_ci flow->exp = exp; 251562306a36Sopenharmony_ci flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION); 251662306a36Sopenharmony_ci flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE); 251762306a36Sopenharmony_ci flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST || 252062306a36Sopenharmony_ci sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) { 252162306a36Sopenharmony_ci u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp; 252262306a36Sopenharmony_ci u64 flow_tsf, curr_tsf; 252362306a36Sopenharmony_ci u32 rem; 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci flow->sched = true; 252662306a36Sopenharmony_ci flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow); 252762306a36Sopenharmony_ci curr_tsf = __mt7996_get_tsf(hw, msta->vif); 252862306a36Sopenharmony_ci div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem); 252962306a36Sopenharmony_ci flow_tsf = curr_tsf + interval - rem; 253062306a36Sopenharmony_ci twt_agrt->twt = cpu_to_le64(flow_tsf); 253162306a36Sopenharmony_ci } else { 253262306a36Sopenharmony_ci list_add_tail(&flow->list, &dev->twt_list); 253362306a36Sopenharmony_ci } 253462306a36Sopenharmony_ci flow->tsf = le64_to_cpu(twt_agrt->twt); 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD)) 253762306a36Sopenharmony_ci goto unlock; 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci setup_cmd = TWT_SETUP_CMD_ACCEPT; 254062306a36Sopenharmony_ci dev->twt.table_mask |= BIT(table_id); 254162306a36Sopenharmony_ci msta->twt.flowid_mask |= BIT(flowid); 254262306a36Sopenharmony_ci dev->twt.n_agrt++; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ciunlock: 254562306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 254662306a36Sopenharmony_ciout: 254762306a36Sopenharmony_ci twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD); 254862306a36Sopenharmony_ci twt_agrt->req_type |= 254962306a36Sopenharmony_ci le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD); 255062306a36Sopenharmony_ci twt->control = twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED; 255162306a36Sopenharmony_ci} 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_civoid mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, 255462306a36Sopenharmony_ci struct mt7996_sta *msta, 255562306a36Sopenharmony_ci u8 flowid) 255662306a36Sopenharmony_ci{ 255762306a36Sopenharmony_ci struct mt7996_twt_flow *flow; 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci lockdep_assert_held(&dev->mt76.mutex); 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci if (flowid >= ARRAY_SIZE(msta->twt.flow)) 256262306a36Sopenharmony_ci return; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci if (!(msta->twt.flowid_mask & BIT(flowid))) 256562306a36Sopenharmony_ci return; 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci flow = &msta->twt.flow[flowid]; 256862306a36Sopenharmony_ci if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, 256962306a36Sopenharmony_ci MCU_TWT_AGRT_DELETE)) 257062306a36Sopenharmony_ci return; 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci list_del_init(&flow->list); 257362306a36Sopenharmony_ci msta->twt.flowid_mask &= ~BIT(flowid); 257462306a36Sopenharmony_ci dev->twt.table_mask &= ~BIT(flow->table_id); 257562306a36Sopenharmony_ci dev->twt.n_agrt--; 257662306a36Sopenharmony_ci} 2577