18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "mt7601u.h" 88c2ecf20Sopenharmony_ci#include "trace.h" 98c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_civoid mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci ether_addr_copy(dev->macaddr, addr); 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(dev->macaddr)) { 168c2ecf20Sopenharmony_ci eth_random_addr(dev->macaddr); 178c2ecf20Sopenharmony_ci dev_info(dev->dev, 188c2ecf20Sopenharmony_ci "Invalid MAC address, using random address %pM\n", 198c2ecf20Sopenharmony_ci dev->macaddr); 208c2ecf20Sopenharmony_ci } 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); 238c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) | 248c2ecf20Sopenharmony_ci FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic void 288c2ecf20Sopenharmony_cimt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci u8 idx = FIELD_GET(MT_TXWI_RATE_MCS, rate); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci txrate->idx = 0; 338c2ecf20Sopenharmony_ci txrate->flags = 0; 348c2ecf20Sopenharmony_ci txrate->count = 1; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_TXWI_RATE_PHY_MODE, rate)) { 378c2ecf20Sopenharmony_ci case MT_PHY_TYPE_OFDM: 388c2ecf20Sopenharmony_ci txrate->idx = idx + 4; 398c2ecf20Sopenharmony_ci return; 408c2ecf20Sopenharmony_ci case MT_PHY_TYPE_CCK: 418c2ecf20Sopenharmony_ci if (idx >= 8) 428c2ecf20Sopenharmony_ci idx -= 8; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci txrate->idx = idx; 458c2ecf20Sopenharmony_ci return; 468c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 478c2ecf20Sopenharmony_ci txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; 488c2ecf20Sopenharmony_ci fallthrough; 498c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT: 508c2ecf20Sopenharmony_ci txrate->flags |= IEEE80211_TX_RC_MCS; 518c2ecf20Sopenharmony_ci txrate->idx = idx; 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci default: 548c2ecf20Sopenharmony_ci WARN_ON(1); 558c2ecf20Sopenharmony_ci return; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (FIELD_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40) 598c2ecf20Sopenharmony_ci txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (rate & MT_TXWI_RATE_SGI) 628c2ecf20Sopenharmony_ci txrate->flags |= IEEE80211_TX_RC_SHORT_GI; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void 668c2ecf20Sopenharmony_cimt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info, 678c2ecf20Sopenharmony_ci struct mt76_tx_status *st) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rate = info->status.rates; 708c2ecf20Sopenharmony_ci int cur_idx, last_rate; 718c2ecf20Sopenharmony_ci int i; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); 748c2ecf20Sopenharmony_ci mt76_mac_process_tx_rate(&rate[last_rate], st->rate); 758c2ecf20Sopenharmony_ci if (last_rate < IEEE80211_TX_MAX_RATES - 1) 768c2ecf20Sopenharmony_ci rate[last_rate + 1].idx = -1; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci cur_idx = rate[last_rate].idx + st->retry; 798c2ecf20Sopenharmony_ci for (i = 0; i <= last_rate; i++) { 808c2ecf20Sopenharmony_ci rate[i].flags = rate[last_rate].flags; 818c2ecf20Sopenharmony_ci rate[i].idx = max_t(int, 0, cur_idx - i); 828c2ecf20Sopenharmony_ci rate[i].count = 1; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (last_rate > 0) 868c2ecf20Sopenharmony_ci rate[last_rate - 1].count = st->retry + 1 - last_rate; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci info->status.ampdu_len = 1; 898c2ecf20Sopenharmony_ci info->status.ampdu_ack_len = st->success; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (st->is_probe) 928c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (st->aggr) 958c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_AMPDU | 968c2ecf20Sopenharmony_ci IEEE80211_TX_STAT_AMPDU; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!st->ack_req) 998c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_NO_ACK; 1008c2ecf20Sopenharmony_ci else if (st->success) 1018c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciu16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev, 1058c2ecf20Sopenharmony_ci const struct ieee80211_tx_rate *rate, u8 *nss_val) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci u16 rateval; 1088c2ecf20Sopenharmony_ci u8 phy, rate_idx; 1098c2ecf20Sopenharmony_ci u8 nss = 1; 1108c2ecf20Sopenharmony_ci u8 bw = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_MCS) { 1138c2ecf20Sopenharmony_ci rate_idx = rate->idx; 1148c2ecf20Sopenharmony_ci nss = 1 + (rate->idx >> 3); 1158c2ecf20Sopenharmony_ci phy = MT_PHY_TYPE_HT; 1168c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) 1178c2ecf20Sopenharmony_ci phy = MT_PHY_TYPE_HT_GF; 1188c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1198c2ecf20Sopenharmony_ci bw = 1; 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci const struct ieee80211_rate *r; 1228c2ecf20Sopenharmony_ci int band = dev->chandef.chan->band; 1238c2ecf20Sopenharmony_ci u16 val; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx]; 1268c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 1278c2ecf20Sopenharmony_ci val = r->hw_value_short; 1288c2ecf20Sopenharmony_ci else 1298c2ecf20Sopenharmony_ci val = r->hw_value; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci phy = val >> 8; 1328c2ecf20Sopenharmony_ci rate_idx = val & 0xff; 1338c2ecf20Sopenharmony_ci bw = 0; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci rateval = FIELD_PREP(MT_RXWI_RATE_MCS, rate_idx); 1378c2ecf20Sopenharmony_ci rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); 1388c2ecf20Sopenharmony_ci rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); 1398c2ecf20Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_SHORT_GI) 1408c2ecf20Sopenharmony_ci rateval |= MT_RXWI_RATE_SGI; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci *nss_val = nss; 1438c2ecf20Sopenharmony_ci return rateval; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_civoid mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid, 1478c2ecf20Sopenharmony_ci const struct ieee80211_tx_rate *rate) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci unsigned long flags; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 1528c2ecf20Sopenharmony_ci wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); 1538c2ecf20Sopenharmony_ci wcid->tx_rate_set = true; 1548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistruct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct mt76_tx_status stat = {}; 1608c2ecf20Sopenharmony_ci u32 val; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci val = mt7601u_rr(dev, MT_TX_STAT_FIFO); 1638c2ecf20Sopenharmony_ci stat.valid = !!(val & MT_TX_STAT_FIFO_VALID); 1648c2ecf20Sopenharmony_ci stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS); 1658c2ecf20Sopenharmony_ci stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR); 1668c2ecf20Sopenharmony_ci stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ); 1678c2ecf20Sopenharmony_ci stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_PID_TYPE, val); 1688c2ecf20Sopenharmony_ci stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, val); 1698c2ecf20Sopenharmony_ci stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, val); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return stat; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_civoid mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct ieee80211_tx_info info = {}; 1778c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = NULL; 1788c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = NULL; 1798c2ecf20Sopenharmony_ci void *msta; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci rcu_read_lock(); 1828c2ecf20Sopenharmony_ci if (stat->wcid < ARRAY_SIZE(dev->wcid)) 1838c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->wcid[stat->wcid]); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (wcid) { 1868c2ecf20Sopenharmony_ci msta = container_of(wcid, struct mt76_sta, wcid); 1878c2ecf20Sopenharmony_ci sta = container_of(msta, struct ieee80211_sta, 1888c2ecf20Sopenharmony_ci drv_priv); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci mt76_mac_fill_tx_status(dev, &info, stat); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci spin_lock_bh(&dev->mac_lock); 1948c2ecf20Sopenharmony_ci ieee80211_tx_status_noskb(dev->hw, sta, &info); 1958c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->mac_lock); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci rcu_read_unlock(); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_civoid mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot, 2018c2ecf20Sopenharmony_ci int ht_mode) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; 2048c2ecf20Sopenharmony_ci bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 2058c2ecf20Sopenharmony_ci u32 prot[6]; 2068c2ecf20Sopenharmony_ci bool ht_rts[4] = {}; 2078c2ecf20Sopenharmony_ci int i; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci prot[0] = MT_PROT_NAV_SHORT | 2108c2ecf20Sopenharmony_ci MT_PROT_TXOP_ALLOW_ALL | 2118c2ecf20Sopenharmony_ci MT_PROT_RTS_THR_EN; 2128c2ecf20Sopenharmony_ci prot[1] = prot[0]; 2138c2ecf20Sopenharmony_ci if (legacy_prot) 2148c2ecf20Sopenharmony_ci prot[1] |= MT_PROT_CTRL_CTS2SELF; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20; 2178c2ecf20Sopenharmony_ci prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (legacy_prot) { 2208c2ecf20Sopenharmony_ci prot[2] |= MT_PROT_RATE_CCK_11; 2218c2ecf20Sopenharmony_ci prot[3] |= MT_PROT_RATE_CCK_11; 2228c2ecf20Sopenharmony_ci prot[4] |= MT_PROT_RATE_CCK_11; 2238c2ecf20Sopenharmony_ci prot[5] |= MT_PROT_RATE_CCK_11; 2248c2ecf20Sopenharmony_ci } else { 2258c2ecf20Sopenharmony_ci prot[2] |= MT_PROT_RATE_OFDM_24; 2268c2ecf20Sopenharmony_ci prot[3] |= MT_PROT_RATE_DUP_OFDM_24; 2278c2ecf20Sopenharmony_ci prot[4] |= MT_PROT_RATE_OFDM_24; 2288c2ecf20Sopenharmony_ci prot[5] |= MT_PROT_RATE_DUP_OFDM_24; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci switch (mode) { 2328c2ecf20Sopenharmony_ci case IEEE80211_HT_OP_MODE_PROTECTION_NONE: 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: 2368c2ecf20Sopenharmony_ci ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: 2408c2ecf20Sopenharmony_ci ht_rts[1] = ht_rts[3] = true; 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: 2448c2ecf20Sopenharmony_ci ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (non_gf) 2498c2ecf20Sopenharmony_ci ht_rts[2] = ht_rts[3] = true; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 2528c2ecf20Sopenharmony_ci if (ht_rts[i]) 2538c2ecf20Sopenharmony_ci prot[i + 2] |= MT_PROT_CTRL_RTS_CTS; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 2568c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_civoid mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci if (short_preamb) 2628c2ecf20Sopenharmony_ci mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_civoid mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci val &= ~(MT_BEACON_TIME_CFG_TIMER_EN | 2728c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_SYNC_MODE | 2738c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_TBTT_EN); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (!enable) { 2768c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_BEACON_TIME_CFG, val); 2778c2ecf20Sopenharmony_ci return; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci val &= ~MT_BEACON_TIME_CFG_INTVAL; 2818c2ecf20Sopenharmony_ci val |= FIELD_PREP(MT_BEACON_TIME_CFG_INTVAL, interval << 4) | 2828c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_TIMER_EN | 2838c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_SYNC_MODE | 2848c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_TBTT_EN; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic void mt7601u_check_mac_err(struct mt7601u_dev *dev) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci u32 val = mt7601u_rr(dev, 0x10f4); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) 2928c2ecf20Sopenharmony_ci return; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci dev_err(dev->dev, "Error: MAC specific condition occurred\n"); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); 2978c2ecf20Sopenharmony_ci udelay(10); 2988c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_civoid mt7601u_mac_work(struct work_struct *work) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, 3048c2ecf20Sopenharmony_ci mac_work.work); 3058c2ecf20Sopenharmony_ci struct { 3068c2ecf20Sopenharmony_ci u32 addr_base; 3078c2ecf20Sopenharmony_ci u32 span; 3088c2ecf20Sopenharmony_ci u64 *stat_base; 3098c2ecf20Sopenharmony_ci } spans[] = { 3108c2ecf20Sopenharmony_ci { MT_RX_STA_CNT0, 3, dev->stats.rx_stat }, 3118c2ecf20Sopenharmony_ci { MT_TX_STA_CNT0, 3, dev->stats.tx_stat }, 3128c2ecf20Sopenharmony_ci { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat }, 3138c2ecf20Sopenharmony_ci { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del }, 3148c2ecf20Sopenharmony_ci { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] }, 3158c2ecf20Sopenharmony_ci { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] }, 3168c2ecf20Sopenharmony_ci }; 3178c2ecf20Sopenharmony_ci u32 sum, n; 3188c2ecf20Sopenharmony_ci int i, j, k; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Note: using MCU_RANDOM_READ is actually slower then reading all the 3218c2ecf20Sopenharmony_ci * registers by hand. MCU takes ca. 20ms to complete read of 24 3228c2ecf20Sopenharmony_ci * registers while reading them one by one will takes roughly 3238c2ecf20Sopenharmony_ci * 24*200us =~ 5ms. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci k = 0; 3278c2ecf20Sopenharmony_ci n = 0; 3288c2ecf20Sopenharmony_ci sum = 0; 3298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(spans); i++) 3308c2ecf20Sopenharmony_ci for (j = 0; j < spans[i].span; j++) { 3318c2ecf20Sopenharmony_ci u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci spans[i].stat_base[j * 2] += val & 0xffff; 3348c2ecf20Sopenharmony_ci spans[i].stat_base[j * 2 + 1] += val >> 16; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Calculate average AMPDU length */ 3378c2ecf20Sopenharmony_ci if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 && 3388c2ecf20Sopenharmony_ci spans[i].addr_base != MT_TX_AGG_CNT_BASE1) 3398c2ecf20Sopenharmony_ci continue; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci n += (val >> 16) + (val & 0xffff); 3428c2ecf20Sopenharmony_ci sum += (val & 0xffff) * (1 + k * 2) + 3438c2ecf20Sopenharmony_ci (val >> 16) * (2 + k * 2); 3448c2ecf20Sopenharmony_ci k++; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci mt7601u_check_mac_err(dev); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_civoid 3558c2ecf20Sopenharmony_cimt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci u8 zmac[ETH_ALEN] = {}; 3588c2ecf20Sopenharmony_ci u32 attr; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | 3618c2ecf20Sopenharmony_ci FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WCID_ATTR(idx), attr); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (mac) 3668c2ecf20Sopenharmony_ci memcpy(zmac, mac, sizeof(zmac)); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_civoid mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 3748c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 3758c2ecf20Sopenharmony_ci void *msta; 3768c2ecf20Sopenharmony_ci u8 min_factor = 3; 3778c2ecf20Sopenharmony_ci int i; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci rcu_read_lock(); 3808c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { 3818c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->wcid[i]); 3828c2ecf20Sopenharmony_ci if (!wcid) 3838c2ecf20Sopenharmony_ci continue; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci msta = container_of(wcid, struct mt76_sta, wcid); 3868c2ecf20Sopenharmony_ci sta = container_of(msta, struct ieee80211_sta, drv_priv); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci min_factor = min(min_factor, sta->ht_cap.ampdu_factor); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci rcu_read_unlock(); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff | 3938c2ecf20Sopenharmony_ci FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic void 3978c2ecf20Sopenharmony_cimt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci u8 idx = FIELD_GET(MT_RXWI_RATE_MCS, rate); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { 4028c2ecf20Sopenharmony_ci case MT_PHY_TYPE_OFDM: 4038c2ecf20Sopenharmony_ci if (WARN_ON(idx >= 8)) 4048c2ecf20Sopenharmony_ci idx = 0; 4058c2ecf20Sopenharmony_ci idx += 4; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci status->rate_idx = idx; 4088c2ecf20Sopenharmony_ci return; 4098c2ecf20Sopenharmony_ci case MT_PHY_TYPE_CCK: 4108c2ecf20Sopenharmony_ci if (idx >= 8) { 4118c2ecf20Sopenharmony_ci idx -= 8; 4128c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_SHORTPRE; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (WARN_ON(idx >= 4)) 4168c2ecf20Sopenharmony_ci idx = 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci status->rate_idx = idx; 4198c2ecf20Sopenharmony_ci return; 4208c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 4218c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_HT_GF; 4228c2ecf20Sopenharmony_ci fallthrough; 4238c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT: 4248c2ecf20Sopenharmony_ci status->encoding = RX_ENC_HT; 4258c2ecf20Sopenharmony_ci status->rate_idx = idx; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci default: 4288c2ecf20Sopenharmony_ci WARN_ON(1); 4298c2ecf20Sopenharmony_ci return; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (rate & MT_RXWI_RATE_SGI) 4338c2ecf20Sopenharmony_ci status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (rate & MT_RXWI_RATE_STBC) 4368c2ecf20Sopenharmony_ci status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (rate & MT_RXWI_RATE_BW) 4398c2ecf20Sopenharmony_ci status->bw = RATE_INFO_BW_40; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void 4438c2ecf20Sopenharmony_cimt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, 4448c2ecf20Sopenharmony_ci u16 rate, int rssi) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci dev->bcn_freq_off = rxwi->freq_off; 4478c2ecf20Sopenharmony_ci dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate); 4488c2ecf20Sopenharmony_ci ewma_rssi_add(&dev->avg_rssi, -rssi); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int 4528c2ecf20Sopenharmony_cimt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return ieee80211_is_beacon(hdr->frame_control) && 4578c2ecf20Sopenharmony_ci ether_addr_equal(hdr->addr2, dev->ap_bssid); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ciu32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, 4618c2ecf20Sopenharmony_ci u8 *data, void *rxi) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 4648c2ecf20Sopenharmony_ci struct mt7601u_rxwi *rxwi = rxi; 4658c2ecf20Sopenharmony_ci u32 len, ctl = le32_to_cpu(rxwi->ctl); 4668c2ecf20Sopenharmony_ci u16 rate = le16_to_cpu(rxwi->rate); 4678c2ecf20Sopenharmony_ci int rssi; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); 4708c2ecf20Sopenharmony_ci if (len < 10) 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { 4748c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_DECRYPTED; 4758c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_MMIC_STRIPPED; 4768c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_MIC_STRIPPED; 4778c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_ICV_STRIPPED; 4788c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_IV_STRIPPED; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci /* let mac80211 take care of PN validation since apparently 4818c2ecf20Sopenharmony_ci * the hardware does not support it 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_ci if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_PN_LEN)) 4848c2ecf20Sopenharmony_ci status->flag &= ~RX_FLAG_IV_STRIPPED; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci status->chains = BIT(0); 4878c2ecf20Sopenharmony_ci rssi = mt7601u_phy_get_rssi(dev, rxwi, rate); 4888c2ecf20Sopenharmony_ci status->chain_signal[0] = status->signal = rssi; 4898c2ecf20Sopenharmony_ci status->freq = dev->chandef.chan->center_freq; 4908c2ecf20Sopenharmony_ci status->band = dev->chandef.chan->band; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci mt76_mac_process_rate(status, rate); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci spin_lock_bh(&dev->con_mon_lock); 4958c2ecf20Sopenharmony_ci if (mt7601u_rx_is_our_beacon(dev, data)) 4968c2ecf20Sopenharmony_ci mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi); 4978c2ecf20Sopenharmony_ci else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) 4988c2ecf20Sopenharmony_ci ewma_rssi_add(&dev->avg_rssi, -rssi); 4998c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->con_mon_lock); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return len; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic enum mt76_cipher_type 5058c2ecf20Sopenharmony_cimt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci memset(key_data, 0, 32); 5088c2ecf20Sopenharmony_ci if (!key) 5098c2ecf20Sopenharmony_ci return MT_CIPHER_NONE; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (key->keylen > 32) 5128c2ecf20Sopenharmony_ci return MT_CIPHER_NONE; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci memcpy(key_data, key->key, key->keylen); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci switch (key->cipher) { 5178c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 5188c2ecf20Sopenharmony_ci return MT_CIPHER_WEP40; 5198c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 5208c2ecf20Sopenharmony_ci return MT_CIPHER_WEP104; 5218c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 5228c2ecf20Sopenharmony_ci return MT_CIPHER_TKIP; 5238c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 5248c2ecf20Sopenharmony_ci return MT_CIPHER_AES_CCMP; 5258c2ecf20Sopenharmony_ci default: 5268c2ecf20Sopenharmony_ci return MT_CIPHER_NONE; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ciint mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx, 5318c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci enum mt76_cipher_type cipher; 5348c2ecf20Sopenharmony_ci u8 key_data[32]; 5358c2ecf20Sopenharmony_ci u8 iv_data[8]; 5368c2ecf20Sopenharmony_ci u32 val; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci cipher = mt76_mac_get_key_info(key, key_data); 5398c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_NONE && key) 5408c2ecf20Sopenharmony_ci return -EINVAL; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci trace_set_key(dev, idx); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci memset(iv_data, 0, sizeof(iv_data)); 5478c2ecf20Sopenharmony_ci if (key) { 5488c2ecf20Sopenharmony_ci iv_data[3] = key->keyidx << 6; 5498c2ecf20Sopenharmony_ci if (cipher >= MT_CIPHER_TKIP) { 5508c2ecf20Sopenharmony_ci /* Note: start with 1 to comply with spec, 5518c2ecf20Sopenharmony_ci * (see comment on common/cmm_wpa.c:4291). 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ci iv_data[0] |= 1; 5548c2ecf20Sopenharmony_ci iv_data[3] |= 0x20; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci val = mt7601u_rr(dev, MT_WCID_ATTR(idx)); 5608c2ecf20Sopenharmony_ci val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT; 5618c2ecf20Sopenharmony_ci val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) | 5628c2ecf20Sopenharmony_ci FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3); 5638c2ecf20Sopenharmony_ci val &= ~MT_WCID_ATTR_PAIRWISE; 5648c2ecf20Sopenharmony_ci val |= MT_WCID_ATTR_PAIRWISE * 5658c2ecf20Sopenharmony_ci !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE); 5668c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_WCID_ATTR(idx), val); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ciint mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx, 5728c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci enum mt76_cipher_type cipher; 5758c2ecf20Sopenharmony_ci u8 key_data[32]; 5768c2ecf20Sopenharmony_ci u32 val; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci cipher = mt76_mac_get_key_info(key, key_data); 5798c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_NONE && key) 5808c2ecf20Sopenharmony_ci return -EINVAL; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci trace_set_shared_key(dev, vif_idx, key_idx); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx), 5858c2ecf20Sopenharmony_ci key_data, sizeof(key_data)); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); 5888c2ecf20Sopenharmony_ci val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); 5898c2ecf20Sopenharmony_ci val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); 5908c2ecf20Sopenharmony_ci mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 594