162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/etherdevice.h> 562306a36Sopenharmony_ci#include <linux/timekeeping.h> 662306a36Sopenharmony_ci#include "coredump.h" 762306a36Sopenharmony_ci#include "mt7915.h" 862306a36Sopenharmony_ci#include "../dma.h" 962306a36Sopenharmony_ci#include "mac.h" 1062306a36Sopenharmony_ci#include "mcu.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic const struct mt7915_dfs_radar_spec etsi_radar_specs = { 1562306a36Sopenharmony_ci .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, 1662306a36Sopenharmony_ci .radar_pattern = { 1762306a36Sopenharmony_ci [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, 1862306a36Sopenharmony_ci [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, 1962306a36Sopenharmony_ci [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, 2062306a36Sopenharmony_ci [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, 2162306a36Sopenharmony_ci [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, 2262306a36Sopenharmony_ci [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, 2362306a36Sopenharmony_ci [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, 2462306a36Sopenharmony_ci [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, 2562306a36Sopenharmony_ci }, 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct mt7915_dfs_radar_spec fcc_radar_specs = { 2962306a36Sopenharmony_ci .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, 3062306a36Sopenharmony_ci .radar_pattern = { 3162306a36Sopenharmony_ci [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, 3262306a36Sopenharmony_ci [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, 3362306a36Sopenharmony_ci [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, 3462306a36Sopenharmony_ci [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, 3562306a36Sopenharmony_ci [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, 3662306a36Sopenharmony_ci }, 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const struct mt7915_dfs_radar_spec jp_radar_specs = { 4062306a36Sopenharmony_ci .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, 4162306a36Sopenharmony_ci .radar_pattern = { 4262306a36Sopenharmony_ci [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, 4362306a36Sopenharmony_ci [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, 4462306a36Sopenharmony_ci [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, 4562306a36Sopenharmony_ci [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, 4662306a36Sopenharmony_ci [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, 4762306a36Sopenharmony_ci [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, 4862306a36Sopenharmony_ci [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, 4962306a36Sopenharmony_ci [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, 5062306a36Sopenharmony_ci }, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev, 5462306a36Sopenharmony_ci u16 idx, bool unicast) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct mt7915_sta *sta; 5762306a36Sopenharmony_ci struct mt76_wcid *wcid; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (idx >= ARRAY_SIZE(dev->mt76.wcid)) 6062306a36Sopenharmony_ci return NULL; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 6362306a36Sopenharmony_ci if (unicast || !wcid) 6462306a36Sopenharmony_ci return wcid; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (!wcid->sta) 6762306a36Sopenharmony_ci return NULL; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci sta = container_of(wcid, struct mt7915_sta, wcid); 7062306a36Sopenharmony_ci if (!sta->vif) 7162306a36Sopenharmony_ci return NULL; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return &sta->vif->sta.wcid; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cibool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, 7962306a36Sopenharmony_ci FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 8262306a36Sopenharmony_ci 0, 5000); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ciu32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci mt76_wr(dev, MT_WTBLON_TOP_WDUCR, 8862306a36Sopenharmony_ci FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return MT_WTBL_LMAC_OFFS(wcid, dw); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void mt7915_mac_sta_poll(struct mt7915_dev *dev) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci static const u8 ac_to_tid[] = { 9662306a36Sopenharmony_ci [IEEE80211_AC_BE] = 0, 9762306a36Sopenharmony_ci [IEEE80211_AC_BK] = 1, 9862306a36Sopenharmony_ci [IEEE80211_AC_VI] = 4, 9962306a36Sopenharmony_ci [IEEE80211_AC_VO] = 6 10062306a36Sopenharmony_ci }; 10162306a36Sopenharmony_ci struct ieee80211_sta *sta; 10262306a36Sopenharmony_ci struct mt7915_sta *msta; 10362306a36Sopenharmony_ci struct rate_info *rate; 10462306a36Sopenharmony_ci u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; 10562306a36Sopenharmony_ci LIST_HEAD(sta_poll_list); 10662306a36Sopenharmony_ci int i; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 10962306a36Sopenharmony_ci list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); 11062306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci rcu_read_lock(); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci while (true) { 11562306a36Sopenharmony_ci bool clear = false; 11662306a36Sopenharmony_ci u32 addr, val; 11762306a36Sopenharmony_ci u16 idx; 11862306a36Sopenharmony_ci s8 rssi[4]; 11962306a36Sopenharmony_ci u8 bw; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 12262306a36Sopenharmony_ci if (list_empty(&sta_poll_list)) { 12362306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci msta = list_first_entry(&sta_poll_list, 12762306a36Sopenharmony_ci struct mt7915_sta, wcid.poll_list); 12862306a36Sopenharmony_ci list_del_init(&msta->wcid.poll_list); 12962306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci idx = msta->wcid.idx; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* refresh peer's airtime reporting */ 13462306a36Sopenharmony_ci addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 13762306a36Sopenharmony_ci u32 tx_last = msta->airtime_ac[i]; 13862306a36Sopenharmony_ci u32 rx_last = msta->airtime_ac[i + 4]; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci msta->airtime_ac[i] = mt76_rr(dev, addr); 14162306a36Sopenharmony_ci msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci tx_time[i] = msta->airtime_ac[i] - tx_last; 14462306a36Sopenharmony_ci rx_time[i] = msta->airtime_ac[i + 4] - rx_last; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if ((tx_last | rx_last) & BIT(30)) 14762306a36Sopenharmony_ci clear = true; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci addr += 8; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (clear) { 15362306a36Sopenharmony_ci mt7915_mac_wtbl_update(dev, idx, 15462306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 15562306a36Sopenharmony_ci memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (!msta->wcid.sta) 15962306a36Sopenharmony_ci continue; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, 16262306a36Sopenharmony_ci drv_priv); 16362306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 16462306a36Sopenharmony_ci u8 queue = mt76_connac_lmac_mapping(i); 16562306a36Sopenharmony_ci u32 tx_cur = tx_time[queue]; 16662306a36Sopenharmony_ci u32 rx_cur = rx_time[queue]; 16762306a36Sopenharmony_ci u8 tid = ac_to_tid[i]; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (!tx_cur && !rx_cur) 17062306a36Sopenharmony_ci continue; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ieee80211_sta_register_airtime(sta, tid, tx_cur, 17362306a36Sopenharmony_ci rx_cur); 17462306a36Sopenharmony_ci } 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 addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 7); 18462306a36Sopenharmony_ci val = mt76_rr(dev, addr); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci switch (rate->bw) { 18762306a36Sopenharmony_ci case RATE_INFO_BW_160: 18862306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_160; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci case RATE_INFO_BW_80: 19162306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_80; 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci case RATE_INFO_BW_40: 19462306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_40; 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci default: 19762306a36Sopenharmony_ci bw = IEEE80211_STA_RX_BW_20; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { 20262306a36Sopenharmony_ci u8 offs = 24 + 2 * bw; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rate->he_gi = (val & (0x3 << offs)) >> offs; 20562306a36Sopenharmony_ci } else if (rate->flags & 20662306a36Sopenharmony_ci (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) { 20762306a36Sopenharmony_ci if (val & BIT(12 + bw)) 20862306a36Sopenharmony_ci rate->flags |= RATE_INFO_FLAGS_SHORT_GI; 20962306a36Sopenharmony_ci else 21062306a36Sopenharmony_ci rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* get signal strength of resp frames (CTS/BA/ACK) */ 21462306a36Sopenharmony_ci addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 30); 21562306a36Sopenharmony_ci val = mt76_rr(dev, addr); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci rssi[0] = to_rssi(GENMASK(7, 0), val); 21862306a36Sopenharmony_ci rssi[1] = to_rssi(GENMASK(15, 8), val); 21962306a36Sopenharmony_ci rssi[2] = to_rssi(GENMASK(23, 16), val); 22062306a36Sopenharmony_ci rssi[3] = to_rssi(GENMASK(31, 14), val); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci msta->ack_signal = 22362306a36Sopenharmony_ci mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci rcu_read_unlock(); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_civoid mt7915_mac_enable_rtscts(struct mt7915_dev *dev, 23262306a36Sopenharmony_ci struct ieee80211_vif *vif, bool enable) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 23562306a36Sopenharmony_ci u32 addr; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); 23862306a36Sopenharmony_ci if (enable) 23962306a36Sopenharmony_ci mt76_set(dev, addr, BIT(5)); 24062306a36Sopenharmony_ci else 24162306a36Sopenharmony_ci mt76_clear(dev, addr, BIT(5)); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void 24562306a36Sopenharmony_cimt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, 24662306a36Sopenharmony_ci struct mt7915_sta *msta, struct sk_buff *skb, 24762306a36Sopenharmony_ci u32 info) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct ieee80211_vif *vif; 25062306a36Sopenharmony_ci struct wireless_dev *wdev; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (!msta || !msta->vif) 25362306a36Sopenharmony_ci return; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (!mt76_queue_is_wed_rx(q)) 25662306a36Sopenharmony_ci return; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!(info & MT_DMA_INFO_PPE_VLD)) 25962306a36Sopenharmony_ci return; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci vif = container_of((void *)msta->vif, struct ieee80211_vif, 26262306a36Sopenharmony_ci drv_priv); 26362306a36Sopenharmony_ci wdev = ieee80211_vif_to_wdev(vif); 26462306a36Sopenharmony_ci skb->dev = wdev->netdev; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, 26762306a36Sopenharmony_ci FIELD_GET(MT_DMA_PPE_CPU_REASON, info), 26862306a36Sopenharmony_ci FIELD_GET(MT_DMA_PPE_ENTRY, info)); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int 27262306a36Sopenharmony_cimt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb, 27362306a36Sopenharmony_ci enum mt76_rxq_id q, u32 *info) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 27662306a36Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 27762306a36Sopenharmony_ci struct mt7915_phy *phy = &dev->phy; 27862306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 27962306a36Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 28062306a36Sopenharmony_ci __le32 *rxv = NULL; 28162306a36Sopenharmony_ci u32 rxd0 = le32_to_cpu(rxd[0]); 28262306a36Sopenharmony_ci u32 rxd1 = le32_to_cpu(rxd[1]); 28362306a36Sopenharmony_ci u32 rxd2 = le32_to_cpu(rxd[2]); 28462306a36Sopenharmony_ci u32 rxd3 = le32_to_cpu(rxd[3]); 28562306a36Sopenharmony_ci u32 rxd4 = le32_to_cpu(rxd[4]); 28662306a36Sopenharmony_ci u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; 28762306a36Sopenharmony_ci bool unicast, insert_ccmp_hdr = false; 28862306a36Sopenharmony_ci u8 remove_pad, amsdu_info; 28962306a36Sopenharmony_ci u8 mode = 0, qos_ctl = 0; 29062306a36Sopenharmony_ci struct mt7915_sta *msta = NULL; 29162306a36Sopenharmony_ci u32 csum_status = *(u32 *)skb->cb; 29262306a36Sopenharmony_ci bool hdr_trans; 29362306a36Sopenharmony_ci u16 hdr_gap; 29462306a36Sopenharmony_ci u16 seq_ctrl = 0; 29562306a36Sopenharmony_ci __le16 fc = 0; 29662306a36Sopenharmony_ci int idx; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci memset(status, 0, sizeof(*status)); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->mt76->band_idx) { 30162306a36Sopenharmony_ci mphy = dev->mt76.phys[MT_BAND1]; 30262306a36Sopenharmony_ci if (!mphy) 30362306a36Sopenharmony_ci return -EINVAL; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci phy = mphy->priv; 30662306a36Sopenharmony_ci status->phy_idx = 1; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; 31662306a36Sopenharmony_ci if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM)) 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* ICV error or CCMP/BIP/WPI MIC error */ 32062306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) 32162306a36Sopenharmony_ci status->flag |= RX_FLAG_ONLY_MONITOR; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; 32462306a36Sopenharmony_ci idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); 32562306a36Sopenharmony_ci status->wcid = mt7915_rx_get_wcid(dev, idx, unicast); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (status->wcid) { 32862306a36Sopenharmony_ci msta = container_of(status->wcid, struct mt7915_sta, wcid); 32962306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 33062306a36Sopenharmony_ci if (list_empty(&msta->wcid.poll_list)) 33162306a36Sopenharmony_ci list_add_tail(&msta->wcid.poll_list, 33262306a36Sopenharmony_ci &dev->mt76.sta_poll_list); 33362306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci status->freq = mphy->chandef.chan->center_freq; 33762306a36Sopenharmony_ci status->band = mphy->chandef.chan->band; 33862306a36Sopenharmony_ci if (status->band == NL80211_BAND_5GHZ) 33962306a36Sopenharmony_ci sband = &mphy->sband_5g.sband; 34062306a36Sopenharmony_ci else if (status->band == NL80211_BAND_6GHZ) 34162306a36Sopenharmony_ci sband = &mphy->sband_6g.sband; 34262306a36Sopenharmony_ci else 34362306a36Sopenharmony_ci sband = &mphy->sband_2g.sband; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (!sband->channels) 34662306a36Sopenharmony_ci return -EINVAL; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if ((rxd0 & csum_mask) == csum_mask && 34962306a36Sopenharmony_ci !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) 35062306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) 35362306a36Sopenharmony_ci status->flag |= RX_FLAG_FAILED_FCS_CRC; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) 35662306a36Sopenharmony_ci status->flag |= RX_FLAG_MMIC_ERROR; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 && 35962306a36Sopenharmony_ci !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { 36062306a36Sopenharmony_ci status->flag |= RX_FLAG_DECRYPTED; 36162306a36Sopenharmony_ci status->flag |= RX_FLAG_IV_STRIPPED; 36262306a36Sopenharmony_ci status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) 36862306a36Sopenharmony_ci return -EINVAL; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci rxd += 6; 37162306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { 37262306a36Sopenharmony_ci u32 v0 = le32_to_cpu(rxd[0]); 37362306a36Sopenharmony_ci u32 v2 = le32_to_cpu(rxd[2]); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0)); 37662306a36Sopenharmony_ci qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2); 37762306a36Sopenharmony_ci seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci rxd += 4; 38062306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { 38562306a36Sopenharmony_ci u8 *data = (u8 *)rxd; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) { 38862306a36Sopenharmony_ci switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { 38962306a36Sopenharmony_ci case MT_CIPHER_AES_CCMP: 39062306a36Sopenharmony_ci case MT_CIPHER_CCMP_CCX: 39162306a36Sopenharmony_ci case MT_CIPHER_CCMP_256: 39262306a36Sopenharmony_ci insert_ccmp_hdr = 39362306a36Sopenharmony_ci FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); 39462306a36Sopenharmony_ci fallthrough; 39562306a36Sopenharmony_ci case MT_CIPHER_TKIP: 39662306a36Sopenharmony_ci case MT_CIPHER_TKIP_NO_MIC: 39762306a36Sopenharmony_ci case MT_CIPHER_GCMP: 39862306a36Sopenharmony_ci case MT_CIPHER_GCMP_256: 39962306a36Sopenharmony_ci status->iv[0] = data[5]; 40062306a36Sopenharmony_ci status->iv[1] = data[4]; 40162306a36Sopenharmony_ci status->iv[2] = data[3]; 40262306a36Sopenharmony_ci status->iv[3] = data[2]; 40362306a36Sopenharmony_ci status->iv[4] = data[1]; 40462306a36Sopenharmony_ci status->iv[5] = data[0]; 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci default: 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci rxd += 4; 41162306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 41262306a36Sopenharmony_ci return -EINVAL; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { 41662306a36Sopenharmony_ci status->timestamp = le32_to_cpu(rxd[0]); 41762306a36Sopenharmony_ci status->flag |= RX_FLAG_MACTIME_START; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { 42062306a36Sopenharmony_ci status->flag |= RX_FLAG_AMPDU_DETAILS; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* all subframes of an A-MPDU have the same timestamp */ 42362306a36Sopenharmony_ci if (phy->rx_ampdu_ts != status->timestamp) { 42462306a36Sopenharmony_ci if (!++phy->ampdu_ref) 42562306a36Sopenharmony_ci phy->ampdu_ref++; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci phy->rx_ampdu_ts = status->timestamp; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci status->ampdu_ref = phy->ampdu_ref; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci rxd += 2; 43362306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* RXD Group 3 - P-RXV */ 43862306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { 43962306a36Sopenharmony_ci u32 v0, v1; 44062306a36Sopenharmony_ci int ret; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci rxv = rxd; 44362306a36Sopenharmony_ci rxd += 2; 44462306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 44562306a36Sopenharmony_ci return -EINVAL; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci v0 = le32_to_cpu(rxv[0]); 44862306a36Sopenharmony_ci v1 = le32_to_cpu(rxv[1]); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (v0 & MT_PRXV_HT_AD_CODE) 45162306a36Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_LDPC; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci status->chains = mphy->antenna_mask; 45462306a36Sopenharmony_ci status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1); 45562306a36Sopenharmony_ci status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); 45662306a36Sopenharmony_ci status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); 45762306a36Sopenharmony_ci status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* RXD Group 5 - C-RXV */ 46062306a36Sopenharmony_ci if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { 46162306a36Sopenharmony_ci rxd += 18; 46262306a36Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 46362306a36Sopenharmony_ci return -EINVAL; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!is_mt7915(&dev->mt76) || (rxd1 & MT_RXD1_NORMAL_GROUP_5)) { 46762306a36Sopenharmony_ci ret = mt76_connac2_mac_fill_rx_rate(&dev->mt76, status, 46862306a36Sopenharmony_ci sband, rxv, &mode); 46962306a36Sopenharmony_ci if (ret < 0) 47062306a36Sopenharmony_ci return ret; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); 47562306a36Sopenharmony_ci status->amsdu = !!amsdu_info; 47662306a36Sopenharmony_ci if (status->amsdu) { 47762306a36Sopenharmony_ci status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; 47862306a36Sopenharmony_ci status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; 48262306a36Sopenharmony_ci if (hdr_trans && ieee80211_has_morefrags(fc)) { 48362306a36Sopenharmony_ci struct ieee80211_vif *vif; 48462306a36Sopenharmony_ci int err; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (!msta || !msta->vif) 48762306a36Sopenharmony_ci return -EINVAL; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci vif = container_of((void *)msta->vif, struct ieee80211_vif, 49062306a36Sopenharmony_ci drv_priv); 49162306a36Sopenharmony_ci err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap); 49262306a36Sopenharmony_ci if (err) 49362306a36Sopenharmony_ci return err; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci hdr_trans = false; 49662306a36Sopenharmony_ci } else { 49762306a36Sopenharmony_ci int pad_start = 0; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci skb_pull(skb, hdr_gap); 50062306a36Sopenharmony_ci if (!hdr_trans && status->amsdu) { 50162306a36Sopenharmony_ci pad_start = ieee80211_get_hdrlen_from_skb(skb); 50262306a36Sopenharmony_ci } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) { 50362306a36Sopenharmony_ci /* 50462306a36Sopenharmony_ci * When header translation failure is indicated, 50562306a36Sopenharmony_ci * the hardware will insert an extra 2-byte field 50662306a36Sopenharmony_ci * containing the data length after the protocol 50762306a36Sopenharmony_ci * type field. This happens either when the LLC-SNAP 50862306a36Sopenharmony_ci * pattern did not match, or if a VLAN header was 50962306a36Sopenharmony_ci * detected. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci pad_start = 12; 51262306a36Sopenharmony_ci if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) 51362306a36Sopenharmony_ci pad_start += 4; 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci pad_start = 0; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (pad_start) { 51962306a36Sopenharmony_ci memmove(skb->data + 2, skb->data, pad_start); 52062306a36Sopenharmony_ci skb_pull(skb, 2); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!hdr_trans) { 52562306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (insert_ccmp_hdr) { 52862306a36Sopenharmony_ci u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci mt76_insert_ccmp_hdr(skb, key_id); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci hdr = mt76_skb_get_hdr(skb); 53462306a36Sopenharmony_ci fc = hdr->frame_control; 53562306a36Sopenharmony_ci if (ieee80211_is_data_qos(fc)) { 53662306a36Sopenharmony_ci seq_ctrl = le16_to_cpu(hdr->seq_ctrl); 53762306a36Sopenharmony_ci qos_ctl = *ieee80211_get_qos_ctl(hdr); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci } else { 54062306a36Sopenharmony_ci status->flag |= RX_FLAG_8023; 54162306a36Sopenharmony_ci mt7915_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, 54262306a36Sopenharmony_ci *info); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) 54662306a36Sopenharmony_ci mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (!status->wcid || !ieee80211_is_data_qos(fc)) 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci status->aggr = unicast && 55262306a36Sopenharmony_ci !ieee80211_is_qos_nullfunc(fc); 55362306a36Sopenharmony_ci status->qos_ctl = qos_ctl; 55462306a36Sopenharmony_ci status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic void 56062306a36Sopenharmony_cimt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE 56362306a36Sopenharmony_ci struct mt7915_phy *phy = &dev->phy; 56462306a36Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 56562306a36Sopenharmony_ci __le32 *rxv_hdr = rxd + 2; 56662306a36Sopenharmony_ci __le32 *rxv = rxd + 4; 56762306a36Sopenharmony_ci u32 rcpi, ib_rssi, wb_rssi, v20, v21; 56862306a36Sopenharmony_ci u8 band_idx; 56962306a36Sopenharmony_ci s32 foe; 57062306a36Sopenharmony_ci u8 snr; 57162306a36Sopenharmony_ci int i; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci band_idx = le32_get_bits(rxv_hdr[1], MT_RXV_HDR_BAND_IDX); 57462306a36Sopenharmony_ci if (band_idx && !phy->mt76->band_idx) { 57562306a36Sopenharmony_ci phy = mt7915_ext_phy(dev); 57662306a36Sopenharmony_ci if (!phy) 57762306a36Sopenharmony_ci goto out; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci rcpi = le32_to_cpu(rxv[6]); 58162306a36Sopenharmony_ci ib_rssi = le32_to_cpu(rxv[7]); 58262306a36Sopenharmony_ci wb_rssi = le32_to_cpu(rxv[8]) >> 5; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci for (i = 0; i < 4; i++, rcpi >>= 8, ib_rssi >>= 8, wb_rssi >>= 9) { 58562306a36Sopenharmony_ci if (i == 3) 58662306a36Sopenharmony_ci wb_rssi = le32_to_cpu(rxv[9]); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci phy->test.last_rcpi[i] = rcpi & 0xff; 58962306a36Sopenharmony_ci phy->test.last_ib_rssi[i] = ib_rssi & 0xff; 59062306a36Sopenharmony_ci phy->test.last_wb_rssi[i] = wb_rssi & 0xff; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci v20 = le32_to_cpu(rxv[20]); 59462306a36Sopenharmony_ci v21 = le32_to_cpu(rxv[21]); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci foe = FIELD_GET(MT_CRXV_FOE_LO, v20) | 59762306a36Sopenharmony_ci (FIELD_GET(MT_CRXV_FOE_HI, v21) << MT_CRXV_FOE_SHIFT); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci snr = FIELD_GET(MT_CRXV_SNR, v20) - 16; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci phy->test.last_freq_offset = foe; 60262306a36Sopenharmony_ci phy->test.last_snr = snr; 60362306a36Sopenharmony_ciout: 60462306a36Sopenharmony_ci#endif 60562306a36Sopenharmony_ci dev_kfree_skb(skb); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic void 60962306a36Sopenharmony_cimt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, 61062306a36Sopenharmony_ci struct sk_buff *skb) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE 61362306a36Sopenharmony_ci struct mt76_testmode_data *td = &phy->mt76->test; 61462306a36Sopenharmony_ci const struct ieee80211_rate *r; 61562306a36Sopenharmony_ci u8 bw, mode, nss = td->tx_rate_nss; 61662306a36Sopenharmony_ci u8 rate_idx = td->tx_rate_idx; 61762306a36Sopenharmony_ci u16 rateval = 0; 61862306a36Sopenharmony_ci u32 val; 61962306a36Sopenharmony_ci bool cck = false; 62062306a36Sopenharmony_ci int band; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (skb != phy->mt76->test.tx_skb) 62362306a36Sopenharmony_ci return; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci switch (td->tx_rate_mode) { 62662306a36Sopenharmony_ci case MT76_TM_TX_MODE_HT: 62762306a36Sopenharmony_ci nss = 1 + (rate_idx >> 3); 62862306a36Sopenharmony_ci mode = MT_PHY_TYPE_HT; 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci case MT76_TM_TX_MODE_VHT: 63162306a36Sopenharmony_ci mode = MT_PHY_TYPE_VHT; 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_SU: 63462306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_SU; 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_EXT_SU: 63762306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_EXT_SU; 63862306a36Sopenharmony_ci break; 63962306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_TB: 64062306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_TB; 64162306a36Sopenharmony_ci break; 64262306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_MU: 64362306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_MU; 64462306a36Sopenharmony_ci break; 64562306a36Sopenharmony_ci case MT76_TM_TX_MODE_CCK: 64662306a36Sopenharmony_ci cck = true; 64762306a36Sopenharmony_ci fallthrough; 64862306a36Sopenharmony_ci case MT76_TM_TX_MODE_OFDM: 64962306a36Sopenharmony_ci band = phy->mt76->chandef.chan->band; 65062306a36Sopenharmony_ci if (band == NL80211_BAND_2GHZ && !cck) 65162306a36Sopenharmony_ci rate_idx += 4; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci r = &phy->mt76->hw->wiphy->bands[band]->bitrates[rate_idx]; 65462306a36Sopenharmony_ci val = cck ? r->hw_value_short : r->hw_value; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci mode = val >> 8; 65762306a36Sopenharmony_ci rate_idx = val & 0xff; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci default: 66062306a36Sopenharmony_ci mode = MT_PHY_TYPE_OFDM; 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci switch (phy->mt76->chandef.width) { 66562306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 66662306a36Sopenharmony_ci bw = 1; 66762306a36Sopenharmony_ci break; 66862306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 66962306a36Sopenharmony_ci bw = 2; 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 67262306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 67362306a36Sopenharmony_ci bw = 3; 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci default: 67662306a36Sopenharmony_ci bw = 0; 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (td->tx_rate_stbc && nss == 1) { 68162306a36Sopenharmony_ci nss++; 68262306a36Sopenharmony_ci rateval |= MT_TX_RATE_STBC; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci rateval |= FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | 68662306a36Sopenharmony_ci FIELD_PREP(MT_TX_RATE_MODE, mode) | 68762306a36Sopenharmony_ci FIELD_PREP(MT_TX_RATE_NSS, nss - 1); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci le32p_replace_bits(&txwi[3], 1, MT_TXD3_REM_TX_COUNT); 69262306a36Sopenharmony_ci if (td->tx_rate_mode < MT76_TM_TX_MODE_HT) 69362306a36Sopenharmony_ci txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci val = MT_TXD6_FIXED_BW | 69662306a36Sopenharmony_ci FIELD_PREP(MT_TXD6_BW, bw) | 69762306a36Sopenharmony_ci FIELD_PREP(MT_TXD6_TX_RATE, rateval) | 69862306a36Sopenharmony_ci FIELD_PREP(MT_TXD6_SGI, td->tx_rate_sgi); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* for HE_SU/HE_EXT_SU PPDU 70162306a36Sopenharmony_ci * - 1x, 2x, 4x LTF + 0.8us GI 70262306a36Sopenharmony_ci * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI 70362306a36Sopenharmony_ci * for HE_MU PPDU 70462306a36Sopenharmony_ci * - 2x, 4x LTF + 0.8us GI 70562306a36Sopenharmony_ci * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI 70662306a36Sopenharmony_ci * for HE_TB PPDU 70762306a36Sopenharmony_ci * - 1x, 2x LTF + 1.6us GI 70862306a36Sopenharmony_ci * - 4x LTF + 3.2us GI 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (mode >= MT_PHY_TYPE_HE_SU) 71162306a36Sopenharmony_ci val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (td->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU)) 71462306a36Sopenharmony_ci val |= MT_TXD6_LDPC; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci txwi[3] &= ~cpu_to_le32(MT_TXD3_SN_VALID); 71762306a36Sopenharmony_ci txwi[6] |= cpu_to_le32(val); 71862306a36Sopenharmony_ci txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, 71962306a36Sopenharmony_ci phy->test.spe_idx)); 72062306a36Sopenharmony_ci#endif 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_civoid mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, 72462306a36Sopenharmony_ci struct sk_buff *skb, struct mt76_wcid *wcid, int pid, 72562306a36Sopenharmony_ci struct ieee80211_key_conf *key, 72662306a36Sopenharmony_ci enum mt76_txq_id qid, u32 changed) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 72962306a36Sopenharmony_ci u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; 73062306a36Sopenharmony_ci struct mt76_phy *mphy = &dev->phy; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (phy_idx && dev->phys[MT_BAND1]) 73362306a36Sopenharmony_ci mphy = dev->phys[MT_BAND1]; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, qid, changed); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (mt76_testmode_enabled(mphy)) 73862306a36Sopenharmony_ci mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ciint mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, 74262306a36Sopenharmony_ci enum mt76_txq_id qid, struct mt76_wcid *wcid, 74362306a36Sopenharmony_ci struct ieee80211_sta *sta, 74462306a36Sopenharmony_ci struct mt76_tx_info *tx_info) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; 74762306a36Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 74862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); 74962306a36Sopenharmony_ci struct ieee80211_key_conf *key = info->control.hw_key; 75062306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 75162306a36Sopenharmony_ci struct mt76_connac_fw_txp *txp; 75262306a36Sopenharmony_ci struct mt76_txwi_cache *t; 75362306a36Sopenharmony_ci int id, i, nbuf = tx_info->nbuf - 1; 75462306a36Sopenharmony_ci u8 *txwi = (u8 *)txwi_ptr; 75562306a36Sopenharmony_ci int pid; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (unlikely(tx_info->skb->len <= ETH_HLEN)) 75862306a36Sopenharmony_ci return -EINVAL; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (!wcid) 76162306a36Sopenharmony_ci wcid = &dev->mt76.global_wcid; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (sta) { 76462306a36Sopenharmony_ci struct mt7915_sta *msta; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci msta = (struct mt7915_sta *)sta->drv_priv; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (time_after(jiffies, msta->jiffies + HZ / 4)) { 76962306a36Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; 77062306a36Sopenharmony_ci msta->jiffies = jiffies; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); 77562306a36Sopenharmony_ci t->skb = tx_info->skb; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci id = mt76_token_consume(mdev, &t); 77862306a36Sopenharmony_ci if (id < 0) 77962306a36Sopenharmony_ci return id; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); 78262306a36Sopenharmony_ci mt7915_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, pid, key, 78362306a36Sopenharmony_ci qid, 0); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci txp = (struct mt76_connac_fw_txp *)(txwi + MT_TXD_SIZE); 78662306a36Sopenharmony_ci for (i = 0; i < nbuf; i++) { 78762306a36Sopenharmony_ci txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); 78862306a36Sopenharmony_ci txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci txp->nbuf = nbuf; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD | MT_CT_INFO_FROM_HOST); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (!key) 79562306a36Sopenharmony_ci txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && 79862306a36Sopenharmony_ci ieee80211_is_mgmt(hdr->frame_control)) 79962306a36Sopenharmony_ci txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (vif) { 80262306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci txp->bss_idx = mvif->mt76.idx; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci txp->token = cpu_to_le16(id); 80862306a36Sopenharmony_ci if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) 80962306a36Sopenharmony_ci txp->rept_wds_wcid = cpu_to_le16(wcid->idx); 81062306a36Sopenharmony_ci else 81162306a36Sopenharmony_ci txp->rept_wds_wcid = cpu_to_le16(0x3ff); 81262306a36Sopenharmony_ci tx_info->skb = NULL; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* pass partial skb header to fw */ 81562306a36Sopenharmony_ci tx_info->buf[1].len = MT_CT_PARSE_LEN; 81662306a36Sopenharmony_ci tx_info->buf[1].skip_unmap = true; 81762306a36Sopenharmony_ci tx_info->nbuf = MT_CT_DMA_BUF_NUM; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ciu32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; 82562306a36Sopenharmony_ci __le32 *txwi = ptr; 82662306a36Sopenharmony_ci u32 val; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp)); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) | 83162306a36Sopenharmony_ci FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT); 83262306a36Sopenharmony_ci txwi[0] = cpu_to_le32(val); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci val = MT_TXD1_LONG_FORMAT | 83562306a36Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3); 83662306a36Sopenharmony_ci txwi[1] = cpu_to_le32(val); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci txp->token = cpu_to_le16(token_id); 83962306a36Sopenharmony_ci txp->nbuf = 1; 84062306a36Sopenharmony_ci txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp)); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return MT_TXD_SIZE + sizeof(*txp); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic void 84662306a36Sopenharmony_cimt7915_mac_tx_free_prepare(struct mt7915_dev *dev) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 84962306a36Sopenharmony_ci struct mt76_phy *mphy_ext = mdev->phys[MT_BAND1]; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* clean DMA queues and unmap buffers first */ 85262306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); 85362306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false); 85462306a36Sopenharmony_ci if (mphy_ext) { 85562306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false); 85662306a36Sopenharmony_ci mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false); 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic void 86162306a36Sopenharmony_cimt7915_mac_tx_free_done(struct mt7915_dev *dev, 86262306a36Sopenharmony_ci struct list_head *free_list, bool wake) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci mt7915_mac_sta_poll(dev); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (wake) 86962306a36Sopenharmony_ci mt76_set_tx_blocked(&dev->mt76, false); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci mt76_worker_schedule(&dev->mt76.tx_worker); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci list_for_each_entry_safe(skb, tmp, free_list, list) { 87462306a36Sopenharmony_ci skb_list_del_init(skb); 87562306a36Sopenharmony_ci napi_consume_skb(skb, 1); 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic void 88062306a36Sopenharmony_cimt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct mt76_connac_tx_free *free = data; 88362306a36Sopenharmony_ci __le32 *tx_info = (__le32 *)(data + sizeof(*free)); 88462306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 88562306a36Sopenharmony_ci struct mt76_txwi_cache *txwi; 88662306a36Sopenharmony_ci struct ieee80211_sta *sta = NULL; 88762306a36Sopenharmony_ci struct mt76_wcid *wcid = NULL; 88862306a36Sopenharmony_ci LIST_HEAD(free_list); 88962306a36Sopenharmony_ci void *end = data + len; 89062306a36Sopenharmony_ci bool v3, wake = false; 89162306a36Sopenharmony_ci u16 total, count = 0; 89262306a36Sopenharmony_ci u32 txd = le32_to_cpu(free->txd); 89362306a36Sopenharmony_ci __le32 *cur_info; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci mt7915_mac_tx_free_prepare(dev); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT); 89862306a36Sopenharmony_ci v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci for (cur_info = tx_info; count < total; cur_info++) { 90162306a36Sopenharmony_ci u32 msdu, info; 90262306a36Sopenharmony_ci u8 i; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (WARN_ON_ONCE((void *)cur_info >= end)) 90562306a36Sopenharmony_ci return; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* 90862306a36Sopenharmony_ci * 1'b1: new wcid pair. 90962306a36Sopenharmony_ci * 1'b0: msdu_id with the same 'wcid pair' as above. 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_ci info = le32_to_cpu(*cur_info); 91262306a36Sopenharmony_ci if (info & MT_TX_FREE_PAIR) { 91362306a36Sopenharmony_ci struct mt7915_sta *msta; 91462306a36Sopenharmony_ci u16 idx; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info); 91762306a36Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 91862306a36Sopenharmony_ci sta = wcid_to_sta(wcid); 91962306a36Sopenharmony_ci if (!sta) 92062306a36Sopenharmony_ci continue; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci msta = container_of(wcid, struct mt7915_sta, wcid); 92362306a36Sopenharmony_ci spin_lock_bh(&mdev->sta_poll_lock); 92462306a36Sopenharmony_ci if (list_empty(&msta->wcid.poll_list)) 92562306a36Sopenharmony_ci list_add_tail(&msta->wcid.poll_list, 92662306a36Sopenharmony_ci &mdev->sta_poll_list); 92762306a36Sopenharmony_ci spin_unlock_bh(&mdev->sta_poll_lock); 92862306a36Sopenharmony_ci continue; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (!mtk_wed_device_active(&mdev->mmio.wed) && wcid) { 93262306a36Sopenharmony_ci u32 tx_retries = 0, tx_failed = 0; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) { 93562306a36Sopenharmony_ci tx_retries = 93662306a36Sopenharmony_ci FIELD_GET(MT_TX_FREE_COUNT_V3, info) - 1; 93762306a36Sopenharmony_ci tx_failed = tx_retries + 93862306a36Sopenharmony_ci !!FIELD_GET(MT_TX_FREE_STAT_V3, info); 93962306a36Sopenharmony_ci } else if (!v3 && (info & MT_TX_FREE_MPDU_HEADER)) { 94062306a36Sopenharmony_ci tx_retries = 94162306a36Sopenharmony_ci FIELD_GET(MT_TX_FREE_COUNT, info) - 1; 94262306a36Sopenharmony_ci tx_failed = tx_retries + 94362306a36Sopenharmony_ci !!FIELD_GET(MT_TX_FREE_STAT, info); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci wcid->stats.tx_retries += tx_retries; 94662306a36Sopenharmony_ci wcid->stats.tx_failed += tx_failed; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) 95062306a36Sopenharmony_ci continue; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci for (i = 0; i < 1 + v3; i++) { 95362306a36Sopenharmony_ci if (v3) { 95462306a36Sopenharmony_ci msdu = (info >> (15 * i)) & MT_TX_FREE_MSDU_ID_V3; 95562306a36Sopenharmony_ci if (msdu == MT_TX_FREE_MSDU_ID_V3) 95662306a36Sopenharmony_ci continue; 95762306a36Sopenharmony_ci } else { 95862306a36Sopenharmony_ci msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci count++; 96162306a36Sopenharmony_ci txwi = mt76_token_release(mdev, msdu, &wake); 96262306a36Sopenharmony_ci if (!txwi) 96362306a36Sopenharmony_ci continue; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci mt76_connac2_txwi_free(mdev, txwi, sta, &free_list); 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci mt7915_mac_tx_free_done(dev, &free_list, wake); 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic void 97362306a36Sopenharmony_cimt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct mt76_connac_tx_free *free = data; 97662306a36Sopenharmony_ci __le16 *info = (__le16 *)(data + sizeof(*free)); 97762306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 97862306a36Sopenharmony_ci void *end = data + len; 97962306a36Sopenharmony_ci LIST_HEAD(free_list); 98062306a36Sopenharmony_ci bool wake = false; 98162306a36Sopenharmony_ci u8 i, count; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci mt7915_mac_tx_free_prepare(dev); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci count = FIELD_GET(MT_TX_FREE_MSDU_CNT_V0, le16_to_cpu(free->ctrl)); 98662306a36Sopenharmony_ci if (WARN_ON_ONCE((void *)&info[count] > end)) 98762306a36Sopenharmony_ci return; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci for (i = 0; i < count; i++) { 99062306a36Sopenharmony_ci struct mt76_txwi_cache *txwi; 99162306a36Sopenharmony_ci u16 msdu = le16_to_cpu(info[i]); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci txwi = mt76_token_release(mdev, msdu, &wake); 99462306a36Sopenharmony_ci if (!txwi) 99562306a36Sopenharmony_ci continue; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci mt76_connac2_txwi_free(mdev, txwi, NULL, &free_list); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci mt7915_mac_tx_free_done(dev, &free_list, wake); 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct mt7915_sta *msta = NULL; 100662306a36Sopenharmony_ci struct mt76_wcid *wcid; 100762306a36Sopenharmony_ci __le32 *txs_data = data; 100862306a36Sopenharmony_ci u16 wcidx; 100962306a36Sopenharmony_ci u8 pid; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); 101262306a36Sopenharmony_ci pid = le32_get_bits(txs_data[3], MT_TXS3_PID); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if (pid < MT_PACKET_ID_WED) 101562306a36Sopenharmony_ci return; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (wcidx >= mt7915_wtbl_size(dev)) 101862306a36Sopenharmony_ci return; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci rcu_read_lock(); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[wcidx]); 102362306a36Sopenharmony_ci if (!wcid) 102462306a36Sopenharmony_ci goto out; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci msta = container_of(wcid, struct mt7915_sta, wcid); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (pid == MT_PACKET_ID_WED) 102962306a36Sopenharmony_ci mt76_connac2_mac_fill_txs(&dev->mt76, wcid, txs_data); 103062306a36Sopenharmony_ci else 103162306a36Sopenharmony_ci mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (!wcid->sta) 103462306a36Sopenharmony_ci goto out; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 103762306a36Sopenharmony_ci if (list_empty(&msta->wcid.poll_list)) 103862306a36Sopenharmony_ci list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); 103962306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ciout: 104262306a36Sopenharmony_ci rcu_read_unlock(); 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cibool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 104862306a36Sopenharmony_ci __le32 *rxd = (__le32 *)data; 104962306a36Sopenharmony_ci __le32 *end = (__le32 *)&rxd[len / 4]; 105062306a36Sopenharmony_ci enum rx_pkt_type type; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci switch (type) { 105562306a36Sopenharmony_ci case PKT_TYPE_TXRX_NOTIFY: 105662306a36Sopenharmony_ci mt7915_mac_tx_free(dev, data, len); 105762306a36Sopenharmony_ci return false; 105862306a36Sopenharmony_ci case PKT_TYPE_TXRX_NOTIFY_V0: 105962306a36Sopenharmony_ci mt7915_mac_tx_free_v0(dev, data, len); 106062306a36Sopenharmony_ci return false; 106162306a36Sopenharmony_ci case PKT_TYPE_TXS: 106262306a36Sopenharmony_ci for (rxd += 2; rxd + 8 <= end; rxd += 8) 106362306a36Sopenharmony_ci mt7915_mac_add_txs(dev, rxd); 106462306a36Sopenharmony_ci return false; 106562306a36Sopenharmony_ci case PKT_TYPE_RX_FW_MONITOR: 106662306a36Sopenharmony_ci mt7915_debugfs_rx_fw_monitor(dev, data, len); 106762306a36Sopenharmony_ci return false; 106862306a36Sopenharmony_ci default: 106962306a36Sopenharmony_ci return true; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_civoid mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, 107462306a36Sopenharmony_ci struct sk_buff *skb, u32 *info) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 107762306a36Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 107862306a36Sopenharmony_ci __le32 *end = (__le32 *)&skb->data[skb->len]; 107962306a36Sopenharmony_ci enum rx_pkt_type type; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci switch (type) { 108462306a36Sopenharmony_ci case PKT_TYPE_TXRX_NOTIFY: 108562306a36Sopenharmony_ci mt7915_mac_tx_free(dev, skb->data, skb->len); 108662306a36Sopenharmony_ci napi_consume_skb(skb, 1); 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci case PKT_TYPE_TXRX_NOTIFY_V0: 108962306a36Sopenharmony_ci mt7915_mac_tx_free_v0(dev, skb->data, skb->len); 109062306a36Sopenharmony_ci napi_consume_skb(skb, 1); 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci case PKT_TYPE_RX_EVENT: 109362306a36Sopenharmony_ci mt7915_mcu_rx_event(dev, skb); 109462306a36Sopenharmony_ci break; 109562306a36Sopenharmony_ci case PKT_TYPE_TXRXV: 109662306a36Sopenharmony_ci mt7915_mac_fill_rx_vector(dev, skb); 109762306a36Sopenharmony_ci break; 109862306a36Sopenharmony_ci case PKT_TYPE_TXS: 109962306a36Sopenharmony_ci for (rxd += 2; rxd + 8 <= end; rxd += 8) 110062306a36Sopenharmony_ci mt7915_mac_add_txs(dev, rxd); 110162306a36Sopenharmony_ci dev_kfree_skb(skb); 110262306a36Sopenharmony_ci break; 110362306a36Sopenharmony_ci case PKT_TYPE_RX_FW_MONITOR: 110462306a36Sopenharmony_ci mt7915_debugfs_rx_fw_monitor(dev, skb->data, skb->len); 110562306a36Sopenharmony_ci dev_kfree_skb(skb); 110662306a36Sopenharmony_ci break; 110762306a36Sopenharmony_ci case PKT_TYPE_NORMAL: 110862306a36Sopenharmony_ci if (!mt7915_mac_fill_rx(dev, skb, q, info)) { 110962306a36Sopenharmony_ci mt76_rx(&dev->mt76, q, skb); 111062306a36Sopenharmony_ci return; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci fallthrough; 111362306a36Sopenharmony_ci default: 111462306a36Sopenharmony_ci dev_kfree_skb(skb); 111562306a36Sopenharmony_ci break; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_civoid mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 112262306a36Sopenharmony_ci u32 reg = MT_WF_PHY_RX_CTRL1(phy->mt76->band_idx); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci mt76_clear(dev, reg, MT_WF_PHY_RX_CTRL1_STSCNT_EN); 112562306a36Sopenharmony_ci mt76_set(dev, reg, BIT(11) | BIT(9)); 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_civoid mt7915_mac_reset_counters(struct mt7915_phy *phy) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 113162306a36Sopenharmony_ci int i; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 113462306a36Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT(phy->mt76->band_idx, i)); 113562306a36Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT2(phy->mt76->band_idx, i)); 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci phy->mt76->survey_time = ktime_get_boottime(); 113962306a36Sopenharmony_ci memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* reset airtime counters */ 114262306a36Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(phy->mt76->band_idx), 114362306a36Sopenharmony_ci MT_WF_RMAC_MIB_RXTIME_CLR); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci mt7915_mcu_get_chan_mib_info(phy, true); 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_civoid mt7915_mac_set_timing(struct mt7915_phy *phy) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci s16 coverage_class = phy->coverage_class; 115162306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 115262306a36Sopenharmony_ci struct mt7915_phy *ext_phy = mt7915_ext_phy(dev); 115362306a36Sopenharmony_ci u32 val, reg_offset; 115462306a36Sopenharmony_ci u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | 115562306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); 115662306a36Sopenharmony_ci u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | 115762306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); 115862306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 115962306a36Sopenharmony_ci int eifs_ofdm = 360, sifs = 10, offset; 116062306a36Sopenharmony_ci bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 116362306a36Sopenharmony_ci return; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (ext_phy) 116662306a36Sopenharmony_ci coverage_class = max_t(s16, dev->phy.coverage_class, 116762306a36Sopenharmony_ci ext_phy->coverage_class); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci mt76_set(dev, MT_ARB_SCR(band), 117062306a36Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 117162306a36Sopenharmony_ci udelay(1); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci offset = 3 * coverage_class; 117462306a36Sopenharmony_ci reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | 117562306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (!is_mt7915(&dev->mt76)) { 117862306a36Sopenharmony_ci if (!a_band) { 117962306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_ICR1(band), 118062306a36Sopenharmony_ci FIELD_PREP(MT_IFS_EIFS_CCK, 314)); 118162306a36Sopenharmony_ci eifs_ofdm = 78; 118262306a36Sopenharmony_ci } else { 118362306a36Sopenharmony_ci eifs_ofdm = 84; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci } else if (a_band) { 118662306a36Sopenharmony_ci sifs = 16; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_CDTR(band), cck + reg_offset); 119062306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_ODTR(band), ofdm + reg_offset); 119162306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_ICR0(band), 119262306a36Sopenharmony_ci FIELD_PREP(MT_IFS_EIFS_OFDM, eifs_ofdm) | 119362306a36Sopenharmony_ci FIELD_PREP(MT_IFS_RIFS, 2) | 119462306a36Sopenharmony_ci FIELD_PREP(MT_IFS_SIFS, sifs) | 119562306a36Sopenharmony_ci FIELD_PREP(MT_IFS_SLOT, phy->slottime)); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (phy->slottime < 20 || a_band) 119862306a36Sopenharmony_ci val = MT7915_CFEND_RATE_DEFAULT; 119962306a36Sopenharmony_ci else 120062306a36Sopenharmony_ci val = MT7915_CFEND_RATE_11B; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci mt76_rmw_field(dev, MT_AGG_ACR0(band), MT_AGG_ACR_CFEND_RATE, val); 120362306a36Sopenharmony_ci mt76_clear(dev, MT_ARB_SCR(band), 120462306a36Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_civoid mt7915_mac_enable_nf(struct mt7915_dev *dev, bool band) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci u32 reg; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RXTD12(band) : 121262306a36Sopenharmony_ci MT_WF_PHY_RXTD12_MT7916(band); 121362306a36Sopenharmony_ci mt76_set(dev, reg, 121462306a36Sopenharmony_ci MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY | 121562306a36Sopenharmony_ci MT_WF_PHY_RXTD12_IRPI_SW_CLR); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RX_CTRL1(band) : 121862306a36Sopenharmony_ci MT_WF_PHY_RX_CTRL1_MT7916(band); 121962306a36Sopenharmony_ci mt76_set(dev, reg, FIELD_PREP(MT_WF_PHY_RX_CTRL1_IPI_EN, 0x5)); 122062306a36Sopenharmony_ci} 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_cistatic u8 122362306a36Sopenharmony_cimt7915_phy_get_nf(struct mt7915_phy *phy, int idx) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 }; 122662306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 122762306a36Sopenharmony_ci u32 val, sum = 0, n = 0; 122862306a36Sopenharmony_ci int nss, i; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci for (nss = 0; nss < hweight8(phy->mt76->chainmask); nss++) { 123162306a36Sopenharmony_ci u32 reg = is_mt7915(&dev->mt76) ? 123262306a36Sopenharmony_ci MT_WF_IRPI_NSS(0, nss + (idx << dev->dbdc_support)) : 123362306a36Sopenharmony_ci MT_WF_IRPI_NSS_MT7916(idx, nss); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { 123662306a36Sopenharmony_ci val = mt76_rr(dev, reg); 123762306a36Sopenharmony_ci sum += val * nf_power[i]; 123862306a36Sopenharmony_ci n += val; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci if (!n) 124362306a36Sopenharmony_ci return 0; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci return sum / n; 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_civoid mt7915_update_channel(struct mt76_phy *mphy) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; 125162306a36Sopenharmony_ci struct mt76_channel_state *state = mphy->chan_state; 125262306a36Sopenharmony_ci int nf; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci mt7915_mcu_get_chan_mib_info(phy, false); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci nf = mt7915_phy_get_nf(phy, phy->mt76->band_idx); 125762306a36Sopenharmony_ci if (!phy->noise) 125862306a36Sopenharmony_ci phy->noise = nf << 4; 125962306a36Sopenharmony_ci else if (nf) 126062306a36Sopenharmony_ci phy->noise += nf - (phy->noise >> 4); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci state->noise = -(phy->noise >> 4); 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic bool 126662306a36Sopenharmony_cimt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci bool ret; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci ret = wait_event_timeout(dev->reset_wait, 127162306a36Sopenharmony_ci (READ_ONCE(dev->recovery.state) & state), 127262306a36Sopenharmony_ci MT7915_RESET_TIMEOUT); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); 127562306a36Sopenharmony_ci return ret; 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic void 127962306a36Sopenharmony_cimt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci struct ieee80211_hw *hw = priv; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci switch (vif->type) { 128462306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 128562306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 128662306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 128762306a36Sopenharmony_ci mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon, 128862306a36Sopenharmony_ci BSS_CHANGED_BEACON_ENABLED); 128962306a36Sopenharmony_ci break; 129062306a36Sopenharmony_ci default: 129162306a36Sopenharmony_ci break; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic void 129662306a36Sopenharmony_cimt7915_update_beacons(struct mt7915_dev *dev) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci ieee80211_iterate_active_interfaces(dev->mt76.hw, 130162306a36Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 130262306a36Sopenharmony_ci mt7915_update_vif_beacon, dev->mt76.hw); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (!mphy_ext) 130562306a36Sopenharmony_ci return; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci ieee80211_iterate_active_interfaces(mphy_ext->hw, 130862306a36Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 130962306a36Sopenharmony_ci mt7915_update_vif_beacon, mphy_ext->hw); 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic int 131362306a36Sopenharmony_cimt7915_mac_restart(struct mt7915_dev *dev) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci struct mt7915_phy *phy2; 131662306a36Sopenharmony_ci struct mt76_phy *ext_phy; 131762306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 131862306a36Sopenharmony_ci int i, ret; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci ext_phy = dev->mt76.phys[MT_BAND1]; 132162306a36Sopenharmony_ci phy2 = ext_phy ? ext_phy->priv : NULL; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (dev->hif2) { 132462306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); 132562306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (dev_is_pci(mdev->dev)) { 132962306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); 133062306a36Sopenharmony_ci if (dev->hif2) { 133162306a36Sopenharmony_ci if (is_mt7915(mdev)) 133262306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0); 133362306a36Sopenharmony_ci else 133462306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0x0); 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 133962306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &dev->mphy.state); 134062306a36Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 134162306a36Sopenharmony_ci if (ext_phy) { 134262306a36Sopenharmony_ci set_bit(MT76_RESET, &ext_phy->state); 134362306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &ext_phy->state); 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci /* lock/unlock all queues to ensure that no tx is pending */ 134762306a36Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 134862306a36Sopenharmony_ci if (ext_phy) 134962306a36Sopenharmony_ci mt76_txq_schedule_all(ext_phy); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* disable all tx/rx napi */ 135262306a36Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 135362306a36Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 135462306a36Sopenharmony_ci if (mdev->q_rx[i].ndesc) 135562306a36Sopenharmony_ci napi_disable(&dev->mt76.napi[i]); 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci napi_disable(&dev->mt76.tx_napi); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci /* token reinit */ 136062306a36Sopenharmony_ci mt76_connac2_tx_token_put(&dev->mt76); 136162306a36Sopenharmony_ci idr_init(&dev->mt76.token); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci mt7915_dma_reset(dev, true); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci local_bh_disable(); 136662306a36Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 136762306a36Sopenharmony_ci if (mdev->q_rx[i].ndesc) { 136862306a36Sopenharmony_ci napi_enable(&dev->mt76.napi[i]); 136962306a36Sopenharmony_ci napi_schedule(&dev->mt76.napi[i]); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci local_bh_enable(); 137362306a36Sopenharmony_ci clear_bit(MT76_MCU_RESET, &dev->mphy.state); 137462306a36Sopenharmony_ci clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); 137762306a36Sopenharmony_ci mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (dev->hif2) { 138062306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask); 138162306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci if (dev_is_pci(mdev->dev)) { 138462306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); 138562306a36Sopenharmony_ci if (dev->hif2) { 138662306a36Sopenharmony_ci if (is_mt7915(mdev)) 138762306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); 138862306a36Sopenharmony_ci else 138962306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff); 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* load firmware */ 139462306a36Sopenharmony_ci ret = mt7915_mcu_init_firmware(dev); 139562306a36Sopenharmony_ci if (ret) 139662306a36Sopenharmony_ci goto out; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci /* set the necessary init items */ 139962306a36Sopenharmony_ci ret = mt7915_mcu_set_eeprom(dev); 140062306a36Sopenharmony_ci if (ret) 140162306a36Sopenharmony_ci goto out; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci mt7915_mac_init(dev); 140462306a36Sopenharmony_ci mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); 140562306a36Sopenharmony_ci mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); 140662306a36Sopenharmony_ci ret = mt7915_txbf_init(dev); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { 140962306a36Sopenharmony_ci ret = mt7915_run(dev->mphy.hw); 141062306a36Sopenharmony_ci if (ret) 141162306a36Sopenharmony_ci goto out; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) { 141562306a36Sopenharmony_ci ret = mt7915_run(ext_phy->hw); 141662306a36Sopenharmony_ci if (ret) 141762306a36Sopenharmony_ci goto out; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ciout: 142162306a36Sopenharmony_ci /* reset done */ 142262306a36Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 142362306a36Sopenharmony_ci if (phy2) 142462306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy2->mt76->state); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci local_bh_disable(); 142762306a36Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 142862306a36Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 142962306a36Sopenharmony_ci local_bh_enable(); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci return ret; 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic void 143762306a36Sopenharmony_cimt7915_mac_full_reset(struct mt7915_dev *dev) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci struct mt76_phy *ext_phy; 144062306a36Sopenharmony_ci int i; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci ext_phy = dev->mt76.phys[MT_BAND1]; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci dev->recovery.hw_full_reset = true; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 144762306a36Sopenharmony_ci ieee80211_stop_queues(mt76_hw(dev)); 144862306a36Sopenharmony_ci if (ext_phy) 144962306a36Sopenharmony_ci ieee80211_stop_queues(ext_phy->hw); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->mphy.mac_work); 145262306a36Sopenharmony_ci if (ext_phy) 145362306a36Sopenharmony_ci cancel_delayed_work_sync(&ext_phy->mac_work); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 145662306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 145762306a36Sopenharmony_ci if (!mt7915_mac_restart(dev)) 145862306a36Sopenharmony_ci break; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (i == 10) 146362306a36Sopenharmony_ci dev_err(dev->mt76.dev, "chip full reset failed\n"); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci ieee80211_restart_hw(mt76_hw(dev)); 146662306a36Sopenharmony_ci if (ext_phy) 146762306a36Sopenharmony_ci ieee80211_restart_hw(ext_phy->hw); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci ieee80211_wake_queues(mt76_hw(dev)); 147062306a36Sopenharmony_ci if (ext_phy) 147162306a36Sopenharmony_ci ieee80211_wake_queues(ext_phy->hw); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci dev->recovery.hw_full_reset = false; 147462306a36Sopenharmony_ci ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, 147562306a36Sopenharmony_ci MT7915_WATCHDOG_TIME); 147662306a36Sopenharmony_ci if (ext_phy) 147762306a36Sopenharmony_ci ieee80211_queue_delayed_work(ext_phy->hw, 147862306a36Sopenharmony_ci &ext_phy->mac_work, 147962306a36Sopenharmony_ci MT7915_WATCHDOG_TIME); 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci/* system error recovery */ 148362306a36Sopenharmony_civoid mt7915_mac_reset_work(struct work_struct *work) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci struct mt7915_phy *phy2; 148662306a36Sopenharmony_ci struct mt76_phy *ext_phy; 148762306a36Sopenharmony_ci struct mt7915_dev *dev; 148862306a36Sopenharmony_ci int i; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci dev = container_of(work, struct mt7915_dev, reset_work); 149162306a36Sopenharmony_ci ext_phy = dev->mt76.phys[MT_BAND1]; 149262306a36Sopenharmony_ci phy2 = ext_phy ? ext_phy->priv : NULL; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci /* chip full reset */ 149562306a36Sopenharmony_ci if (dev->recovery.restart) { 149662306a36Sopenharmony_ci /* disable WA/WM WDT */ 149762306a36Sopenharmony_ci mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA, 149862306a36Sopenharmony_ci MT_MCU_CMD_WDT_MASK); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT) 150162306a36Sopenharmony_ci dev->recovery.wa_reset_count++; 150262306a36Sopenharmony_ci else 150362306a36Sopenharmony_ci dev->recovery.wm_reset_count++; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci mt7915_mac_full_reset(dev); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci /* enable mcu irq */ 150862306a36Sopenharmony_ci mt7915_irq_enable(dev, MT_INT_MCU_CMD); 150962306a36Sopenharmony_ci mt7915_irq_disable(dev, 0); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci /* enable WA/WM WDT */ 151262306a36Sopenharmony_ci mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci dev->recovery.state = MT_MCU_CMD_NORMAL_STATE; 151562306a36Sopenharmony_ci dev->recovery.restart = false; 151662306a36Sopenharmony_ci return; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci /* chip partial reset */ 152062306a36Sopenharmony_ci if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) 152162306a36Sopenharmony_ci return; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { 152462306a36Sopenharmony_ci mtk_wed_device_stop(&dev->mt76.mmio.wed); 152562306a36Sopenharmony_ci if (!is_mt798x(&dev->mt76)) 152662306a36Sopenharmony_ci mt76_wr(dev, MT_INT_WED_MASK_CSR, 0); 152762306a36Sopenharmony_ci } 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci ieee80211_stop_queues(mt76_hw(dev)); 153062306a36Sopenharmony_ci if (ext_phy) 153162306a36Sopenharmony_ci ieee80211_stop_queues(ext_phy->hw); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 153462306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &dev->mphy.state); 153562306a36Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 153662306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->mphy.mac_work); 153762306a36Sopenharmony_ci if (phy2) { 153862306a36Sopenharmony_ci set_bit(MT76_RESET, &phy2->mt76->state); 153962306a36Sopenharmony_ci cancel_delayed_work_sync(&phy2->mt76->mac_work); 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 154262306a36Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) 154362306a36Sopenharmony_ci napi_disable(&dev->mt76.napi[i]); 154462306a36Sopenharmony_ci napi_disable(&dev->mt76.tx_napi); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { 155162306a36Sopenharmony_ci mt7915_dma_reset(dev, false); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci mt76_connac2_tx_token_put(&dev->mt76); 155462306a36Sopenharmony_ci idr_init(&dev->mt76.token); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); 155762306a36Sopenharmony_ci mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); 156162306a36Sopenharmony_ci mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* enable DMA Tx/Rx and interrupt */ 156462306a36Sopenharmony_ci mt7915_dma_start(dev, false, false); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci clear_bit(MT76_MCU_RESET, &dev->mphy.state); 156762306a36Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 156862306a36Sopenharmony_ci if (phy2) 156962306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy2->mt76->state); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci local_bh_disable(); 157262306a36Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) { 157362306a36Sopenharmony_ci napi_enable(&dev->mt76.napi[i]); 157462306a36Sopenharmony_ci napi_schedule(&dev->mt76.napi[i]); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci local_bh_enable(); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci tasklet_schedule(&dev->mt76.irq_tasklet); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci local_bh_disable(); 158362306a36Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 158462306a36Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 158562306a36Sopenharmony_ci local_bh_enable(); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci ieee80211_wake_queues(mt76_hw(dev)); 158862306a36Sopenharmony_ci if (ext_phy) 158962306a36Sopenharmony_ci ieee80211_wake_queues(ext_phy->hw); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci mt7915_update_beacons(dev); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, 159662306a36Sopenharmony_ci MT7915_WATCHDOG_TIME); 159762306a36Sopenharmony_ci if (phy2) 159862306a36Sopenharmony_ci ieee80211_queue_delayed_work(ext_phy->hw, 159962306a36Sopenharmony_ci &phy2->mt76->mac_work, 160062306a36Sopenharmony_ci MT7915_WATCHDOG_TIME); 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci/* firmware coredump */ 160462306a36Sopenharmony_civoid mt7915_mac_dump_work(struct work_struct *work) 160562306a36Sopenharmony_ci{ 160662306a36Sopenharmony_ci const struct mt7915_mem_region *mem_region; 160762306a36Sopenharmony_ci struct mt7915_crash_data *crash_data; 160862306a36Sopenharmony_ci struct mt7915_dev *dev; 160962306a36Sopenharmony_ci struct mt7915_mem_hdr *hdr; 161062306a36Sopenharmony_ci size_t buf_len; 161162306a36Sopenharmony_ci int i; 161262306a36Sopenharmony_ci u32 num; 161362306a36Sopenharmony_ci u8 *buf; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci dev = container_of(work, struct mt7915_dev, dump_work); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci mutex_lock(&dev->dump_mutex); 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci crash_data = mt7915_coredump_new(dev); 162062306a36Sopenharmony_ci if (!crash_data) { 162162306a36Sopenharmony_ci mutex_unlock(&dev->dump_mutex); 162262306a36Sopenharmony_ci goto skip_coredump; 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci mem_region = mt7915_coredump_get_mem_layout(dev, &num); 162662306a36Sopenharmony_ci if (!mem_region || !crash_data->memdump_buf_len) { 162762306a36Sopenharmony_ci mutex_unlock(&dev->dump_mutex); 162862306a36Sopenharmony_ci goto skip_memdump; 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci buf = crash_data->memdump_buf; 163262306a36Sopenharmony_ci buf_len = crash_data->memdump_buf_len; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci /* dumping memory content... */ 163562306a36Sopenharmony_ci memset(buf, 0, buf_len); 163662306a36Sopenharmony_ci for (i = 0; i < num; i++) { 163762306a36Sopenharmony_ci if (mem_region->len > buf_len) { 163862306a36Sopenharmony_ci dev_warn(dev->mt76.dev, "%s len %lu is too large\n", 163962306a36Sopenharmony_ci mem_region->name, 164062306a36Sopenharmony_ci (unsigned long)mem_region->len); 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci /* reserve space for the header */ 164562306a36Sopenharmony_ci hdr = (void *)buf; 164662306a36Sopenharmony_ci buf += sizeof(*hdr); 164762306a36Sopenharmony_ci buf_len -= sizeof(*hdr); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci mt7915_memcpy_fromio(dev, buf, mem_region->start, 165062306a36Sopenharmony_ci mem_region->len); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci hdr->start = mem_region->start; 165362306a36Sopenharmony_ci hdr->len = mem_region->len; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci if (!mem_region->len) 165662306a36Sopenharmony_ci /* note: the header remains, just with zero length */ 165762306a36Sopenharmony_ci break; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci buf += mem_region->len; 166062306a36Sopenharmony_ci buf_len -= mem_region->len; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci mem_region++; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci mutex_unlock(&dev->dump_mutex); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ciskip_memdump: 166862306a36Sopenharmony_ci mt7915_coredump_submit(dev); 166962306a36Sopenharmony_ciskip_coredump: 167062306a36Sopenharmony_ci queue_work(dev->mt76.wq, &dev->reset_work); 167162306a36Sopenharmony_ci} 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_civoid mt7915_reset(struct mt7915_dev *dev) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci if (!dev->recovery.hw_init_done) 167662306a36Sopenharmony_ci return; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (dev->recovery.hw_full_reset) 167962306a36Sopenharmony_ci return; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci /* wm/wa exception: do full recovery */ 168262306a36Sopenharmony_ci if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) { 168362306a36Sopenharmony_ci dev->recovery.restart = true; 168462306a36Sopenharmony_ci dev_info(dev->mt76.dev, 168562306a36Sopenharmony_ci "%s indicated firmware crash, attempting recovery\n", 168662306a36Sopenharmony_ci wiphy_name(dev->mt76.hw->wiphy)); 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci mt7915_irq_disable(dev, MT_INT_MCU_CMD); 168962306a36Sopenharmony_ci queue_work(dev->mt76.wq, &dev->dump_work); 169062306a36Sopenharmony_ci return; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci queue_work(dev->mt76.wq, &dev->reset_work); 169462306a36Sopenharmony_ci wake_up(&dev->reset_wait); 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_civoid mt7915_mac_update_stats(struct mt7915_phy *phy) 169862306a36Sopenharmony_ci{ 169962306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 170062306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 170162306a36Sopenharmony_ci int i, aggr0 = 0, aggr1, cnt; 170262306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 170362306a36Sopenharmony_ci u32 val; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR3(band)); 170662306a36Sopenharmony_ci mib->fcs_err_cnt += is_mt7915(&dev->mt76) ? 170762306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : 170862306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR4(band)); 171162306a36Sopenharmony_ci mib->rx_fifo_full_cnt += FIELD_GET(MT_MIB_SDR4_RX_FIFO_FULL_MASK, cnt); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR5(band)); 171462306a36Sopenharmony_ci mib->rx_mpdu_cnt += cnt; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR6(band)); 171762306a36Sopenharmony_ci mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt); 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR7(band)); 172062306a36Sopenharmony_ci mib->rx_vector_mismatch_cnt += 172162306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt); 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR8(band)); 172462306a36Sopenharmony_ci mib->rx_delimiter_fail_cnt += 172562306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR10(band)); 172862306a36Sopenharmony_ci mib->rx_mrdy_cnt += is_mt7915(&dev->mt76) ? 172962306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK, cnt) : 173062306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK_MT7916, cnt); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR11(band)); 173362306a36Sopenharmony_ci mib->rx_len_mismatch_cnt += 173462306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR12(band)); 173762306a36Sopenharmony_ci mib->tx_ampdu_cnt += cnt; 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR13(band)); 174062306a36Sopenharmony_ci mib->tx_stop_q_empty_cnt += 174162306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR14(band)); 174462306a36Sopenharmony_ci mib->tx_mpdu_attempts_cnt += is_mt7915(&dev->mt76) ? 174562306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK, cnt) : 174662306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK_MT7916, cnt); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR15(band)); 174962306a36Sopenharmony_ci mib->tx_mpdu_success_cnt += is_mt7915(&dev->mt76) ? 175062306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt) : 175162306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916, cnt); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR16(band)); 175462306a36Sopenharmony_ci mib->primary_cca_busy_time += 175562306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK, cnt); 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR17(band)); 175862306a36Sopenharmony_ci mib->secondary_cca_busy_time += 175962306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK, cnt); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR18(band)); 176262306a36Sopenharmony_ci mib->primary_energy_detect_time += 176362306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK, cnt); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR19(band)); 176662306a36Sopenharmony_ci mib->cck_mdrdy_time += FIELD_GET(MT_MIB_SDR19_CCK_MDRDY_TIME_MASK, cnt); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR20(band)); 176962306a36Sopenharmony_ci mib->ofdm_mdrdy_time += 177062306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK, cnt); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR21(band)); 177362306a36Sopenharmony_ci mib->green_mdrdy_time += 177462306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR21_GREEN_MDRDY_TIME_MASK, cnt); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR22(band)); 177762306a36Sopenharmony_ci mib->rx_ampdu_cnt += cnt; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR23(band)); 178062306a36Sopenharmony_ci mib->rx_ampdu_bytes_cnt += cnt; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR24(band)); 178362306a36Sopenharmony_ci mib->rx_ampdu_valid_subframe_cnt += is_mt7915(&dev->mt76) ? 178462306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK, cnt) : 178562306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK_MT7916, cnt); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR25(band)); 178862306a36Sopenharmony_ci mib->rx_ampdu_valid_subframe_bytes_cnt += cnt; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR27(band)); 179162306a36Sopenharmony_ci mib->tx_rwp_fail_cnt += 179262306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR28(band)); 179562306a36Sopenharmony_ci mib->tx_rwp_need_cnt += 179662306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR29(band)); 179962306a36Sopenharmony_ci mib->rx_pfdrop_cnt += is_mt7915(&dev->mt76) ? 180062306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK, cnt) : 180162306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK_MT7916, cnt); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDRVEC(band)); 180462306a36Sopenharmony_ci mib->rx_vec_queue_overflow_drop_cnt += is_mt7915(&dev->mt76) ? 180562306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK, cnt) : 180662306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK_MT7916, cnt); 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR31(band)); 180962306a36Sopenharmony_ci mib->rx_ba_cnt += cnt; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDRMUBF(band)); 181262306a36Sopenharmony_ci mib->tx_bf_cnt += FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt); 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_DR8(band)); 181562306a36Sopenharmony_ci mib->tx_mu_mpdu_cnt += cnt; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_DR9(band)); 181862306a36Sopenharmony_ci mib->tx_mu_acked_mpdu_cnt += cnt; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_DR11(band)); 182162306a36Sopenharmony_ci mib->tx_su_acked_mpdu_cnt += cnt; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_ETBF_PAR_RPT0(band)); 182462306a36Sopenharmony_ci mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_PAR_RPT0_FB_BW, cnt); 182562306a36Sopenharmony_ci mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NC, cnt); 182662306a36Sopenharmony_ci mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NR, cnt); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { 182962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); 183062306a36Sopenharmony_ci mib->tx_amsdu[i] += cnt; 183162306a36Sopenharmony_ci mib->tx_amsdu_cnt += cnt; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci if (is_mt7915(&dev->mt76)) { 183562306a36Sopenharmony_ci for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) { 183662306a36Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 4))); 183762306a36Sopenharmony_ci mib->ba_miss_cnt += 183862306a36Sopenharmony_ci FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); 183962306a36Sopenharmony_ci mib->ack_fail_cnt += 184062306a36Sopenharmony_ci FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 4))); 184362306a36Sopenharmony_ci mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); 184462306a36Sopenharmony_ci mib->rts_retries_cnt += 184562306a36Sopenharmony_ci FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci val = mt76_rr(dev, MT_TX_AGG_CNT(band, i)); 184862306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr0++] += val & 0xffff; 184962306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr0++] += val >> 16; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci val = mt76_rr(dev, MT_TX_AGG_CNT2(band, i)); 185262306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr1++] += val & 0xffff; 185362306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr1++] += val >> 16; 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR32(band)); 185762306a36Sopenharmony_ci mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR33(band)); 186062306a36Sopenharmony_ci mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR33_TX_PKT_IBF_CNT, cnt); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(band)); 186362306a36Sopenharmony_ci mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt); 186462306a36Sopenharmony_ci mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(band)); 186762306a36Sopenharmony_ci mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_ETBF_TX_FB_CPL, cnt); 186862306a36Sopenharmony_ci mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_ETBF_TX_FB_TRI, cnt); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(band)); 187162306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, cnt); 187262306a36Sopenharmony_ci mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, cnt); 187362306a36Sopenharmony_ci mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, cnt); 187462306a36Sopenharmony_ci mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, cnt); 187562306a36Sopenharmony_ci } else { 187662306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 187762306a36Sopenharmony_ci /* rts count */ 187862306a36Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 2))); 187962306a36Sopenharmony_ci mib->rts_cnt += FIELD_GET(GENMASK(15, 0), val); 188062306a36Sopenharmony_ci mib->rts_cnt += FIELD_GET(GENMASK(31, 16), val); 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci /* rts retry count */ 188362306a36Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 2))); 188462306a36Sopenharmony_ci mib->rts_retries_cnt += FIELD_GET(GENMASK(15, 0), val); 188562306a36Sopenharmony_ci mib->rts_retries_cnt += FIELD_GET(GENMASK(31, 16), val); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* ba miss count */ 188862306a36Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_SDR2(band, (i << 2))); 188962306a36Sopenharmony_ci mib->ba_miss_cnt += FIELD_GET(GENMASK(15, 0), val); 189062306a36Sopenharmony_ci mib->ba_miss_cnt += FIELD_GET(GENMASK(31, 16), val); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci /* ack fail count */ 189362306a36Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_BFTF(band, (i << 2))); 189462306a36Sopenharmony_ci mib->ack_fail_cnt += FIELD_GET(GENMASK(15, 0), val); 189562306a36Sopenharmony_ci mib->ack_fail_cnt += FIELD_GET(GENMASK(31, 16), val); 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 189962306a36Sopenharmony_ci val = mt76_rr(dev, MT_TX_AGG_CNT(band, i)); 190062306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(15, 0), val); 190162306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(31, 16), val); 190262306a36Sopenharmony_ci } 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR32(band)); 190562306a36Sopenharmony_ci mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt); 190662306a36Sopenharmony_ci mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt); 190762306a36Sopenharmony_ci mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); 190862306a36Sopenharmony_ci mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BFCR7(band)); 191162306a36Sopenharmony_ci mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_MIB_BFCR7_BFEE_TX_FB_CPL, cnt); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BFCR2(band)); 191462306a36Sopenharmony_ci mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_MIB_BFCR2_BFEE_TX_FB_TRIG, cnt); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BFCR0(band)); 191762306a36Sopenharmony_ci mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt); 191862306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt); 191962306a36Sopenharmony_ci mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt); 192062306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt); 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_BFCR1(band)); 192362306a36Sopenharmony_ci mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt); 192462306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt); 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci} 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_cistatic void mt7915_mac_severe_check(struct mt7915_phy *phy) 192962306a36Sopenharmony_ci{ 193062306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 193162306a36Sopenharmony_ci u32 trb; 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci if (!phy->omac_mask) 193462306a36Sopenharmony_ci return; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* In rare cases, TRB pointers might be out of sync leads to RMAC 193762306a36Sopenharmony_ci * stopping Rx, so check status periodically to see if TRB hardware 193862306a36Sopenharmony_ci * requires minimal recovery. 193962306a36Sopenharmony_ci */ 194062306a36Sopenharmony_ci trb = mt76_rr(dev, MT_TRB_RXPSR0(phy->mt76->band_idx)); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if ((FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, trb) != 194362306a36Sopenharmony_ci FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, trb)) && 194462306a36Sopenharmony_ci (FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, phy->trb_ts) != 194562306a36Sopenharmony_ci FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, phy->trb_ts)) && 194662306a36Sopenharmony_ci trb == phy->trb_ts) 194762306a36Sopenharmony_ci mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L3_RX_ABORT, 194862306a36Sopenharmony_ci phy->mt76->band_idx); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci phy->trb_ts = trb; 195162306a36Sopenharmony_ci} 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_civoid mt7915_mac_sta_rc_work(struct work_struct *work) 195462306a36Sopenharmony_ci{ 195562306a36Sopenharmony_ci struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work); 195662306a36Sopenharmony_ci struct ieee80211_sta *sta; 195762306a36Sopenharmony_ci struct ieee80211_vif *vif; 195862306a36Sopenharmony_ci struct mt7915_sta *msta; 195962306a36Sopenharmony_ci u32 changed; 196062306a36Sopenharmony_ci LIST_HEAD(list); 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 196362306a36Sopenharmony_ci list_splice_init(&dev->sta_rc_list, &list); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci while (!list_empty(&list)) { 196662306a36Sopenharmony_ci msta = list_first_entry(&list, struct mt7915_sta, rc_list); 196762306a36Sopenharmony_ci list_del_init(&msta->rc_list); 196862306a36Sopenharmony_ci changed = msta->changed; 196962306a36Sopenharmony_ci msta->changed = 0; 197062306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); 197362306a36Sopenharmony_ci vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED | 197662306a36Sopenharmony_ci IEEE80211_RC_NSS_CHANGED | 197762306a36Sopenharmony_ci IEEE80211_RC_BW_CHANGED)) 197862306a36Sopenharmony_ci mt7915_mcu_add_rate_ctrl(dev, vif, sta, true); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci if (changed & IEEE80211_RC_SMPS_CHANGED) 198162306a36Sopenharmony_ci mt7915_mcu_add_smps(dev, vif, sta); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 198762306a36Sopenharmony_ci} 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_civoid mt7915_mac_work(struct work_struct *work) 199062306a36Sopenharmony_ci{ 199162306a36Sopenharmony_ci struct mt7915_phy *phy; 199262306a36Sopenharmony_ci struct mt76_phy *mphy; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, 199562306a36Sopenharmony_ci mac_work.work); 199662306a36Sopenharmony_ci phy = mphy->priv; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci mutex_lock(&mphy->dev->mutex); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci mt76_update_survey(mphy); 200162306a36Sopenharmony_ci if (++mphy->mac_work_count == 5) { 200262306a36Sopenharmony_ci mphy->mac_work_count = 0; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci mt7915_mac_update_stats(phy); 200562306a36Sopenharmony_ci mt7915_mac_severe_check(phy); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (phy->dev->muru_debug) 200862306a36Sopenharmony_ci mt7915_mcu_muru_debug_get(phy); 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci mutex_unlock(&mphy->dev->mutex); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci mt76_tx_status_check(mphy->dev, false); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, 201662306a36Sopenharmony_ci MT7915_WATCHDOG_TIME); 201762306a36Sopenharmony_ci} 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_cistatic void mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy) 202062306a36Sopenharmony_ci{ 202162306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci if (phy->rdd_state & BIT(0)) 202462306a36Sopenharmony_ci mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 0, 202562306a36Sopenharmony_ci MT_RX_SEL0, 0); 202662306a36Sopenharmony_ci if (phy->rdd_state & BIT(1)) 202762306a36Sopenharmony_ci mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 1, 202862306a36Sopenharmony_ci MT_RX_SEL0, 0); 202962306a36Sopenharmony_ci} 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_cistatic int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci int err, region; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci switch (dev->mt76.region) { 203662306a36Sopenharmony_ci case NL80211_DFS_ETSI: 203762306a36Sopenharmony_ci region = 0; 203862306a36Sopenharmony_ci break; 203962306a36Sopenharmony_ci case NL80211_DFS_JP: 204062306a36Sopenharmony_ci region = 2; 204162306a36Sopenharmony_ci break; 204262306a36Sopenharmony_ci case NL80211_DFS_FCC: 204362306a36Sopenharmony_ci default: 204462306a36Sopenharmony_ci region = 1; 204562306a36Sopenharmony_ci break; 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, chain, 204962306a36Sopenharmony_ci MT_RX_SEL0, region); 205062306a36Sopenharmony_ci if (err < 0) 205162306a36Sopenharmony_ci return err; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (is_mt7915(&dev->mt76)) { 205462306a36Sopenharmony_ci err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, chain, 205562306a36Sopenharmony_ci 0, dev->dbdc_support ? 2 : 0); 205662306a36Sopenharmony_ci if (err < 0) 205762306a36Sopenharmony_ci return err; 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, chain, 206162306a36Sopenharmony_ci MT_RX_SEL0, 1); 206262306a36Sopenharmony_ci} 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_cistatic int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy) 206562306a36Sopenharmony_ci{ 206662306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 206762306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 206862306a36Sopenharmony_ci int err; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci /* start CAC */ 207162306a36Sopenharmony_ci err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, 207262306a36Sopenharmony_ci phy->mt76->band_idx, MT_RX_SEL0, 0); 207362306a36Sopenharmony_ci if (err < 0) 207462306a36Sopenharmony_ci return err; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci err = mt7915_dfs_start_rdd(dev, phy->mt76->band_idx); 207762306a36Sopenharmony_ci if (err < 0) 207862306a36Sopenharmony_ci return err; 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci phy->rdd_state |= BIT(phy->mt76->band_idx); 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci if (!is_mt7915(&dev->mt76)) 208362306a36Sopenharmony_ci return 0; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_160 || 208662306a36Sopenharmony_ci chandef->width == NL80211_CHAN_WIDTH_80P80) { 208762306a36Sopenharmony_ci err = mt7915_dfs_start_rdd(dev, 1); 208862306a36Sopenharmony_ci if (err < 0) 208962306a36Sopenharmony_ci return err; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci phy->rdd_state |= BIT(1); 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci return 0; 209562306a36Sopenharmony_ci} 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_cistatic int 209862306a36Sopenharmony_cimt7915_dfs_init_radar_specs(struct mt7915_phy *phy) 209962306a36Sopenharmony_ci{ 210062306a36Sopenharmony_ci const struct mt7915_dfs_radar_spec *radar_specs; 210162306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 210262306a36Sopenharmony_ci int err, i; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci switch (dev->mt76.region) { 210562306a36Sopenharmony_ci case NL80211_DFS_FCC: 210662306a36Sopenharmony_ci radar_specs = &fcc_radar_specs; 210762306a36Sopenharmony_ci err = mt7915_mcu_set_fcc5_lpn(dev, 8); 210862306a36Sopenharmony_ci if (err < 0) 210962306a36Sopenharmony_ci return err; 211062306a36Sopenharmony_ci break; 211162306a36Sopenharmony_ci case NL80211_DFS_ETSI: 211262306a36Sopenharmony_ci radar_specs = &etsi_radar_specs; 211362306a36Sopenharmony_ci break; 211462306a36Sopenharmony_ci case NL80211_DFS_JP: 211562306a36Sopenharmony_ci radar_specs = &jp_radar_specs; 211662306a36Sopenharmony_ci break; 211762306a36Sopenharmony_ci default: 211862306a36Sopenharmony_ci return -EINVAL; 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { 212262306a36Sopenharmony_ci err = mt7915_mcu_set_radar_th(dev, i, 212362306a36Sopenharmony_ci &radar_specs->radar_pattern[i]); 212462306a36Sopenharmony_ci if (err < 0) 212562306a36Sopenharmony_ci return err; 212662306a36Sopenharmony_ci } 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci return mt7915_mcu_set_pulse_th(dev, &radar_specs->pulse_th); 212962306a36Sopenharmony_ci} 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ciint mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) 213262306a36Sopenharmony_ci{ 213362306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 213462306a36Sopenharmony_ci enum mt76_dfs_state dfs_state, prev_state; 213562306a36Sopenharmony_ci int err; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci prev_state = phy->mt76->dfs_state; 213862306a36Sopenharmony_ci dfs_state = mt76_phy_dfs_state(phy->mt76); 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (prev_state == dfs_state) 214162306a36Sopenharmony_ci return 0; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci if (prev_state == MT_DFS_STATE_UNKNOWN) 214462306a36Sopenharmony_ci mt7915_dfs_stop_radar_detector(phy); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if (dfs_state == MT_DFS_STATE_DISABLED) 214762306a36Sopenharmony_ci goto stop; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci if (prev_state <= MT_DFS_STATE_DISABLED) { 215062306a36Sopenharmony_ci err = mt7915_dfs_init_radar_specs(phy); 215162306a36Sopenharmony_ci if (err < 0) 215262306a36Sopenharmony_ci return err; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci err = mt7915_dfs_start_radar_detector(phy); 215562306a36Sopenharmony_ci if (err < 0) 215662306a36Sopenharmony_ci return err; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_CAC; 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci if (dfs_state == MT_DFS_STATE_CAC) 216262306a36Sopenharmony_ci return 0; 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END, 216562306a36Sopenharmony_ci phy->mt76->band_idx, MT_RX_SEL0, 0); 216662306a36Sopenharmony_ci if (err < 0) { 216762306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; 216862306a36Sopenharmony_ci return err; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE; 217262306a36Sopenharmony_ci return 0; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_cistop: 217562306a36Sopenharmony_ci err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START, 217662306a36Sopenharmony_ci phy->mt76->band_idx, MT_RX_SEL0, 0); 217762306a36Sopenharmony_ci if (err < 0) 217862306a36Sopenharmony_ci return err; 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci if (is_mt7915(&dev->mt76)) { 218162306a36Sopenharmony_ci err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, 218262306a36Sopenharmony_ci phy->mt76->band_idx, 0, 218362306a36Sopenharmony_ci dev->dbdc_support ? 2 : 0); 218462306a36Sopenharmony_ci if (err < 0) 218562306a36Sopenharmony_ci return err; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci mt7915_dfs_stop_radar_detector(phy); 218962306a36Sopenharmony_ci phy->mt76->dfs_state = MT_DFS_STATE_DISABLED; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci return 0; 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cistatic int 219562306a36Sopenharmony_cimt7915_mac_twt_duration_align(int duration) 219662306a36Sopenharmony_ci{ 219762306a36Sopenharmony_ci return duration << 8; 219862306a36Sopenharmony_ci} 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_cistatic u64 220162306a36Sopenharmony_cimt7915_mac_twt_sched_list_add(struct mt7915_dev *dev, 220262306a36Sopenharmony_ci struct mt7915_twt_flow *flow) 220362306a36Sopenharmony_ci{ 220462306a36Sopenharmony_ci struct mt7915_twt_flow *iter, *iter_next; 220562306a36Sopenharmony_ci u32 duration = flow->duration << 8; 220662306a36Sopenharmony_ci u64 start_tsf; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci iter = list_first_entry_or_null(&dev->twt_list, 220962306a36Sopenharmony_ci struct mt7915_twt_flow, list); 221062306a36Sopenharmony_ci if (!iter || !iter->sched || iter->start_tsf > duration) { 221162306a36Sopenharmony_ci /* add flow as first entry in the list */ 221262306a36Sopenharmony_ci list_add(&flow->list, &dev->twt_list); 221362306a36Sopenharmony_ci return 0; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) { 221762306a36Sopenharmony_ci start_tsf = iter->start_tsf + 221862306a36Sopenharmony_ci mt7915_mac_twt_duration_align(iter->duration); 221962306a36Sopenharmony_ci if (list_is_last(&iter->list, &dev->twt_list)) 222062306a36Sopenharmony_ci break; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (!iter_next->sched || 222362306a36Sopenharmony_ci iter_next->start_tsf > start_tsf + duration) { 222462306a36Sopenharmony_ci list_add(&flow->list, &iter->list); 222562306a36Sopenharmony_ci goto out; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci /* add flow as last entry in the list */ 223062306a36Sopenharmony_ci list_add_tail(&flow->list, &dev->twt_list); 223162306a36Sopenharmony_ciout: 223262306a36Sopenharmony_ci return start_tsf; 223362306a36Sopenharmony_ci} 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_cistatic int mt7915_mac_check_twt_req(struct ieee80211_twt_setup *twt) 223662306a36Sopenharmony_ci{ 223762306a36Sopenharmony_ci struct ieee80211_twt_params *twt_agrt; 223862306a36Sopenharmony_ci u64 interval, duration; 223962306a36Sopenharmony_ci u16 mantissa; 224062306a36Sopenharmony_ci u8 exp; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci /* only individual agreement supported */ 224362306a36Sopenharmony_ci if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) 224462306a36Sopenharmony_ci return -EOPNOTSUPP; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci /* only 256us unit supported */ 224762306a36Sopenharmony_ci if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) 224862306a36Sopenharmony_ci return -EOPNOTSUPP; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci twt_agrt = (struct ieee80211_twt_params *)twt->params; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci /* explicit agreement not supported */ 225362306a36Sopenharmony_ci if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT))) 225462306a36Sopenharmony_ci return -EOPNOTSUPP; 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, 225762306a36Sopenharmony_ci le16_to_cpu(twt_agrt->req_type)); 225862306a36Sopenharmony_ci mantissa = le16_to_cpu(twt_agrt->mantissa); 225962306a36Sopenharmony_ci duration = twt_agrt->min_twt_dur << 8; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci interval = (u64)mantissa << exp; 226262306a36Sopenharmony_ci if (interval < duration) 226362306a36Sopenharmony_ci return -EOPNOTSUPP; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci return 0; 226662306a36Sopenharmony_ci} 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_cistatic bool 226962306a36Sopenharmony_cimt7915_mac_twt_param_equal(struct mt7915_sta *msta, 227062306a36Sopenharmony_ci struct ieee80211_twt_params *twt_agrt) 227162306a36Sopenharmony_ci{ 227262306a36Sopenharmony_ci u16 type = le16_to_cpu(twt_agrt->req_type); 227362306a36Sopenharmony_ci u8 exp; 227462306a36Sopenharmony_ci int i; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type); 227762306a36Sopenharmony_ci for (i = 0; i < MT7915_MAX_STA_TWT_AGRT; i++) { 227862306a36Sopenharmony_ci struct mt7915_twt_flow *f; 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci if (!(msta->twt.flowid_mask & BIT(i))) 228162306a36Sopenharmony_ci continue; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci f = &msta->twt.flow[i]; 228462306a36Sopenharmony_ci if (f->duration == twt_agrt->min_twt_dur && 228562306a36Sopenharmony_ci f->mantissa == twt_agrt->mantissa && 228662306a36Sopenharmony_ci f->exp == exp && 228762306a36Sopenharmony_ci f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) && 228862306a36Sopenharmony_ci f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) && 228962306a36Sopenharmony_ci f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER)) 229062306a36Sopenharmony_ci return true; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci return false; 229462306a36Sopenharmony_ci} 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_civoid mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, 229762306a36Sopenharmony_ci struct ieee80211_sta *sta, 229862306a36Sopenharmony_ci struct ieee80211_twt_setup *twt) 229962306a36Sopenharmony_ci{ 230062306a36Sopenharmony_ci enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT; 230162306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 230262306a36Sopenharmony_ci struct ieee80211_twt_params *twt_agrt = (void *)twt->params; 230362306a36Sopenharmony_ci u16 req_type = le16_to_cpu(twt_agrt->req_type); 230462306a36Sopenharmony_ci enum ieee80211_twt_setup_cmd sta_setup_cmd; 230562306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 230662306a36Sopenharmony_ci struct mt7915_twt_flow *flow; 230762306a36Sopenharmony_ci int flowid, table_id; 230862306a36Sopenharmony_ci u8 exp; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci if (mt7915_mac_check_twt_req(twt)) 231162306a36Sopenharmony_ci goto out; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci if (dev->twt.n_agrt == MT7915_MAX_TWT_AGRT) 231662306a36Sopenharmony_ci goto unlock; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) 231962306a36Sopenharmony_ci goto unlock; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci if (twt_agrt->min_twt_dur < MT7915_MIN_TWT_DUR) { 232262306a36Sopenharmony_ci setup_cmd = TWT_SETUP_CMD_DICTATE; 232362306a36Sopenharmony_ci twt_agrt->min_twt_dur = MT7915_MIN_TWT_DUR; 232462306a36Sopenharmony_ci goto unlock; 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci flowid = ffs(~msta->twt.flowid_mask) - 1; 232862306a36Sopenharmony_ci twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID); 232962306a36Sopenharmony_ci twt_agrt->req_type |= le16_encode_bits(flowid, 233062306a36Sopenharmony_ci IEEE80211_TWT_REQTYPE_FLOWID); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci table_id = ffs(~dev->twt.table_mask) - 1; 233362306a36Sopenharmony_ci exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type); 233462306a36Sopenharmony_ci sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type); 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci if (mt7915_mac_twt_param_equal(msta, twt_agrt)) 233762306a36Sopenharmony_ci goto unlock; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci flow = &msta->twt.flow[flowid]; 234062306a36Sopenharmony_ci memset(flow, 0, sizeof(*flow)); 234162306a36Sopenharmony_ci INIT_LIST_HEAD(&flow->list); 234262306a36Sopenharmony_ci flow->wcid = msta->wcid.idx; 234362306a36Sopenharmony_ci flow->table_id = table_id; 234462306a36Sopenharmony_ci flow->id = flowid; 234562306a36Sopenharmony_ci flow->duration = twt_agrt->min_twt_dur; 234662306a36Sopenharmony_ci flow->mantissa = twt_agrt->mantissa; 234762306a36Sopenharmony_ci flow->exp = exp; 234862306a36Sopenharmony_ci flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION); 234962306a36Sopenharmony_ci flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE); 235062306a36Sopenharmony_ci flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER); 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST || 235362306a36Sopenharmony_ci sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) { 235462306a36Sopenharmony_ci u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp; 235562306a36Sopenharmony_ci u64 flow_tsf, curr_tsf; 235662306a36Sopenharmony_ci u32 rem; 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci flow->sched = true; 235962306a36Sopenharmony_ci flow->start_tsf = mt7915_mac_twt_sched_list_add(dev, flow); 236062306a36Sopenharmony_ci curr_tsf = __mt7915_get_tsf(hw, msta->vif); 236162306a36Sopenharmony_ci div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem); 236262306a36Sopenharmony_ci flow_tsf = curr_tsf + interval - rem; 236362306a36Sopenharmony_ci twt_agrt->twt = cpu_to_le64(flow_tsf); 236462306a36Sopenharmony_ci } else { 236562306a36Sopenharmony_ci list_add_tail(&flow->list, &dev->twt_list); 236662306a36Sopenharmony_ci } 236762306a36Sopenharmony_ci flow->tsf = le64_to_cpu(twt_agrt->twt); 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD)) 237062306a36Sopenharmony_ci goto unlock; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci setup_cmd = TWT_SETUP_CMD_ACCEPT; 237362306a36Sopenharmony_ci dev->twt.table_mask |= BIT(table_id); 237462306a36Sopenharmony_ci msta->twt.flowid_mask |= BIT(flowid); 237562306a36Sopenharmony_ci dev->twt.n_agrt++; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ciunlock: 237862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 237962306a36Sopenharmony_ciout: 238062306a36Sopenharmony_ci twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD); 238162306a36Sopenharmony_ci twt_agrt->req_type |= 238262306a36Sopenharmony_ci le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD); 238362306a36Sopenharmony_ci twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) | 238462306a36Sopenharmony_ci (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED); 238562306a36Sopenharmony_ci} 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_civoid mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev, 238862306a36Sopenharmony_ci struct mt7915_sta *msta, 238962306a36Sopenharmony_ci u8 flowid) 239062306a36Sopenharmony_ci{ 239162306a36Sopenharmony_ci struct mt7915_twt_flow *flow; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci lockdep_assert_held(&dev->mt76.mutex); 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci if (flowid >= ARRAY_SIZE(msta->twt.flow)) 239662306a36Sopenharmony_ci return; 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci if (!(msta->twt.flowid_mask & BIT(flowid))) 239962306a36Sopenharmony_ci return; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci flow = &msta->twt.flow[flowid]; 240262306a36Sopenharmony_ci if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, 240362306a36Sopenharmony_ci MCU_TWT_AGRT_DELETE)) 240462306a36Sopenharmony_ci return; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci list_del_init(&flow->list); 240762306a36Sopenharmony_ci msta->twt.flowid_mask &= ~BIT(flowid); 240862306a36Sopenharmony_ci dev->twt.table_mask &= ~BIT(flow->table_id); 240962306a36Sopenharmony_ci dev->twt.n_agrt--; 241062306a36Sopenharmony_ci} 2411