18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* Copyright (C) 2019 MediaTek Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author: Ryder Lee <ryder.lee@mediatek.com> 58c2ecf20Sopenharmony_ci * Roy Luo <royluo@google.com> 68c2ecf20Sopenharmony_ci * Felix Fietkau <nbd@nbd.name> 78c2ecf20Sopenharmony_ci * Lorenzo Bianconi <lorenzo@kernel.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/timekeeping.h> 128c2ecf20Sopenharmony_ci#include "mt7615.h" 138c2ecf20Sopenharmony_ci#include "../trace.h" 148c2ecf20Sopenharmony_ci#include "../dma.h" 158c2ecf20Sopenharmony_ci#include "mt7615_trace.h" 168c2ecf20Sopenharmony_ci#include "mac.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic const struct mt7615_dfs_radar_spec etsi_radar_specs = { 218c2ecf20Sopenharmony_ci .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, 228c2ecf20Sopenharmony_ci .radar_pattern = { 238c2ecf20Sopenharmony_ci [5] = { 1, 0, 6, 32, 28, 0, 17, 990, 5010, 1, 1 }, 248c2ecf20Sopenharmony_ci [6] = { 1, 0, 9, 32, 28, 0, 27, 615, 5010, 1, 1 }, 258c2ecf20Sopenharmony_ci [7] = { 1, 0, 15, 32, 28, 0, 27, 240, 445, 1, 1 }, 268c2ecf20Sopenharmony_ci [8] = { 1, 0, 12, 32, 28, 0, 42, 240, 510, 1, 1 }, 278c2ecf20Sopenharmony_ci [9] = { 1, 1, 0, 0, 0, 0, 14, 2490, 3343, 0, 0, 12, 32, 28 }, 288c2ecf20Sopenharmony_ci [10] = { 1, 1, 0, 0, 0, 0, 14, 2490, 3343, 0, 0, 15, 32, 24 }, 298c2ecf20Sopenharmony_ci [11] = { 1, 1, 0, 0, 0, 0, 14, 823, 2510, 0, 0, 18, 32, 28 }, 308c2ecf20Sopenharmony_ci [12] = { 1, 1, 0, 0, 0, 0, 14, 823, 2510, 0, 0, 27, 32, 24 }, 318c2ecf20Sopenharmony_ci }, 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const struct mt7615_dfs_radar_spec fcc_radar_specs = { 358c2ecf20Sopenharmony_ci .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, 368c2ecf20Sopenharmony_ci .radar_pattern = { 378c2ecf20Sopenharmony_ci [0] = { 1, 0, 9, 32, 28, 0, 13, 508, 3076, 1, 1 }, 388c2ecf20Sopenharmony_ci [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, 398c2ecf20Sopenharmony_ci [2] = { 1, 0, 8, 32, 28, 0, 22, 190, 510, 1, 1 }, 408c2ecf20Sopenharmony_ci [3] = { 1, 0, 6, 32, 28, 0, 32, 190, 510, 1, 1 }, 418c2ecf20Sopenharmony_ci [4] = { 1, 0, 9, 255, 28, 0, 13, 323, 343, 1, 32 }, 428c2ecf20Sopenharmony_ci }, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic const struct mt7615_dfs_radar_spec jp_radar_specs = { 468c2ecf20Sopenharmony_ci .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, 478c2ecf20Sopenharmony_ci .radar_pattern = { 488c2ecf20Sopenharmony_ci [0] = { 1, 0, 8, 32, 28, 0, 13, 508, 3076, 1, 1 }, 498c2ecf20Sopenharmony_ci [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, 508c2ecf20Sopenharmony_ci [2] = { 1, 0, 8, 32, 28, 0, 22, 190, 510, 1, 1 }, 518c2ecf20Sopenharmony_ci [3] = { 1, 0, 6, 32, 28, 0, 32, 190, 510, 1, 1 }, 528c2ecf20Sopenharmony_ci [4] = { 1, 0, 9, 32, 28, 0, 13, 323, 343, 1, 32 }, 538c2ecf20Sopenharmony_ci [13] = { 1, 0, 8, 32, 28, 0, 14, 3836, 3856, 1, 1 }, 548c2ecf20Sopenharmony_ci [14] = { 1, 0, 8, 32, 28, 0, 14, 3990, 4010, 1, 1 }, 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev, 598c2ecf20Sopenharmony_ci u8 idx, bool unicast) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct mt7615_sta *sta; 628c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (idx >= MT7615_WTBL_SIZE) 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 688c2ecf20Sopenharmony_ci if (unicast || !wcid) 698c2ecf20Sopenharmony_ci return wcid; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (!wcid->sta) 728c2ecf20Sopenharmony_ci return NULL; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci sta = container_of(wcid, struct mt7615_sta, wcid); 758c2ecf20Sopenharmony_ci if (!sta->vif) 768c2ecf20Sopenharmony_ci return NULL; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return &sta->vif->sta.wcid; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_civoid mt7615_mac_reset_counters(struct mt7615_dev *dev) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci int i; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 868c2ecf20Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT(0, i)); 878c2ecf20Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT(1, i)); 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); 918c2ecf20Sopenharmony_ci dev->mt76.phy.survey_time = ktime_get_boottime(); 928c2ecf20Sopenharmony_ci if (dev->mt76.phy2) 938c2ecf20Sopenharmony_ci dev->mt76.phy2->survey_time = ktime_get_boottime(); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* reset airtime counters */ 968c2ecf20Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR9(0)); 978c2ecf20Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR9(1)); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR36(0)); 1008c2ecf20Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR36(1)); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR37(0)); 1038c2ecf20Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR37(1)); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); 1068c2ecf20Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_civoid mt7615_mac_set_timing(struct mt7615_phy *phy) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci s16 coverage_class = phy->coverage_class; 1128c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 1138c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 1148c2ecf20Sopenharmony_ci u32 val, reg_offset; 1158c2ecf20Sopenharmony_ci u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | 1168c2ecf20Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); 1178c2ecf20Sopenharmony_ci u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | 1188c2ecf20Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); 1198c2ecf20Sopenharmony_ci int sifs, offset; 1208c2ecf20Sopenharmony_ci bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 1238c2ecf20Sopenharmony_ci return; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (is_5ghz) 1268c2ecf20Sopenharmony_ci sifs = 16; 1278c2ecf20Sopenharmony_ci else 1288c2ecf20Sopenharmony_ci sifs = 10; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (ext_phy) { 1318c2ecf20Sopenharmony_ci coverage_class = max_t(s16, dev->phy.coverage_class, 1328c2ecf20Sopenharmony_ci coverage_class); 1338c2ecf20Sopenharmony_ci mt76_set(dev, MT_ARB_SCR, 1348c2ecf20Sopenharmony_ci MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE); 1358c2ecf20Sopenharmony_ci } else { 1368c2ecf20Sopenharmony_ci struct mt7615_phy *phy_ext = mt7615_ext_phy(dev); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (phy_ext) 1398c2ecf20Sopenharmony_ci coverage_class = max_t(s16, phy_ext->coverage_class, 1408c2ecf20Sopenharmony_ci coverage_class); 1418c2ecf20Sopenharmony_ci mt76_set(dev, MT_ARB_SCR, 1428c2ecf20Sopenharmony_ci MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci udelay(1); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci offset = 3 * coverage_class; 1478c2ecf20Sopenharmony_ci reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | 1488c2ecf20Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); 1498c2ecf20Sopenharmony_ci mt76_wr(dev, MT_TMAC_CDTR, cck + reg_offset); 1508c2ecf20Sopenharmony_ci mt76_wr(dev, MT_TMAC_ODTR, ofdm + reg_offset); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci mt76_wr(dev, MT_TMAC_ICR(ext_phy), 1538c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_EIFS, 360) | 1548c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_RIFS, 2) | 1558c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_SIFS, sifs) | 1568c2ecf20Sopenharmony_ci FIELD_PREP(MT_IFS_SLOT, phy->slottime)); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (phy->slottime < 20 || is_5ghz) 1598c2ecf20Sopenharmony_ci val = MT7615_CFEND_RATE_DEFAULT; 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci val = MT7615_CFEND_RATE_11B; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci mt76_rmw_field(dev, MT_AGG_ACR(ext_phy), MT_AGG_ACR_CFEND_RATE, val); 1648c2ecf20Sopenharmony_ci if (ext_phy) 1658c2ecf20Sopenharmony_ci mt76_clear(dev, MT_ARB_SCR, 1668c2ecf20Sopenharmony_ci MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE); 1678c2ecf20Sopenharmony_ci else 1688c2ecf20Sopenharmony_ci mt76_clear(dev, MT_ARB_SCR, 1698c2ecf20Sopenharmony_ci MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void 1748c2ecf20Sopenharmony_cimt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, 1758c2ecf20Sopenharmony_ci struct mt76_rx_status *status, u8 chfreq) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if (!test_bit(MT76_HW_SCANNING, &mphy->state) && 1788c2ecf20Sopenharmony_ci !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) && 1798c2ecf20Sopenharmony_ci !test_bit(MT76_STATE_ROC, &mphy->state)) { 1808c2ecf20Sopenharmony_ci status->freq = mphy->chandef.chan->center_freq; 1818c2ecf20Sopenharmony_ci status->band = mphy->chandef.chan->band; 1828c2ecf20Sopenharmony_ci return; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci status->band = chfreq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; 1868c2ecf20Sopenharmony_ci status->freq = ieee80211_channel_to_frequency(chfreq, status->band); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE 1928c2ecf20Sopenharmony_ci u32 rxv1 = le32_to_cpu(rxv[0]); 1938c2ecf20Sopenharmony_ci u32 rxv3 = le32_to_cpu(rxv[2]); 1948c2ecf20Sopenharmony_ci u32 rxv4 = le32_to_cpu(rxv[3]); 1958c2ecf20Sopenharmony_ci u32 rxv5 = le32_to_cpu(rxv[4]); 1968c2ecf20Sopenharmony_ci u8 cbw = FIELD_GET(MT_RXV1_FRAME_MODE, rxv1); 1978c2ecf20Sopenharmony_ci u8 mode = FIELD_GET(MT_RXV1_TX_MODE, rxv1); 1988c2ecf20Sopenharmony_ci s16 foe = FIELD_GET(MT_RXV5_FOE, rxv5); 1998c2ecf20Sopenharmony_ci u32 foe_const = (BIT(cbw + 1) & 0xf) * 10000; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!mode) { 2028c2ecf20Sopenharmony_ci /* CCK */ 2038c2ecf20Sopenharmony_ci foe &= ~BIT(11); 2048c2ecf20Sopenharmony_ci foe *= 1000; 2058c2ecf20Sopenharmony_ci foe >>= 11; 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci if (foe > 2048) 2088c2ecf20Sopenharmony_ci foe -= 4096; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci foe = (foe * foe_const) >> 15; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci dev->test.last_freq_offset = foe; 2148c2ecf20Sopenharmony_ci dev->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4); 2158c2ecf20Sopenharmony_ci dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4); 2168c2ecf20Sopenharmony_ci dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4); 2178c2ecf20Sopenharmony_ci dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4); 2188c2ecf20Sopenharmony_ci dev->test.last_ib_rssi = FIELD_GET(MT_RXV3_IB_RSSI, rxv3); 2198c2ecf20Sopenharmony_ci dev->test.last_wb_rssi = FIELD_GET(MT_RXV3_WB_RSSI, rxv3); 2208c2ecf20Sopenharmony_ci#endif 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 2268c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 2278c2ecf20Sopenharmony_ci struct mt7615_phy *phy = &dev->phy; 2288c2ecf20Sopenharmony_ci struct mt7615_phy *phy2 = dev->mt76.phy2 ? dev->mt76.phy2->priv : NULL; 2298c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 2308c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 2318c2ecf20Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 2328c2ecf20Sopenharmony_ci u32 rxd0 = le32_to_cpu(rxd[0]); 2338c2ecf20Sopenharmony_ci u32 rxd1 = le32_to_cpu(rxd[1]); 2348c2ecf20Sopenharmony_ci u32 rxd2 = le32_to_cpu(rxd[2]); 2358c2ecf20Sopenharmony_ci __le32 rxd12 = rxd[12]; 2368c2ecf20Sopenharmony_ci bool unicast, remove_pad, insert_ccmp_hdr = false; 2378c2ecf20Sopenharmony_ci int phy_idx; 2388c2ecf20Sopenharmony_ci int i, idx; 2398c2ecf20Sopenharmony_ci u8 chfreq; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci memset(status, 0, sizeof(*status)); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci chfreq = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1); 2448c2ecf20Sopenharmony_ci if (!phy2) 2458c2ecf20Sopenharmony_ci phy_idx = 0; 2468c2ecf20Sopenharmony_ci else if (phy2->chfreq == phy->chfreq) 2478c2ecf20Sopenharmony_ci phy_idx = -1; 2488c2ecf20Sopenharmony_ci else if (phy->chfreq == chfreq) 2498c2ecf20Sopenharmony_ci phy_idx = 0; 2508c2ecf20Sopenharmony_ci else if (phy2->chfreq == chfreq) 2518c2ecf20Sopenharmony_ci phy_idx = 1; 2528c2ecf20Sopenharmony_ci else 2538c2ecf20Sopenharmony_ci phy_idx = -1; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M; 2568c2ecf20Sopenharmony_ci idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2); 2578c2ecf20Sopenharmony_ci status->wcid = mt7615_rx_get_wcid(dev, idx, unicast); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (status->wcid) { 2608c2ecf20Sopenharmony_ci struct mt7615_sta *msta; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci msta = container_of(status->wcid, struct mt7615_sta, wcid); 2638c2ecf20Sopenharmony_ci spin_lock_bh(&dev->sta_poll_lock); 2648c2ecf20Sopenharmony_ci if (list_empty(&msta->poll_list)) 2658c2ecf20Sopenharmony_ci list_add_tail(&msta->poll_list, &dev->sta_poll_list); 2668c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->sta_poll_lock); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_FCS_ERR) 2708c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_FAILED_FCS_CRC; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR) 2738c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_MMIC_ERROR; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && 2768c2ecf20Sopenharmony_ci !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) { 2778c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_DECRYPTED; 2788c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_IV_STRIPPED; 2798c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) 2858c2ecf20Sopenharmony_ci return -EINVAL; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci rxd += 4; 2888c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_4) { 2898c2ecf20Sopenharmony_ci rxd += 4; 2908c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 2918c2ecf20Sopenharmony_ci return -EINVAL; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_1) { 2958c2ecf20Sopenharmony_ci u8 *data = (u8 *)rxd; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) { 2988c2ecf20Sopenharmony_ci status->iv[0] = data[5]; 2998c2ecf20Sopenharmony_ci status->iv[1] = data[4]; 3008c2ecf20Sopenharmony_ci status->iv[2] = data[3]; 3018c2ecf20Sopenharmony_ci status->iv[3] = data[2]; 3028c2ecf20Sopenharmony_ci status->iv[4] = data[1]; 3038c2ecf20Sopenharmony_ci status->iv[5] = data[0]; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci rxd += 4; 3088c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_2) { 3138c2ecf20Sopenharmony_ci rxd += 2; 3148c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 3158c2ecf20Sopenharmony_ci return -EINVAL; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_3) { 3198c2ecf20Sopenharmony_ci u32 rxdg5 = le32_to_cpu(rxd[5]); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* 3228c2ecf20Sopenharmony_ci * If both PHYs are on the same channel and we don't have a WCID, 3238c2ecf20Sopenharmony_ci * we need to figure out which PHY this packet was received on. 3248c2ecf20Sopenharmony_ci * On the primary PHY, the noise value for the chains belonging to the 3258c2ecf20Sopenharmony_ci * second PHY will be set to the noise value of the last packet from 3268c2ecf20Sopenharmony_ci * that PHY. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci if (phy_idx < 0) { 3298c2ecf20Sopenharmony_ci int first_chain = ffs(phy2->chainmask) - 1; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci phy_idx = ((rxdg5 >> (first_chain * 8)) & 0xff) == 0; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (phy_idx == 1 && phy2) { 3368c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 3378c2ecf20Sopenharmony_ci phy = phy2; 3388c2ecf20Sopenharmony_ci status->ext_phy = true; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev) && chfreq != phy->chfreq) 3428c2ecf20Sopenharmony_ci return -EINVAL; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci mt7615_get_status_freq_info(dev, mphy, status, chfreq); 3458c2ecf20Sopenharmony_ci if (status->band == NL80211_BAND_5GHZ) 3468c2ecf20Sopenharmony_ci sband = &mphy->sband_5g.sband; 3478c2ecf20Sopenharmony_ci else 3488c2ecf20Sopenharmony_ci sband = &mphy->sband_2g.sband; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (!sband->channels) 3548c2ecf20Sopenharmony_ci return -EINVAL; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | 3578c2ecf20Sopenharmony_ci MT_RXD2_NORMAL_NON_AMPDU))) { 3588c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_AMPDU_DETAILS; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* all subframes of an A-MPDU have the same timestamp */ 3618c2ecf20Sopenharmony_ci if (phy->rx_ampdu_ts != rxd12) { 3628c2ecf20Sopenharmony_ci if (!++phy->ampdu_ref) 3638c2ecf20Sopenharmony_ci phy->ampdu_ref++; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci phy->rx_ampdu_ts = rxd12; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci status->ampdu_ref = phy->ampdu_ref; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (rxd0 & MT_RXD0_NORMAL_GROUP_3) { 3718c2ecf20Sopenharmony_ci u32 rxdg0 = le32_to_cpu(rxd[0]); 3728c2ecf20Sopenharmony_ci u32 rxdg1 = le32_to_cpu(rxd[1]); 3738c2ecf20Sopenharmony_ci u32 rxdg3 = le32_to_cpu(rxd[3]); 3748c2ecf20Sopenharmony_ci u8 stbc = FIELD_GET(MT_RXV1_HT_STBC, rxdg0); 3758c2ecf20Sopenharmony_ci bool cck = false; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0); 3788c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) { 3798c2ecf20Sopenharmony_ci case MT_PHY_TYPE_CCK: 3808c2ecf20Sopenharmony_ci cck = true; 3818c2ecf20Sopenharmony_ci fallthrough; 3828c2ecf20Sopenharmony_ci case MT_PHY_TYPE_OFDM: 3838c2ecf20Sopenharmony_ci i = mt76_get_rate(&dev->mt76, sband, i, cck); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 3868c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT: 3878c2ecf20Sopenharmony_ci status->encoding = RX_ENC_HT; 3888c2ecf20Sopenharmony_ci if (i > 31) 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci case MT_PHY_TYPE_VHT: 3928c2ecf20Sopenharmony_ci status->nss = FIELD_GET(MT_RXV2_NSTS, rxdg1) + 1; 3938c2ecf20Sopenharmony_ci status->encoding = RX_ENC_VHT; 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci default: 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci status->rate_idx = i; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0)) { 4018c2ecf20Sopenharmony_ci case MT_PHY_BW_20: 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case MT_PHY_BW_40: 4048c2ecf20Sopenharmony_ci status->bw = RATE_INFO_BW_40; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case MT_PHY_BW_80: 4078c2ecf20Sopenharmony_ci status->bw = RATE_INFO_BW_80; 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case MT_PHY_BW_160: 4108c2ecf20Sopenharmony_ci status->bw = RATE_INFO_BW_160; 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci default: 4138c2ecf20Sopenharmony_ci return -EINVAL; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (rxdg0 & MT_RXV1_HT_SHORT_GI) 4178c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 4188c2ecf20Sopenharmony_ci if (rxdg0 & MT_RXV1_HT_AD_CODE) 4198c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_LDPC; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci status->chains = mphy->antenna_mask; 4248c2ecf20Sopenharmony_ci status->chain_signal[0] = to_rssi(MT_RXV4_RCPI0, rxdg3); 4258c2ecf20Sopenharmony_ci status->chain_signal[1] = to_rssi(MT_RXV4_RCPI1, rxdg3); 4268c2ecf20Sopenharmony_ci status->chain_signal[2] = to_rssi(MT_RXV4_RCPI2, rxdg3); 4278c2ecf20Sopenharmony_ci status->chain_signal[3] = to_rssi(MT_RXV4_RCPI3, rxdg3); 4288c2ecf20Sopenharmony_ci status->signal = status->chain_signal[0]; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci for (i = 1; i < hweight8(mphy->antenna_mask); i++) { 4318c2ecf20Sopenharmony_ci if (!(status->chains & BIT(i))) 4328c2ecf20Sopenharmony_ci continue; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci status->signal = max(status->signal, 4358c2ecf20Sopenharmony_ci status->chain_signal[i]); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci mt7615_mac_fill_tm_rx(dev, rxd); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci rxd += 6; 4418c2ecf20Sopenharmony_ci if ((u8 *)rxd - skb->data >= skb->len) 4428c2ecf20Sopenharmony_ci return -EINVAL; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (insert_ccmp_hdr) { 4488c2ecf20Sopenharmony_ci u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci mt76_insert_ccmp_hdr(skb, key_id); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 4548c2ecf20Sopenharmony_ci if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci status->aggr = unicast && 4588c2ecf20Sopenharmony_ci !ieee80211_is_qos_nullfunc(hdr->frame_control); 4598c2ecf20Sopenharmony_ci status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 4608c2ecf20Sopenharmony_ci status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_civoid mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_sta_ps); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic u16 4718c2ecf20Sopenharmony_cimt7615_mac_tx_rate_val(struct mt7615_dev *dev, 4728c2ecf20Sopenharmony_ci struct mt76_phy *mphy, 4738c2ecf20Sopenharmony_ci const struct ieee80211_tx_rate *rate, 4748c2ecf20Sopenharmony_ci bool stbc, u8 *bw) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci u8 phy, nss, rate_idx; 4778c2ecf20Sopenharmony_ci u16 rateval = 0; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci *bw = 0; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { 4828c2ecf20Sopenharmony_ci rate_idx = ieee80211_rate_get_vht_mcs(rate); 4838c2ecf20Sopenharmony_ci nss = ieee80211_rate_get_vht_nss(rate); 4848c2ecf20Sopenharmony_ci phy = MT_PHY_TYPE_VHT; 4858c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 4868c2ecf20Sopenharmony_ci *bw = 1; 4878c2ecf20Sopenharmony_ci else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 4888c2ecf20Sopenharmony_ci *bw = 2; 4898c2ecf20Sopenharmony_ci else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 4908c2ecf20Sopenharmony_ci *bw = 3; 4918c2ecf20Sopenharmony_ci } else if (rate->flags & IEEE80211_TX_RC_MCS) { 4928c2ecf20Sopenharmony_ci rate_idx = rate->idx; 4938c2ecf20Sopenharmony_ci nss = 1 + (rate->idx >> 3); 4948c2ecf20Sopenharmony_ci phy = MT_PHY_TYPE_HT; 4958c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) 4968c2ecf20Sopenharmony_ci phy = MT_PHY_TYPE_HT_GF; 4978c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 4988c2ecf20Sopenharmony_ci *bw = 1; 4998c2ecf20Sopenharmony_ci } else { 5008c2ecf20Sopenharmony_ci const struct ieee80211_rate *r; 5018c2ecf20Sopenharmony_ci int band = mphy->chandef.chan->band; 5028c2ecf20Sopenharmony_ci u16 val; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci nss = 1; 5058c2ecf20Sopenharmony_ci r = &mphy->hw->wiphy->bands[band]->bitrates[rate->idx]; 5068c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 5078c2ecf20Sopenharmony_ci val = r->hw_value_short; 5088c2ecf20Sopenharmony_ci else 5098c2ecf20Sopenharmony_ci val = r->hw_value; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci phy = val >> 8; 5128c2ecf20Sopenharmony_ci rate_idx = val & 0xff; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (stbc && nss == 1) { 5168c2ecf20Sopenharmony_ci nss++; 5178c2ecf20Sopenharmony_ci rateval |= MT_TX_RATE_STBC; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci rateval |= (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | 5218c2ecf20Sopenharmony_ci FIELD_PREP(MT_TX_RATE_MODE, phy) | 5228c2ecf20Sopenharmony_ci FIELD_PREP(MT_TX_RATE_NSS, nss - 1)); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return rateval; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciint mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, 5288c2ecf20Sopenharmony_ci struct sk_buff *skb, struct mt76_wcid *wcid, 5298c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, int pid, 5308c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key, bool beacon) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 5338c2ecf20Sopenharmony_ci u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; 5348c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 5358c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rate = &info->control.rates[0]; 5368c2ecf20Sopenharmony_ci bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; 5378c2ecf20Sopenharmony_ci bool multicast = is_multicast_ether_addr(hdr->addr1); 5388c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 5398c2ecf20Sopenharmony_ci bool is_mmio = mt76_is_mmio(&dev->mt76); 5408c2ecf20Sopenharmony_ci u32 val, sz_txd = is_mmio ? MT_TXD_SIZE : MT_USB_TXD_SIZE; 5418c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mphy; 5428c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 5438c2ecf20Sopenharmony_ci int tx_count = 8; 5448c2ecf20Sopenharmony_ci u16 seqno = 0; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (vif) { 5478c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci omac_idx = mvif->omac_idx; 5508c2ecf20Sopenharmony_ci wmm_idx = mvif->wmm_idx; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (sta) { 5548c2ecf20Sopenharmony_ci struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci tx_count = msta->rate_count; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (ext_phy && dev->mt76.phy2) 5608c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; 5638c2ecf20Sopenharmony_ci fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (beacon) { 5668c2ecf20Sopenharmony_ci p_fmt = MT_TX_TYPE_FW; 5678c2ecf20Sopenharmony_ci q_idx = ext_phy ? MT_LMAC_BCN1 : MT_LMAC_BCN0; 5688c2ecf20Sopenharmony_ci } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { 5698c2ecf20Sopenharmony_ci p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; 5708c2ecf20Sopenharmony_ci q_idx = ext_phy ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; 5718c2ecf20Sopenharmony_ci } else { 5728c2ecf20Sopenharmony_ci p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; 5738c2ecf20Sopenharmony_ci q_idx = wmm_idx * MT7615_MAX_WMM_SETS + 5748c2ecf20Sopenharmony_ci mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb)); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | 5788c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_LMAC) | 5798c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD0_Q_IDX, q_idx); 5808c2ecf20Sopenharmony_ci txwi[0] = cpu_to_le32(val); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci val = MT_TXD1_LONG_FORMAT | 5838c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | 5848c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | 5858c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_INFO, 5868c2ecf20Sopenharmony_ci ieee80211_get_hdrlen_from_skb(skb) / 2) | 5878c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_TID, 5888c2ecf20Sopenharmony_ci skb->priority & IEEE80211_QOS_CTL_TID_MASK) | 5898c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_PKT_FMT, p_fmt) | 5908c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); 5918c2ecf20Sopenharmony_ci txwi[1] = cpu_to_le32(val); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | 5948c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | 5958c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD2_MULTICAST, multicast); 5968c2ecf20Sopenharmony_ci if (key) { 5978c2ecf20Sopenharmony_ci if (multicast && ieee80211_is_robust_mgmt_frame(skb) && 5988c2ecf20Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { 5998c2ecf20Sopenharmony_ci val |= MT_TXD2_BIP; 6008c2ecf20Sopenharmony_ci txwi[3] = 0; 6018c2ecf20Sopenharmony_ci } else { 6028c2ecf20Sopenharmony_ci txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME); 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } else { 6058c2ecf20Sopenharmony_ci txwi[3] = 0; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci txwi[2] = cpu_to_le32(val); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) 6108c2ecf20Sopenharmony_ci txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci txwi[4] = 0; 6138c2ecf20Sopenharmony_ci txwi[6] = 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (rate->idx >= 0 && rate->count && 6168c2ecf20Sopenharmony_ci !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) { 6178c2ecf20Sopenharmony_ci bool stbc = info->flags & IEEE80211_TX_CTL_STBC; 6188c2ecf20Sopenharmony_ci u8 bw; 6198c2ecf20Sopenharmony_ci u16 rateval = mt7615_mac_tx_rate_val(dev, mphy, rate, stbc, 6208c2ecf20Sopenharmony_ci &bw); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci val = MT_TXD6_FIXED_BW | 6258c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD6_BW, bw) | 6268c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD6_TX_RATE, rateval); 6278c2ecf20Sopenharmony_ci txwi[6] |= cpu_to_le32(val); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_SHORT_GI) 6308c2ecf20Sopenharmony_ci txwi[6] |= cpu_to_le32(MT_TXD6_SGI); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_LDPC) 6338c2ecf20Sopenharmony_ci txwi[6] |= cpu_to_le32(MT_TXD6_LDPC); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (!(rate->flags & (IEEE80211_TX_RC_MCS | 6368c2ecf20Sopenharmony_ci IEEE80211_TX_RC_VHT_MCS))) 6378c2ecf20Sopenharmony_ci txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci tx_count = rate->count; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!ieee80211_is_beacon(fc)) { 6438c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = mt76_hw(dev); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci val = MT_TXD5_TX_STATUS_HOST | FIELD_PREP(MT_TXD5_PID, pid); 6468c2ecf20Sopenharmony_ci if (!ieee80211_hw_check(hw, SUPPORTS_PS)) 6478c2ecf20Sopenharmony_ci val |= MT_TXD5_SW_POWER_MGMT; 6488c2ecf20Sopenharmony_ci txwi[5] = cpu_to_le32(val); 6498c2ecf20Sopenharmony_ci } else { 6508c2ecf20Sopenharmony_ci txwi[5] = 0; 6518c2ecf20Sopenharmony_ci /* use maximum tx count for beacons */ 6528c2ecf20Sopenharmony_ci tx_count = 0x1f; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); 6568c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_INJECTED) { 6578c2ecf20Sopenharmony_ci seqno = le16_to_cpu(hdr->seq_ctrl); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (ieee80211_is_back_req(hdr->frame_control)) { 6608c2ecf20Sopenharmony_ci struct ieee80211_bar *bar; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci bar = (struct ieee80211_bar *)skb->data; 6638c2ecf20Sopenharmony_ci seqno = le16_to_cpu(bar->start_seq_num); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci val |= MT_TXD3_SN_VALID | 6678c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci txwi[3] |= cpu_to_le32(val); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_ACK) 6738c2ecf20Sopenharmony_ci txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | 6768c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) | 6778c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD7_SPE_IDX, 0x18); 6788c2ecf20Sopenharmony_ci txwi[7] = cpu_to_le32(val); 6798c2ecf20Sopenharmony_ci if (!is_mmio) { 6808c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | 6818c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); 6828c2ecf20Sopenharmony_ci txwi[8] = cpu_to_le32(val); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_write_txwi); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic void 6908c2ecf20Sopenharmony_cimt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt7615_fw_txp *txp) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci int i; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci for (i = 0; i < txp->nbuf; i++) 6958c2ecf20Sopenharmony_ci dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]), 6968c2ecf20Sopenharmony_ci le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void 7008c2ecf20Sopenharmony_cimt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci u32 last_mask; 7038c2ecf20Sopenharmony_ci int i; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci last_mask = is_mt7663(dev) ? MT_TXD_LEN_LAST : MT_TXD_LEN_MSDU_LAST; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) { 7088c2ecf20Sopenharmony_ci struct mt7615_txp_ptr *ptr = &txp->ptr[i]; 7098c2ecf20Sopenharmony_ci bool last; 7108c2ecf20Sopenharmony_ci u16 len; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci len = le16_to_cpu(ptr->len0); 7138c2ecf20Sopenharmony_ci last = len & last_mask; 7148c2ecf20Sopenharmony_ci len &= MT_TXD_LEN_MASK; 7158c2ecf20Sopenharmony_ci dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, 7168c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7178c2ecf20Sopenharmony_ci if (last) 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci len = le16_to_cpu(ptr->len1); 7218c2ecf20Sopenharmony_ci last = len & last_mask; 7228c2ecf20Sopenharmony_ci len &= MT_TXD_LEN_MASK; 7238c2ecf20Sopenharmony_ci dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, 7248c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7258c2ecf20Sopenharmony_ci if (last) 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_civoid mt7615_txp_skb_unmap(struct mt76_dev *dev, 7318c2ecf20Sopenharmony_ci struct mt76_txwi_cache *t) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct mt7615_txp_common *txp; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci txp = mt7615_txwi_to_txp(dev, t); 7368c2ecf20Sopenharmony_ci if (is_mt7615(dev)) 7378c2ecf20Sopenharmony_ci mt7615_txp_skb_unmap_fw(dev, &txp->fw); 7388c2ecf20Sopenharmony_ci else 7398c2ecf20Sopenharmony_ci mt7615_txp_skb_unmap_hw(dev, &txp->hw); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_txp_skb_unmap); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cibool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, 7468c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 7498c2ecf20Sopenharmony_ci 0, 5000); 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_civoid mt7615_mac_sta_poll(struct mt7615_dev *dev) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci static const u8 ac_to_tid[4] = { 7558c2ecf20Sopenharmony_ci [IEEE80211_AC_BE] = 0, 7568c2ecf20Sopenharmony_ci [IEEE80211_AC_BK] = 1, 7578c2ecf20Sopenharmony_ci [IEEE80211_AC_VI] = 4, 7588c2ecf20Sopenharmony_ci [IEEE80211_AC_VO] = 6 7598c2ecf20Sopenharmony_ci }; 7608c2ecf20Sopenharmony_ci static const u8 hw_queue_map[] = { 7618c2ecf20Sopenharmony_ci [IEEE80211_AC_BK] = 0, 7628c2ecf20Sopenharmony_ci [IEEE80211_AC_BE] = 1, 7638c2ecf20Sopenharmony_ci [IEEE80211_AC_VI] = 2, 7648c2ecf20Sopenharmony_ci [IEEE80211_AC_VO] = 3, 7658c2ecf20Sopenharmony_ci }; 7668c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 7678c2ecf20Sopenharmony_ci struct mt7615_sta *msta; 7688c2ecf20Sopenharmony_ci u32 addr, tx_time[4], rx_time[4]; 7698c2ecf20Sopenharmony_ci struct list_head sta_poll_list; 7708c2ecf20Sopenharmony_ci int i; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sta_poll_list); 7738c2ecf20Sopenharmony_ci spin_lock_bh(&dev->sta_poll_lock); 7748c2ecf20Sopenharmony_ci list_splice_init(&dev->sta_poll_list, &sta_poll_list); 7758c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->sta_poll_lock); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci while (!list_empty(&sta_poll_list)) { 7788c2ecf20Sopenharmony_ci bool clear = false; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci msta = list_first_entry(&sta_poll_list, struct mt7615_sta, 7818c2ecf20Sopenharmony_ci poll_list); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci spin_lock_bh(&dev->sta_poll_lock); 7848c2ecf20Sopenharmony_ci list_del_init(&msta->poll_list); 7858c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->sta_poll_lock); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++, addr += 8) { 7908c2ecf20Sopenharmony_ci u32 tx_last = msta->airtime_ac[i]; 7918c2ecf20Sopenharmony_ci u32 rx_last = msta->airtime_ac[i + 4]; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci msta->airtime_ac[i] = mt76_rr(dev, addr); 7948c2ecf20Sopenharmony_ci msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); 7958c2ecf20Sopenharmony_ci tx_time[i] = msta->airtime_ac[i] - tx_last; 7968c2ecf20Sopenharmony_ci rx_time[i] = msta->airtime_ac[i + 4] - rx_last; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if ((tx_last | rx_last) & BIT(30)) 7998c2ecf20Sopenharmony_ci clear = true; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (clear) { 8038c2ecf20Sopenharmony_ci mt7615_mac_wtbl_update(dev, msta->wcid.idx, 8048c2ecf20Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 8058c2ecf20Sopenharmony_ci memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (!msta->wcid.sta) 8098c2ecf20Sopenharmony_ci continue; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, 8128c2ecf20Sopenharmony_ci drv_priv); 8138c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 8148c2ecf20Sopenharmony_ci u32 tx_cur = tx_time[i]; 8158c2ecf20Sopenharmony_ci u32 rx_cur = rx_time[hw_queue_map[i]]; 8168c2ecf20Sopenharmony_ci u8 tid = ac_to_tid[i]; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (!tx_cur && !rx_cur) 8198c2ecf20Sopenharmony_ci continue; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci ieee80211_sta_register_airtime(sta, tid, tx_cur, 8228c2ecf20Sopenharmony_ci rx_cur); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_sta_poll); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic void 8298c2ecf20Sopenharmony_cimt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta, 8308c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *probe_rate, 8318c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates, 8328c2ecf20Sopenharmony_ci struct mt7615_rate_desc *rd) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 8358c2ecf20Sopenharmony_ci struct mt76_phy *mphy = phy->mt76; 8368c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *ref; 8378c2ecf20Sopenharmony_ci bool rateset, stbc = false; 8388c2ecf20Sopenharmony_ci int n_rates = sta->n_rates; 8398c2ecf20Sopenharmony_ci u8 bw, bw_prev; 8408c2ecf20Sopenharmony_ci int i, j; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci for (i = n_rates; i < 4; i++) 8438c2ecf20Sopenharmony_ci rates[i] = rates[n_rates - 1]; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci rateset = !(sta->rate_set_tsf & BIT(0)); 8468c2ecf20Sopenharmony_ci memcpy(sta->rateset[rateset].rates, rates, 8478c2ecf20Sopenharmony_ci sizeof(sta->rateset[rateset].rates)); 8488c2ecf20Sopenharmony_ci if (probe_rate) { 8498c2ecf20Sopenharmony_ci sta->rateset[rateset].probe_rate = *probe_rate; 8508c2ecf20Sopenharmony_ci ref = &sta->rateset[rateset].probe_rate; 8518c2ecf20Sopenharmony_ci } else { 8528c2ecf20Sopenharmony_ci sta->rateset[rateset].probe_rate.idx = -1; 8538c2ecf20Sopenharmony_ci ref = &sta->rateset[rateset].rates[0]; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci rates = sta->rateset[rateset].rates; 8578c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) { 8588c2ecf20Sopenharmony_ci /* 8598c2ecf20Sopenharmony_ci * We don't support switching between short and long GI 8608c2ecf20Sopenharmony_ci * within the rate set. For accurate tx status reporting, we 8618c2ecf20Sopenharmony_ci * need to make sure that flags match. 8628c2ecf20Sopenharmony_ci * For improved performance, avoid duplicate entries by 8638c2ecf20Sopenharmony_ci * decrementing the MCS index if necessary 8648c2ecf20Sopenharmony_ci */ 8658c2ecf20Sopenharmony_ci if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI) 8668c2ecf20Sopenharmony_ci rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 8698c2ecf20Sopenharmony_ci if (rates[i].idx != rates[j].idx) 8708c2ecf20Sopenharmony_ci continue; 8718c2ecf20Sopenharmony_ci if ((rates[i].flags ^ rates[j].flags) & 8728c2ecf20Sopenharmony_ci (IEEE80211_TX_RC_40_MHZ_WIDTH | 8738c2ecf20Sopenharmony_ci IEEE80211_TX_RC_80_MHZ_WIDTH | 8748c2ecf20Sopenharmony_ci IEEE80211_TX_RC_160_MHZ_WIDTH)) 8758c2ecf20Sopenharmony_ci continue; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (!rates[i].idx) 8788c2ecf20Sopenharmony_ci continue; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci rates[i].idx--; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci rd->val[0] = mt7615_mac_tx_rate_val(dev, mphy, &rates[0], stbc, &bw); 8858c2ecf20Sopenharmony_ci bw_prev = bw; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (probe_rate) { 8888c2ecf20Sopenharmony_ci rd->probe_val = mt7615_mac_tx_rate_val(dev, mphy, probe_rate, 8898c2ecf20Sopenharmony_ci stbc, &bw); 8908c2ecf20Sopenharmony_ci if (bw) 8918c2ecf20Sopenharmony_ci rd->bw_idx = 1; 8928c2ecf20Sopenharmony_ci else 8938c2ecf20Sopenharmony_ci bw_prev = 0; 8948c2ecf20Sopenharmony_ci } else { 8958c2ecf20Sopenharmony_ci rd->probe_val = rd->val[0]; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci rd->val[1] = mt7615_mac_tx_rate_val(dev, mphy, &rates[1], stbc, &bw); 8998c2ecf20Sopenharmony_ci if (bw_prev) { 9008c2ecf20Sopenharmony_ci rd->bw_idx = 3; 9018c2ecf20Sopenharmony_ci bw_prev = bw; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci rd->val[2] = mt7615_mac_tx_rate_val(dev, mphy, &rates[2], stbc, &bw); 9058c2ecf20Sopenharmony_ci if (bw_prev) { 9068c2ecf20Sopenharmony_ci rd->bw_idx = 5; 9078c2ecf20Sopenharmony_ci bw_prev = bw; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci rd->val[3] = mt7615_mac_tx_rate_val(dev, mphy, &rates[3], stbc, &bw); 9118c2ecf20Sopenharmony_ci if (bw_prev) 9128c2ecf20Sopenharmony_ci rd->bw_idx = 7; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci rd->rateset = rateset; 9158c2ecf20Sopenharmony_ci rd->bw = bw; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic int 9198c2ecf20Sopenharmony_cimt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, 9208c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *probe_rate, 9218c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 9248c2ecf20Sopenharmony_ci struct mt7615_wtbl_desc *wd; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (work_pending(&dev->wtbl_work)) 9278c2ecf20Sopenharmony_ci return -EBUSY; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci wd = kzalloc(sizeof(*wd), GFP_ATOMIC); 9308c2ecf20Sopenharmony_ci if (!wd) 9318c2ecf20Sopenharmony_ci return -ENOMEM; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci wd->type = MT7615_WTBL_RATE_DESC; 9348c2ecf20Sopenharmony_ci wd->sta = sta; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, 9378c2ecf20Sopenharmony_ci &wd->rate); 9388c2ecf20Sopenharmony_ci list_add_tail(&wd->node, &dev->wd_head); 9398c2ecf20Sopenharmony_ci queue_work(dev->mt76.wq, &dev->wtbl_work); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci return 0; 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ciu32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci u32 addr, val, val2; 9478c2ecf20Sopenharmony_ci u8 offset; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci addr = mt7615_mac_wtbl_addr(dev, wcid) + 11 * 4; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci offset = tid * 12; 9528c2ecf20Sopenharmony_ci addr += 4 * (offset / 32); 9538c2ecf20Sopenharmony_ci offset %= 32; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci val = mt76_rr(dev, addr); 9568c2ecf20Sopenharmony_ci val >>= offset; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (offset > 20) { 9598c2ecf20Sopenharmony_ci addr += 4; 9608c2ecf20Sopenharmony_ci val2 = mt76_rr(dev, addr); 9618c2ecf20Sopenharmony_ci val |= val2 << (32 - offset); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return val & GENMASK(11, 0); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_civoid mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, 9688c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *probe_rate, 9698c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci int wcid = sta->wcid.idx, n_rates = sta->n_rates; 9728c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 9738c2ecf20Sopenharmony_ci struct mt7615_rate_desc rd; 9748c2ecf20Sopenharmony_ci u32 w5, w27, addr; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (!mt76_is_mmio(&dev->mt76)) { 9778c2ecf20Sopenharmony_ci mt7615_mac_queue_rate_update(phy, sta, probe_rate, rates); 9788c2ecf20Sopenharmony_ci return; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) 9828c2ecf20Sopenharmony_ci return; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci memset(&rd, 0, sizeof(struct mt7615_rate_desc)); 9858c2ecf20Sopenharmony_ci mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &rd); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci addr = mt7615_mac_wtbl_addr(dev, wcid); 9888c2ecf20Sopenharmony_ci w27 = mt76_rr(dev, addr + 27 * 4); 9898c2ecf20Sopenharmony_ci w27 &= ~MT_WTBL_W27_CC_BW_SEL; 9908c2ecf20Sopenharmony_ci w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rd.bw); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci w5 = mt76_rr(dev, addr + 5 * 4); 9938c2ecf20Sopenharmony_ci w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | 9948c2ecf20Sopenharmony_ci MT_WTBL_W5_MPDU_OK_COUNT | 9958c2ecf20Sopenharmony_ci MT_WTBL_W5_MPDU_FAIL_COUNT | 9968c2ecf20Sopenharmony_ci MT_WTBL_W5_RATE_IDX); 9978c2ecf20Sopenharmony_ci w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rd.bw) | 9988c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, 9998c2ecf20Sopenharmony_ci rd.bw_idx ? rd.bw_idx - 1 : 7); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR0, w5); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR1, 10048c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rd.probe_val) | 10058c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rd.val[0]) | 10068c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rd.val[1])); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR2, 10098c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rd.val[1] >> 8) | 10108c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rd.val[1]) | 10118c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rd.val[2]) | 10128c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rd.val[2])); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RIUCR3, 10158c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rd.val[2] >> 4) | 10168c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rd.val[3]) | 10178c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rd.val[3])); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_UPDATE, 10208c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | 10218c2ecf20Sopenharmony_ci MT_WTBL_UPDATE_RATE_UPDATE | 10228c2ecf20Sopenharmony_ci MT_WTBL_UPDATE_TX_COUNT_CLEAR); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci mt76_wr(dev, addr + 27 * 4, w27); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ 10278c2ecf20Sopenharmony_ci sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0); 10288c2ecf20Sopenharmony_ci sta->rate_set_tsf |= rd.rateset; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) 10318c2ecf20Sopenharmony_ci mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates; 10348c2ecf20Sopenharmony_ci sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 10358c2ecf20Sopenharmony_ci sta->rate_probe = !!probe_rate; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_set_rates); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ciint mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, 10408c2ecf20Sopenharmony_ci struct mt76_wcid *wcid, 10418c2ecf20Sopenharmony_ci u8 *key, u8 keylen, 10428c2ecf20Sopenharmony_ci enum mt7615_cipher_type cipher, 10438c2ecf20Sopenharmony_ci enum set_key_cmd cmd) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4; 10468c2ecf20Sopenharmony_ci u8 data[32] = {}; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (keylen > sizeof(data)) 10498c2ecf20Sopenharmony_ci return -EINVAL; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci mt76_rr_copy(dev, addr, data, sizeof(data)); 10528c2ecf20Sopenharmony_ci if (cmd == SET_KEY) { 10538c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_TKIP) { 10548c2ecf20Sopenharmony_ci /* Rx/Tx MIC keys are swapped */ 10558c2ecf20Sopenharmony_ci memcpy(data, key, 16); 10568c2ecf20Sopenharmony_ci memcpy(data + 16, key + 24, 8); 10578c2ecf20Sopenharmony_ci memcpy(data + 24, key + 16, 8); 10588c2ecf20Sopenharmony_ci } else { 10598c2ecf20Sopenharmony_ci if (cipher != MT_CIPHER_BIP_CMAC_128 && wcid->cipher) 10608c2ecf20Sopenharmony_ci memmove(data + 16, data, 16); 10618c2ecf20Sopenharmony_ci if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher) 10628c2ecf20Sopenharmony_ci memcpy(data, key, keylen); 10638c2ecf20Sopenharmony_ci else if (cipher == MT_CIPHER_BIP_CMAC_128) 10648c2ecf20Sopenharmony_ci memcpy(data + 16, key, 16); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci } else { 10678c2ecf20Sopenharmony_ci if (wcid->cipher & ~BIT(cipher)) { 10688c2ecf20Sopenharmony_ci if (cipher != MT_CIPHER_BIP_CMAC_128) 10698c2ecf20Sopenharmony_ci memmove(data, data + 16, 16); 10708c2ecf20Sopenharmony_ci memset(data + 16, 0, 16); 10718c2ecf20Sopenharmony_ci } else { 10728c2ecf20Sopenharmony_ci memset(data, 0, sizeof(data)); 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci mt76_wr_copy(dev, addr, data, sizeof(data)); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return 0; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_key); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ciint mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, 10828c2ecf20Sopenharmony_ci struct mt76_wcid *wcid, 10838c2ecf20Sopenharmony_ci enum mt7615_cipher_type cipher, 10848c2ecf20Sopenharmony_ci int keyidx, enum set_key_cmd cmd) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) 10898c2ecf20Sopenharmony_ci return -ETIMEDOUT; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci w0 = mt76_rr(dev, addr); 10928c2ecf20Sopenharmony_ci w1 = mt76_rr(dev, addr + 4); 10938c2ecf20Sopenharmony_ci if (cmd == SET_KEY) { 10948c2ecf20Sopenharmony_ci w0 |= MT_WTBL_W0_RX_KEY_VALID | 10958c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_W0_RX_IK_VALID, 10968c2ecf20Sopenharmony_ci cipher == MT_CIPHER_BIP_CMAC_128); 10978c2ecf20Sopenharmony_ci if (cipher != MT_CIPHER_BIP_CMAC_128 || 10988c2ecf20Sopenharmony_ci !wcid->cipher) 10998c2ecf20Sopenharmony_ci w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx); 11008c2ecf20Sopenharmony_ci } else { 11018c2ecf20Sopenharmony_ci if (!(wcid->cipher & ~BIT(cipher))) 11028c2ecf20Sopenharmony_ci w0 &= ~(MT_WTBL_W0_RX_KEY_VALID | 11038c2ecf20Sopenharmony_ci MT_WTBL_W0_KEY_IDX); 11048c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_BIP_CMAC_128) 11058c2ecf20Sopenharmony_ci w0 &= ~MT_WTBL_W0_RX_IK_VALID; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RICR0, w0); 11088c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WTBL_RICR1, w1); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (!mt7615_mac_wtbl_update(dev, wcid->idx, 11118c2ecf20Sopenharmony_ci MT_WTBL_UPDATE_RXINFO_UPDATE)) 11128c2ecf20Sopenharmony_ci return -ETIMEDOUT; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci return 0; 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_pk); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_civoid mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, 11198c2ecf20Sopenharmony_ci struct mt76_wcid *wcid, 11208c2ecf20Sopenharmony_ci enum mt7615_cipher_type cipher, 11218c2ecf20Sopenharmony_ci enum set_key_cmd cmd) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (cmd == SET_KEY) { 11268c2ecf20Sopenharmony_ci if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher) 11278c2ecf20Sopenharmony_ci mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE, 11288c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_W2_KEY_TYPE, cipher)); 11298c2ecf20Sopenharmony_ci } else { 11308c2ecf20Sopenharmony_ci if (cipher != MT_CIPHER_BIP_CMAC_128 && 11318c2ecf20Sopenharmony_ci wcid->cipher & BIT(MT_CIPHER_BIP_CMAC_128)) 11328c2ecf20Sopenharmony_ci mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE, 11338c2ecf20Sopenharmony_ci FIELD_PREP(MT_WTBL_W2_KEY_TYPE, 11348c2ecf20Sopenharmony_ci MT_CIPHER_BIP_CMAC_128)); 11358c2ecf20Sopenharmony_ci else if (!(wcid->cipher & ~BIT(cipher))) 11368c2ecf20Sopenharmony_ci mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE); 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_cipher); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ciint mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, 11428c2ecf20Sopenharmony_ci struct mt76_wcid *wcid, 11438c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key, 11448c2ecf20Sopenharmony_ci enum set_key_cmd cmd) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci enum mt7615_cipher_type cipher; 11478c2ecf20Sopenharmony_ci int err; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci cipher = mt7615_mac_get_cipher(key->cipher); 11508c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_NONE) 11518c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci spin_lock_bh(&dev->mt76.lock); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cmd); 11568c2ecf20Sopenharmony_ci err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, 11578c2ecf20Sopenharmony_ci cipher, cmd); 11588c2ecf20Sopenharmony_ci if (err < 0) 11598c2ecf20Sopenharmony_ci goto out; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, 11628c2ecf20Sopenharmony_ci cmd); 11638c2ecf20Sopenharmony_ci if (err < 0) 11648c2ecf20Sopenharmony_ci goto out; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (cmd == SET_KEY) 11678c2ecf20Sopenharmony_ci wcid->cipher |= BIT(cipher); 11688c2ecf20Sopenharmony_ci else 11698c2ecf20Sopenharmony_ci wcid->cipher &= ~BIT(cipher); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ciout: 11728c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->mt76.lock); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci return err; 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, 11788c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info, __le32 *txs_data) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 11818c2ecf20Sopenharmony_ci struct mt7615_rate_set *rs; 11828c2ecf20Sopenharmony_ci struct mt76_phy *mphy; 11838c2ecf20Sopenharmony_ci int first_idx = 0, last_idx; 11848c2ecf20Sopenharmony_ci int i, idx, count; 11858c2ecf20Sopenharmony_ci bool fixed_rate, ack_timeout; 11868c2ecf20Sopenharmony_ci bool ampdu, cck = false; 11878c2ecf20Sopenharmony_ci bool rs_idx; 11888c2ecf20Sopenharmony_ci u32 rate_set_tsf; 11898c2ecf20Sopenharmony_ci u32 final_rate, final_rate_flags, final_nss, txs; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[1]); 11928c2ecf20Sopenharmony_ci ampdu = txs & MT_TXS1_AMPDU; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[3]); 11958c2ecf20Sopenharmony_ci count = FIELD_GET(MT_TXS3_TX_COUNT, txs); 11968c2ecf20Sopenharmony_ci last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[0]); 11998c2ecf20Sopenharmony_ci fixed_rate = txs & MT_TXS0_FIXED_RATE; 12008c2ecf20Sopenharmony_ci final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs); 12018c2ecf20Sopenharmony_ci ack_timeout = txs & MT_TXS0_ACK_TIMEOUT; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT)) 12048c2ecf20Sopenharmony_ci return false; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (txs & MT_TXS0_QUEUE_TIMEOUT) 12078c2ecf20Sopenharmony_ci return false; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (!ack_timeout) 12108c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci info->status.ampdu_len = 1; 12138c2ecf20Sopenharmony_ci info->status.ampdu_ack_len = !!(info->flags & 12148c2ecf20Sopenharmony_ci IEEE80211_TX_STAT_ACK); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) 12178c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (fixed_rate) { 12228c2ecf20Sopenharmony_ci info->status.rates[0].count = count; 12238c2ecf20Sopenharmony_ci i = 0; 12248c2ecf20Sopenharmony_ci goto out; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci rate_set_tsf = READ_ONCE(sta->rate_set_tsf); 12288c2ecf20Sopenharmony_ci rs_idx = !((u32)(FIELD_GET(MT_TXS4_F0_TIMESTAMP, le32_to_cpu(txs_data[4])) - 12298c2ecf20Sopenharmony_ci rate_set_tsf) < 1000000); 12308c2ecf20Sopenharmony_ci rs_idx ^= rate_set_tsf & BIT(0); 12318c2ecf20Sopenharmony_ci rs = &sta->rateset[rs_idx]; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (!first_idx && rs->probe_rate.idx >= 0) { 12348c2ecf20Sopenharmony_ci info->status.rates[0] = rs->probe_rate; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci spin_lock_bh(&dev->mt76.lock); 12378c2ecf20Sopenharmony_ci if (sta->rate_probe) { 12388c2ecf20Sopenharmony_ci struct mt7615_phy *phy = &dev->phy; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (sta->wcid.ext_phy && dev->mt76.phy2) 12418c2ecf20Sopenharmony_ci phy = dev->mt76.phy2->priv; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci mt7615_mac_set_rates(phy, sta, NULL, sta->rates); 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->mt76.lock); 12468c2ecf20Sopenharmony_ci } else { 12478c2ecf20Sopenharmony_ci info->status.rates[0] = rs->rates[first_idx / 2]; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci info->status.rates[0].count = 0; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) { 12528c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *cur_rate; 12538c2ecf20Sopenharmony_ci int cur_count; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci cur_rate = &rs->rates[idx / 2]; 12568c2ecf20Sopenharmony_ci cur_count = min_t(int, MT7615_RATE_RETRY, count); 12578c2ecf20Sopenharmony_ci count -= cur_count; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (idx && (cur_rate->idx != info->status.rates[i].idx || 12608c2ecf20Sopenharmony_ci cur_rate->flags != info->status.rates[i].flags)) { 12618c2ecf20Sopenharmony_ci i++; 12628c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(info->status.rates)) { 12638c2ecf20Sopenharmony_ci i--; 12648c2ecf20Sopenharmony_ci break; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci info->status.rates[i] = *cur_rate; 12688c2ecf20Sopenharmony_ci info->status.rates[i].count = 0; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci info->status.rates[i].count += cur_count; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ciout: 12758c2ecf20Sopenharmony_ci final_rate_flags = info->status.rates[i].flags; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) { 12788c2ecf20Sopenharmony_ci case MT_PHY_TYPE_CCK: 12798c2ecf20Sopenharmony_ci cck = true; 12808c2ecf20Sopenharmony_ci fallthrough; 12818c2ecf20Sopenharmony_ci case MT_PHY_TYPE_OFDM: 12828c2ecf20Sopenharmony_ci mphy = &dev->mphy; 12838c2ecf20Sopenharmony_ci if (sta->wcid.ext_phy && dev->mt76.phy2) 12848c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 12878c2ecf20Sopenharmony_ci sband = &mphy->sband_5g.sband; 12888c2ecf20Sopenharmony_ci else 12898c2ecf20Sopenharmony_ci sband = &mphy->sband_2g.sband; 12908c2ecf20Sopenharmony_ci final_rate &= MT_TX_RATE_IDX; 12918c2ecf20Sopenharmony_ci final_rate = mt76_get_rate(&dev->mt76, sband, final_rate, 12928c2ecf20Sopenharmony_ci cck); 12938c2ecf20Sopenharmony_ci final_rate_flags = 0; 12948c2ecf20Sopenharmony_ci break; 12958c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 12968c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT: 12978c2ecf20Sopenharmony_ci final_rate_flags |= IEEE80211_TX_RC_MCS; 12988c2ecf20Sopenharmony_ci final_rate &= MT_TX_RATE_IDX; 12998c2ecf20Sopenharmony_ci if (final_rate > 31) 13008c2ecf20Sopenharmony_ci return false; 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci case MT_PHY_TYPE_VHT: 13038c2ecf20Sopenharmony_ci final_nss = FIELD_GET(MT_TX_RATE_NSS, final_rate); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if ((final_rate & MT_TX_RATE_STBC) && final_nss) 13068c2ecf20Sopenharmony_ci final_nss--; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci final_rate_flags |= IEEE80211_TX_RC_VHT_MCS; 13098c2ecf20Sopenharmony_ci final_rate = (final_rate & MT_TX_RATE_IDX) | (final_nss << 4); 13108c2ecf20Sopenharmony_ci break; 13118c2ecf20Sopenharmony_ci default: 13128c2ecf20Sopenharmony_ci return false; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci info->status.rates[i].idx = final_rate; 13168c2ecf20Sopenharmony_ci info->status.rates[i].flags = final_rate_flags; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return true; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev, 13228c2ecf20Sopenharmony_ci struct mt7615_sta *sta, int pid, 13238c2ecf20Sopenharmony_ci __le32 *txs_data) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 13268c2ecf20Sopenharmony_ci struct sk_buff_head list; 13278c2ecf20Sopenharmony_ci struct sk_buff *skb; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (pid < MT_PACKET_ID_FIRST) 13308c2ecf20Sopenharmony_ci return false; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci trace_mac_txdone(mdev, sta->wcid.idx, pid); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci mt76_tx_status_lock(mdev, &list); 13358c2ecf20Sopenharmony_ci skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list); 13368c2ecf20Sopenharmony_ci if (skb) { 13378c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci if (!mt7615_fill_txs(dev, sta, info, txs_data)) { 13408c2ecf20Sopenharmony_ci ieee80211_tx_info_clear_status(info); 13418c2ecf20Sopenharmony_ci info->status.rates[0].idx = -1; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci mt76_tx_status_skb_done(mdev, skb, &list); 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci mt76_tx_status_unlock(mdev, &list); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci return !!skb; 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci struct ieee80211_tx_info info = {}; 13548c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = NULL; 13558c2ecf20Sopenharmony_ci struct mt7615_sta *msta = NULL; 13568c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 13578c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 13588c2ecf20Sopenharmony_ci __le32 *txs_data = data; 13598c2ecf20Sopenharmony_ci u32 txs; 13608c2ecf20Sopenharmony_ci u8 wcidx; 13618c2ecf20Sopenharmony_ci u8 pid; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[0]); 13648c2ecf20Sopenharmony_ci pid = FIELD_GET(MT_TXS0_PID, txs); 13658c2ecf20Sopenharmony_ci txs = le32_to_cpu(txs_data[2]); 13668c2ecf20Sopenharmony_ci wcidx = FIELD_GET(MT_TXS2_WCID, txs); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (pid == MT_PACKET_ID_NO_ACK) 13698c2ecf20Sopenharmony_ci return; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci if (wcidx >= MT7615_WTBL_SIZE) 13728c2ecf20Sopenharmony_ci return; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci rcu_read_lock(); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[wcidx]); 13778c2ecf20Sopenharmony_ci if (!wcid) 13788c2ecf20Sopenharmony_ci goto out; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci msta = container_of(wcid, struct mt7615_sta, wcid); 13818c2ecf20Sopenharmony_ci sta = wcid_to_sta(wcid); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci spin_lock_bh(&dev->sta_poll_lock); 13848c2ecf20Sopenharmony_ci if (list_empty(&msta->poll_list)) 13858c2ecf20Sopenharmony_ci list_add_tail(&msta->poll_list, &dev->sta_poll_list); 13868c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->sta_poll_lock); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data)) 13898c2ecf20Sopenharmony_ci goto out; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (wcidx >= MT7615_WTBL_STA || !sta) 13928c2ecf20Sopenharmony_ci goto out; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (wcid->ext_phy && dev->mt76.phy2) 13958c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (mt7615_fill_txs(dev, msta, &info, txs_data)) 13988c2ecf20Sopenharmony_ci ieee80211_tx_status_noskb(mphy->hw, sta, &info); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ciout: 14018c2ecf20Sopenharmony_ci rcu_read_unlock(); 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic void 14058c2ecf20Sopenharmony_cimt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 14088c2ecf20Sopenharmony_ci struct mt76_txwi_cache *txwi; 14098c2ecf20Sopenharmony_ci __le32 *txwi_data; 14108c2ecf20Sopenharmony_ci u32 val; 14118c2ecf20Sopenharmony_ci u8 wcid; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci trace_mac_tx_free(dev, token); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci spin_lock_bh(&dev->token_lock); 14168c2ecf20Sopenharmony_ci txwi = idr_remove(&dev->token, token); 14178c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->token_lock); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (!txwi) 14208c2ecf20Sopenharmony_ci return; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi); 14238c2ecf20Sopenharmony_ci val = le32_to_cpu(txwi_data[1]); 14248c2ecf20Sopenharmony_ci wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci mt7615_txp_skb_unmap(mdev, txwi); 14278c2ecf20Sopenharmony_ci if (txwi->skb) { 14288c2ecf20Sopenharmony_ci mt76_tx_complete_skb(mdev, wcid, txwi->skb); 14298c2ecf20Sopenharmony_ci txwi->skb = NULL; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci mt76_put_txwi(mdev, txwi); 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cistatic void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data; 14388c2ecf20Sopenharmony_ci u8 i, count; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false); 14418c2ecf20Sopenharmony_ci if (is_mt7615(&dev->mt76)) { 14428c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false); 14438c2ecf20Sopenharmony_ci } else { 14448c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) 14458c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, false); 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci count = FIELD_GET(MT_TX_FREE_MSDU_ID_CNT, le16_to_cpu(free->ctrl)); 14498c2ecf20Sopenharmony_ci if (is_mt7615(&dev->mt76)) { 14508c2ecf20Sopenharmony_ci __le16 *token = &free->token[0]; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 14538c2ecf20Sopenharmony_ci mt7615_mac_tx_free_token(dev, le16_to_cpu(token[i])); 14548c2ecf20Sopenharmony_ci } else { 14558c2ecf20Sopenharmony_ci __le32 *token = (__le32 *)&free->token[0]; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 14588c2ecf20Sopenharmony_ci mt7615_mac_tx_free_token(dev, le32_to_cpu(token[i])); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state)) 14648c2ecf20Sopenharmony_ci return; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci rcu_read_lock(); 14678c2ecf20Sopenharmony_ci mt7615_mac_sta_poll(dev); 14688c2ecf20Sopenharmony_ci rcu_read_unlock(); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci mt7615_pm_power_save_sched(dev); 14718c2ecf20Sopenharmony_ci mt76_worker_schedule(&dev->mt76.tx_worker); 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_civoid mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, 14758c2ecf20Sopenharmony_ci struct sk_buff *skb) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 14788c2ecf20Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 14798c2ecf20Sopenharmony_ci __le32 *end = (__le32 *)&skb->data[skb->len]; 14808c2ecf20Sopenharmony_ci enum rx_pkt_type type; 14818c2ecf20Sopenharmony_ci u16 flag; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); 14848c2ecf20Sopenharmony_ci flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0])); 14858c2ecf20Sopenharmony_ci if (type == PKT_TYPE_RX_EVENT && flag == 0x1) 14868c2ecf20Sopenharmony_ci type = PKT_TYPE_NORMAL_MCU; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci switch (type) { 14898c2ecf20Sopenharmony_ci case PKT_TYPE_TXS: 14908c2ecf20Sopenharmony_ci for (rxd++; rxd + 7 <= end; rxd += 7) 14918c2ecf20Sopenharmony_ci mt7615_mac_add_txs(dev, rxd); 14928c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 14938c2ecf20Sopenharmony_ci break; 14948c2ecf20Sopenharmony_ci case PKT_TYPE_TXRX_NOTIFY: 14958c2ecf20Sopenharmony_ci mt7615_mac_tx_free(dev, skb); 14968c2ecf20Sopenharmony_ci break; 14978c2ecf20Sopenharmony_ci case PKT_TYPE_RX_EVENT: 14988c2ecf20Sopenharmony_ci mt7615_mcu_rx_event(dev, skb); 14998c2ecf20Sopenharmony_ci break; 15008c2ecf20Sopenharmony_ci case PKT_TYPE_NORMAL_MCU: 15018c2ecf20Sopenharmony_ci case PKT_TYPE_NORMAL: 15028c2ecf20Sopenharmony_ci if (!mt7615_mac_fill_rx(dev, skb)) { 15038c2ecf20Sopenharmony_ci mt76_rx(&dev->mt76, q, skb); 15048c2ecf20Sopenharmony_ci return; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci fallthrough; 15078c2ecf20Sopenharmony_ci default: 15088c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 15098c2ecf20Sopenharmony_ci break; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_queue_rx_skb); 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic void 15158c2ecf20Sopenharmony_cimt7615_mac_set_sensitivity(struct mt7615_phy *phy, int val, bool ofdm) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 15188c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) { 15218c2ecf20Sopenharmony_ci if (ofdm) 15228c2ecf20Sopenharmony_ci mt76_rmw(dev, MT7663_WF_PHY_MIN_PRI_PWR(ext_phy), 15238c2ecf20Sopenharmony_ci MT_WF_PHY_PD_OFDM_MASK(0), 15248c2ecf20Sopenharmony_ci MT_WF_PHY_PD_OFDM(0, val)); 15258c2ecf20Sopenharmony_ci else 15268c2ecf20Sopenharmony_ci mt76_rmw(dev, MT7663_WF_PHY_RXTD_CCK_PD(ext_phy), 15278c2ecf20Sopenharmony_ci MT_WF_PHY_PD_CCK_MASK(ext_phy), 15288c2ecf20Sopenharmony_ci MT_WF_PHY_PD_CCK(ext_phy, val)); 15298c2ecf20Sopenharmony_ci return; 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (ofdm) 15338c2ecf20Sopenharmony_ci mt76_rmw(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), 15348c2ecf20Sopenharmony_ci MT_WF_PHY_PD_OFDM_MASK(ext_phy), 15358c2ecf20Sopenharmony_ci MT_WF_PHY_PD_OFDM(ext_phy, val)); 15368c2ecf20Sopenharmony_ci else 15378c2ecf20Sopenharmony_ci mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy), 15388c2ecf20Sopenharmony_ci MT_WF_PHY_PD_CCK_MASK(ext_phy), 15398c2ecf20Sopenharmony_ci MT_WF_PHY_PD_CCK(ext_phy, val)); 15408c2ecf20Sopenharmony_ci} 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_cistatic void 15438c2ecf20Sopenharmony_cimt7615_mac_set_default_sensitivity(struct mt7615_phy *phy) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci /* ofdm */ 15468c2ecf20Sopenharmony_ci mt7615_mac_set_sensitivity(phy, 0x13c, true); 15478c2ecf20Sopenharmony_ci /* cck */ 15488c2ecf20Sopenharmony_ci mt7615_mac_set_sensitivity(phy, 0x92, false); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci phy->ofdm_sensitivity = -98; 15518c2ecf20Sopenharmony_ci phy->cck_sensitivity = -110; 15528c2ecf20Sopenharmony_ci phy->last_cca_adj = jiffies; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_civoid mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 15588c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 15598c2ecf20Sopenharmony_ci u32 reg, mask; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci mt7615_mutex_acquire(dev); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (phy->scs_en == enable) 15648c2ecf20Sopenharmony_ci goto out; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) { 15678c2ecf20Sopenharmony_ci reg = MT7663_WF_PHY_MIN_PRI_PWR(ext_phy); 15688c2ecf20Sopenharmony_ci mask = MT_WF_PHY_PD_BLK(0); 15698c2ecf20Sopenharmony_ci } else { 15708c2ecf20Sopenharmony_ci reg = MT_WF_PHY_MIN_PRI_PWR(ext_phy); 15718c2ecf20Sopenharmony_ci mask = MT_WF_PHY_PD_BLK(ext_phy); 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if (enable) { 15758c2ecf20Sopenharmony_ci mt76_set(dev, reg, mask); 15768c2ecf20Sopenharmony_ci if (is_mt7622(&dev->mt76)) { 15778c2ecf20Sopenharmony_ci mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7 << 8); 15788c2ecf20Sopenharmony_ci mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7); 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci } else { 15818c2ecf20Sopenharmony_ci mt76_clear(dev, reg, mask); 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci mt7615_mac_set_default_sensitivity(phy); 15858c2ecf20Sopenharmony_ci phy->scs_en = enable; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ciout: 15888c2ecf20Sopenharmony_ci mt7615_mutex_release(dev); 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_civoid mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci u32 rxtd, reg; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) 15968c2ecf20Sopenharmony_ci reg = MT7663_WF_PHY_R0_PHYMUX_5; 15978c2ecf20Sopenharmony_ci else 15988c2ecf20Sopenharmony_ci reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (ext_phy) 16018c2ecf20Sopenharmony_ci rxtd = MT_WF_PHY_RXTD2(10); 16028c2ecf20Sopenharmony_ci else 16038c2ecf20Sopenharmony_ci rxtd = MT_WF_PHY_RXTD(12); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci mt76_set(dev, rxtd, BIT(18) | BIT(29)); 16068c2ecf20Sopenharmony_ci mt76_set(dev, reg, 0x5 << 12); 16078c2ecf20Sopenharmony_ci} 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_civoid mt7615_mac_cca_stats_reset(struct mt7615_phy *phy) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 16128c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 16138c2ecf20Sopenharmony_ci u32 reg; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) 16168c2ecf20Sopenharmony_ci reg = MT7663_WF_PHY_R0_PHYMUX_5; 16178c2ecf20Sopenharmony_ci else 16188c2ecf20Sopenharmony_ci reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci /* reset PD and MDRDY counters */ 16218c2ecf20Sopenharmony_ci mt76_clear(dev, reg, GENMASK(22, 20)); 16228c2ecf20Sopenharmony_ci mt76_set(dev, reg, BIT(22) | BIT(20)); 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_cistatic void 16268c2ecf20Sopenharmony_cimt7615_mac_adjust_sensitivity(struct mt7615_phy *phy, 16278c2ecf20Sopenharmony_ci u32 rts_err_rate, bool ofdm) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 16308c2ecf20Sopenharmony_ci int false_cca = ofdm ? phy->false_cca_ofdm : phy->false_cca_cck; 16318c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 16328c2ecf20Sopenharmony_ci s16 def_th = ofdm ? -98 : -110; 16338c2ecf20Sopenharmony_ci bool update = false; 16348c2ecf20Sopenharmony_ci s8 *sensitivity; 16358c2ecf20Sopenharmony_ci int signal; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci sensitivity = ofdm ? &phy->ofdm_sensitivity : &phy->cck_sensitivity; 16388c2ecf20Sopenharmony_ci signal = mt76_get_min_avg_rssi(&dev->mt76, ext_phy); 16398c2ecf20Sopenharmony_ci if (!signal) { 16408c2ecf20Sopenharmony_ci mt7615_mac_set_default_sensitivity(phy); 16418c2ecf20Sopenharmony_ci return; 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci signal = min(signal, -72); 16458c2ecf20Sopenharmony_ci if (false_cca > 500) { 16468c2ecf20Sopenharmony_ci if (rts_err_rate > MT_FRAC(40, 100)) 16478c2ecf20Sopenharmony_ci return; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* decrease coverage */ 16508c2ecf20Sopenharmony_ci if (*sensitivity == def_th && signal > -90) { 16518c2ecf20Sopenharmony_ci *sensitivity = -90; 16528c2ecf20Sopenharmony_ci update = true; 16538c2ecf20Sopenharmony_ci } else if (*sensitivity + 2 < signal) { 16548c2ecf20Sopenharmony_ci *sensitivity += 2; 16558c2ecf20Sopenharmony_ci update = true; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci } else if ((false_cca > 0 && false_cca < 50) || 16588c2ecf20Sopenharmony_ci rts_err_rate > MT_FRAC(60, 100)) { 16598c2ecf20Sopenharmony_ci /* increase coverage */ 16608c2ecf20Sopenharmony_ci if (*sensitivity - 2 >= def_th) { 16618c2ecf20Sopenharmony_ci *sensitivity -= 2; 16628c2ecf20Sopenharmony_ci update = true; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci if (*sensitivity > signal) { 16678c2ecf20Sopenharmony_ci *sensitivity = signal; 16688c2ecf20Sopenharmony_ci update = true; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (update) { 16728c2ecf20Sopenharmony_ci u16 val = ofdm ? *sensitivity * 2 + 512 : *sensitivity + 256; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci mt7615_mac_set_sensitivity(phy, val, ofdm); 16758c2ecf20Sopenharmony_ci phy->last_cca_adj = jiffies; 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci} 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_cistatic void 16808c2ecf20Sopenharmony_cimt7615_mac_scs_check(struct mt7615_phy *phy) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 16838c2ecf20Sopenharmony_ci struct mib_stats *mib = &phy->mib; 16848c2ecf20Sopenharmony_ci u32 val, rts_err_rate = 0; 16858c2ecf20Sopenharmony_ci u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm; 16868c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (!phy->scs_en) 16898c2ecf20Sopenharmony_ci return; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) 16928c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); 16938c2ecf20Sopenharmony_ci else 16948c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); 16958c2ecf20Sopenharmony_ci pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val); 16968c2ecf20Sopenharmony_ci pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) 16998c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS5(ext_phy)); 17008c2ecf20Sopenharmony_ci else 17018c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS5(ext_phy)); 17028c2ecf20Sopenharmony_ci mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val); 17038c2ecf20Sopenharmony_ci mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci phy->false_cca_ofdm = pd_ofdm - mdrdy_ofdm; 17068c2ecf20Sopenharmony_ci phy->false_cca_cck = pd_cck - mdrdy_cck; 17078c2ecf20Sopenharmony_ci mt7615_mac_cca_stats_reset(phy); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (mib->rts_cnt + mib->rts_retries_cnt) 17108c2ecf20Sopenharmony_ci rts_err_rate = MT_FRAC(mib->rts_retries_cnt, 17118c2ecf20Sopenharmony_ci mib->rts_cnt + mib->rts_retries_cnt); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci /* cck */ 17148c2ecf20Sopenharmony_ci mt7615_mac_adjust_sensitivity(phy, rts_err_rate, false); 17158c2ecf20Sopenharmony_ci /* ofdm */ 17168c2ecf20Sopenharmony_ci mt7615_mac_adjust_sensitivity(phy, rts_err_rate, true); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (time_after(jiffies, phy->last_cca_adj + 10 * HZ)) 17198c2ecf20Sopenharmony_ci mt7615_mac_set_default_sensitivity(phy); 17208c2ecf20Sopenharmony_ci} 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_cistatic u8 17238c2ecf20Sopenharmony_cimt7615_phy_get_nf(struct mt7615_dev *dev, int idx) 17248c2ecf20Sopenharmony_ci{ 17258c2ecf20Sopenharmony_ci static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 }; 17268c2ecf20Sopenharmony_ci u32 reg, val, sum = 0, n = 0; 17278c2ecf20Sopenharmony_ci int i; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) 17308c2ecf20Sopenharmony_ci reg = MT7663_WF_PHY_RXTD(20); 17318c2ecf20Sopenharmony_ci else 17328c2ecf20Sopenharmony_ci reg = idx ? MT_WF_PHY_RXTD2(17) : MT_WF_PHY_RXTD(20); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { 17358c2ecf20Sopenharmony_ci val = mt76_rr(dev, reg); 17368c2ecf20Sopenharmony_ci sum += val * nf_power[i]; 17378c2ecf20Sopenharmony_ci n += val; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (!n) 17418c2ecf20Sopenharmony_ci return 0; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci return sum / n; 17448c2ecf20Sopenharmony_ci} 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_cistatic void 17478c2ecf20Sopenharmony_cimt7615_phy_update_channel(struct mt76_phy *mphy, int idx) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76); 17508c2ecf20Sopenharmony_ci struct mt7615_phy *phy = mphy->priv; 17518c2ecf20Sopenharmony_ci struct mt76_channel_state *state; 17528c2ecf20Sopenharmony_ci u64 busy_time, tx_time, rx_time, obss_time; 17538c2ecf20Sopenharmony_ci u32 obss_reg = idx ? MT_WF_RMAC_MIB_TIME6 : MT_WF_RMAC_MIB_TIME5; 17548c2ecf20Sopenharmony_ci int nf; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), 17578c2ecf20Sopenharmony_ci MT_MIB_SDR9_BUSY_MASK); 17588c2ecf20Sopenharmony_ci tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), 17598c2ecf20Sopenharmony_ci MT_MIB_SDR36_TXTIME_MASK); 17608c2ecf20Sopenharmony_ci rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), 17618c2ecf20Sopenharmony_ci MT_MIB_SDR37_RXTIME_MASK); 17628c2ecf20Sopenharmony_ci obss_time = mt76_get_field(dev, obss_reg, MT_MIB_OBSSTIME_MASK); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci nf = mt7615_phy_get_nf(dev, idx); 17658c2ecf20Sopenharmony_ci if (!phy->noise) 17668c2ecf20Sopenharmony_ci phy->noise = nf << 4; 17678c2ecf20Sopenharmony_ci else if (nf) 17688c2ecf20Sopenharmony_ci phy->noise += nf - (phy->noise >> 4); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci state = mphy->chan_state; 17718c2ecf20Sopenharmony_ci state->cc_busy += busy_time; 17728c2ecf20Sopenharmony_ci state->cc_tx += tx_time; 17738c2ecf20Sopenharmony_ci state->cc_rx += rx_time + obss_time; 17748c2ecf20Sopenharmony_ci state->cc_bss_rx += rx_time; 17758c2ecf20Sopenharmony_ci state->noise = -(phy->noise >> 4); 17768c2ecf20Sopenharmony_ci} 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_cistatic void __mt7615_update_channel(struct mt7615_dev *dev) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci mt7615_phy_update_channel(&mdev->phy, 0); 17838c2ecf20Sopenharmony_ci if (mdev->phy2) 17848c2ecf20Sopenharmony_ci mt7615_phy_update_channel(mdev->phy2, 1); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci /* reset obss airtime */ 17878c2ecf20Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); 17888c2ecf20Sopenharmony_ci} 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_civoid mt7615_update_channel(struct mt76_dev *mdev) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (mt7615_pm_wake(dev)) 17958c2ecf20Sopenharmony_ci return; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci __mt7615_update_channel(dev); 17988c2ecf20Sopenharmony_ci mt7615_pm_power_save_sched(dev); 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_update_channel); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_cistatic void mt7615_update_survey(struct mt7615_dev *dev) 18038c2ecf20Sopenharmony_ci{ 18048c2ecf20Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 18058c2ecf20Sopenharmony_ci ktime_t cur_time; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci __mt7615_update_channel(dev); 18088c2ecf20Sopenharmony_ci cur_time = ktime_get_boottime(); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci mt76_update_survey_active_time(&mdev->phy, cur_time); 18118c2ecf20Sopenharmony_ci if (mdev->phy2) 18128c2ecf20Sopenharmony_ci mt76_update_survey_active_time(mdev->phy2, cur_time); 18138c2ecf20Sopenharmony_ci} 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cistatic void 18168c2ecf20Sopenharmony_cimt7615_mac_update_mib_stats(struct mt7615_phy *phy) 18178c2ecf20Sopenharmony_ci{ 18188c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 18198c2ecf20Sopenharmony_ci struct mib_stats *mib = &phy->mib; 18208c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 18218c2ecf20Sopenharmony_ci int i, aggr; 18228c2ecf20Sopenharmony_ci u32 val, val2; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(ext_phy), 18258c2ecf20Sopenharmony_ci MT_MIB_SDR3_FCS_ERR_MASK); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci val = mt76_get_field(dev, MT_MIB_SDR14(ext_phy), 18288c2ecf20Sopenharmony_ci MT_MIB_AMPDU_MPDU_COUNT); 18298c2ecf20Sopenharmony_ci if (val) { 18308c2ecf20Sopenharmony_ci val2 = mt76_get_field(dev, MT_MIB_SDR15(ext_phy), 18318c2ecf20Sopenharmony_ci MT_MIB_AMPDU_ACK_COUNT); 18328c2ecf20Sopenharmony_ci mib->aggr_per = 1000 * (val - val2) / val; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci aggr = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; 18368c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 18378c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_SDR1(ext_phy, i)); 18388c2ecf20Sopenharmony_ci mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); 18398c2ecf20Sopenharmony_ci mib->ack_fail_cnt += FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, 18408c2ecf20Sopenharmony_ci val); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i)); 18438c2ecf20Sopenharmony_ci mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); 18448c2ecf20Sopenharmony_ci mib->rts_retries_cnt += FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, 18458c2ecf20Sopenharmony_ci val); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); 18488c2ecf20Sopenharmony_ci dev->mt76.aggr_stats[aggr++] += val & 0xffff; 18498c2ecf20Sopenharmony_ci dev->mt76.aggr_stats[aggr++] += val >> 16; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_civoid mt7615_pm_wake_work(struct work_struct *work) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci struct mt7615_dev *dev; 18568c2ecf20Sopenharmony_ci struct mt76_phy *mphy; 18578c2ecf20Sopenharmony_ci int i; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, 18608c2ecf20Sopenharmony_ci pm.wake_work); 18618c2ecf20Sopenharmony_ci mphy = dev->phy.mt76; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci if (mt7615_mcu_set_drv_ctrl(dev)) { 18648c2ecf20Sopenharmony_ci dev_err(mphy->dev->dev, "failed to wake device\n"); 18658c2ecf20Sopenharmony_ci goto out; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci spin_lock_bh(&dev->pm.txq_lock); 18698c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 18708c2ecf20Sopenharmony_ci struct mt7615_sta *msta = dev->pm.tx_q[i].msta; 18718c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = NULL; 18728c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (!dev->pm.tx_q[i].skb) 18758c2ecf20Sopenharmony_ci continue; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci wcid = msta ? &msta->wcid : &dev->mt76.global_wcid; 18788c2ecf20Sopenharmony_ci if (msta && wcid->sta) 18798c2ecf20Sopenharmony_ci sta = container_of((void *)msta, struct ieee80211_sta, 18808c2ecf20Sopenharmony_ci drv_priv); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci mt76_tx(mphy, sta, wcid, dev->pm.tx_q[i].skb); 18838c2ecf20Sopenharmony_ci dev->pm.tx_q[i].skb = NULL; 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->pm.txq_lock); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci mt76_worker_schedule(&dev->mt76.tx_worker); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ciout: 18908c2ecf20Sopenharmony_ci ieee80211_wake_queues(mphy->hw); 18918c2ecf20Sopenharmony_ci complete_all(&dev->pm.wake_cmpl); 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ciint mt7615_pm_wake(struct mt7615_dev *dev) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci struct mt76_phy *mphy = dev->phy.mt76; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 18998c2ecf20Sopenharmony_ci return 0; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (!mt76_is_mmio(mphy->dev)) 19028c2ecf20Sopenharmony_ci return 0; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_PM, &mphy->state)) 19058c2ecf20Sopenharmony_ci return 0; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci if (test_bit(MT76_HW_SCANNING, &mphy->state) || 19088c2ecf20Sopenharmony_ci test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) 19098c2ecf20Sopenharmony_ci return 0; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci if (queue_work(dev->mt76.wq, &dev->pm.wake_work)) 19128c2ecf20Sopenharmony_ci reinit_completion(&dev->pm.wake_cmpl); 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&dev->pm.wake_cmpl, 3 * HZ)) { 19158c2ecf20Sopenharmony_ci ieee80211_wake_queues(mphy->hw); 19168c2ecf20Sopenharmony_ci return -ETIMEDOUT; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci return 0; 19208c2ecf20Sopenharmony_ci} 19218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_pm_wake); 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_civoid mt7615_pm_power_save_sched(struct mt7615_dev *dev) 19248c2ecf20Sopenharmony_ci{ 19258c2ecf20Sopenharmony_ci struct mt76_phy *mphy = dev->phy.mt76; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 19288c2ecf20Sopenharmony_ci return; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci if (!mt76_is_mmio(mphy->dev)) 19318c2ecf20Sopenharmony_ci return; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci if (!dev->pm.enable || !test_bit(MT76_STATE_RUNNING, &mphy->state)) 19348c2ecf20Sopenharmony_ci return; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci dev->pm.last_activity = jiffies; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci if (test_bit(MT76_HW_SCANNING, &mphy->state) || 19398c2ecf20Sopenharmony_ci test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) 19408c2ecf20Sopenharmony_ci return; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_PM, &mphy->state)) 19438c2ecf20Sopenharmony_ci queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, 19448c2ecf20Sopenharmony_ci dev->pm.idle_timeout); 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_pm_power_save_sched); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_civoid mt7615_pm_power_save_work(struct work_struct *work) 19498c2ecf20Sopenharmony_ci{ 19508c2ecf20Sopenharmony_ci struct mt7615_dev *dev; 19518c2ecf20Sopenharmony_ci unsigned long delta; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, 19548c2ecf20Sopenharmony_ci pm.ps_work.work); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci delta = dev->pm.idle_timeout; 19578c2ecf20Sopenharmony_ci if (time_is_after_jiffies(dev->pm.last_activity + delta)) { 19588c2ecf20Sopenharmony_ci delta = dev->pm.last_activity + delta - jiffies; 19598c2ecf20Sopenharmony_ci goto out; 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci if (!mt7615_mcu_set_fw_ctrl(dev)) 19638c2ecf20Sopenharmony_ci return; 19648c2ecf20Sopenharmony_ciout: 19658c2ecf20Sopenharmony_ci queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_cistatic void 19698c2ecf20Sopenharmony_cimt7615_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci struct mt7615_phy *phy = priv; 19728c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 19738c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci if (mt7615_mcu_set_bss_pm(dev, vif, dev->pm.enable)) 19768c2ecf20Sopenharmony_ci return; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (dev->pm.enable) { 19798c2ecf20Sopenharmony_ci vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; 19808c2ecf20Sopenharmony_ci mt76_set(dev, MT_WF_RFCR(ext_phy), 19818c2ecf20Sopenharmony_ci MT_WF_RFCR_DROP_OTHER_BEACON); 19828c2ecf20Sopenharmony_ci } else { 19838c2ecf20Sopenharmony_ci vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; 19848c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WF_RFCR(ext_phy), 19858c2ecf20Sopenharmony_ci MT_WF_RFCR_DROP_OTHER_BEACON); 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ciint mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable) 19908c2ecf20Sopenharmony_ci{ 19918c2ecf20Sopenharmony_ci struct mt76_phy *mphy = dev->phy.mt76; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76)) 19948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci mt7615_mutex_acquire(dev); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci if (dev->pm.enable == enable) 19998c2ecf20Sopenharmony_ci goto out; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci dev->pm.enable = enable; 20028c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces(mphy->hw, 20038c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 20048c2ecf20Sopenharmony_ci mt7615_pm_interface_iter, mphy->priv); 20058c2ecf20Sopenharmony_ciout: 20068c2ecf20Sopenharmony_ci mt7615_mutex_release(dev); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci return 0; 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_civoid mt7615_mac_work(struct work_struct *work) 20128c2ecf20Sopenharmony_ci{ 20138c2ecf20Sopenharmony_ci struct mt7615_phy *phy; 20148c2ecf20Sopenharmony_ci struct mt76_dev *mdev; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, 20178c2ecf20Sopenharmony_ci mac_work.work); 20188c2ecf20Sopenharmony_ci mdev = &phy->dev->mt76; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci mt7615_mutex_acquire(phy->dev); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci mt7615_update_survey(phy->dev); 20238c2ecf20Sopenharmony_ci if (++phy->mac_work_count == 5) { 20248c2ecf20Sopenharmony_ci phy->mac_work_count = 0; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci mt7615_mac_update_mib_stats(phy); 20278c2ecf20Sopenharmony_ci mt7615_mac_scs_check(phy); 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci mt7615_mutex_release(phy->dev); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci mt76_tx_status_check(mdev, NULL, false); 20338c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, 20348c2ecf20Sopenharmony_ci MT7615_WATCHDOG_TIME); 20358c2ecf20Sopenharmony_ci} 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_cistatic bool 20388c2ecf20Sopenharmony_cimt7615_wait_reset_state(struct mt7615_dev *dev, u32 state) 20398c2ecf20Sopenharmony_ci{ 20408c2ecf20Sopenharmony_ci bool ret; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci ret = wait_event_timeout(dev->reset_wait, 20438c2ecf20Sopenharmony_ci (READ_ONCE(dev->reset_state) & state), 20448c2ecf20Sopenharmony_ci MT7615_RESET_TIMEOUT); 20458c2ecf20Sopenharmony_ci WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); 20468c2ecf20Sopenharmony_ci return ret; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_cistatic void 20508c2ecf20Sopenharmony_cimt7615_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = priv; 20538c2ecf20Sopenharmony_ci struct mt7615_dev *dev = mt7615_hw_dev(hw); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci mt7615_mcu_add_beacon(dev, hw, vif, vif->bss_conf.enable_beacon); 20568c2ecf20Sopenharmony_ci} 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_cistatic void 20598c2ecf20Sopenharmony_cimt7615_update_beacons(struct mt7615_dev *dev) 20608c2ecf20Sopenharmony_ci{ 20618c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces(dev->mt76.hw, 20628c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 20638c2ecf20Sopenharmony_ci mt7615_update_vif_beacon, dev->mt76.hw); 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci if (!dev->mt76.phy2) 20668c2ecf20Sopenharmony_ci return; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw, 20698c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 20708c2ecf20Sopenharmony_ci mt7615_update_vif_beacon, dev->mt76.phy2->hw); 20718c2ecf20Sopenharmony_ci} 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_civoid mt7615_dma_reset(struct mt7615_dev *dev) 20748c2ecf20Sopenharmony_ci{ 20758c2ecf20Sopenharmony_ci int i; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, 20788c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN | 20798c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); 20808c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci for (i = 0; i < __MT_TXQ_MAX; i++) 20838c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, true); 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) { 20868c2ecf20Sopenharmony_ci mt76_queue_rx_reset(dev, i); 20878c2ecf20Sopenharmony_ci } 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci mt76_set(dev, MT_WPDMA_GLO_CFG, 20908c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN | 20918c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); 20928c2ecf20Sopenharmony_ci} 20938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_dma_reset); 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_civoid mt7615_tx_token_put(struct mt7615_dev *dev) 20968c2ecf20Sopenharmony_ci{ 20978c2ecf20Sopenharmony_ci struct mt76_txwi_cache *txwi; 20988c2ecf20Sopenharmony_ci int id; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci spin_lock_bh(&dev->token_lock); 21018c2ecf20Sopenharmony_ci idr_for_each_entry(&dev->token, txwi, id) { 21028c2ecf20Sopenharmony_ci mt7615_txp_skb_unmap(&dev->mt76, txwi); 21038c2ecf20Sopenharmony_ci if (txwi->skb) { 21048c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); 21078c2ecf20Sopenharmony_ci ieee80211_free_txskb(hw, txwi->skb); 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci mt76_put_txwi(&dev->mt76, txwi); 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->token_lock); 21128c2ecf20Sopenharmony_ci idr_destroy(&dev->token); 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_tx_token_put); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_civoid mt7615_mac_reset_work(struct work_struct *work) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci struct mt7615_phy *phy2; 21198c2ecf20Sopenharmony_ci struct mt76_phy *ext_phy; 21208c2ecf20Sopenharmony_ci struct mt7615_dev *dev; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci dev = container_of(work, struct mt7615_dev, reset_work); 21238c2ecf20Sopenharmony_ci ext_phy = dev->mt76.phy2; 21248c2ecf20Sopenharmony_ci phy2 = ext_phy ? ext_phy->priv : NULL; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_PDMA)) 21278c2ecf20Sopenharmony_ci return; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci ieee80211_stop_queues(mt76_hw(dev)); 21308c2ecf20Sopenharmony_ci if (ext_phy) 21318c2ecf20Sopenharmony_ci ieee80211_stop_queues(ext_phy->hw); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 21348c2ecf20Sopenharmony_ci set_bit(MT76_MCU_RESET, &dev->mphy.state); 21358c2ecf20Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 21368c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&dev->phy.mac_work); 21378c2ecf20Sopenharmony_ci del_timer_sync(&dev->phy.roc_timer); 21388c2ecf20Sopenharmony_ci cancel_work_sync(&dev->phy.roc_work); 21398c2ecf20Sopenharmony_ci if (phy2) { 21408c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&phy2->mac_work); 21418c2ecf20Sopenharmony_ci del_timer_sync(&phy2->roc_timer); 21428c2ecf20Sopenharmony_ci cancel_work_sync(&phy2->roc_work); 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci /* lock/unlock all queues to ensure that no tx is pending */ 21468c2ecf20Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 21478c2ecf20Sopenharmony_ci if (ext_phy) 21488c2ecf20Sopenharmony_ci mt76_txq_schedule_all(ext_phy); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 21518c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.napi[0]); 21528c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.napi[1]); 21538c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.tx_napi); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci mt7615_mutex_acquire(dev); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_STOPPED); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci mt7615_tx_token_put(dev); 21608c2ecf20Sopenharmony_ci idr_init(&dev->token); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (mt7615_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { 21638c2ecf20Sopenharmony_ci mt7615_dma_reset(dev); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WPDMA_MEM_RNG_ERR, 0); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_INIT); 21688c2ecf20Sopenharmony_ci mt7615_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci clear_bit(MT76_MCU_RESET, &dev->mphy.state); 21728c2ecf20Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 21758c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 21768c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.napi[0]); 21798c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[0]); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.napi[1]); 21828c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[1]); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci ieee80211_wake_queues(mt76_hw(dev)); 21858c2ecf20Sopenharmony_ci if (ext_phy) 21868c2ecf20Sopenharmony_ci ieee80211_wake_queues(ext_phy->hw); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); 21898c2ecf20Sopenharmony_ci mt7615_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci mt7615_update_beacons(dev); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci mt7615_mutex_release(dev); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work, 21968c2ecf20Sopenharmony_ci MT7615_WATCHDOG_TIME); 21978c2ecf20Sopenharmony_ci if (phy2) 21988c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mac_work, 21998c2ecf20Sopenharmony_ci MT7615_WATCHDOG_TIME); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci} 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_cistatic void mt7615_dfs_stop_radar_detector(struct mt7615_phy *phy) 22048c2ecf20Sopenharmony_ci{ 22058c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci if (phy->rdd_state & BIT(0)) 22088c2ecf20Sopenharmony_ci mt7615_mcu_rdd_cmd(dev, RDD_STOP, 0, MT_RX_SEL0, 0); 22098c2ecf20Sopenharmony_ci if (phy->rdd_state & BIT(1)) 22108c2ecf20Sopenharmony_ci mt7615_mcu_rdd_cmd(dev, RDD_STOP, 1, MT_RX_SEL0, 0); 22118c2ecf20Sopenharmony_ci} 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_cistatic int mt7615_dfs_start_rdd(struct mt7615_dev *dev, int chain) 22148c2ecf20Sopenharmony_ci{ 22158c2ecf20Sopenharmony_ci int err; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci err = mt7615_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, 0); 22188c2ecf20Sopenharmony_ci if (err < 0) 22198c2ecf20Sopenharmony_ci return err; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci return mt7615_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, 22228c2ecf20Sopenharmony_ci MT_RX_SEL0, 1); 22238c2ecf20Sopenharmony_ci} 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_cistatic int mt7615_dfs_start_radar_detector(struct mt7615_phy *phy) 22268c2ecf20Sopenharmony_ci{ 22278c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 22288c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 22298c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 22308c2ecf20Sopenharmony_ci int err; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci /* start CAC */ 22338c2ecf20Sopenharmony_ci err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_START, ext_phy, MT_RX_SEL0, 0); 22348c2ecf20Sopenharmony_ci if (err < 0) 22358c2ecf20Sopenharmony_ci return err; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci err = mt7615_dfs_start_rdd(dev, ext_phy); 22388c2ecf20Sopenharmony_ci if (err < 0) 22398c2ecf20Sopenharmony_ci return err; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci phy->rdd_state |= BIT(ext_phy); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_160 || 22448c2ecf20Sopenharmony_ci chandef->width == NL80211_CHAN_WIDTH_80P80) { 22458c2ecf20Sopenharmony_ci err = mt7615_dfs_start_rdd(dev, 1); 22468c2ecf20Sopenharmony_ci if (err < 0) 22478c2ecf20Sopenharmony_ci return err; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci phy->rdd_state |= BIT(1); 22508c2ecf20Sopenharmony_ci } 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci return 0; 22538c2ecf20Sopenharmony_ci} 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_cistatic int 22568c2ecf20Sopenharmony_cimt7615_dfs_init_radar_specs(struct mt7615_phy *phy) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci const struct mt7615_dfs_radar_spec *radar_specs; 22598c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 22608c2ecf20Sopenharmony_ci int err, i; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci switch (dev->mt76.region) { 22638c2ecf20Sopenharmony_ci case NL80211_DFS_FCC: 22648c2ecf20Sopenharmony_ci radar_specs = &fcc_radar_specs; 22658c2ecf20Sopenharmony_ci err = mt7615_mcu_set_fcc5_lpn(dev, 8); 22668c2ecf20Sopenharmony_ci if (err < 0) 22678c2ecf20Sopenharmony_ci return err; 22688c2ecf20Sopenharmony_ci break; 22698c2ecf20Sopenharmony_ci case NL80211_DFS_ETSI: 22708c2ecf20Sopenharmony_ci radar_specs = &etsi_radar_specs; 22718c2ecf20Sopenharmony_ci break; 22728c2ecf20Sopenharmony_ci case NL80211_DFS_JP: 22738c2ecf20Sopenharmony_ci radar_specs = &jp_radar_specs; 22748c2ecf20Sopenharmony_ci break; 22758c2ecf20Sopenharmony_ci default: 22768c2ecf20Sopenharmony_ci return -EINVAL; 22778c2ecf20Sopenharmony_ci } 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { 22808c2ecf20Sopenharmony_ci err = mt7615_mcu_set_radar_th(dev, i, 22818c2ecf20Sopenharmony_ci &radar_specs->radar_pattern[i]); 22828c2ecf20Sopenharmony_ci if (err < 0) 22838c2ecf20Sopenharmony_ci return err; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci return mt7615_mcu_set_pulse_th(dev, &radar_specs->pulse_th); 22878c2ecf20Sopenharmony_ci} 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ciint mt7615_dfs_init_radar_detector(struct mt7615_phy *phy) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 22928c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 22938c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 22948c2ecf20Sopenharmony_ci int err; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) 22978c2ecf20Sopenharmony_ci return 0; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (dev->mt76.region == NL80211_DFS_UNSET) { 23008c2ecf20Sopenharmony_ci phy->dfs_state = -1; 23018c2ecf20Sopenharmony_ci if (phy->rdd_state) 23028c2ecf20Sopenharmony_ci goto stop; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci return 0; 23058c2ecf20Sopenharmony_ci } 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci if (test_bit(MT76_SCANNING, &phy->mt76->state)) 23088c2ecf20Sopenharmony_ci return 0; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (phy->dfs_state == chandef->chan->dfs_state) 23118c2ecf20Sopenharmony_ci return 0; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci err = mt7615_dfs_init_radar_specs(phy); 23148c2ecf20Sopenharmony_ci if (err < 0) { 23158c2ecf20Sopenharmony_ci phy->dfs_state = -1; 23168c2ecf20Sopenharmony_ci goto stop; 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci phy->dfs_state = chandef->chan->dfs_state; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (chandef->chan->flags & IEEE80211_CHAN_RADAR) { 23228c2ecf20Sopenharmony_ci if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 23238c2ecf20Sopenharmony_ci return mt7615_dfs_start_radar_detector(phy); 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy, 23268c2ecf20Sopenharmony_ci MT_RX_SEL0, 0); 23278c2ecf20Sopenharmony_ci } 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_cistop: 23308c2ecf20Sopenharmony_ci err = mt7615_mcu_rdd_cmd(dev, RDD_NORMAL_START, ext_phy, MT_RX_SEL0, 0); 23318c2ecf20Sopenharmony_ci if (err < 0) 23328c2ecf20Sopenharmony_ci return err; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci mt7615_dfs_stop_radar_detector(phy); 23358c2ecf20Sopenharmony_ci return 0; 23368c2ecf20Sopenharmony_ci} 2337