18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 48c2ecf20Sopenharmony_ci#include <linux/timekeeping.h> 58c2ecf20Sopenharmony_ci#include "mt7603.h" 68c2ecf20Sopenharmony_ci#include "mac.h" 78c2ecf20Sopenharmony_ci#include "../trace.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define MT_PSE_PAGE_SIZE 128 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic u32 128c2ecf20Sopenharmony_cimt7603_ac_queue_mask0(u32 mask) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci u32 ret = 0; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci ret |= GENMASK(3, 0) * !!(mask & BIT(0)); 178c2ecf20Sopenharmony_ci ret |= GENMASK(8, 5) * !!(mask & BIT(1)); 188c2ecf20Sopenharmony_ci ret |= GENMASK(13, 10) * !!(mask & BIT(2)); 198c2ecf20Sopenharmony_ci ret |= GENMASK(19, 16) * !!(mask & BIT(3)); 208c2ecf20Sopenharmony_ci return ret; 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void 248c2ecf20Sopenharmony_cimt76_stop_tx_ac(struct mt7603_dev *dev, u32 mask) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci mt76_set(dev, MT_WF_ARB_TX_STOP_0, mt7603_ac_queue_mask0(mask)); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void 308c2ecf20Sopenharmony_cimt76_start_tx_ac(struct mt7603_dev *dev, u32 mask) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask)); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_civoid mt7603_mac_reset_counters(struct mt7603_dev *dev) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci int i; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 408c2ecf20Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT(i)); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_civoid mt7603_mac_set_timing(struct mt7603_dev *dev) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | 488c2ecf20Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); 498c2ecf20Sopenharmony_ci u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | 508c2ecf20Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 24); 518c2ecf20Sopenharmony_ci int offset = 3 * dev->coverage_class; 528c2ecf20Sopenharmony_ci u32 reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | 538c2ecf20Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); 548c2ecf20Sopenharmony_ci bool is_5ghz = dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ; 558c2ecf20Sopenharmony_ci int sifs; 568c2ecf20Sopenharmony_ci u32 val; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (is_5ghz) 598c2ecf20Sopenharmony_ci sifs = 16; 608c2ecf20Sopenharmony_ci else 618c2ecf20Sopenharmony_ci sifs = 10; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci mt76_set(dev, MT_ARB_SCR, 648c2ecf20Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 658c2ecf20Sopenharmony_ci udelay(1); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci mt76_wr(dev, MT_TIMEOUT_CCK, cck + reg_offset); 688c2ecf20Sopenharmony_ci mt76_wr(dev, MT_TIMEOUT_OFDM, ofdm + reg_offset); 698c2ecf20Sopenharmony_ci mt76_wr(dev, MT_IFS, 708c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_EIFS, 360) | 718c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_RIFS, 2) | 728c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_SIFS, sifs) | 738c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_SLOT, dev->slottime)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (dev->slottime < 20 || is_5ghz) 768c2ecf20Sopenharmony_ci val = MT7603_CFEND_RATE_DEFAULT; 778c2ecf20Sopenharmony_ci else 788c2ecf20Sopenharmony_ci val = MT7603_CFEND_RATE_11B; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci mt76_rmw_field(dev, MT_AGG_CONTROL, MT_AGG_CONTROL_CFEND_RATE, val); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci mt76_clear(dev, MT_ARB_SCR, 838c2ecf20Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void 878c2ecf20Sopenharmony_cimt7603_wtbl_update(struct mt7603_dev *dev, int idx, u32 mask) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, 908c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic u32 968c2ecf20Sopenharmony_cimt7603_wtbl1_addr(int idx) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci return MT_WTBL1_BASE + idx * MT_WTBL1_SIZE; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic u32 1028c2ecf20Sopenharmony_cimt7603_wtbl2_addr(int idx) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci /* Mapped to WTBL2 */ 1058c2ecf20Sopenharmony_ci return MT_PCIE_REMAP_BASE_1 + idx * MT_WTBL2_SIZE; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic u32 1098c2ecf20Sopenharmony_cimt7603_wtbl3_addr(int idx) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci u32 base = mt7603_wtbl2_addr(MT7603_WTBL_SIZE); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return base + idx * MT_WTBL3_SIZE; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic u32 1178c2ecf20Sopenharmony_cimt7603_wtbl4_addr(int idx) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci u32 base = mt7603_wtbl3_addr(MT7603_WTBL_SIZE); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return base + idx * MT_WTBL4_SIZE; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_civoid mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, 1258c2ecf20Sopenharmony_ci const u8 *mac_addr) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci const void *_mac = mac_addr; 1288c2ecf20Sopenharmony_ci u32 addr = mt7603_wtbl1_addr(idx); 1298c2ecf20Sopenharmony_ci u32 w0 = 0, w1 = 0; 1308c2ecf20Sopenharmony_ci int i; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (_mac) { 1338c2ecf20Sopenharmony_ci w0 = FIELD_PREP(MT_WTBL1_W0_ADDR_HI, 1348c2ecf20Sopenharmony_ci get_unaligned_le16(_mac + 4)); 1358c2ecf20Sopenharmony_ci w1 = FIELD_PREP(MT_WTBL1_W1_ADDR_LO, 1368c2ecf20Sopenharmony_ci get_unaligned_le32(_mac)); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (vif < 0) 1408c2ecf20Sopenharmony_ci vif = 0; 1418c2ecf20Sopenharmony_ci else 1428c2ecf20Sopenharmony_ci w0 |= MT_WTBL1_W0_RX_CHECK_A1; 1438c2ecf20Sopenharmony_ci w0 |= FIELD_PREP(MT_WTBL1_W0_MUAR_IDX, vif); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci mt76_set(dev, addr + 0 * 4, w0); 1488c2ecf20Sopenharmony_ci mt76_set(dev, addr + 1 * 4, w1); 1498c2ecf20Sopenharmony_ci mt76_set(dev, addr + 2 * 4, MT_WTBL1_W2_ADMISSION_CONTROL); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci mt76_stop_tx_ac(dev, GENMASK(3, 0)); 1528c2ecf20Sopenharmony_ci addr = mt7603_wtbl2_addr(idx); 1538c2ecf20Sopenharmony_ci for (i = 0; i < MT_WTBL2_SIZE; i += 4) 1548c2ecf20Sopenharmony_ci mt76_wr(dev, addr + i, 0); 1558c2ecf20Sopenharmony_ci mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2); 1568c2ecf20Sopenharmony_ci mt76_start_tx_ac(dev, GENMASK(3, 0)); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci addr = mt7603_wtbl3_addr(idx); 1598c2ecf20Sopenharmony_ci for (i = 0; i < MT_WTBL3_SIZE; i += 4) 1608c2ecf20Sopenharmony_ci mt76_wr(dev, addr + i, 0); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci addr = mt7603_wtbl4_addr(idx); 1638c2ecf20Sopenharmony_ci for (i = 0; i < MT_WTBL4_SIZE; i += 4) 1648c2ecf20Sopenharmony_ci mt76_wr(dev, addr + i, 0); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void 1708c2ecf20Sopenharmony_cimt7603_wtbl_set_skip_tx(struct mt7603_dev *dev, int idx, bool enabled) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci u32 addr = mt7603_wtbl1_addr(idx); 1738c2ecf20Sopenharmony_ci u32 val = mt76_rr(dev, addr + 3 * 4); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci val &= ~MT_WTBL1_W3_SKIP_TX; 1768c2ecf20Sopenharmony_ci val |= enabled * MT_WTBL1_W3_SKIP_TX; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 3 * 4, val); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_civoid mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci int i, port, queue; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (abort) { 1868c2ecf20Sopenharmony_ci port = 3; /* PSE */ 1878c2ecf20Sopenharmony_ci queue = 8; /* free queue */ 1888c2ecf20Sopenharmony_ci } else { 1898c2ecf20Sopenharmony_ci port = 0; /* HIF */ 1908c2ecf20Sopenharmony_ci queue = 1; /* MCU queue */ 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci mt7603_wtbl_set_skip_tx(dev, idx, true); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci mt76_wr(dev, MT_TX_ABORT, MT_TX_ABORT_EN | 1968c2ecf20Sopenharmony_ci FIELD_PREP(MT_TX_ABORT_WCID, idx)); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 1998c2ecf20Sopenharmony_ci mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY | 2008c2ecf20Sopenharmony_ci FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, idx) | 2018c2ecf20Sopenharmony_ci FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, i) | 2028c2ecf20Sopenharmony_ci FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, port) | 2038c2ecf20Sopenharmony_ci FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, queue)); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci WARN_ON_ONCE(!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 2068c2ecf20Sopenharmony_ci 0, 5000)); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci mt76_wr(dev, MT_TX_ABORT, 0); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci mt7603_wtbl_set_skip_tx(dev, idx, false); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_civoid mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta, 2158c2ecf20Sopenharmony_ci bool enabled) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci u32 addr = mt7603_wtbl1_addr(sta->wcid.idx); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (sta->smps == enabled) 2208c2ecf20Sopenharmony_ci return; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_SMPS, enabled); 2238c2ecf20Sopenharmony_ci sta->smps = enabled; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_civoid mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, 2278c2ecf20Sopenharmony_ci bool enabled) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci int idx = sta->wcid.idx; 2308c2ecf20Sopenharmony_ci u32 addr; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci spin_lock_bh(&dev->ps_lock); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (sta->ps == enabled) 2358c2ecf20Sopenharmony_ci goto out; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci mt76_wr(dev, MT_PSE_RTA, 2388c2ecf20Sopenharmony_ci FIELD_PREP(MT_PSE_RTA_TAG_ID, idx) | 2398c2ecf20Sopenharmony_ci FIELD_PREP(MT_PSE_RTA_PORT_ID, 0) | 2408c2ecf20Sopenharmony_ci FIELD_PREP(MT_PSE_RTA_QUEUE_ID, 1) | 2418c2ecf20Sopenharmony_ci FIELD_PREP(MT_PSE_RTA_REDIRECT_EN, enabled) | 2428c2ecf20Sopenharmony_ci MT_PSE_RTA_WRITE | MT_PSE_RTA_BUSY); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (enabled) 2478c2ecf20Sopenharmony_ci mt7603_filter_tx(dev, idx, false); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci addr = mt7603_wtbl1_addr(idx); 2508c2ecf20Sopenharmony_ci mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); 2518c2ecf20Sopenharmony_ci mt76_rmw(dev, addr + 3 * 4, MT_WTBL1_W3_POWER_SAVE, 2528c2ecf20Sopenharmony_ci enabled * MT_WTBL1_W3_POWER_SAVE); 2538c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); 2548c2ecf20Sopenharmony_ci sta->ps = enabled; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciout: 2578c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->ps_lock); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_civoid mt7603_wtbl_clear(struct mt7603_dev *dev, int idx) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int wtbl2_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL2_SIZE; 2638c2ecf20Sopenharmony_ci int wtbl2_frame = idx / wtbl2_frame_size; 2648c2ecf20Sopenharmony_ci int wtbl2_entry = idx % wtbl2_frame_size; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci int wtbl3_base_frame = MT_WTBL3_OFFSET / MT_PSE_PAGE_SIZE; 2678c2ecf20Sopenharmony_ci int wtbl3_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL3_SIZE; 2688c2ecf20Sopenharmony_ci int wtbl3_frame = wtbl3_base_frame + idx / wtbl3_frame_size; 2698c2ecf20Sopenharmony_ci int wtbl3_entry = (idx % wtbl3_frame_size) * 2; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci int wtbl4_base_frame = MT_WTBL4_OFFSET / MT_PSE_PAGE_SIZE; 2728c2ecf20Sopenharmony_ci int wtbl4_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL4_SIZE; 2738c2ecf20Sopenharmony_ci int wtbl4_frame = wtbl4_base_frame + idx / wtbl4_frame_size; 2748c2ecf20Sopenharmony_ci int wtbl4_entry = idx % wtbl4_frame_size; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci u32 addr = MT_WTBL1_BASE + idx * MT_WTBL1_SIZE; 2778c2ecf20Sopenharmony_ci int i; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 0 * 4, 2828c2ecf20Sopenharmony_ci MT_WTBL1_W0_RX_CHECK_A1 | 2838c2ecf20Sopenharmony_ci MT_WTBL1_W0_RX_CHECK_A2 | 2848c2ecf20Sopenharmony_ci MT_WTBL1_W0_RX_VALID); 2858c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 1 * 4, 0); 2868c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 2 * 4, 0); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 3 * 4, 2918c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL1_W3_WTBL2_FRAME_ID, wtbl2_frame) | 2928c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL1_W3_WTBL2_ENTRY_ID, wtbl2_entry) | 2938c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL1_W3_WTBL4_FRAME_ID, wtbl4_frame) | 2948c2ecf20Sopenharmony_ci MT_WTBL1_W3_I_PSM | MT_WTBL1_W3_KEEP_I_PSM); 2958c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 4 * 4, 2968c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL1_W4_WTBL3_FRAME_ID, wtbl3_frame) | 2978c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL1_W4_WTBL3_ENTRY_ID, wtbl3_entry) | 2988c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL1_W4_WTBL4_ENTRY_ID, wtbl4_entry)); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci addr = mt7603_wtbl2_addr(idx); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Clear BA information */ 3058c2ecf20Sopenharmony_ci mt76_wr(dev, addr + (15 * 4), 0); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci mt76_stop_tx_ac(dev, GENMASK(3, 0)); 3088c2ecf20Sopenharmony_ci for (i = 2; i <= 4; i++) 3098c2ecf20Sopenharmony_ci mt76_wr(dev, addr + (i * 4), 0); 3108c2ecf20Sopenharmony_ci mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2); 3118c2ecf20Sopenharmony_ci mt76_start_tx_ac(dev, GENMASK(3, 0)); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_RX_COUNT_CLEAR); 3148c2ecf20Sopenharmony_ci mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_TX_COUNT_CLEAR); 3158c2ecf20Sopenharmony_ci mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_civoid mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; 3218c2ecf20Sopenharmony_ci int idx = msta->wcid.idx; 3228c2ecf20Sopenharmony_ci u8 ampdu_density; 3238c2ecf20Sopenharmony_ci u32 addr; 3248c2ecf20Sopenharmony_ci u32 val; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci addr = mt7603_wtbl1_addr(idx); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci ampdu_density = sta->ht_cap.ampdu_density; 3298c2ecf20Sopenharmony_ci if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4) 3308c2ecf20Sopenharmony_ci ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci val = mt76_rr(dev, addr + 2 * 4); 3338c2ecf20Sopenharmony_ci val &= MT_WTBL1_W2_KEY_TYPE | MT_WTBL1_W2_ADMISSION_CONTROL; 3348c2ecf20Sopenharmony_ci val |= FIELD_PREP(MT_WTBL1_W2_AMPDU_FACTOR, sta->ht_cap.ampdu_factor) | 3358c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL1_W2_MPDU_DENSITY, sta->ht_cap.ampdu_density) | 3368c2ecf20Sopenharmony_ci MT_WTBL1_W2_TXS_BAF_REPORT; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (sta->ht_cap.cap) 3398c2ecf20Sopenharmony_ci val |= MT_WTBL1_W2_HT; 3408c2ecf20Sopenharmony_ci if (sta->vht_cap.cap) 3418c2ecf20Sopenharmony_ci val |= MT_WTBL1_W2_VHT; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 2 * 4, val); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci addr = mt7603_wtbl2_addr(idx); 3468c2ecf20Sopenharmony_ci val = mt76_rr(dev, addr + 9 * 4); 3478c2ecf20Sopenharmony_ci val &= ~(MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 | 3488c2ecf20Sopenharmony_ci MT_WTBL2_W9_SHORT_GI_80); 3498c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) 3508c2ecf20Sopenharmony_ci val |= MT_WTBL2_W9_SHORT_GI_20; 3518c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) 3528c2ecf20Sopenharmony_ci val |= MT_WTBL2_W9_SHORT_GI_40; 3538c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 9 * 4, val); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_civoid mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci mt76_wr(dev, MT_BA_CONTROL_0, get_unaligned_le32(addr)); 3598c2ecf20Sopenharmony_ci mt76_wr(dev, MT_BA_CONTROL_1, 3608c2ecf20Sopenharmony_ci (get_unaligned_le16(addr + 4) | 3618c2ecf20Sopenharmony_ci FIELD_PREP(MT_BA_CONTROL_1_TID, tid) | 3628c2ecf20Sopenharmony_ci MT_BA_CONTROL_1_RESET)); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_civoid mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, 3668c2ecf20Sopenharmony_ci int ba_size) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci u32 addr = mt7603_wtbl2_addr(wcid); 3698c2ecf20Sopenharmony_ci u32 tid_mask = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) | 3708c2ecf20Sopenharmony_ci (MT_WTBL2_W15_BA_WIN_SIZE << 3718c2ecf20Sopenharmony_ci (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT)); 3728c2ecf20Sopenharmony_ci u32 tid_val; 3738c2ecf20Sopenharmony_ci int i; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (ba_size < 0) { 3768c2ecf20Sopenharmony_ci /* disable */ 3778c2ecf20Sopenharmony_ci mt76_clear(dev, addr + (15 * 4), tid_mask); 3788c2ecf20Sopenharmony_ci return; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci for (i = 7; i > 0; i--) { 3828c2ecf20Sopenharmony_ci if (ba_size >= MT_AGG_SIZE_LIMIT(i)) 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci tid_val = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) | 3878c2ecf20Sopenharmony_ci i << (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_civoid mt7603_mac_sta_poll(struct mt7603_dev *dev) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci static const u8 ac_to_tid[4] = { 3958c2ecf20Sopenharmony_ci [IEEE80211_AC_BE] = 0, 3968c2ecf20Sopenharmony_ci [IEEE80211_AC_BK] = 1, 3978c2ecf20Sopenharmony_ci [IEEE80211_AC_VI] = 4, 3988c2ecf20Sopenharmony_ci [IEEE80211_AC_VO] = 6 3998c2ecf20Sopenharmony_ci }; 4008c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 4018c2ecf20Sopenharmony_ci struct mt7603_sta *msta; 4028c2ecf20Sopenharmony_ci u32 total_airtime = 0; 4038c2ecf20Sopenharmony_ci u32 airtime[4]; 4048c2ecf20Sopenharmony_ci u32 addr; 4058c2ecf20Sopenharmony_ci int i; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci rcu_read_lock(); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci while (1) { 4108c2ecf20Sopenharmony_ci bool clear = false; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci spin_lock_bh(&dev->sta_poll_lock); 4138c2ecf20Sopenharmony_ci if (list_empty(&dev->sta_poll_list)) { 4148c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->sta_poll_lock); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta, 4198c2ecf20Sopenharmony_ci poll_list); 4208c2ecf20Sopenharmony_ci list_del_init(&msta->poll_list); 4218c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->sta_poll_lock); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci addr = mt7603_wtbl4_addr(msta->wcid.idx); 4248c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 4258c2ecf20Sopenharmony_ci u32 airtime_last = msta->tx_airtime_ac[i]; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8); 4288c2ecf20Sopenharmony_ci airtime[i] = msta->tx_airtime_ac[i] - airtime_last; 4298c2ecf20Sopenharmony_ci airtime[i] *= 32; 4308c2ecf20Sopenharmony_ci total_airtime += airtime[i]; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (msta->tx_airtime_ac[i] & BIT(22)) 4338c2ecf20Sopenharmony_ci clear = true; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (clear) { 4378c2ecf20Sopenharmony_ci mt7603_wtbl_update(dev, msta->wcid.idx, 4388c2ecf20Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 4398c2ecf20Sopenharmony_ci memset(msta->tx_airtime_ac, 0, 4408c2ecf20Sopenharmony_ci sizeof(msta->tx_airtime_ac)); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (!msta->wcid.sta) 4448c2ecf20Sopenharmony_ci continue; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); 4478c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 4488c2ecf20Sopenharmony_ci struct mt76_queue *q = dev->mt76.q_tx[i]; 4498c2ecf20Sopenharmony_ci u8 qidx = q->hw_idx; 4508c2ecf20Sopenharmony_ci u8 tid = ac_to_tid[i]; 4518c2ecf20Sopenharmony_ci u32 txtime = airtime[qidx]; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (!txtime) 4548c2ecf20Sopenharmony_ci continue; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ieee80211_sta_register_airtime(sta, tid, txtime, 0); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rcu_read_unlock(); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (!total_airtime) 4638c2ecf20Sopenharmony_ci return; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci spin_lock_bh(&dev->mt76.cc_lock); 4668c2ecf20Sopenharmony_ci dev->mphy.chan_state->cc_tx += total_airtime; 4678c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->mt76.cc_lock); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic struct mt76_wcid * 4718c2ecf20Sopenharmony_cimt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct mt7603_sta *sta; 4748c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (idx >= MT7603_WTBL_SIZE) 4778c2ecf20Sopenharmony_ci return NULL; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 4808c2ecf20Sopenharmony_ci if (unicast || !wcid) 4818c2ecf20Sopenharmony_ci return wcid; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (!wcid->sta) 4848c2ecf20Sopenharmony_ci return NULL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci sta = container_of(wcid, struct mt7603_sta, wcid); 4878c2ecf20Sopenharmony_ci if (!sta->vif) 4888c2ecf20Sopenharmony_ci return NULL; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return &sta->vif->sta.wcid; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ciint 4948c2ecf20Sopenharmony_cimt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 4978c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 4988c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 4998c2ecf20Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 5008c2ecf20Sopenharmony_ci u32 rxd0 = le32_to_cpu(rxd[0]); 5018c2ecf20Sopenharmony_ci u32 rxd1 = le32_to_cpu(rxd[1]); 5028c2ecf20Sopenharmony_ci u32 rxd2 = le32_to_cpu(rxd[2]); 5038c2ecf20Sopenharmony_ci bool unicast = rxd1 & MT_RXD1_NORMAL_U2M; 5048c2ecf20Sopenharmony_ci bool insert_ccmp_hdr = false; 5058c2ecf20Sopenharmony_ci bool remove_pad; 5068c2ecf20Sopenharmony_ci int idx; 5078c2ecf20Sopenharmony_ci int i; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci memset(status, 0, sizeof(*status)); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci i = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1); 5128c2ecf20Sopenharmony_ci sband = (i & 1) ? &dev->mphy.sband_5g.sband : &dev->mphy.sband_2g.sband; 5138c2ecf20Sopenharmony_ci i >>= 1; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2); 5168c2ecf20Sopenharmony_ci status->wcid = mt7603_rx_get_wcid(dev, idx, unicast); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci status->band = sband->band; 5198c2ecf20Sopenharmony_ci if (i < sband->n_channels) 5208c2ecf20Sopenharmony_ci status->freq = sband->channels[i].center_freq; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_FCS_ERR) 5238c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_FAILED_FCS_CRC; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR) 5268c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_MMIC_ERROR; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && 5298c2ecf20Sopenharmony_ci !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) { 5308c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_DECRYPTED; 5318c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_IV_STRIPPED; 5328c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | 5368c2ecf20Sopenharmony_ci MT_RXD2_NORMAL_NON_AMPDU))) { 5378c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_AMPDU_DETAILS; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* all subframes of an A-MPDU have the same timestamp */ 5408c2ecf20Sopenharmony_ci if (dev->rx_ampdu_ts != rxd[12]) { 5418c2ecf20Sopenharmony_ci if (!++dev->ampdu_ref) 5428c2ecf20Sopenharmony_ci dev->ampdu_ref++; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci dev->rx_ampdu_ts = rxd[12]; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci status->ampdu_ref = dev->ampdu_ref; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) 5528c2ecf20Sopenharmony_ci return -EINVAL; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (!sband->channels) 5558c2ecf20Sopenharmony_ci return -EINVAL; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci rxd += 4; 5588c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_4) { 5598c2ecf20Sopenharmony_ci rxd += 4; 5608c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 5618c2ecf20Sopenharmony_ci return -EINVAL; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_1) { 5648c2ecf20Sopenharmony_ci u8 *data = (u8 *)rxd; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) { 5678c2ecf20Sopenharmony_ci status->iv[0] = data[5]; 5688c2ecf20Sopenharmony_ci status->iv[1] = data[4]; 5698c2ecf20Sopenharmony_ci status->iv[2] = data[3]; 5708c2ecf20Sopenharmony_ci status->iv[3] = data[2]; 5718c2ecf20Sopenharmony_ci status->iv[4] = data[1]; 5728c2ecf20Sopenharmony_ci status->iv[5] = data[0]; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci rxd += 4; 5788c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 5798c2ecf20Sopenharmony_ci return -EINVAL; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_2) { 5828c2ecf20Sopenharmony_ci rxd += 2; 5838c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 5848c2ecf20Sopenharmony_ci return -EINVAL; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_3) { 5878c2ecf20Sopenharmony_ci u32 rxdg0 = le32_to_cpu(rxd[0]); 5888c2ecf20Sopenharmony_ci u32 rxdg3 = le32_to_cpu(rxd[3]); 5898c2ecf20Sopenharmony_ci bool cck = false; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0); 5928c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) { 5938c2ecf20Sopenharmony_ci case MT_PHY_TYPE_CCK: 5948c2ecf20Sopenharmony_ci cck = true; 5958c2ecf20Sopenharmony_ci fallthrough; 5968c2ecf20Sopenharmony_ci case MT_PHY_TYPE_OFDM: 5978c2ecf20Sopenharmony_ci i = mt76_get_rate(&dev->mt76, sband, i, cck); 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 6008c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT: 6018c2ecf20Sopenharmony_ci status->encoding = RX_ENC_HT; 6028c2ecf20Sopenharmony_ci if (i > 15) 6038c2ecf20Sopenharmony_ci return -EINVAL; 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci default: 6068c2ecf20Sopenharmony_ci return -EINVAL; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (rxdg0 & MT_RXV1_HT_SHORT_GI) 6108c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 6118c2ecf20Sopenharmony_ci if (rxdg0 & MT_RXV1_HT_AD_CODE) 6128c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_LDPC; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_STBC_MASK * 6158c2ecf20Sopenharmony_ci FIELD_GET(MT_RXV1_HT_STBC, rxdg0); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci status->rate_idx = i; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci status->chains = dev->mphy.antenna_mask; 6208c2ecf20Sopenharmony_ci status->chain_signal[0] = FIELD_GET(MT_RXV4_IB_RSSI0, rxdg3) + 6218c2ecf20Sopenharmony_ci dev->rssi_offset[0]; 6228c2ecf20Sopenharmony_ci status->chain_signal[1] = FIELD_GET(MT_RXV4_IB_RSSI1, rxdg3) + 6238c2ecf20Sopenharmony_ci dev->rssi_offset[1]; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci status->signal = status->chain_signal[0]; 6268c2ecf20Sopenharmony_ci if (status->chains & BIT(1)) 6278c2ecf20Sopenharmony_ci status->signal = max(status->signal, 6288c2ecf20Sopenharmony_ci status->chain_signal[1]); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0) == 1) 6318c2ecf20Sopenharmony_ci status->bw = RATE_INFO_BW_40; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci rxd += 6; 6348c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 6358c2ecf20Sopenharmony_ci return -EINVAL; 6368c2ecf20Sopenharmony_ci } else { 6378c2ecf20Sopenharmony_ci return -EINVAL; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (insert_ccmp_hdr) { 6438c2ecf20Sopenharmony_ci u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci mt76_insert_ccmp_hdr(skb, key_id); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 6498c2ecf20Sopenharmony_ci if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci status->aggr = unicast && 6538c2ecf20Sopenharmony_ci !ieee80211_is_qos_nullfunc(hdr->frame_control); 6548c2ecf20Sopenharmony_ci status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 6558c2ecf20Sopenharmony_ci status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic u16 6618c2ecf20Sopenharmony_cimt7603_mac_tx_rate_val(struct mt7603_dev *dev, 6628c2ecf20Sopenharmony_ci const struct ieee80211_tx_rate *rate, bool stbc, u8 *bw) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci u8 phy, nss, rate_idx; 6658c2ecf20Sopenharmony_ci u16 rateval; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci *bw = 0; 6688c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_MCS) { 6698c2ecf20Sopenharmony_ci rate_idx = rate->idx; 6708c2ecf20Sopenharmony_ci nss = 1 + (rate->idx >> 3); 6718c2ecf20Sopenharmony_ci phy = MT_PHY_TYPE_HT; 6728c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) 6738c2ecf20Sopenharmony_ci phy = MT_PHY_TYPE_HT_GF; 6748c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 6758c2ecf20Sopenharmony_ci *bw = 1; 6768c2ecf20Sopenharmony_ci } else { 6778c2ecf20Sopenharmony_ci const struct ieee80211_rate *r; 6788c2ecf20Sopenharmony_ci int band = dev->mphy.chandef.chan->band; 6798c2ecf20Sopenharmony_ci u16 val; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci nss = 1; 6828c2ecf20Sopenharmony_ci r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx]; 6838c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 6848c2ecf20Sopenharmony_ci val = r->hw_value_short; 6858c2ecf20Sopenharmony_ci else 6868c2ecf20Sopenharmony_ci val = r->hw_value; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci phy = val >> 8; 6898c2ecf20Sopenharmony_ci rate_idx = val & 0xff; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | 6938c2ecf20Sopenharmony_ci FIELD_PREP(MT_TX_RATE_MODE, phy)); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (stbc && nss == 1) 6968c2ecf20Sopenharmony_ci rateval |= MT_TX_RATE_STBC; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return rateval; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_civoid mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, 7028c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *probe_rate, 7038c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *ref; 7068c2ecf20Sopenharmony_ci int wcid = sta->wcid.idx; 7078c2ecf20Sopenharmony_ci u32 addr = mt7603_wtbl2_addr(wcid); 7088c2ecf20Sopenharmony_ci bool stbc = false; 7098c2ecf20Sopenharmony_ci int n_rates = sta->n_rates; 7108c2ecf20Sopenharmony_ci u8 bw, bw_prev, bw_idx = 0; 7118c2ecf20Sopenharmony_ci u16 val[4]; 7128c2ecf20Sopenharmony_ci u16 probe_val; 7138c2ecf20Sopenharmony_ci u32 w9 = mt76_rr(dev, addr + 9 * 4); 7148c2ecf20Sopenharmony_ci bool rateset; 7158c2ecf20Sopenharmony_ci int i, k; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) 7188c2ecf20Sopenharmony_ci return; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci for (i = n_rates; i < 4; i++) 7218c2ecf20Sopenharmony_ci rates[i] = rates[n_rates - 1]; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci rateset = !(sta->rate_set_tsf & BIT(0)); 7248c2ecf20Sopenharmony_ci memcpy(sta->rateset[rateset].rates, rates, 7258c2ecf20Sopenharmony_ci sizeof(sta->rateset[rateset].rates)); 7268c2ecf20Sopenharmony_ci if (probe_rate) { 7278c2ecf20Sopenharmony_ci sta->rateset[rateset].probe_rate = *probe_rate; 7288c2ecf20Sopenharmony_ci ref = &sta->rateset[rateset].probe_rate; 7298c2ecf20Sopenharmony_ci } else { 7308c2ecf20Sopenharmony_ci sta->rateset[rateset].probe_rate.idx = -1; 7318c2ecf20Sopenharmony_ci ref = &sta->rateset[rateset].rates[0]; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci rates = sta->rateset[rateset].rates; 7358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) { 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * We don't support switching between short and long GI 7388c2ecf20Sopenharmony_ci * within the rate set. For accurate tx status reporting, we 7398c2ecf20Sopenharmony_ci * need to make sure that flags match. 7408c2ecf20Sopenharmony_ci * For improved performance, avoid duplicate entries by 7418c2ecf20Sopenharmony_ci * decrementing the MCS index if necessary 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_ci if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI) 7448c2ecf20Sopenharmony_ci rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci for (k = 0; k < i; k++) { 7478c2ecf20Sopenharmony_ci if (rates[i].idx != rates[k].idx) 7488c2ecf20Sopenharmony_ci continue; 7498c2ecf20Sopenharmony_ci if ((rates[i].flags ^ rates[k].flags) & 7508c2ecf20Sopenharmony_ci IEEE80211_TX_RC_40_MHZ_WIDTH) 7518c2ecf20Sopenharmony_ci continue; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (!rates[i].idx) 7548c2ecf20Sopenharmony_ci continue; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci rates[i].idx--; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci w9 &= MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 | 7618c2ecf20Sopenharmony_ci MT_WTBL2_W9_SHORT_GI_80; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci val[0] = mt7603_mac_tx_rate_val(dev, &rates[0], stbc, &bw); 7648c2ecf20Sopenharmony_ci bw_prev = bw; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (probe_rate) { 7678c2ecf20Sopenharmony_ci probe_val = mt7603_mac_tx_rate_val(dev, probe_rate, stbc, &bw); 7688c2ecf20Sopenharmony_ci if (bw) 7698c2ecf20Sopenharmony_ci bw_idx = 1; 7708c2ecf20Sopenharmony_ci else 7718c2ecf20Sopenharmony_ci bw_prev = 0; 7728c2ecf20Sopenharmony_ci } else { 7738c2ecf20Sopenharmony_ci probe_val = val[0]; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci w9 |= FIELD_PREP(MT_WTBL2_W9_CC_BW_SEL, bw); 7778c2ecf20Sopenharmony_ci w9 |= FIELD_PREP(MT_WTBL2_W9_BW_CAP, bw); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci val[1] = mt7603_mac_tx_rate_val(dev, &rates[1], stbc, &bw); 7808c2ecf20Sopenharmony_ci if (bw_prev) { 7818c2ecf20Sopenharmony_ci bw_idx = 3; 7828c2ecf20Sopenharmony_ci bw_prev = bw; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci val[2] = mt7603_mac_tx_rate_val(dev, &rates[2], stbc, &bw); 7868c2ecf20Sopenharmony_ci if (bw_prev) { 7878c2ecf20Sopenharmony_ci bw_idx = 5; 7888c2ecf20Sopenharmony_ci bw_prev = bw; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci val[3] = mt7603_mac_tx_rate_val(dev, &rates[3], stbc, &bw); 7928c2ecf20Sopenharmony_ci if (bw_prev) 7938c2ecf20Sopenharmony_ci bw_idx = 7; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci w9 |= FIELD_PREP(MT_WTBL2_W9_CHANGE_BW_RATE, 7968c2ecf20Sopenharmony_ci bw_idx ? bw_idx - 1 : 7); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR0, w9); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR1, 8018c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) | 8028c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) | 8038c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1])); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR2, 8068c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) | 8078c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) | 8088c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) | 8098c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2])); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR3, 8128c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) | 8138c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) | 8148c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3])); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ 8178c2ecf20Sopenharmony_ci sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_UPDATE, 8208c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | 8218c2ecf20Sopenharmony_ci MT_WTBL_UPDATE_RATE_UPDATE | 8228c2ecf20Sopenharmony_ci MT_WTBL_UPDATE_TX_COUNT_CLEAR); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) 8258c2ecf20Sopenharmony_ci mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci sta->rate_count = 2 * MT7603_RATE_RETRY * n_rates; 8288c2ecf20Sopenharmony_ci sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic enum mt7603_cipher_type 8328c2ecf20Sopenharmony_cimt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci memset(key_data, 0, 32); 8358c2ecf20Sopenharmony_ci if (!key) 8368c2ecf20Sopenharmony_ci return MT_CIPHER_NONE; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (key->keylen > 32) 8398c2ecf20Sopenharmony_ci return MT_CIPHER_NONE; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci memcpy(key_data, key->key, key->keylen); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci switch (key->cipher) { 8448c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 8458c2ecf20Sopenharmony_ci return MT_CIPHER_WEP40; 8468c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 8478c2ecf20Sopenharmony_ci return MT_CIPHER_WEP104; 8488c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 8498c2ecf20Sopenharmony_ci /* Rx/Tx MIC keys are swapped */ 8508c2ecf20Sopenharmony_ci memcpy(key_data + 16, key->key + 24, 8); 8518c2ecf20Sopenharmony_ci memcpy(key_data + 24, key->key + 16, 8); 8528c2ecf20Sopenharmony_ci return MT_CIPHER_TKIP; 8538c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 8548c2ecf20Sopenharmony_ci return MT_CIPHER_AES_CCMP; 8558c2ecf20Sopenharmony_ci default: 8568c2ecf20Sopenharmony_ci return MT_CIPHER_NONE; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ciint mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, 8618c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci enum mt7603_cipher_type cipher; 8648c2ecf20Sopenharmony_ci u32 addr = mt7603_wtbl3_addr(wcid); 8658c2ecf20Sopenharmony_ci u8 key_data[32]; 8668c2ecf20Sopenharmony_ci int key_len = sizeof(key_data); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci cipher = mt7603_mac_get_key_info(key, key_data); 8698c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_NONE && key) 8708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (key && (cipher == MT_CIPHER_WEP40 || cipher == MT_CIPHER_WEP104)) { 8738c2ecf20Sopenharmony_ci addr += key->keyidx * 16; 8748c2ecf20Sopenharmony_ci key_len = 16; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci mt76_wr_copy(dev, addr, key_data, key_len); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci addr = mt7603_wtbl1_addr(wcid); 8808c2ecf20Sopenharmony_ci mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_KEY_TYPE, cipher); 8818c2ecf20Sopenharmony_ci if (key) 8828c2ecf20Sopenharmony_ci mt76_rmw_field(dev, addr, MT_WTBL1_W0_KEY_IDX, key->keyidx); 8838c2ecf20Sopenharmony_ci mt76_rmw_field(dev, addr, MT_WTBL1_W0_RX_KEY_VALID, !!key); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return 0; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int 8898c2ecf20Sopenharmony_cimt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi, 8908c2ecf20Sopenharmony_ci struct sk_buff *skb, enum mt76_txq_id qid, 8918c2ecf20Sopenharmony_ci struct mt76_wcid *wcid, struct ieee80211_sta *sta, 8928c2ecf20Sopenharmony_ci int pid, struct ieee80211_key_conf *key) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 8958c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rate = &info->control.rates[0]; 8968c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 8978c2ecf20Sopenharmony_ci struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; 8988c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 8998c2ecf20Sopenharmony_ci struct mt76_queue *q = dev->mt76.q_tx[qid]; 9008c2ecf20Sopenharmony_ci struct mt7603_vif *mvif; 9018c2ecf20Sopenharmony_ci int wlan_idx; 9028c2ecf20Sopenharmony_ci int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 9038c2ecf20Sopenharmony_ci int tx_count = 8; 9048c2ecf20Sopenharmony_ci u8 frame_type, frame_subtype; 9058c2ecf20Sopenharmony_ci u16 fc = le16_to_cpu(hdr->frame_control); 9068c2ecf20Sopenharmony_ci u16 seqno = 0; 9078c2ecf20Sopenharmony_ci u8 vif_idx = 0; 9088c2ecf20Sopenharmony_ci u32 val; 9098c2ecf20Sopenharmony_ci u8 bw; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (vif) { 9128c2ecf20Sopenharmony_ci mvif = (struct mt7603_vif *)vif->drv_priv; 9138c2ecf20Sopenharmony_ci vif_idx = mvif->idx; 9148c2ecf20Sopenharmony_ci if (vif_idx && qid >= MT_TXQ_BEACON) 9158c2ecf20Sopenharmony_ci vif_idx += 0x10; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (sta) { 9198c2ecf20Sopenharmony_ci struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci tx_count = msta->rate_count; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (wcid) 9258c2ecf20Sopenharmony_ci wlan_idx = wcid->idx; 9268c2ecf20Sopenharmony_ci else 9278c2ecf20Sopenharmony_ci wlan_idx = MT7603_WTBL_RESERVED; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci frame_type = (fc & IEEE80211_FCTL_FTYPE) >> 2; 9308c2ecf20Sopenharmony_ci frame_subtype = (fc & IEEE80211_FCTL_STYPE) >> 4; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | 9338c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD0_Q_IDX, q->hw_idx); 9348c2ecf20Sopenharmony_ci txwi[0] = cpu_to_le32(val); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci val = MT_TXD1_LONG_FORMAT | 9378c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_OWN_MAC, vif_idx) | 9388c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_TID, 9398c2ecf20Sopenharmony_ci skb->priority & IEEE80211_QOS_CTL_TID_MASK) | 9408c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | 9418c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_INFO, hdr_len / 2) | 9428c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_WLAN_IDX, wlan_idx) | 9438c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_PROTECTED, !!key); 9448c2ecf20Sopenharmony_ci txwi[1] = cpu_to_le32(val); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_ACK) 9478c2ecf20Sopenharmony_ci txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD2_FRAME_TYPE, frame_type) | 9508c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD2_SUB_TYPE, frame_subtype) | 9518c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD2_MULTICAST, 9528c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)); 9538c2ecf20Sopenharmony_ci txwi[2] = cpu_to_le32(val); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) 9568c2ecf20Sopenharmony_ci txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci txwi[4] = 0; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci val = MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT | 9618c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD5_PID, pid); 9628c2ecf20Sopenharmony_ci txwi[5] = cpu_to_le32(val); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci txwi[6] = 0; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (rate->idx >= 0 && rate->count && 9678c2ecf20Sopenharmony_ci !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) { 9688c2ecf20Sopenharmony_ci bool stbc = info->flags & IEEE80211_TX_CTL_STBC; 9698c2ecf20Sopenharmony_ci u16 rateval = mt7603_mac_tx_rate_val(dev, rate, stbc, &bw); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci val = MT_TXD6_FIXED_BW | 9748c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD6_BW, bw) | 9758c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD6_TX_RATE, rateval); 9768c2ecf20Sopenharmony_ci txwi[6] |= cpu_to_le32(val); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_SHORT_GI) 9798c2ecf20Sopenharmony_ci txwi[6] |= cpu_to_le32(MT_TXD6_SGI); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (!(rate->flags & IEEE80211_TX_RC_MCS)) 9828c2ecf20Sopenharmony_ci txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci tx_count = rate->count; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* use maximum tx count for beacons and buffered multicast */ 9888c2ecf20Sopenharmony_ci if (qid >= MT_TXQ_BEACON) 9898c2ecf20Sopenharmony_ci tx_count = 0x1f; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count) | 9928c2ecf20Sopenharmony_ci MT_TXD3_SN_VALID; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 9958c2ecf20Sopenharmony_ci seqno = le16_to_cpu(hdr->seq_ctrl); 9968c2ecf20Sopenharmony_ci else if (ieee80211_is_back_req(hdr->frame_control)) 9978c2ecf20Sopenharmony_ci seqno = le16_to_cpu(bar->start_seq_num); 9988c2ecf20Sopenharmony_ci else 9998c2ecf20Sopenharmony_ci val &= ~MT_TXD3_SN_VALID; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci val |= FIELD_PREP(MT_TXD3_SEQ, seqno >> 4); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci txwi[3] = cpu_to_le32(val); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if (key) { 10068c2ecf20Sopenharmony_ci u64 pn = atomic64_inc_return(&key->tx_pn); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci txwi[3] |= cpu_to_le32(MT_TXD3_PN_VALID); 10098c2ecf20Sopenharmony_ci txwi[4] = cpu_to_le32(pn & GENMASK(31, 0)); 10108c2ecf20Sopenharmony_ci txwi[5] |= cpu_to_le32(FIELD_PREP(MT_TXD5_PN_HIGH, pn >> 32)); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci txwi[7] = 0; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ciint mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, 10198c2ecf20Sopenharmony_ci enum mt76_txq_id qid, struct mt76_wcid *wcid, 10208c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 10218c2ecf20Sopenharmony_ci struct mt76_tx_info *tx_info) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 10248c2ecf20Sopenharmony_ci struct mt7603_sta *msta = container_of(wcid, struct mt7603_sta, wcid); 10258c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); 10268c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key = info->control.hw_key; 10278c2ecf20Sopenharmony_ci int pid; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (!wcid) 10308c2ecf20Sopenharmony_ci wcid = &dev->global_sta.wcid; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (sta) { 10338c2ecf20Sopenharmony_ci msta = (struct mt7603_sta *)sta->drv_priv; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if ((info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER | 10368c2ecf20Sopenharmony_ci IEEE80211_TX_CTL_CLEAR_PS_FILT)) || 10378c2ecf20Sopenharmony_ci (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) 10388c2ecf20Sopenharmony_ci mt7603_wtbl_set_ps(dev, msta, false); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci mt76_tx_check_agg_ssn(sta, tx_info->skb); 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { 10468c2ecf20Sopenharmony_ci spin_lock_bh(&dev->mt76.lock); 10478c2ecf20Sopenharmony_ci mt7603_wtbl_set_rates(dev, msta, &info->control.rates[0], 10488c2ecf20Sopenharmony_ci msta->rates); 10498c2ecf20Sopenharmony_ci msta->rate_probe = true; 10508c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->mt76.lock); 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci mt7603_mac_write_txwi(dev, txwi_ptr, tx_info->skb, qid, wcid, 10548c2ecf20Sopenharmony_ci sta, pid, key); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci return 0; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic bool 10608c2ecf20Sopenharmony_cimt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, 10618c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info, __le32 *txs_data) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 10648c2ecf20Sopenharmony_ci struct mt7603_rate_set *rs; 10658c2ecf20Sopenharmony_ci int first_idx = 0, last_idx; 10668c2ecf20Sopenharmony_ci u32 rate_set_tsf; 10678c2ecf20Sopenharmony_ci u32 final_rate; 10688c2ecf20Sopenharmony_ci u32 final_rate_flags; 10698c2ecf20Sopenharmony_ci bool rs_idx; 10708c2ecf20Sopenharmony_ci bool ack_timeout; 10718c2ecf20Sopenharmony_ci bool fixed_rate; 10728c2ecf20Sopenharmony_ci bool probe; 10738c2ecf20Sopenharmony_ci bool ampdu; 10748c2ecf20Sopenharmony_ci bool cck = false; 10758c2ecf20Sopenharmony_ci int count; 10768c2ecf20Sopenharmony_ci u32 txs; 10778c2ecf20Sopenharmony_ci int idx; 10788c2ecf20Sopenharmony_ci int i; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci fixed_rate = info->status.rates[0].count; 10818c2ecf20Sopenharmony_ci probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[4]); 10848c2ecf20Sopenharmony_ci ampdu = !fixed_rate && (txs & MT_TXS4_AMPDU); 10858c2ecf20Sopenharmony_ci count = FIELD_GET(MT_TXS4_TX_COUNT, txs); 10868c2ecf20Sopenharmony_ci last_idx = FIELD_GET(MT_TXS4_LAST_TX_RATE, txs); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[0]); 10898c2ecf20Sopenharmony_ci final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs); 10908c2ecf20Sopenharmony_ci ack_timeout = txs & MT_TXS0_ACK_TIMEOUT; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT)) 10938c2ecf20Sopenharmony_ci return false; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (txs & MT_TXS0_QUEUE_TIMEOUT) 10968c2ecf20Sopenharmony_ci return false; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (!ack_timeout) 10998c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci info->status.ampdu_len = 1; 11028c2ecf20Sopenharmony_ci info->status.ampdu_ack_len = !!(info->flags & 11038c2ecf20Sopenharmony_ci IEEE80211_TX_STAT_ACK); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) 11068c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci first_idx = max_t(int, 0, last_idx - (count - 1) / MT7603_RATE_RETRY); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (fixed_rate && !probe) { 11118c2ecf20Sopenharmony_ci info->status.rates[0].count = count; 11128c2ecf20Sopenharmony_ci i = 0; 11138c2ecf20Sopenharmony_ci goto out; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci rate_set_tsf = READ_ONCE(sta->rate_set_tsf); 11178c2ecf20Sopenharmony_ci rs_idx = !((u32)(FIELD_GET(MT_TXS1_F0_TIMESTAMP, le32_to_cpu(txs_data[1])) - 11188c2ecf20Sopenharmony_ci rate_set_tsf) < 1000000); 11198c2ecf20Sopenharmony_ci rs_idx ^= rate_set_tsf & BIT(0); 11208c2ecf20Sopenharmony_ci rs = &sta->rateset[rs_idx]; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (!first_idx && rs->probe_rate.idx >= 0) { 11238c2ecf20Sopenharmony_ci info->status.rates[0] = rs->probe_rate; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci spin_lock_bh(&dev->mt76.lock); 11268c2ecf20Sopenharmony_ci if (sta->rate_probe) { 11278c2ecf20Sopenharmony_ci mt7603_wtbl_set_rates(dev, sta, NULL, 11288c2ecf20Sopenharmony_ci sta->rates); 11298c2ecf20Sopenharmony_ci sta->rate_probe = false; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->mt76.lock); 11328c2ecf20Sopenharmony_ci } else { 11338c2ecf20Sopenharmony_ci info->status.rates[0] = rs->rates[first_idx / 2]; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci info->status.rates[0].count = 0; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) { 11388c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *cur_rate; 11398c2ecf20Sopenharmony_ci int cur_count; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci cur_rate = &rs->rates[idx / 2]; 11428c2ecf20Sopenharmony_ci cur_count = min_t(int, MT7603_RATE_RETRY, count); 11438c2ecf20Sopenharmony_ci count -= cur_count; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (idx && (cur_rate->idx != info->status.rates[i].idx || 11468c2ecf20Sopenharmony_ci cur_rate->flags != info->status.rates[i].flags)) { 11478c2ecf20Sopenharmony_ci i++; 11488c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(info->status.rates)) { 11498c2ecf20Sopenharmony_ci i--; 11508c2ecf20Sopenharmony_ci break; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci info->status.rates[i] = *cur_rate; 11548c2ecf20Sopenharmony_ci info->status.rates[i].count = 0; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci info->status.rates[i].count += cur_count; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ciout: 11618c2ecf20Sopenharmony_ci final_rate_flags = info->status.rates[i].flags; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) { 11648c2ecf20Sopenharmony_ci case MT_PHY_TYPE_CCK: 11658c2ecf20Sopenharmony_ci cck = true; 11668c2ecf20Sopenharmony_ci fallthrough; 11678c2ecf20Sopenharmony_ci case MT_PHY_TYPE_OFDM: 11688c2ecf20Sopenharmony_ci if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ) 11698c2ecf20Sopenharmony_ci sband = &dev->mphy.sband_5g.sband; 11708c2ecf20Sopenharmony_ci else 11718c2ecf20Sopenharmony_ci sband = &dev->mphy.sband_2g.sband; 11728c2ecf20Sopenharmony_ci final_rate &= GENMASK(5, 0); 11738c2ecf20Sopenharmony_ci final_rate = mt76_get_rate(&dev->mt76, sband, final_rate, 11748c2ecf20Sopenharmony_ci cck); 11758c2ecf20Sopenharmony_ci final_rate_flags = 0; 11768c2ecf20Sopenharmony_ci break; 11778c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 11788c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT: 11798c2ecf20Sopenharmony_ci final_rate_flags |= IEEE80211_TX_RC_MCS; 11808c2ecf20Sopenharmony_ci final_rate &= GENMASK(5, 0); 11818c2ecf20Sopenharmony_ci if (final_rate > 15) 11828c2ecf20Sopenharmony_ci return false; 11838c2ecf20Sopenharmony_ci break; 11848c2ecf20Sopenharmony_ci default: 11858c2ecf20Sopenharmony_ci return false; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci info->status.rates[i].idx = final_rate; 11898c2ecf20Sopenharmony_ci info->status.rates[i].flags = final_rate_flags; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci return true; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic bool 11958c2ecf20Sopenharmony_cimt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid, 11968c2ecf20Sopenharmony_ci __le32 *txs_data) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 11998c2ecf20Sopenharmony_ci struct sk_buff_head list; 12008c2ecf20Sopenharmony_ci struct sk_buff *skb; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (pid < MT_PACKET_ID_FIRST) 12038c2ecf20Sopenharmony_ci return false; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci trace_mac_txdone(mdev, sta->wcid.idx, pid); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci mt76_tx_status_lock(mdev, &list); 12088c2ecf20Sopenharmony_ci skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list); 12098c2ecf20Sopenharmony_ci if (skb) { 12108c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci if (!mt7603_fill_txs(dev, sta, info, txs_data)) { 12138c2ecf20Sopenharmony_ci ieee80211_tx_info_clear_status(info); 12148c2ecf20Sopenharmony_ci info->status.rates[0].idx = -1; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci mt76_tx_status_skb_done(mdev, skb, &list); 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci mt76_tx_status_unlock(mdev, &list); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci return !!skb; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_civoid mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci struct ieee80211_tx_info info = {}; 12278c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = NULL; 12288c2ecf20Sopenharmony_ci struct mt7603_sta *msta = NULL; 12298c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 12308c2ecf20Sopenharmony_ci __le32 *txs_data = data; 12318c2ecf20Sopenharmony_ci u32 txs; 12328c2ecf20Sopenharmony_ci u8 wcidx; 12338c2ecf20Sopenharmony_ci u8 pid; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[4]); 12368c2ecf20Sopenharmony_ci pid = FIELD_GET(MT_TXS4_PID, txs); 12378c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[3]); 12388c2ecf20Sopenharmony_ci wcidx = FIELD_GET(MT_TXS3_WCID, txs); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (pid == MT_PACKET_ID_NO_ACK) 12418c2ecf20Sopenharmony_ci return; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (wcidx >= MT7603_WTBL_SIZE) 12448c2ecf20Sopenharmony_ci return; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci rcu_read_lock(); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[wcidx]); 12498c2ecf20Sopenharmony_ci if (!wcid) 12508c2ecf20Sopenharmony_ci goto out; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci msta = container_of(wcid, struct mt7603_sta, wcid); 12538c2ecf20Sopenharmony_ci sta = wcid_to_sta(wcid); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (list_empty(&msta->poll_list)) { 12568c2ecf20Sopenharmony_ci spin_lock_bh(&dev->sta_poll_lock); 12578c2ecf20Sopenharmony_ci list_add_tail(&msta->poll_list, &dev->sta_poll_list); 12588c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->sta_poll_lock); 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) 12628c2ecf20Sopenharmony_ci goto out; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (wcidx >= MT7603_WTBL_STA || !sta) 12658c2ecf20Sopenharmony_ci goto out; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (mt7603_fill_txs(dev, msta, &info, txs_data)) 12688c2ecf20Sopenharmony_ci ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ciout: 12718c2ecf20Sopenharmony_ci rcu_read_unlock(); 12728c2ecf20Sopenharmony_ci} 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_civoid mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 12778c2ecf20Sopenharmony_ci struct sk_buff *skb = e->skb; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (!e->txwi) { 12808c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12818c2ecf20Sopenharmony_ci return; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci dev->tx_hang_check = 0; 12858c2ecf20Sopenharmony_ci mt76_tx_complete_skb(mdev, e->wcid, skb); 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic bool 12898c2ecf20Sopenharmony_ciwait_for_wpdma(struct mt7603_dev *dev) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci return mt76_poll(dev, MT_WPDMA_GLO_CFG, 12928c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 12938c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 12948c2ecf20Sopenharmony_ci 0, 1000); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic void mt7603_pse_reset(struct mt7603_dev *dev) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci /* Clear previous reset result */ 13008c2ecf20Sopenharmony_ci if (!dev->reset_cause[RESET_CAUSE_RESET_FAILED]) 13018c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE_S); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* Reset PSE */ 13048c2ecf20Sopenharmony_ci mt76_set(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_MCU_DEBUG_RESET, 13078c2ecf20Sopenharmony_ci MT_MCU_DEBUG_RESET_PSE_S, 13088c2ecf20Sopenharmony_ci MT_MCU_DEBUG_RESET_PSE_S, 500)) { 13098c2ecf20Sopenharmony_ci dev->reset_cause[RESET_CAUSE_RESET_FAILED]++; 13108c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE); 13118c2ecf20Sopenharmony_ci } else { 13128c2ecf20Sopenharmony_ci dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0; 13138c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_QUEUES); 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] >= 3) 13178c2ecf20Sopenharmony_ci dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0; 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_civoid mt7603_mac_dma_start(struct mt7603_dev *dev) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci mt7603_mac_start(dev); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci wait_for_wpdma(dev); 13258c2ecf20Sopenharmony_ci usleep_range(50, 100); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci mt76_set(dev, MT_WPDMA_GLO_CFG, 13288c2ecf20Sopenharmony_ci (MT_WPDMA_GLO_CFG_TX_DMA_EN | 13298c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_EN | 13308c2ecf20Sopenharmony_ci FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) | 13318c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE)); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci mt7603_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL); 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_civoid mt7603_mac_start(struct mt7603_dev *dev) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci mt76_clear(dev, MT_ARB_SCR, 13398c2ecf20Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 13408c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WF_ARB_TX_START_0, ~0); 13418c2ecf20Sopenharmony_ci mt76_set(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START); 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_civoid mt7603_mac_stop(struct mt7603_dev *dev) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci mt76_set(dev, MT_ARB_SCR, 13478c2ecf20Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 13488c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WF_ARB_TX_START_0, 0); 13498c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START); 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_civoid mt7603_pse_client_reset(struct mt7603_dev *dev) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci u32 addr; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR + 13578c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Clear previous reset state */ 13608c2ecf20Sopenharmony_ci mt76_clear(dev, addr, 13618c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_1 | 13628c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_2 | 13638c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_1_S | 13648c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_2_S); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci /* Start PSE client TX abort */ 13678c2ecf20Sopenharmony_ci mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_1); 13688c2ecf20Sopenharmony_ci mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_1_S, 13698c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_1_S, 500); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_2); 13728c2ecf20Sopenharmony_ci mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* Wait for PSE client to clear TX FIFO */ 13758c2ecf20Sopenharmony_ci mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_2_S, 13768c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_2_S, 500); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci /* Clear PSE client TX abort state */ 13798c2ecf20Sopenharmony_ci mt76_clear(dev, addr, 13808c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_1 | 13818c2ecf20Sopenharmony_ci MT_CLIENT_RESET_TX_R_E_2); 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic void mt7603_dma_sched_reset(struct mt7603_dev *dev) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci if (!is_mt7628(dev)) 13878c2ecf20Sopenharmony_ci return; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci mt76_set(dev, MT_SCH_4, MT_SCH_4_RESET); 13908c2ecf20Sopenharmony_ci mt76_clear(dev, MT_SCH_4, MT_SCH_4_RESET); 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_cistatic void mt7603_mac_watchdog_reset(struct mt7603_dev *dev) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci int beacon_int = dev->mt76.beacon_int; 13968c2ecf20Sopenharmony_ci u32 mask = dev->mt76.mmio.irqmask; 13978c2ecf20Sopenharmony_ci int i; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci ieee80211_stop_queues(dev->mt76.hw); 14008c2ecf20Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* lock/unlock all queues to ensure that no tx is pending */ 14038c2ecf20Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 14068c2ecf20Sopenharmony_ci tasklet_disable(&dev->mt76.pre_tbtt_tasklet); 14078c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.napi[0]); 14088c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.napi[1]); 14098c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.tx_napi); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci mt7603_beacon_set_timer(dev, -1, 0); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] || 14168c2ecf20Sopenharmony_ci dev->cur_reset_cause == RESET_CAUSE_RX_PSE_BUSY || 14178c2ecf20Sopenharmony_ci dev->cur_reset_cause == RESET_CAUSE_BEACON_STUCK || 14188c2ecf20Sopenharmony_ci dev->cur_reset_cause == RESET_CAUSE_TX_HANG) 14198c2ecf20Sopenharmony_ci mt7603_pse_reset(dev); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (dev->reset_cause[RESET_CAUSE_RESET_FAILED]) 14228c2ecf20Sopenharmony_ci goto skip_dma_reset; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci mt7603_mac_stop(dev); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, 14278c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN | 14288c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); 14298c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci mt7603_irq_disable(dev, mask); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FORCE_TX_EOF); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci mt7603_pse_client_reset(dev); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci for (i = 0; i < __MT_TXQ_MAX; i++) 14388c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, true); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) { 14418c2ecf20Sopenharmony_ci mt76_queue_rx_reset(dev, i); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci mt7603_dma_sched_reset(dev); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci mt7603_mac_dma_start(dev); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci mt7603_irq_enable(dev, mask); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ciskip_dma_reset: 14518c2ecf20Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 14528c2ecf20Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 14558c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 14568c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci tasklet_enable(&dev->mt76.pre_tbtt_tasklet); 14598c2ecf20Sopenharmony_ci mt7603_beacon_set_timer(dev, -1, beacon_int); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.napi[0]); 14628c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[0]); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.napi[1]); 14658c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[1]); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci ieee80211_wake_queues(dev->mt76.hw); 14688c2ecf20Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic u32 mt7603_dma_debug(struct mt7603_dev *dev, u8 index) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci u32 val; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WPDMA_DEBUG, 14768c2ecf20Sopenharmony_ci FIELD_PREP(MT_WPDMA_DEBUG_IDX, index) | 14778c2ecf20Sopenharmony_ci MT_WPDMA_DEBUG_SEL); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_WPDMA_DEBUG); 14808c2ecf20Sopenharmony_ci return FIELD_GET(MT_WPDMA_DEBUG_VALUE, val); 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_cistatic bool mt7603_rx_fifo_busy(struct mt7603_dev *dev) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci if (is_mt7628(dev)) 14868c2ecf20Sopenharmony_ci return mt7603_dma_debug(dev, 9) & BIT(9); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci return mt7603_dma_debug(dev, 2) & BIT(8); 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic bool mt7603_rx_dma_busy(struct mt7603_dev *dev) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_RX_DMA_BUSY)) 14948c2ecf20Sopenharmony_ci return false; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci return mt7603_rx_fifo_busy(dev); 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic bool mt7603_tx_dma_busy(struct mt7603_dev *dev) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci u32 val; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_TX_DMA_BUSY)) 15048c2ecf20Sopenharmony_ci return false; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci val = mt7603_dma_debug(dev, 9); 15078c2ecf20Sopenharmony_ci return (val & BIT(8)) && (val & 0xf) != 0xf; 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_cistatic bool mt7603_tx_hang(struct mt7603_dev *dev) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct mt76_queue *q; 15138c2ecf20Sopenharmony_ci u32 dma_idx, prev_dma_idx; 15148c2ecf20Sopenharmony_ci int i; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 15178c2ecf20Sopenharmony_ci q = dev->mt76.q_tx[i]; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (!q->queued) 15208c2ecf20Sopenharmony_ci continue; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci prev_dma_idx = dev->tx_dma_idx[i]; 15238c2ecf20Sopenharmony_ci dma_idx = readl(&q->regs->dma_idx); 15248c2ecf20Sopenharmony_ci dev->tx_dma_idx[i] = dma_idx; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (dma_idx == prev_dma_idx && 15278c2ecf20Sopenharmony_ci dma_idx != readl(&q->regs->cpu_idx)) 15288c2ecf20Sopenharmony_ci break; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci return i < 4; 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cistatic bool mt7603_rx_pse_busy(struct mt7603_dev *dev) 15358c2ecf20Sopenharmony_ci{ 15368c2ecf20Sopenharmony_ci u32 addr, val; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (mt7603_rx_fifo_busy(dev)) 15398c2ecf20Sopenharmony_ci goto out; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR + MT_CLIENT_STATUS); 15428c2ecf20Sopenharmony_ci mt76_wr(dev, addr, 3); 15438c2ecf20Sopenharmony_ci val = mt76_rr(dev, addr) >> 16; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci if (!(val & BIT(0))) 15468c2ecf20Sopenharmony_ci return false; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if (is_mt7628(dev)) 15498c2ecf20Sopenharmony_ci val &= 0xa000; 15508c2ecf20Sopenharmony_ci else 15518c2ecf20Sopenharmony_ci val &= 0x8000; 15528c2ecf20Sopenharmony_ci if (!val) 15538c2ecf20Sopenharmony_ci return false; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ciout: 15568c2ecf20Sopenharmony_ci if (mt76_rr(dev, MT_INT_SOURCE_CSR) & 15578c2ecf20Sopenharmony_ci (MT_INT_RX_DONE(0) | MT_INT_RX_DONE(1))) 15588c2ecf20Sopenharmony_ci return false; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci return true; 15618c2ecf20Sopenharmony_ci} 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_cistatic bool 15648c2ecf20Sopenharmony_cimt7603_watchdog_check(struct mt7603_dev *dev, u8 *counter, 15658c2ecf20Sopenharmony_ci enum mt7603_reset_cause cause, 15668c2ecf20Sopenharmony_ci bool (*check)(struct mt7603_dev *dev)) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci if (dev->reset_test == cause + 1) { 15698c2ecf20Sopenharmony_ci dev->reset_test = 0; 15708c2ecf20Sopenharmony_ci goto trigger; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (check) { 15748c2ecf20Sopenharmony_ci if (!check(dev) && *counter < MT7603_WATCHDOG_TIMEOUT) { 15758c2ecf20Sopenharmony_ci *counter = 0; 15768c2ecf20Sopenharmony_ci return false; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci (*counter)++; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (*counter < MT7603_WATCHDOG_TIMEOUT) 15838c2ecf20Sopenharmony_ci return false; 15848c2ecf20Sopenharmony_citrigger: 15858c2ecf20Sopenharmony_ci dev->cur_reset_cause = cause; 15868c2ecf20Sopenharmony_ci dev->reset_cause[cause]++; 15878c2ecf20Sopenharmony_ci return true; 15888c2ecf20Sopenharmony_ci} 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_civoid mt7603_update_channel(struct mt76_dev *mdev) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 15938c2ecf20Sopenharmony_ci struct mt76_channel_state *state; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci state = mdev->phy.chan_state; 15968c2ecf20Sopenharmony_ci state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA); 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_civoid 16008c2ecf20Sopenharmony_cimt7603_edcca_set_strict(struct mt7603_dev *dev, bool val) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci u32 rxtd_6 = 0xd7c80000; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (val == dev->ed_strict_mode) 16058c2ecf20Sopenharmony_ci return; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci dev->ed_strict_mode = val; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci /* Ensure that ED/CCA does not trigger if disabled */ 16108c2ecf20Sopenharmony_ci if (!dev->ed_monitor) 16118c2ecf20Sopenharmony_ci rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x34); 16128c2ecf20Sopenharmony_ci else 16138c2ecf20Sopenharmony_ci rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x7d); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (dev->ed_monitor && !dev->ed_strict_mode) 16168c2ecf20Sopenharmony_ci rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x0f); 16178c2ecf20Sopenharmony_ci else 16188c2ecf20Sopenharmony_ci rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x10); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci mt76_wr(dev, MT_RXTD(6), rxtd_6); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci mt76_rmw_field(dev, MT_RXTD(13), MT_RXTD_13_ACI_TH_EN, 16238c2ecf20Sopenharmony_ci dev->ed_monitor && !dev->ed_strict_mode); 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_cistatic void 16278c2ecf20Sopenharmony_cimt7603_edcca_check(struct mt7603_dev *dev) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci u32 val = mt76_rr(dev, MT_AGC(41)); 16308c2ecf20Sopenharmony_ci ktime_t cur_time; 16318c2ecf20Sopenharmony_ci int rssi0, rssi1; 16328c2ecf20Sopenharmony_ci u32 active; 16338c2ecf20Sopenharmony_ci u32 ed_busy; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (!dev->ed_monitor) 16368c2ecf20Sopenharmony_ci return; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci rssi0 = FIELD_GET(MT_AGC_41_RSSI_0, val); 16398c2ecf20Sopenharmony_ci if (rssi0 > 128) 16408c2ecf20Sopenharmony_ci rssi0 -= 256; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci rssi1 = FIELD_GET(MT_AGC_41_RSSI_1, val); 16438c2ecf20Sopenharmony_ci if (rssi1 > 128) 16448c2ecf20Sopenharmony_ci rssi1 -= 256; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (max(rssi0, rssi1) >= -40 && 16478c2ecf20Sopenharmony_ci dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH) 16488c2ecf20Sopenharmony_ci dev->ed_strong_signal++; 16498c2ecf20Sopenharmony_ci else if (dev->ed_strong_signal > 0) 16508c2ecf20Sopenharmony_ci dev->ed_strong_signal--; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci cur_time = ktime_get_boottime(); 16538c2ecf20Sopenharmony_ci ed_busy = mt76_rr(dev, MT_MIB_STAT_ED) & MT_MIB_STAT_ED_MASK; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci active = ktime_to_us(ktime_sub(cur_time, dev->ed_time)); 16568c2ecf20Sopenharmony_ci dev->ed_time = cur_time; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (!active) 16598c2ecf20Sopenharmony_ci return; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (100 * ed_busy / active > 90) { 16628c2ecf20Sopenharmony_ci if (dev->ed_trigger < 0) 16638c2ecf20Sopenharmony_ci dev->ed_trigger = 0; 16648c2ecf20Sopenharmony_ci dev->ed_trigger++; 16658c2ecf20Sopenharmony_ci } else { 16668c2ecf20Sopenharmony_ci if (dev->ed_trigger > 0) 16678c2ecf20Sopenharmony_ci dev->ed_trigger = 0; 16688c2ecf20Sopenharmony_ci dev->ed_trigger--; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH || 16728c2ecf20Sopenharmony_ci dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH / 2) { 16738c2ecf20Sopenharmony_ci mt7603_edcca_set_strict(dev, true); 16748c2ecf20Sopenharmony_ci } else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) { 16758c2ecf20Sopenharmony_ci mt7603_edcca_set_strict(dev, false); 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH) 16798c2ecf20Sopenharmony_ci dev->ed_trigger = MT7603_EDCCA_BLOCK_TH; 16808c2ecf20Sopenharmony_ci else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) 16818c2ecf20Sopenharmony_ci dev->ed_trigger = -MT7603_EDCCA_BLOCK_TH; 16828c2ecf20Sopenharmony_ci} 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_civoid mt7603_cca_stats_reset(struct mt7603_dev *dev) 16858c2ecf20Sopenharmony_ci{ 16868c2ecf20Sopenharmony_ci mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET); 16878c2ecf20Sopenharmony_ci mt76_clear(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET); 16888c2ecf20Sopenharmony_ci mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_EN); 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cistatic void 16928c2ecf20Sopenharmony_cimt7603_adjust_sensitivity(struct mt7603_dev *dev) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci u32 agc0 = dev->agc0, agc3 = dev->agc3; 16958c2ecf20Sopenharmony_ci u32 adj; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci if (!dev->sensitivity || dev->sensitivity < -100) { 16988c2ecf20Sopenharmony_ci dev->sensitivity = 0; 16998c2ecf20Sopenharmony_ci } else if (dev->sensitivity <= -84) { 17008c2ecf20Sopenharmony_ci adj = 7 + (dev->sensitivity + 92) / 2; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci agc0 = 0x56f0076f; 17038c2ecf20Sopenharmony_ci agc0 |= adj << 12; 17048c2ecf20Sopenharmony_ci agc0 |= adj << 16; 17058c2ecf20Sopenharmony_ci agc3 = 0x81d0d5e3; 17068c2ecf20Sopenharmony_ci } else if (dev->sensitivity <= -72) { 17078c2ecf20Sopenharmony_ci adj = 7 + (dev->sensitivity + 80) / 2; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci agc0 = 0x6af0006f; 17108c2ecf20Sopenharmony_ci agc0 |= adj << 8; 17118c2ecf20Sopenharmony_ci agc0 |= adj << 12; 17128c2ecf20Sopenharmony_ci agc0 |= adj << 16; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci agc3 = 0x8181d5e3; 17158c2ecf20Sopenharmony_ci } else { 17168c2ecf20Sopenharmony_ci if (dev->sensitivity > -54) 17178c2ecf20Sopenharmony_ci dev->sensitivity = -54; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci adj = 7 + (dev->sensitivity + 80) / 2; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci agc0 = 0x7ff0000f; 17228c2ecf20Sopenharmony_ci agc0 |= adj << 4; 17238c2ecf20Sopenharmony_ci agc0 |= adj << 8; 17248c2ecf20Sopenharmony_ci agc0 |= adj << 12; 17258c2ecf20Sopenharmony_ci agc0 |= adj << 16; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci agc3 = 0x818181e3; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci mt76_wr(dev, MT_AGC(0), agc0); 17318c2ecf20Sopenharmony_ci mt76_wr(dev, MT_AGC1(0), agc0); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci mt76_wr(dev, MT_AGC(3), agc3); 17348c2ecf20Sopenharmony_ci mt76_wr(dev, MT_AGC1(3), agc3); 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_cistatic void 17388c2ecf20Sopenharmony_cimt7603_false_cca_check(struct mt7603_dev *dev) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci int pd_cck, pd_ofdm, mdrdy_cck, mdrdy_ofdm; 17418c2ecf20Sopenharmony_ci int false_cca; 17428c2ecf20Sopenharmony_ci int min_signal; 17438c2ecf20Sopenharmony_ci u32 val; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (!dev->dynamic_sensitivity) 17468c2ecf20Sopenharmony_ci return; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_PHYCTRL_STAT_PD); 17498c2ecf20Sopenharmony_ci pd_cck = FIELD_GET(MT_PHYCTRL_STAT_PD_CCK, val); 17508c2ecf20Sopenharmony_ci pd_ofdm = FIELD_GET(MT_PHYCTRL_STAT_PD_OFDM, val); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_PHYCTRL_STAT_MDRDY); 17538c2ecf20Sopenharmony_ci mdrdy_cck = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_CCK, val); 17548c2ecf20Sopenharmony_ci mdrdy_ofdm = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_OFDM, val); 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci dev->false_cca_ofdm = pd_ofdm - mdrdy_ofdm; 17578c2ecf20Sopenharmony_ci dev->false_cca_cck = pd_cck - mdrdy_cck; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci mt7603_cca_stats_reset(dev); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci min_signal = mt76_get_min_avg_rssi(&dev->mt76, false); 17628c2ecf20Sopenharmony_ci if (!min_signal) { 17638c2ecf20Sopenharmony_ci dev->sensitivity = 0; 17648c2ecf20Sopenharmony_ci dev->last_cca_adj = jiffies; 17658c2ecf20Sopenharmony_ci goto out; 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci min_signal -= 15; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci false_cca = dev->false_cca_ofdm + dev->false_cca_cck; 17718c2ecf20Sopenharmony_ci if (false_cca > 600 && 17728c2ecf20Sopenharmony_ci dev->sensitivity < -100 + dev->sensitivity_limit) { 17738c2ecf20Sopenharmony_ci if (!dev->sensitivity) 17748c2ecf20Sopenharmony_ci dev->sensitivity = -92; 17758c2ecf20Sopenharmony_ci else 17768c2ecf20Sopenharmony_ci dev->sensitivity += 2; 17778c2ecf20Sopenharmony_ci dev->last_cca_adj = jiffies; 17788c2ecf20Sopenharmony_ci } else if (false_cca < 100 || 17798c2ecf20Sopenharmony_ci time_after(jiffies, dev->last_cca_adj + 10 * HZ)) { 17808c2ecf20Sopenharmony_ci dev->last_cca_adj = jiffies; 17818c2ecf20Sopenharmony_ci if (!dev->sensitivity) 17828c2ecf20Sopenharmony_ci goto out; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci dev->sensitivity -= 2; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (dev->sensitivity && dev->sensitivity > min_signal) { 17888c2ecf20Sopenharmony_ci dev->sensitivity = min_signal; 17898c2ecf20Sopenharmony_ci dev->last_cca_adj = jiffies; 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ciout: 17938c2ecf20Sopenharmony_ci mt7603_adjust_sensitivity(dev); 17948c2ecf20Sopenharmony_ci} 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_civoid mt7603_mac_work(struct work_struct *work) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci struct mt7603_dev *dev = container_of(work, struct mt7603_dev, 17998c2ecf20Sopenharmony_ci mt76.mac_work.work); 18008c2ecf20Sopenharmony_ci bool reset = false; 18018c2ecf20Sopenharmony_ci int i, idx; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci mt76_tx_status_check(&dev->mt76, NULL, false); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci dev->mac_work_count++; 18088c2ecf20Sopenharmony_ci mt76_update_survey(&dev->mt76); 18098c2ecf20Sopenharmony_ci mt7603_edcca_check(dev); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci for (i = 0, idx = 0; i < 2; i++) { 18128c2ecf20Sopenharmony_ci u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci dev->mt76.aggr_stats[idx++] += val & 0xffff; 18158c2ecf20Sopenharmony_ci dev->mt76.aggr_stats[idx++] += val >> 16; 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci if (dev->mac_work_count == 10) 18198c2ecf20Sopenharmony_ci mt7603_false_cca_check(dev); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci if (mt7603_watchdog_check(dev, &dev->rx_pse_check, 18228c2ecf20Sopenharmony_ci RESET_CAUSE_RX_PSE_BUSY, 18238c2ecf20Sopenharmony_ci mt7603_rx_pse_busy) || 18248c2ecf20Sopenharmony_ci mt7603_watchdog_check(dev, &dev->beacon_check, 18258c2ecf20Sopenharmony_ci RESET_CAUSE_BEACON_STUCK, 18268c2ecf20Sopenharmony_ci NULL) || 18278c2ecf20Sopenharmony_ci mt7603_watchdog_check(dev, &dev->tx_hang_check, 18288c2ecf20Sopenharmony_ci RESET_CAUSE_TX_HANG, 18298c2ecf20Sopenharmony_ci mt7603_tx_hang) || 18308c2ecf20Sopenharmony_ci mt7603_watchdog_check(dev, &dev->tx_dma_check, 18318c2ecf20Sopenharmony_ci RESET_CAUSE_TX_BUSY, 18328c2ecf20Sopenharmony_ci mt7603_tx_dma_busy) || 18338c2ecf20Sopenharmony_ci mt7603_watchdog_check(dev, &dev->rx_dma_check, 18348c2ecf20Sopenharmony_ci RESET_CAUSE_RX_BUSY, 18358c2ecf20Sopenharmony_ci mt7603_rx_dma_busy) || 18368c2ecf20Sopenharmony_ci mt7603_watchdog_check(dev, &dev->mcu_hang, 18378c2ecf20Sopenharmony_ci RESET_CAUSE_MCU_HANG, 18388c2ecf20Sopenharmony_ci NULL) || 18398c2ecf20Sopenharmony_ci dev->reset_cause[RESET_CAUSE_RESET_FAILED]) { 18408c2ecf20Sopenharmony_ci dev->beacon_check = 0; 18418c2ecf20Sopenharmony_ci dev->tx_dma_check = 0; 18428c2ecf20Sopenharmony_ci dev->tx_hang_check = 0; 18438c2ecf20Sopenharmony_ci dev->rx_dma_check = 0; 18448c2ecf20Sopenharmony_ci dev->rx_pse_check = 0; 18458c2ecf20Sopenharmony_ci dev->mcu_hang = 0; 18468c2ecf20Sopenharmony_ci dev->rx_dma_idx = ~0; 18478c2ecf20Sopenharmony_ci memset(dev->tx_dma_idx, 0xff, sizeof(dev->tx_dma_idx)); 18488c2ecf20Sopenharmony_ci reset = true; 18498c2ecf20Sopenharmony_ci dev->mac_work_count = 0; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (dev->mac_work_count >= 10) 18538c2ecf20Sopenharmony_ci dev->mac_work_count = 0; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci if (reset) 18588c2ecf20Sopenharmony_ci mt7603_mac_watchdog_reset(dev); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, 18618c2ecf20Sopenharmony_ci msecs_to_jiffies(MT7603_WATCHDOG_TIME)); 18628c2ecf20Sopenharmony_ci} 1863