18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/firmware.h> 58c2ecf20Sopenharmony_ci#include <linux/fs.h> 68c2ecf20Sopenharmony_ci#include "mt7915.h" 78c2ecf20Sopenharmony_ci#include "mcu.h" 88c2ecf20Sopenharmony_ci#include "mac.h" 98c2ecf20Sopenharmony_ci#include "eeprom.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistruct mt7915_patch_hdr { 128c2ecf20Sopenharmony_ci char build_date[16]; 138c2ecf20Sopenharmony_ci char platform[4]; 148c2ecf20Sopenharmony_ci __be32 hw_sw_ver; 158c2ecf20Sopenharmony_ci __be32 patch_ver; 168c2ecf20Sopenharmony_ci __be16 checksum; 178c2ecf20Sopenharmony_ci u16 reserved; 188c2ecf20Sopenharmony_ci struct { 198c2ecf20Sopenharmony_ci __be32 patch_ver; 208c2ecf20Sopenharmony_ci __be32 subsys; 218c2ecf20Sopenharmony_ci __be32 feature; 228c2ecf20Sopenharmony_ci __be32 n_region; 238c2ecf20Sopenharmony_ci __be32 crc; 248c2ecf20Sopenharmony_ci u32 reserved[11]; 258c2ecf20Sopenharmony_ci } desc; 268c2ecf20Sopenharmony_ci} __packed; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct mt7915_patch_sec { 298c2ecf20Sopenharmony_ci __be32 type; 308c2ecf20Sopenharmony_ci __be32 offs; 318c2ecf20Sopenharmony_ci __be32 size; 328c2ecf20Sopenharmony_ci union { 338c2ecf20Sopenharmony_ci __be32 spec[13]; 348c2ecf20Sopenharmony_ci struct { 358c2ecf20Sopenharmony_ci __be32 addr; 368c2ecf20Sopenharmony_ci __be32 len; 378c2ecf20Sopenharmony_ci __be32 sec_key_idx; 388c2ecf20Sopenharmony_ci __be32 align_len; 398c2ecf20Sopenharmony_ci u32 reserved[9]; 408c2ecf20Sopenharmony_ci } info; 418c2ecf20Sopenharmony_ci }; 428c2ecf20Sopenharmony_ci} __packed; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct mt7915_fw_trailer { 458c2ecf20Sopenharmony_ci u8 chip_id; 468c2ecf20Sopenharmony_ci u8 eco_code; 478c2ecf20Sopenharmony_ci u8 n_region; 488c2ecf20Sopenharmony_ci u8 format_ver; 498c2ecf20Sopenharmony_ci u8 format_flag; 508c2ecf20Sopenharmony_ci u8 reserved[2]; 518c2ecf20Sopenharmony_ci char fw_ver[10]; 528c2ecf20Sopenharmony_ci char build_date[15]; 538c2ecf20Sopenharmony_ci u32 crc; 548c2ecf20Sopenharmony_ci} __packed; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct mt7915_fw_region { 578c2ecf20Sopenharmony_ci __le32 decomp_crc; 588c2ecf20Sopenharmony_ci __le32 decomp_len; 598c2ecf20Sopenharmony_ci __le32 decomp_blk_sz; 608c2ecf20Sopenharmony_ci u8 reserved[4]; 618c2ecf20Sopenharmony_ci __le32 addr; 628c2ecf20Sopenharmony_ci __le32 len; 638c2ecf20Sopenharmony_ci u8 feature_set; 648c2ecf20Sopenharmony_ci u8 reserved1[15]; 658c2ecf20Sopenharmony_ci} __packed; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define MCU_PATCH_ADDRESS 0x200000 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define MT_STA_BFER BIT(0) 708c2ecf20Sopenharmony_ci#define MT_STA_BFEE BIT(1) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define FW_FEATURE_SET_ENCRYPT BIT(0) 738c2ecf20Sopenharmony_ci#define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) 748c2ecf20Sopenharmony_ci#define FW_FEATURE_OVERRIDE_ADDR BIT(5) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define DL_MODE_ENCRYPT BIT(0) 778c2ecf20Sopenharmony_ci#define DL_MODE_KEY_IDX GENMASK(2, 1) 788c2ecf20Sopenharmony_ci#define DL_MODE_RESET_SEC_IV BIT(3) 798c2ecf20Sopenharmony_ci#define DL_MODE_WORKING_PDA_CR4 BIT(4) 808c2ecf20Sopenharmony_ci#define DL_MODE_NEED_RSP BIT(31) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define FW_START_OVERRIDE BIT(0) 838c2ecf20Sopenharmony_ci#define FW_START_WORKING_PDA_CR4 BIT(2) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define PATCH_SEC_TYPE_MASK GENMASK(15, 0) 868c2ecf20Sopenharmony_ci#define PATCH_SEC_TYPE_INFO 0x2 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) 898c2ecf20Sopenharmony_ci#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) 928c2ecf20Sopenharmony_ci#define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic enum mt7915_cipher_type 958c2ecf20Sopenharmony_cimt7915_mcu_get_cipher(int cipher) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci switch (cipher) { 988c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 998c2ecf20Sopenharmony_ci return MT_CIPHER_WEP40; 1008c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 1018c2ecf20Sopenharmony_ci return MT_CIPHER_WEP104; 1028c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 1038c2ecf20Sopenharmony_ci return MT_CIPHER_TKIP; 1048c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 1058c2ecf20Sopenharmony_ci return MT_CIPHER_BIP_CMAC_128; 1068c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 1078c2ecf20Sopenharmony_ci return MT_CIPHER_AES_CCMP; 1088c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 1098c2ecf20Sopenharmony_ci return MT_CIPHER_CCMP_256; 1108c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 1118c2ecf20Sopenharmony_ci return MT_CIPHER_GCMP; 1128c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 1138c2ecf20Sopenharmony_ci return MT_CIPHER_GCMP_256; 1148c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_SMS4: 1158c2ecf20Sopenharmony_ci return MT_CIPHER_WAPI; 1168c2ecf20Sopenharmony_ci default: 1178c2ecf20Sopenharmony_ci return MT_CIPHER_NONE; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic u8 mt7915_mcu_chan_bw(struct cfg80211_chan_def *chandef) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci static const u8 width_to_bw[] = { 1248c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, 1258c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, 1268c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, 1278c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, 1288c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, 1298c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, 1308c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, 1318c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, 1328c2ecf20Sopenharmony_ci }; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (chandef->width >= ARRAY_SIZE(width_to_bw)) 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return width_to_bw[chandef->width]; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct ieee80211_sta_he_cap * 1418c2ecf20Sopenharmony_cimt7915_get_he_phy_cap(struct mt7915_phy *phy, struct ieee80211_vif *vif) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 1448c2ecf20Sopenharmony_ci enum nl80211_band band; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci band = phy->mt76->chandef.chan->band; 1478c2ecf20Sopenharmony_ci sband = phy->mt76->hw->wiphy->bands[band]; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return ieee80211_get_he_iftype_cap(sband, vif->type); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic u8 1538c2ecf20Sopenharmony_cimt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, 1548c2ecf20Sopenharmony_ci enum nl80211_band band, struct ieee80211_sta *sta) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap; 1578c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *vht_cap; 1588c2ecf20Sopenharmony_ci const struct ieee80211_sta_he_cap *he_cap; 1598c2ecf20Sopenharmony_ci u8 mode = 0; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (sta) { 1628c2ecf20Sopenharmony_ci ht_cap = &sta->ht_cap; 1638c2ecf20Sopenharmony_ci vht_cap = &sta->vht_cap; 1648c2ecf20Sopenharmony_ci he_cap = &sta->he_cap; 1658c2ecf20Sopenharmony_ci } else { 1668c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 1678c2ecf20Sopenharmony_ci struct mt7915_phy *phy; 1688c2ecf20Sopenharmony_ci struct mt7915_vif *mvif; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci mvif = (struct mt7915_vif *)vif->drv_priv; 1718c2ecf20Sopenharmony_ci phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; 1728c2ecf20Sopenharmony_ci sband = phy->mt76->hw->wiphy->bands[band]; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci ht_cap = &sband->ht_cap; 1758c2ecf20Sopenharmony_ci vht_cap = &sband->vht_cap; 1768c2ecf20Sopenharmony_ci he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (band == NL80211_BAND_2GHZ) { 1808c2ecf20Sopenharmony_ci mode |= PHY_MODE_B | PHY_MODE_G; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (ht_cap->ht_supported) 1838c2ecf20Sopenharmony_ci mode |= PHY_MODE_GN; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (he_cap && he_cap->has_he) 1868c2ecf20Sopenharmony_ci mode |= PHY_MODE_AX_24G; 1878c2ecf20Sopenharmony_ci } else if (band == NL80211_BAND_5GHZ) { 1888c2ecf20Sopenharmony_ci mode |= PHY_MODE_A; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (ht_cap->ht_supported) 1918c2ecf20Sopenharmony_ci mode |= PHY_MODE_AN; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (vht_cap->vht_supported) 1948c2ecf20Sopenharmony_ci mode |= PHY_MODE_AC; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (he_cap && he_cap->has_he) 1978c2ecf20Sopenharmony_ci mode |= PHY_MODE_AX_5G; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return mode; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic u8 2048c2ecf20Sopenharmony_cimt7915_mcu_get_sta_nss(u16 mcs_map) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci u8 nss; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci for (nss = 8; nss > 0; nss--) { 2098c2ecf20Sopenharmony_ci u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return nss - 1; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int __mt7915_mcu_msg_send(struct mt7915_dev *dev, struct sk_buff *skb, 2198c2ecf20Sopenharmony_ci int cmd, int *wait_seq) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct mt7915_mcu_txd *mcu_txd; 2228c2ecf20Sopenharmony_ci u8 seq, pkt_fmt, qidx; 2238c2ecf20Sopenharmony_ci enum mt76_txq_id txq; 2248c2ecf20Sopenharmony_ci __le32 *txd; 2258c2ecf20Sopenharmony_ci u32 val; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci seq = ++dev->mt76.mcu.msg_seq & 0xf; 2288c2ecf20Sopenharmony_ci if (!seq) 2298c2ecf20Sopenharmony_ci seq = ++dev->mt76.mcu.msg_seq & 0xf; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (cmd == -MCU_CMD_FW_SCATTER) { 2328c2ecf20Sopenharmony_ci txq = MT_TXQ_FWDL; 2338c2ecf20Sopenharmony_ci goto exit; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci mcu_txd = (struct mt7915_mcu_txd *)skb_push(skb, sizeof(*mcu_txd)); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) { 2398c2ecf20Sopenharmony_ci txq = MT_TXQ_MCU_WA; 2408c2ecf20Sopenharmony_ci qidx = MT_TX_MCU_PORT_RX_Q0; 2418c2ecf20Sopenharmony_ci pkt_fmt = MT_TX_TYPE_CMD; 2428c2ecf20Sopenharmony_ci } else { 2438c2ecf20Sopenharmony_ci txq = MT_TXQ_MCU; 2448c2ecf20Sopenharmony_ci qidx = MT_TX_MCU_PORT_RX_Q0; 2458c2ecf20Sopenharmony_ci pkt_fmt = MT_TX_TYPE_CMD; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci txd = mcu_txd->txd; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | 2518c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD0_PKT_FMT, pkt_fmt) | 2528c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD0_Q_IDX, qidx); 2538c2ecf20Sopenharmony_ci txd[0] = cpu_to_le32(val); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci val = MT_TXD1_LONG_FORMAT | 2568c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); 2578c2ecf20Sopenharmony_ci txd[1] = cpu_to_le32(val); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); 2608c2ecf20Sopenharmony_ci mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, qidx)); 2618c2ecf20Sopenharmony_ci mcu_txd->pkt_type = MCU_PKT_ID; 2628c2ecf20Sopenharmony_ci mcu_txd->seq = seq; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (cmd < 0) { 2658c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_NA; 2668c2ecf20Sopenharmony_ci mcu_txd->cid = -cmd; 2678c2ecf20Sopenharmony_ci } else { 2688c2ecf20Sopenharmony_ci mcu_txd->cid = MCU_CMD_EXT_CID; 2698c2ecf20Sopenharmony_ci mcu_txd->ext_cid = cmd; 2708c2ecf20Sopenharmony_ci mcu_txd->ext_cid_ack = 1; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* do not use Q_SET for efuse */ 2738c2ecf20Sopenharmony_ci if (cmd == MCU_EXT_CMD_EFUSE_ACCESS) 2748c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_QUERY; 2758c2ecf20Sopenharmony_ci else 2768c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_SET; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci mcu_txd->s2d_index = MCU_S2D_H2N; 2808c2ecf20Sopenharmony_ci WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && 2818c2ecf20Sopenharmony_ci mcu_txd->set_query != MCU_Q_QUERY); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciexit: 2848c2ecf20Sopenharmony_ci if (wait_seq) 2858c2ecf20Sopenharmony_ci *wait_seq = seq; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return mt76_tx_queue_skb_raw(dev, txq, skb, 0); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int 2918c2ecf20Sopenharmony_cimt7915_mcu_parse_eeprom(struct mt7915_dev *dev, struct sk_buff *skb) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct mt7915_mcu_eeprom_info *res; 2948c2ecf20Sopenharmony_ci u8 *buf; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!skb) 2978c2ecf20Sopenharmony_ci return -EINVAL; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct mt7915_mcu_rxd)); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci res = (struct mt7915_mcu_eeprom_info *)skb->data; 3028c2ecf20Sopenharmony_ci buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); 3038c2ecf20Sopenharmony_ci memcpy(buf, res->data, 16); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int 3098c2ecf20Sopenharmony_cimt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd, 3108c2ecf20Sopenharmony_ci struct sk_buff *skb, int seq) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; 3138c2ecf20Sopenharmony_ci int ret = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (seq != rxd->seq) { 3168c2ecf20Sopenharmony_ci ret = -EAGAIN; 3178c2ecf20Sopenharmony_ci goto out; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci switch (cmd) { 3218c2ecf20Sopenharmony_ci case -MCU_CMD_PATCH_SEM_CONTROL: 3228c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*rxd) - 4); 3238c2ecf20Sopenharmony_ci ret = *skb->data; 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci case MCU_EXT_CMD_THERMAL_CTRL: 3268c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*rxd) + 4); 3278c2ecf20Sopenharmony_ci ret = le32_to_cpu(*(__le32 *)skb->data); 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case MCU_EXT_CMD_EFUSE_ACCESS: 3308c2ecf20Sopenharmony_ci ret = mt7915_mcu_parse_eeprom(dev, skb); 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci default: 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ciout: 3368c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int 3428c2ecf20Sopenharmony_cimt7915_mcu_wait_response(struct mt7915_dev *dev, int cmd, int seq) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci unsigned long expires = jiffies + 20 * HZ; 3458c2ecf20Sopenharmony_ci struct sk_buff *skb; 3468c2ecf20Sopenharmony_ci int ret = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci while (true) { 3498c2ecf20Sopenharmony_ci skb = mt76_mcu_get_response(&dev->mt76, expires); 3508c2ecf20Sopenharmony_ci if (!skb) { 3518c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Message %d (seq %d) timeout\n", 3528c2ecf20Sopenharmony_ci cmd, seq); 3538c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci ret = mt7915_mcu_parse_response(dev, cmd, skb, seq); 3578c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int 3658c2ecf20Sopenharmony_cimt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 3668c2ecf20Sopenharmony_ci int cmd, bool wait_resp) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 3698c2ecf20Sopenharmony_ci int ret, seq; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci mutex_lock(&mdev->mcu.mutex); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci ret = __mt7915_mcu_msg_send(dev, skb, cmd, &seq); 3748c2ecf20Sopenharmony_ci if (ret) 3758c2ecf20Sopenharmony_ci goto out; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (wait_resp) 3788c2ecf20Sopenharmony_ci ret = mt7915_mcu_wait_response(dev, cmd, seq); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ciout: 3818c2ecf20Sopenharmony_ci mutex_unlock(&mdev->mcu.mutex); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return ret; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int 3878c2ecf20Sopenharmony_cimt7915_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, 3888c2ecf20Sopenharmony_ci int len, bool wait_resp) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct sk_buff *skb; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(mdev, data, len); 3938c2ecf20Sopenharmony_ci if (!skb) 3948c2ecf20Sopenharmony_ci return -ENOMEM; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void 4008c2ecf20Sopenharmony_cimt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci if (vif->csa_active) 4038c2ecf20Sopenharmony_ci ieee80211_csa_finish(vif); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void 4078c2ecf20Sopenharmony_cimt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 4108c2ecf20Sopenharmony_ci struct mt7915_mcu_rdd_report *r; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci r = (struct mt7915_mcu_rdd_report *)skb->data; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (r->idx && dev->mt76.phy2) 4158c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ieee80211_radar_detected(mphy->hw); 4188c2ecf20Sopenharmony_ci dev->hw_pattern++; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void 4228c2ecf20Sopenharmony_cimt7915_mcu_tx_rate_cal(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra, 4238c2ecf20Sopenharmony_ci struct rate_info *rate, u16 r) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 4268c2ecf20Sopenharmony_ci u16 ru_idx = le16_to_cpu(ra->ru_idx); 4278c2ecf20Sopenharmony_ci u16 flags = 0; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci rate->mcs = FIELD_GET(MT_RA_RATE_MCS, r); 4308c2ecf20Sopenharmony_ci rate->nss = FIELD_GET(MT_RA_RATE_NSS, r) + 1; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci switch (FIELD_GET(MT_RA_RATE_TX_MODE, r)) { 4338c2ecf20Sopenharmony_ci case MT_PHY_TYPE_CCK: 4348c2ecf20Sopenharmony_ci case MT_PHY_TYPE_OFDM: 4358c2ecf20Sopenharmony_ci if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 4368c2ecf20Sopenharmony_ci sband = &mphy->sband_5g.sband; 4378c2ecf20Sopenharmony_ci else 4388c2ecf20Sopenharmony_ci sband = &mphy->sband_2g.sband; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci rate->legacy = sband->bitrates[rate->mcs].bitrate; 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT: 4438c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HT_GF: 4448c2ecf20Sopenharmony_ci rate->mcs += (rate->nss - 1) * 8; 4458c2ecf20Sopenharmony_ci flags |= RATE_INFO_FLAGS_MCS; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (ra->gi) 4488c2ecf20Sopenharmony_ci flags |= RATE_INFO_FLAGS_SHORT_GI; 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci case MT_PHY_TYPE_VHT: 4518c2ecf20Sopenharmony_ci flags |= RATE_INFO_FLAGS_VHT_MCS; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (ra->gi) 4548c2ecf20Sopenharmony_ci flags |= RATE_INFO_FLAGS_SHORT_GI; 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HE_SU: 4578c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HE_EXT_SU: 4588c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HE_TB: 4598c2ecf20Sopenharmony_ci case MT_PHY_TYPE_HE_MU: 4608c2ecf20Sopenharmony_ci rate->he_gi = ra->gi; 4618c2ecf20Sopenharmony_ci rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci flags |= RATE_INFO_FLAGS_HE_MCS; 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci default: 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci rate->flags = flags; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (ru_idx) { 4718c2ecf20Sopenharmony_ci switch (ru_idx) { 4728c2ecf20Sopenharmony_ci case 1 ... 2: 4738c2ecf20Sopenharmony_ci rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_996; 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci case 3 ... 6: 4768c2ecf20Sopenharmony_ci rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_484; 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci case 7 ... 14: 4798c2ecf20Sopenharmony_ci rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_242; 4808c2ecf20Sopenharmony_ci break; 4818c2ecf20Sopenharmony_ci default: 4828c2ecf20Sopenharmony_ci rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_106; 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci rate->bw = RATE_INFO_BW_HE_RU; 4868c2ecf20Sopenharmony_ci } else { 4878c2ecf20Sopenharmony_ci u8 bw = mt7915_mcu_chan_bw(&mphy->chandef) - 4888c2ecf20Sopenharmony_ci FIELD_GET(MT_RA_RATE_BW, r); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci switch (bw) { 4918c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 4928c2ecf20Sopenharmony_ci rate->bw = RATE_INFO_BW_160; 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_80: 4958c2ecf20Sopenharmony_ci rate->bw = RATE_INFO_BW_80; 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_40: 4988c2ecf20Sopenharmony_ci rate->bw = RATE_INFO_BW_40; 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci default: 5018c2ecf20Sopenharmony_ci rate->bw = RATE_INFO_BW_20; 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic void 5088c2ecf20Sopenharmony_cimt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct mt7915_mcu_ra_info *ra = (struct mt7915_mcu_ra_info *)skb->data; 5118c2ecf20Sopenharmony_ci struct rate_info rate = {}, prob_rate = {}; 5128c2ecf20Sopenharmony_ci u16 probe = le16_to_cpu(ra->prob_up_rate); 5138c2ecf20Sopenharmony_ci u16 attempts = le16_to_cpu(ra->attempts); 5148c2ecf20Sopenharmony_ci u16 curr = le16_to_cpu(ra->curr_rate); 5158c2ecf20Sopenharmony_ci u16 wcidx = le16_to_cpu(ra->wlan_idx); 5168c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mphy; 5178c2ecf20Sopenharmony_ci struct mt7915_sta_stats *stats; 5188c2ecf20Sopenharmony_ci struct mt7915_sta *msta; 5198c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (wcidx >= MT76_N_WCIDS) 5228c2ecf20Sopenharmony_ci return; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[wcidx]); 5258c2ecf20Sopenharmony_ci if (!wcid) 5268c2ecf20Sopenharmony_ci return; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci msta = container_of(wcid, struct mt7915_sta, wcid); 5298c2ecf20Sopenharmony_ci stats = &msta->stats; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (msta->wcid.ext_phy && dev->mt76.phy2) 5328c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* current rate */ 5358c2ecf20Sopenharmony_ci mt7915_mcu_tx_rate_cal(mphy, ra, &rate, curr); 5368c2ecf20Sopenharmony_ci stats->tx_rate = rate; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* probing rate */ 5398c2ecf20Sopenharmony_ci mt7915_mcu_tx_rate_cal(mphy, ra, &prob_rate, probe); 5408c2ecf20Sopenharmony_ci stats->prob_rate = prob_rate; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (attempts) { 5438c2ecf20Sopenharmony_ci u16 success = le16_to_cpu(ra->success); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci stats->per = 1000 * (attempts - success) / attempts; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic void 5508c2ecf20Sopenharmony_cimt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; 5538c2ecf20Sopenharmony_ci const char *data = (char *)&rxd[1]; 5548c2ecf20Sopenharmony_ci const char *type; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci switch (rxd->s2d_index) { 5578c2ecf20Sopenharmony_ci case 0: 5588c2ecf20Sopenharmony_ci type = "WM"; 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci case 2: 5618c2ecf20Sopenharmony_ci type = "WA"; 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci default: 5648c2ecf20Sopenharmony_ci type = "unknown"; 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci wiphy_info(mt76_hw(dev)->wiphy, "%s: %s", type, data); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic void 5728c2ecf20Sopenharmony_cimt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci switch (rxd->ext_eid) { 5778c2ecf20Sopenharmony_ci case MCU_EXT_EVENT_RDD_REPORT: 5788c2ecf20Sopenharmony_ci mt7915_mcu_rx_radar_detected(dev, skb); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci case MCU_EXT_EVENT_CSA_NOTIFY: 5818c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, 5828c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 5838c2ecf20Sopenharmony_ci mt7915_mcu_csa_finish, dev); 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci case MCU_EXT_EVENT_RATE_REPORT: 5868c2ecf20Sopenharmony_ci mt7915_mcu_tx_rate_report(dev, skb); 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci case MCU_EXT_EVENT_FW_LOG_2_HOST: 5898c2ecf20Sopenharmony_ci mt7915_mcu_rx_log_message(dev, skb); 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci default: 5928c2ecf20Sopenharmony_ci break; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void 5978c2ecf20Sopenharmony_cimt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci switch (rxd->eid) { 6028c2ecf20Sopenharmony_ci case MCU_EVENT_EXT: 6038c2ecf20Sopenharmony_ci mt7915_mcu_rx_ext_event(dev, skb); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci default: 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_civoid mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || 6168c2ecf20Sopenharmony_ci rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || 6178c2ecf20Sopenharmony_ci rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || 6188c2ecf20Sopenharmony_ci rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || 6198c2ecf20Sopenharmony_ci rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || 6208c2ecf20Sopenharmony_ci !rxd->seq) 6218c2ecf20Sopenharmony_ci mt7915_mcu_rx_unsolicited_event(dev, skb); 6228c2ecf20Sopenharmony_ci else 6238c2ecf20Sopenharmony_ci mt76_mcu_rx_event(&dev->mt76, skb); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic struct sk_buff * 6278c2ecf20Sopenharmony_cimt7915_mcu_alloc_sta_req(struct mt7915_dev *dev, struct mt7915_vif *mvif, 6288c2ecf20Sopenharmony_ci struct mt7915_sta *msta, int len) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct sta_req_hdr hdr = { 6318c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 6328c2ecf20Sopenharmony_ci .wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0, 6338c2ecf20Sopenharmony_ci .wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0, 6348c2ecf20Sopenharmony_ci .muar_idx = msta && msta->wcid.sta ? mvif->omac_idx : 0xe, 6358c2ecf20Sopenharmony_ci .is_tlv_append = 1, 6368c2ecf20Sopenharmony_ci }; 6378c2ecf20Sopenharmony_ci struct sk_buff *skb; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); 6408c2ecf20Sopenharmony_ci if (!skb) 6418c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci skb_put_data(skb, &hdr, sizeof(hdr)); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return skb; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic struct wtbl_req_hdr * 6498c2ecf20Sopenharmony_cimt7915_mcu_alloc_wtbl_req(struct mt7915_dev *dev, struct mt7915_sta *msta, 6508c2ecf20Sopenharmony_ci int cmd, void *sta_wtbl, struct sk_buff **skb) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct tlv *sta_hdr = sta_wtbl; 6538c2ecf20Sopenharmony_ci struct wtbl_req_hdr hdr = { 6548c2ecf20Sopenharmony_ci .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), 6558c2ecf20Sopenharmony_ci .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), 6568c2ecf20Sopenharmony_ci .operation = cmd, 6578c2ecf20Sopenharmony_ci }; 6588c2ecf20Sopenharmony_ci struct sk_buff *nskb = *skb; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (!nskb) { 6618c2ecf20Sopenharmony_ci nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 6628c2ecf20Sopenharmony_ci MT7915_WTBL_UPDATE_BA_SIZE); 6638c2ecf20Sopenharmony_ci if (!nskb) 6648c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci *skb = nskb; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (sta_hdr) 6708c2ecf20Sopenharmony_ci le16_add_cpu(&sta_hdr->len, sizeof(hdr)); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return skb_put_data(nskb, &hdr, sizeof(hdr)); 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic struct tlv * 6768c2ecf20Sopenharmony_cimt7915_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, 6778c2ecf20Sopenharmony_ci void *sta_ntlv, void *sta_wtbl) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; 6808c2ecf20Sopenharmony_ci struct tlv *sta_hdr = sta_wtbl; 6818c2ecf20Sopenharmony_ci struct tlv *ptlv, tlv = { 6828c2ecf20Sopenharmony_ci .tag = cpu_to_le16(tag), 6838c2ecf20Sopenharmony_ci .len = cpu_to_le16(len), 6848c2ecf20Sopenharmony_ci }; 6858c2ecf20Sopenharmony_ci u16 ntlv; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci ptlv = skb_put(skb, len); 6888c2ecf20Sopenharmony_ci memcpy(ptlv, &tlv, sizeof(tlv)); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci ntlv = le16_to_cpu(ntlv_hdr->tlv_num); 6918c2ecf20Sopenharmony_ci ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (sta_hdr) { 6948c2ecf20Sopenharmony_ci u16 size = le16_to_cpu(sta_hdr->len); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci sta_hdr->len = cpu_to_le16(size + len); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return ptlv; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic struct tlv * 7038c2ecf20Sopenharmony_cimt7915_mcu_add_tlv(struct sk_buff *skb, int tag, int len) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci return mt7915_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic struct tlv * 7098c2ecf20Sopenharmony_cimt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len, 7108c2ecf20Sopenharmony_ci __le16 *sub_ntlv, __le16 *len) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct tlv *ptlv, tlv = { 7138c2ecf20Sopenharmony_ci .tag = cpu_to_le16(sub_tag), 7148c2ecf20Sopenharmony_ci .len = cpu_to_le16(sub_len), 7158c2ecf20Sopenharmony_ci }; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci ptlv = skb_put(skb, sub_len); 7188c2ecf20Sopenharmony_ci memcpy(ptlv, &tlv, sizeof(tlv)); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci le16_add_cpu(sub_ntlv, 1); 7218c2ecf20Sopenharmony_ci le16_add_cpu(len, sub_len); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return ptlv; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci/** bss info **/ 7278c2ecf20Sopenharmony_cistatic int 7288c2ecf20Sopenharmony_cimt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 7298c2ecf20Sopenharmony_ci struct mt7915_phy *phy, bool enable) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 7328c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 7338c2ecf20Sopenharmony_ci enum nl80211_band band = chandef->chan->band; 7348c2ecf20Sopenharmony_ci struct bss_info_basic *bss; 7358c2ecf20Sopenharmony_ci u16 wlan_idx = mvif->sta.wcid.idx; 7368c2ecf20Sopenharmony_ci u32 type = NETWORK_INFRA; 7378c2ecf20Sopenharmony_ci struct tlv *tlv; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci switch (vif->type) { 7428c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 7438c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 7468c2ecf20Sopenharmony_ci /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ 7478c2ecf20Sopenharmony_ci if (enable) { 7488c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 7498c2ecf20Sopenharmony_ci struct mt7915_sta *msta; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci rcu_read_lock(); 7528c2ecf20Sopenharmony_ci sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); 7538c2ecf20Sopenharmony_ci if (!sta) { 7548c2ecf20Sopenharmony_ci rcu_read_unlock(); 7558c2ecf20Sopenharmony_ci return -EINVAL; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci msta = (struct mt7915_sta *)sta->drv_priv; 7598c2ecf20Sopenharmony_ci wlan_idx = msta->wcid.idx; 7608c2ecf20Sopenharmony_ci rcu_read_unlock(); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 7648c2ecf20Sopenharmony_ci type = NETWORK_IBSS; 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci default: 7678c2ecf20Sopenharmony_ci WARN_ON(1); 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci bss = (struct bss_info_basic *)tlv; 7728c2ecf20Sopenharmony_ci memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); 7738c2ecf20Sopenharmony_ci bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); 7748c2ecf20Sopenharmony_ci bss->network_type = cpu_to_le32(type); 7758c2ecf20Sopenharmony_ci bss->dtim_period = vif->bss_conf.dtim_period; 7768c2ecf20Sopenharmony_ci bss->bmc_wcid_lo = to_wcid_lo(wlan_idx); 7778c2ecf20Sopenharmony_ci bss->bmc_wcid_hi = to_wcid_hi(wlan_idx); 7788c2ecf20Sopenharmony_ci bss->phy_mode = mt7915_get_phy_mode(phy->dev, vif, band, NULL); 7798c2ecf20Sopenharmony_ci bss->wmm_idx = mvif->wmm_idx; 7808c2ecf20Sopenharmony_ci bss->active = enable; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic void 7868c2ecf20Sopenharmony_cimt7915_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 7898c2ecf20Sopenharmony_ci struct bss_info_omac *omac; 7908c2ecf20Sopenharmony_ci struct tlv *tlv; 7918c2ecf20Sopenharmony_ci u32 type = 0; 7928c2ecf20Sopenharmony_ci u8 idx; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci switch (vif->type) { 7978c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 7988c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 7998c2ecf20Sopenharmony_ci type = CONNECTION_INFRA_AP; 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 8028c2ecf20Sopenharmony_ci type = CONNECTION_INFRA_STA; 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 8058c2ecf20Sopenharmony_ci type = CONNECTION_IBSS_ADHOC; 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci default: 8088c2ecf20Sopenharmony_ci WARN_ON(1); 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci omac = (struct bss_info_omac *)tlv; 8138c2ecf20Sopenharmony_ci idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; 8148c2ecf20Sopenharmony_ci omac->conn_type = cpu_to_le32(type); 8158c2ecf20Sopenharmony_ci omac->omac_idx = mvif->omac_idx; 8168c2ecf20Sopenharmony_ci omac->band_idx = mvif->band_idx; 8178c2ecf20Sopenharmony_ci omac->hw_bss_idx = idx; 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistruct mt7915_he_obss_narrow_bw_ru_data { 8218c2ecf20Sopenharmony_ci bool tolerated; 8228c2ecf20Sopenharmony_ci}; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, 8258c2ecf20Sopenharmony_ci struct cfg80211_bss *bss, 8268c2ecf20Sopenharmony_ci void *_data) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct mt7915_he_obss_narrow_bw_ru_data *data = _data; 8298c2ecf20Sopenharmony_ci const struct element *elem; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (!elem || elem->datalen <= 10 || 8348c2ecf20Sopenharmony_ci !(elem->data[10] & 8358c2ecf20Sopenharmony_ci WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) 8368c2ecf20Sopenharmony_ci data->tolerated = false; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, 8408c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct mt7915_he_obss_narrow_bw_ru_data iter_data = { 8438c2ecf20Sopenharmony_ci .tolerated = true, 8448c2ecf20Sopenharmony_ci }; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) 8478c2ecf20Sopenharmony_ci return false; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef, 8508c2ecf20Sopenharmony_ci mt7915_check_he_obss_narrow_bw_ru_iter, 8518c2ecf20Sopenharmony_ci &iter_data); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* 8548c2ecf20Sopenharmony_ci * If there is at least one AP on radar channel that cannot 8558c2ecf20Sopenharmony_ci * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU. 8568c2ecf20Sopenharmony_ci */ 8578c2ecf20Sopenharmony_ci return !iter_data.tolerated; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic void 8618c2ecf20Sopenharmony_cimt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 8628c2ecf20Sopenharmony_ci struct mt7915_phy *phy) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 8658c2ecf20Sopenharmony_ci struct bss_info_rf_ch *ch; 8668c2ecf20Sopenharmony_ci struct tlv *tlv; 8678c2ecf20Sopenharmony_ci int freq1 = chandef->center_freq1; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch)); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci ch = (struct bss_info_rf_ch *)tlv; 8728c2ecf20Sopenharmony_ci ch->pri_ch = chandef->chan->hw_value; 8738c2ecf20Sopenharmony_ci ch->center_ch0 = ieee80211_frequency_to_channel(freq1); 8748c2ecf20Sopenharmony_ci ch->bw = mt7915_mcu_chan_bw(chandef); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 8778c2ecf20Sopenharmony_ci int freq2 = chandef->center_freq2; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci ch->center_ch1 = ieee80211_frequency_to_channel(freq2); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) { 8838c2ecf20Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 8848c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 8858c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (ext_phy && dev->mt76.phy2) 8888c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci ch->he_ru26_block = 8918c2ecf20Sopenharmony_ci mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif); 8928c2ecf20Sopenharmony_ci ch->he_all_disable = false; 8938c2ecf20Sopenharmony_ci } else { 8948c2ecf20Sopenharmony_ci ch->he_all_disable = true; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void 8998c2ecf20Sopenharmony_cimt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 9008c2ecf20Sopenharmony_ci struct mt7915_phy *phy) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci struct bss_info_ra *ra; 9038c2ecf20Sopenharmony_ci struct tlv *tlv; 9048c2ecf20Sopenharmony_ci int max_nss = hweight8(phy->chainmask); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra)); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci ra = (struct bss_info_ra *)tlv; 9098c2ecf20Sopenharmony_ci ra->op_mode = vif->type == NL80211_IFTYPE_AP; 9108c2ecf20Sopenharmony_ci ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC; 9118c2ecf20Sopenharmony_ci ra->short_preamble = true; 9128c2ecf20Sopenharmony_ci ra->tx_streams = max_nss; 9138c2ecf20Sopenharmony_ci ra->rx_streams = max_nss; 9148c2ecf20Sopenharmony_ci ra->algo = 4; 9158c2ecf20Sopenharmony_ci ra->train_up_rule = 2; 9168c2ecf20Sopenharmony_ci ra->train_up_high_thres = 110; 9178c2ecf20Sopenharmony_ci ra->train_up_rule_rssi = -70; 9188c2ecf20Sopenharmony_ci ra->low_traffic_thres = 2; 9198c2ecf20Sopenharmony_ci ra->phy_cap = cpu_to_le32(0xfdf); 9208c2ecf20Sopenharmony_ci ra->interval = cpu_to_le32(500); 9218c2ecf20Sopenharmony_ci ra->fast_interval = cpu_to_le32(100); 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic void 9258c2ecf20Sopenharmony_cimt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 9268c2ecf20Sopenharmony_ci struct mt7915_phy *phy) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci#define DEFAULT_HE_PE_DURATION 4 9298c2ecf20Sopenharmony_ci#define DEFAULT_HE_DURATION_RTS_THRES 1023 9308c2ecf20Sopenharmony_ci const struct ieee80211_sta_he_cap *cap; 9318c2ecf20Sopenharmony_ci struct bss_info_he *he; 9328c2ecf20Sopenharmony_ci struct tlv *tlv; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci cap = mt7915_get_he_phy_cap(phy, vif); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he)); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci he = (struct bss_info_he *)tlv; 9398c2ecf20Sopenharmony_ci he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; 9408c2ecf20Sopenharmony_ci if (!he->he_pe_duration) 9418c2ecf20Sopenharmony_ci he->he_pe_duration = DEFAULT_HE_PE_DURATION; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); 9448c2ecf20Sopenharmony_ci if (!he->he_rts_thres) 9458c2ecf20Sopenharmony_ci he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; 9488c2ecf20Sopenharmony_ci he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; 9498c2ecf20Sopenharmony_ci he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic void 9538c2ecf20Sopenharmony_cimt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci#define TXD_CMP_MAP1 GENMASK(15, 0) 9568c2ecf20Sopenharmony_ci#define TXD_CMP_MAP2 (GENMASK(31, 0) & ~BIT(23)) 9578c2ecf20Sopenharmony_ci struct bss_info_hw_amsdu *amsdu; 9588c2ecf20Sopenharmony_ci struct tlv *tlv; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu)); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci amsdu = (struct bss_info_hw_amsdu *)tlv; 9638c2ecf20Sopenharmony_ci amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1); 9648c2ecf20Sopenharmony_ci amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2); 9658c2ecf20Sopenharmony_ci amsdu->trig_thres = cpu_to_le16(2); 9668c2ecf20Sopenharmony_ci amsdu->enable = true; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic void 9708c2ecf20Sopenharmony_cimt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */ 9738c2ecf20Sopenharmony_ci#define BCN_TX_ESTIMATE_TIME (4096 + 20) 9748c2ecf20Sopenharmony_ci struct bss_info_ext_bss *ext; 9758c2ecf20Sopenharmony_ci int ext_bss_idx, tsf_offset; 9768c2ecf20Sopenharmony_ci struct tlv *tlv; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci ext_bss_idx = mvif->omac_idx - EXT_BSSID_START; 9798c2ecf20Sopenharmony_ci if (ext_bss_idx < 0) 9808c2ecf20Sopenharmony_ci return; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext)); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci ext = (struct bss_info_ext_bss *)tlv; 9858c2ecf20Sopenharmony_ci tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME; 9868c2ecf20Sopenharmony_ci ext->mbss_tsf_offset = cpu_to_le32(tsf_offset); 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic void 9908c2ecf20Sopenharmony_cimt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct bss_info_bmc_rate *bmc; 9938c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 9948c2ecf20Sopenharmony_ci enum nl80211_band band = chandef->chan->band; 9958c2ecf20Sopenharmony_ci struct tlv *tlv; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc)); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci bmc = (struct bss_info_bmc_rate *)tlv; 10008c2ecf20Sopenharmony_ci if (band == NL80211_BAND_2GHZ) { 10018c2ecf20Sopenharmony_ci bmc->short_preamble = true; 10028c2ecf20Sopenharmony_ci } else { 10038c2ecf20Sopenharmony_ci bmc->bc_trans = cpu_to_le16(0x2000); 10048c2ecf20Sopenharmony_ci bmc->mc_trans = cpu_to_le16(0x2080); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic void 10098c2ecf20Sopenharmony_cimt7915_mcu_bss_sync_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct bss_info_sync_mode *sync; 10128c2ecf20Sopenharmony_ci struct tlv *tlv; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_SYNC_MODE, sizeof(*sync)); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci sync = (struct bss_info_sync_mode *)tlv; 10178c2ecf20Sopenharmony_ci sync->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); 10188c2ecf20Sopenharmony_ci sync->dtim_period = vif->bss_conf.dtim_period; 10198c2ecf20Sopenharmony_ci sync->enable = true; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ciint mt7915_mcu_add_bss_info(struct mt7915_phy *phy, 10238c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, int enable) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 10268c2ecf20Sopenharmony_ci struct sk_buff *skb; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(phy->dev, mvif, NULL, 10298c2ecf20Sopenharmony_ci MT7915_BSS_UPDATE_MAX_SIZE); 10308c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 10318c2ecf20Sopenharmony_ci return PTR_ERR(skb); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* bss_omac must be first */ 10348c2ecf20Sopenharmony_ci if (enable) 10358c2ecf20Sopenharmony_ci mt7915_mcu_bss_omac_tlv(skb, vif); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci mt7915_mcu_bss_basic_tlv(skb, vif, phy, enable); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (enable) { 10408c2ecf20Sopenharmony_ci mt7915_mcu_bss_rfch_tlv(skb, vif, phy); 10418c2ecf20Sopenharmony_ci mt7915_mcu_bss_bmc_tlv(skb, phy); 10428c2ecf20Sopenharmony_ci mt7915_mcu_bss_ra_tlv(skb, vif, phy); 10438c2ecf20Sopenharmony_ci mt7915_mcu_bss_hw_amsdu_tlv(skb); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (vif->bss_conf.he_support) 10468c2ecf20Sopenharmony_ci mt7915_mcu_bss_he_tlv(skb, vif, phy); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (mvif->omac_idx > HW_BSSID_MAX) 10498c2ecf20Sopenharmony_ci mt7915_mcu_bss_ext_tlv(skb, mvif); 10508c2ecf20Sopenharmony_ci else 10518c2ecf20Sopenharmony_ci mt7915_mcu_bss_sync_tlv(skb, vif); 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, 10558c2ecf20Sopenharmony_ci MCU_EXT_CMD_BSS_INFO_UPDATE, true); 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci/** starec & wtbl **/ 10598c2ecf20Sopenharmony_cistatic int 10608c2ecf20Sopenharmony_cimt7915_mcu_sta_key_tlv(struct sk_buff *skb, struct ieee80211_key_conf *key, 10618c2ecf20Sopenharmony_ci enum set_key_cmd cmd) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct sta_rec_sec *sec; 10648c2ecf20Sopenharmony_ci struct tlv *tlv; 10658c2ecf20Sopenharmony_ci u32 len = sizeof(*sec); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci sec = (struct sta_rec_sec *)tlv; 10708c2ecf20Sopenharmony_ci sec->add = cmd; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (cmd == SET_KEY) { 10738c2ecf20Sopenharmony_ci struct sec_key *sec_key; 10748c2ecf20Sopenharmony_ci u8 cipher; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci cipher = mt7915_mcu_get_cipher(key->cipher); 10778c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_NONE) 10788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci sec_key = &sec->key[0]; 10818c2ecf20Sopenharmony_ci sec_key->cipher_len = sizeof(*sec_key); 10828c2ecf20Sopenharmony_ci sec_key->key_id = key->keyidx; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_BIP_CMAC_128) { 10858c2ecf20Sopenharmony_ci sec_key->cipher_id = MT_CIPHER_AES_CCMP; 10868c2ecf20Sopenharmony_ci sec_key->key_len = 16; 10878c2ecf20Sopenharmony_ci memcpy(sec_key->key, key->key, 16); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci sec_key = &sec->key[1]; 10908c2ecf20Sopenharmony_ci sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; 10918c2ecf20Sopenharmony_ci sec_key->cipher_len = sizeof(*sec_key); 10928c2ecf20Sopenharmony_ci sec_key->key_len = 16; 10938c2ecf20Sopenharmony_ci memcpy(sec_key->key, key->key + 16, 16); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci sec->n_cipher = 2; 10968c2ecf20Sopenharmony_ci } else { 10978c2ecf20Sopenharmony_ci sec_key->cipher_id = cipher; 10988c2ecf20Sopenharmony_ci sec_key->key_len = key->keylen; 10998c2ecf20Sopenharmony_ci memcpy(sec_key->key, key->key, key->keylen); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (cipher == MT_CIPHER_TKIP) { 11028c2ecf20Sopenharmony_ci /* Rx/Tx MIC keys are swapped */ 11038c2ecf20Sopenharmony_ci memcpy(sec_key->key + 16, key->key + 24, 8); 11048c2ecf20Sopenharmony_ci memcpy(sec_key->key + 24, key->key + 16, 8); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci len -= sizeof(*sec_key); 11088c2ecf20Sopenharmony_ci sec->n_cipher = 1; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci } else { 11118c2ecf20Sopenharmony_ci len -= sizeof(sec->key); 11128c2ecf20Sopenharmony_ci sec->n_cipher = 0; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci sec->len = cpu_to_le16(len); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci return 0; 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ciint mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, 11208c2ecf20Sopenharmony_ci struct mt7915_sta *msta, struct ieee80211_key_conf *key, 11218c2ecf20Sopenharmony_ci enum set_key_cmd cmd) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 11248c2ecf20Sopenharmony_ci struct sk_buff *skb; 11258c2ecf20Sopenharmony_ci int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_sec); 11268c2ecf20Sopenharmony_ci int ret; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); 11298c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 11308c2ecf20Sopenharmony_ci return PTR_ERR(skb); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci ret = mt7915_mcu_sta_key_tlv(skb, key, cmd); 11338c2ecf20Sopenharmony_ci if (ret) 11348c2ecf20Sopenharmony_ci return ret; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 11378c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic void 11418c2ecf20Sopenharmony_cimt7915_mcu_sta_ba_tlv(struct sk_buff *skb, 11428c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 11438c2ecf20Sopenharmony_ci bool enable, bool tx) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci struct sta_rec_ba *ba; 11468c2ecf20Sopenharmony_ci struct tlv *tlv; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci ba = (struct sta_rec_ba *)tlv; 11518c2ecf20Sopenharmony_ci ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT, 11528c2ecf20Sopenharmony_ci ba->winsize = cpu_to_le16(params->buf_size); 11538c2ecf20Sopenharmony_ci ba->ssn = cpu_to_le16(params->ssn); 11548c2ecf20Sopenharmony_ci ba->ba_en = enable << params->tid; 11558c2ecf20Sopenharmony_ci ba->amsdu = params->amsdu; 11568c2ecf20Sopenharmony_ci ba->tid = params->tid; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic void 11608c2ecf20Sopenharmony_cimt7915_mcu_wtbl_ba_tlv(struct sk_buff *skb, 11618c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 11628c2ecf20Sopenharmony_ci bool enable, bool tx, void *sta_wtbl, 11638c2ecf20Sopenharmony_ci void *wtbl_tlv) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci struct wtbl_ba *ba; 11668c2ecf20Sopenharmony_ci struct tlv *tlv; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), 11698c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci ba = (struct wtbl_ba *)tlv; 11728c2ecf20Sopenharmony_ci ba->tid = params->tid; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (tx) { 11758c2ecf20Sopenharmony_ci ba->ba_type = MT_BA_TYPE_ORIGINATOR; 11768c2ecf20Sopenharmony_ci ba->sn = enable ? cpu_to_le16(params->ssn) : 0; 11778c2ecf20Sopenharmony_ci ba->ba_en = enable; 11788c2ecf20Sopenharmony_ci } else { 11798c2ecf20Sopenharmony_ci memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); 11808c2ecf20Sopenharmony_ci ba->ba_type = MT_BA_TYPE_RECIPIENT; 11818c2ecf20Sopenharmony_ci ba->rst_ba_tid = params->tid; 11828c2ecf20Sopenharmony_ci ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; 11838c2ecf20Sopenharmony_ci ba->rst_ba_sb = 1; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (enable && tx) 11878c2ecf20Sopenharmony_ci ba->ba_winsize = cpu_to_le16(params->buf_size); 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic int 11918c2ecf20Sopenharmony_cimt7915_mcu_sta_ba(struct mt7915_dev *dev, 11928c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 11938c2ecf20Sopenharmony_ci bool enable, bool tx) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv; 11968c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = msta->vif; 11978c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 11988c2ecf20Sopenharmony_ci struct tlv *sta_wtbl; 11998c2ecf20Sopenharmony_ci struct sk_buff *skb; 12008c2ecf20Sopenharmony_ci int ret; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (enable && tx && !params->amsdu) 12038c2ecf20Sopenharmony_ci msta->wcid.amsdu = false; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, 12068c2ecf20Sopenharmony_ci MT7915_STA_UPDATE_MAX_SIZE); 12078c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 12088c2ecf20Sopenharmony_ci return PTR_ERR(skb); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, 12138c2ecf20Sopenharmony_ci &skb); 12148c2ecf20Sopenharmony_ci mt7915_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci ret = __mt76_mcu_skb_send_msg(&dev->mt76, skb, 12178c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 12188c2ecf20Sopenharmony_ci if (ret) 12198c2ecf20Sopenharmony_ci return ret; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, 12228c2ecf20Sopenharmony_ci MT7915_STA_UPDATE_MAX_SIZE); 12238c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 12248c2ecf20Sopenharmony_ci return PTR_ERR(skb); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 12298c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ciint mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, 12338c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 12348c2ecf20Sopenharmony_ci bool enable) 12358c2ecf20Sopenharmony_ci{ 12368c2ecf20Sopenharmony_ci return mt7915_mcu_sta_ba(dev, params, enable, true); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ciint mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, 12408c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 12418c2ecf20Sopenharmony_ci bool enable) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci return mt7915_mcu_sta_ba(dev, params, enable, false); 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_cistatic void 12478c2ecf20Sopenharmony_cimt7915_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 12488c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, void *sta_wtbl, 12498c2ecf20Sopenharmony_ci void *wtbl_tlv) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 12528c2ecf20Sopenharmony_ci struct wtbl_generic *generic; 12538c2ecf20Sopenharmony_ci struct wtbl_rx *rx; 12548c2ecf20Sopenharmony_ci struct tlv *tlv; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), 12578c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci generic = (struct wtbl_generic *)tlv; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (sta) { 12628c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 12638c2ecf20Sopenharmony_ci generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); 12648c2ecf20Sopenharmony_ci else 12658c2ecf20Sopenharmony_ci generic->partial_aid = cpu_to_le16(sta->aid); 12668c2ecf20Sopenharmony_ci memcpy(generic->peer_addr, sta->addr, ETH_ALEN); 12678c2ecf20Sopenharmony_ci generic->muar_idx = mvif->omac_idx; 12688c2ecf20Sopenharmony_ci generic->qos = sta->wme; 12698c2ecf20Sopenharmony_ci } else { 12708c2ecf20Sopenharmony_ci /* use BSSID in station mode */ 12718c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 12728c2ecf20Sopenharmony_ci memcpy(generic->peer_addr, vif->bss_conf.bssid, 12738c2ecf20Sopenharmony_ci ETH_ALEN); 12748c2ecf20Sopenharmony_ci else 12758c2ecf20Sopenharmony_ci eth_broadcast_addr(generic->peer_addr); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci generic->muar_idx = 0xe; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), 12818c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci rx = (struct wtbl_rx *)tlv; 12848c2ecf20Sopenharmony_ci rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; 12858c2ecf20Sopenharmony_ci rx->rca2 = 1; 12868c2ecf20Sopenharmony_ci rx->rv = 1; 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic void 12908c2ecf20Sopenharmony_cimt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 12918c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci#define EXTRA_INFO_VER BIT(0) 12948c2ecf20Sopenharmony_ci#define EXTRA_INFO_NEW BIT(1) 12958c2ecf20Sopenharmony_ci struct sta_rec_basic *basic; 12968c2ecf20Sopenharmony_ci struct tlv *tlv; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci basic = (struct sta_rec_basic *)tlv; 13018c2ecf20Sopenharmony_ci basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (enable) { 13048c2ecf20Sopenharmony_ci basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); 13058c2ecf20Sopenharmony_ci basic->conn_state = CONN_STATE_PORT_SECURE; 13068c2ecf20Sopenharmony_ci } else { 13078c2ecf20Sopenharmony_ci basic->conn_state = CONN_STATE_DISCONNECT; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (!sta) { 13118c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); 13128c2ecf20Sopenharmony_ci eth_broadcast_addr(basic->peer_addr); 13138c2ecf20Sopenharmony_ci return; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci switch (vif->type) { 13178c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 13188c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 13198c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA); 13208c2ecf20Sopenharmony_ci basic->aid = cpu_to_le16(sta->aid); 13218c2ecf20Sopenharmony_ci break; 13228c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 13238c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP); 13248c2ecf20Sopenharmony_ci basic->aid = cpu_to_le16(vif->bss_conf.aid); 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 13278c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); 13288c2ecf20Sopenharmony_ci basic->aid = cpu_to_le16(sta->aid); 13298c2ecf20Sopenharmony_ci break; 13308c2ecf20Sopenharmony_ci default: 13318c2ecf20Sopenharmony_ci WARN_ON(1); 13328c2ecf20Sopenharmony_ci break; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci memcpy(basic->peer_addr, sta->addr, ETH_ALEN); 13368c2ecf20Sopenharmony_ci basic->qos = sta->wme; 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic void 13408c2ecf20Sopenharmony_cimt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; 13438c2ecf20Sopenharmony_ci struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; 13448c2ecf20Sopenharmony_ci struct sta_rec_he *he; 13458c2ecf20Sopenharmony_ci struct tlv *tlv; 13468c2ecf20Sopenharmony_ci u32 cap = 0; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci he = (struct sta_rec_he *)tlv; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) 13538c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_HTC; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) 13568c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_BSR; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) 13598c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_OM; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU) 13628c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) 13658c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_BQR; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (elem->phy_cap_info[0] & 13688c2ecf20Sopenharmony_ci (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | 13698c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) 13708c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (elem->phy_cap_info[1] & 13738c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) 13748c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_LDPC; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (elem->phy_cap_info[1] & 13778c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) 13788c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (elem->phy_cap_info[2] & 13818c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) 13828c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (elem->phy_cap_info[2] & 13858c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) 13868c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (elem->phy_cap_info[2] & 13898c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) 13908c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci if (elem->phy_cap_info[6] & 13938c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) 13948c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci if (elem->phy_cap_info[7] & 13978c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) 13988c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (elem->phy_cap_info[7] & 14018c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) 14028c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (elem->phy_cap_info[7] & 14058c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) 14068c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (elem->phy_cap_info[8] & 14098c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) 14108c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (elem->phy_cap_info[8] & 14138c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) 14148c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (elem->phy_cap_info[9] & 14178c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK) 14188c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_TRIG_CQI_FK; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (elem->phy_cap_info[9] & 14218c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) 14228c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (elem->phy_cap_info[9] & 14258c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) 14268c2ecf20Sopenharmony_ci cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci he->he_cap = cpu_to_le32(cap); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci switch (sta->bandwidth) { 14318c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 14328c2ecf20Sopenharmony_ci if (elem->phy_cap_info[0] & 14338c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) 14348c2ecf20Sopenharmony_ci he->max_nss_mcs[CMD_HE_MCS_BW8080] = 14358c2ecf20Sopenharmony_ci he_cap->he_mcs_nss_supp.rx_mcs_80p80; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci he->max_nss_mcs[CMD_HE_MCS_BW160] = 14388c2ecf20Sopenharmony_ci he_cap->he_mcs_nss_supp.rx_mcs_160; 14398c2ecf20Sopenharmony_ci fallthrough; 14408c2ecf20Sopenharmony_ci default: 14418c2ecf20Sopenharmony_ci he->max_nss_mcs[CMD_HE_MCS_BW80] = 14428c2ecf20Sopenharmony_ci he_cap->he_mcs_nss_supp.rx_mcs_80; 14438c2ecf20Sopenharmony_ci break; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci he->t_frame_dur = 14478c2ecf20Sopenharmony_ci HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); 14488c2ecf20Sopenharmony_ci he->max_ampdu_exp = 14498c2ecf20Sopenharmony_ci HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci he->bw_set = 14528c2ecf20Sopenharmony_ci HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); 14538c2ecf20Sopenharmony_ci he->device_class = 14548c2ecf20Sopenharmony_ci HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); 14558c2ecf20Sopenharmony_ci he->punc_pream_rx = 14568c2ecf20Sopenharmony_ci HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci he->dcm_tx_mode = 14598c2ecf20Sopenharmony_ci HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); 14608c2ecf20Sopenharmony_ci he->dcm_tx_max_nss = 14618c2ecf20Sopenharmony_ci HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); 14628c2ecf20Sopenharmony_ci he->dcm_rx_mode = 14638c2ecf20Sopenharmony_ci HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); 14648c2ecf20Sopenharmony_ci he->dcm_rx_max_nss = 14658c2ecf20Sopenharmony_ci HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); 14668c2ecf20Sopenharmony_ci he->dcm_rx_max_nss = 14678c2ecf20Sopenharmony_ci HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci he->pkt_ext = 2; 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic void 14738c2ecf20Sopenharmony_cimt7915_mcu_sta_uapsd_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 14748c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci struct sta_rec_uapsd *uapsd; 14778c2ecf20Sopenharmony_ci struct tlv *tlv; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP || !sta->wme) 14808c2ecf20Sopenharmony_ci return; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); 14838c2ecf20Sopenharmony_ci uapsd = (struct sta_rec_uapsd *)tlv; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { 14868c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(3); 14878c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(3); 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { 14908c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(2); 14918c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(2); 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { 14948c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(1); 14958c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(1); 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { 14988c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(0); 14998c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(0); 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci uapsd->max_sp = sta->max_sp; 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic void 15058c2ecf20Sopenharmony_cimt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; 15088c2ecf20Sopenharmony_ci struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; 15098c2ecf20Sopenharmony_ci struct sta_rec_muru *muru; 15108c2ecf20Sopenharmony_ci struct tlv *tlv; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci muru = (struct sta_rec_muru *)tlv; 15158c2ecf20Sopenharmony_ci muru->cfg.ofdma_dl_en = true; 15168c2ecf20Sopenharmony_ci muru->cfg.ofdma_ul_en = true; 15178c2ecf20Sopenharmony_ci muru->cfg.mimo_dl_en = true; 15188c2ecf20Sopenharmony_ci muru->cfg.mimo_ul_en = true; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci muru->ofdma_dl.punc_pream_rx = 15218c2ecf20Sopenharmony_ci HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); 15228c2ecf20Sopenharmony_ci muru->ofdma_dl.he_20m_in_40m_2g = 15238c2ecf20Sopenharmony_ci HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]); 15248c2ecf20Sopenharmony_ci muru->ofdma_dl.he_20m_in_160m = 15258c2ecf20Sopenharmony_ci HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); 15268c2ecf20Sopenharmony_ci muru->ofdma_dl.he_80m_in_160m = 15278c2ecf20Sopenharmony_ci HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); 15288c2ecf20Sopenharmony_ci muru->ofdma_dl.lt16_sigb = 0; 15298c2ecf20Sopenharmony_ci muru->ofdma_dl.rx_su_comp_sigb = 0; 15308c2ecf20Sopenharmony_ci muru->ofdma_dl.rx_su_non_comp_sigb = 0; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci muru->ofdma_ul.t_frame_dur = 15338c2ecf20Sopenharmony_ci HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); 15348c2ecf20Sopenharmony_ci muru->ofdma_ul.mu_cascading = 15358c2ecf20Sopenharmony_ci HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]); 15368c2ecf20Sopenharmony_ci muru->ofdma_ul.uo_ra = 15378c2ecf20Sopenharmony_ci HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]); 15388c2ecf20Sopenharmony_ci muru->ofdma_ul.he_2x996_tone = 0; 15398c2ecf20Sopenharmony_ci muru->ofdma_ul.rx_t_frame_11ac = 0; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci muru->mimo_dl.vht_mu_bfee = 15428c2ecf20Sopenharmony_ci !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); 15438c2ecf20Sopenharmony_ci muru->mimo_dl.partial_bw_dl_mimo = 15448c2ecf20Sopenharmony_ci HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci muru->mimo_ul.full_ul_mimo = 15478c2ecf20Sopenharmony_ci HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); 15488c2ecf20Sopenharmony_ci muru->mimo_ul.partial_ul_mimo = 15498c2ecf20Sopenharmony_ci HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); 15508c2ecf20Sopenharmony_ci} 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_cistatic int 15538c2ecf20Sopenharmony_cimt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, 15548c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 15558c2ecf20Sopenharmony_ci{ 15568c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 15578c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 15588c2ecf20Sopenharmony_ci struct sk_buff *skb; 15598c2ecf20Sopenharmony_ci int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_muru); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) 15628c2ecf20Sopenharmony_ci return 0; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); 15658c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 15668c2ecf20Sopenharmony_ci return PTR_ERR(skb); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* starec muru */ 15698c2ecf20Sopenharmony_ci mt7915_mcu_sta_muru_tlv(skb, sta); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 15728c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_cistatic void 15768c2ecf20Sopenharmony_cimt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 15798c2ecf20Sopenharmony_ci struct sta_rec_amsdu *amsdu; 15808c2ecf20Sopenharmony_ci struct tlv *tlv; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (!sta->max_amsdu_len) 15838c2ecf20Sopenharmony_ci return; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); 15868c2ecf20Sopenharmony_ci amsdu = (struct sta_rec_amsdu *)tlv; 15878c2ecf20Sopenharmony_ci amsdu->max_amsdu_num = 8; 15888c2ecf20Sopenharmony_ci amsdu->amsdu_en = true; 15898c2ecf20Sopenharmony_ci amsdu->max_mpdu_size = sta->max_amsdu_len >= 15908c2ecf20Sopenharmony_ci IEEE80211_MAX_MPDU_LEN_VHT_7991; 15918c2ecf20Sopenharmony_ci msta->wcid.amsdu = true; 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic bool 15958c2ecf20Sopenharmony_cimt7915_hw_amsdu_supported(struct ieee80211_vif *vif) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci switch (vif->type) { 15988c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 15998c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 16008c2ecf20Sopenharmony_ci return true; 16018c2ecf20Sopenharmony_ci default: 16028c2ecf20Sopenharmony_ci return false; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_cistatic void 16078c2ecf20Sopenharmony_cimt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 16088c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, struct ieee80211_vif *vif) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci struct tlv *tlv; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* starec ht */ 16138c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 16148c2ecf20Sopenharmony_ci struct sta_rec_ht *ht; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); 16178c2ecf20Sopenharmony_ci ht = (struct sta_rec_ht *)tlv; 16188c2ecf20Sopenharmony_ci ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (mt7915_hw_amsdu_supported(vif)) 16218c2ecf20Sopenharmony_ci mt7915_mcu_sta_amsdu_tlv(skb, sta); 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci /* starec vht */ 16258c2ecf20Sopenharmony_ci if (sta->vht_cap.vht_supported) { 16268c2ecf20Sopenharmony_ci struct sta_rec_vht *vht; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); 16298c2ecf20Sopenharmony_ci vht = (struct sta_rec_vht *)tlv; 16308c2ecf20Sopenharmony_ci vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); 16318c2ecf20Sopenharmony_ci vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; 16328c2ecf20Sopenharmony_ci vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci /* starec he */ 16368c2ecf20Sopenharmony_ci if (sta->he_cap.has_he) 16378c2ecf20Sopenharmony_ci mt7915_mcu_sta_he_tlv(skb, sta); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* starec uapsd */ 16408c2ecf20Sopenharmony_ci mt7915_mcu_sta_uapsd_tlv(skb, sta, vif); 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic void 16448c2ecf20Sopenharmony_cimt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 16458c2ecf20Sopenharmony_ci void *sta_wtbl, void *wtbl_tlv) 16468c2ecf20Sopenharmony_ci{ 16478c2ecf20Sopenharmony_ci struct wtbl_smps *smps; 16488c2ecf20Sopenharmony_ci struct tlv *tlv; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), 16518c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 16528c2ecf20Sopenharmony_ci smps = (struct wtbl_smps *)tlv; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) 16558c2ecf20Sopenharmony_ci smps->smps = true; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic void 16598c2ecf20Sopenharmony_cimt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 16608c2ecf20Sopenharmony_ci void *sta_wtbl, void *wtbl_tlv) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci struct wtbl_ht *ht = NULL; 16638c2ecf20Sopenharmony_ci struct tlv *tlv; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci /* wtbl ht */ 16668c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 16678c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), 16688c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 16698c2ecf20Sopenharmony_ci ht = (struct wtbl_ht *)tlv; 16708c2ecf20Sopenharmony_ci ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; 16718c2ecf20Sopenharmony_ci ht->af = sta->ht_cap.ampdu_factor; 16728c2ecf20Sopenharmony_ci ht->mm = sta->ht_cap.ampdu_density; 16738c2ecf20Sopenharmony_ci ht->ht = true; 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci /* wtbl vht */ 16778c2ecf20Sopenharmony_ci if (sta->vht_cap.vht_supported) { 16788c2ecf20Sopenharmony_ci struct wtbl_vht *vht; 16798c2ecf20Sopenharmony_ci u8 af; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), 16828c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 16838c2ecf20Sopenharmony_ci vht = (struct wtbl_vht *)tlv; 16848c2ecf20Sopenharmony_ci vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC, 16858c2ecf20Sopenharmony_ci vht->vht = true; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, 16888c2ecf20Sopenharmony_ci sta->vht_cap.cap); 16898c2ecf20Sopenharmony_ci if (ht) 16908c2ecf20Sopenharmony_ci ht->af = max_t(u8, ht->af, af); 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv); 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ciint mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, 16978c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 17008c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 17018c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 17028c2ecf20Sopenharmony_ci struct tlv *sta_wtbl; 17038c2ecf20Sopenharmony_ci struct sk_buff *skb; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, 17068c2ecf20Sopenharmony_ci MT7915_STA_UPDATE_MAX_SIZE); 17078c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 17088c2ecf20Sopenharmony_ci return PTR_ERR(skb); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, 17138c2ecf20Sopenharmony_ci &skb); 17148c2ecf20Sopenharmony_ci mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 17178c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cistatic void 17218c2ecf20Sopenharmony_cimt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci bf->sounding_phy = MT_PHY_TYPE_OFDM; 17248c2ecf20Sopenharmony_ci bf->ndp_rate = 0; /* mcs0 */ 17258c2ecf20Sopenharmony_ci bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ 17268c2ecf20Sopenharmony_ci bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic void 17308c2ecf20Sopenharmony_cimt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct sta_rec_bf *bf) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; 17338c2ecf20Sopenharmony_ci u8 n = 0; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci bf->tx_mode = MT_PHY_TYPE_HT; 17368c2ecf20Sopenharmony_ci bf->bf_cap |= MT_IBF; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF && 17398c2ecf20Sopenharmony_ci (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) 17408c2ecf20Sopenharmony_ci n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK, 17418c2ecf20Sopenharmony_ci mcs->tx_params); 17428c2ecf20Sopenharmony_ci else if (mcs->rx_mask[3]) 17438c2ecf20Sopenharmony_ci n = 3; 17448c2ecf20Sopenharmony_ci else if (mcs->rx_mask[2]) 17458c2ecf20Sopenharmony_ci n = 2; 17468c2ecf20Sopenharmony_ci else if (mcs->rx_mask[1]) 17478c2ecf20Sopenharmony_ci n = 1; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci bf->nc = min_t(u8, bf->nr, n); 17508c2ecf20Sopenharmony_ci bf->ibf_ncol = bf->nc; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->nc) 17538c2ecf20Sopenharmony_ci bf->ibf_timeout = 0x48; 17548c2ecf20Sopenharmony_ci} 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_cistatic void 17578c2ecf20Sopenharmony_cimt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy, 17588c2ecf20Sopenharmony_ci struct sta_rec_bf *bf) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *pc = &sta->vht_cap; 17618c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap; 17628c2ecf20Sopenharmony_ci u8 bfee_nr, bfer_nr, n, tx_ant = hweight8(phy->chainmask) - 1; 17638c2ecf20Sopenharmony_ci u16 mcs_map; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci bf->tx_mode = MT_PHY_TYPE_VHT; 17668c2ecf20Sopenharmony_ci bf->bf_cap |= MT_EBF; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci mt7915_mcu_sta_sounding_rate(bf); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci bfee_nr = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 17718c2ecf20Sopenharmony_ci pc->cap); 17728c2ecf20Sopenharmony_ci bfer_nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, 17738c2ecf20Sopenharmony_ci vc->cap); 17748c2ecf20Sopenharmony_ci mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci n = min_t(u8, bfer_nr, bfee_nr); 17778c2ecf20Sopenharmony_ci bf->nr = min_t(u8, n, tx_ant); 17788c2ecf20Sopenharmony_ci n = mt7915_mcu_get_sta_nss(mcs_map); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci bf->nc = min_t(u8, n, bf->nr); 17818c2ecf20Sopenharmony_ci bf->ibf_ncol = bf->nc; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci /* force nr from 4 to 2 */ 17848c2ecf20Sopenharmony_ci if (sta->bandwidth == IEEE80211_STA_RX_BW_160) 17858c2ecf20Sopenharmony_ci bf->nr = 1; 17868c2ecf20Sopenharmony_ci} 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cistatic void 17898c2ecf20Sopenharmony_cimt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, 17908c2ecf20Sopenharmony_ci struct mt7915_phy *phy, struct sta_rec_bf *bf) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci struct ieee80211_sta_he_cap *pc = &sta->he_cap; 17938c2ecf20Sopenharmony_ci struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; 17948c2ecf20Sopenharmony_ci const struct ieee80211_he_cap_elem *ve; 17958c2ecf20Sopenharmony_ci const struct ieee80211_sta_he_cap *vc; 17968c2ecf20Sopenharmony_ci u8 bfee_nr, bfer_nr, nss_mcs; 17978c2ecf20Sopenharmony_ci u16 mcs_map; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci vc = mt7915_get_he_phy_cap(phy, vif); 18008c2ecf20Sopenharmony_ci ve = &vc->he_cap_elem; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci bf->tx_mode = MT_PHY_TYPE_HE_SU; 18038c2ecf20Sopenharmony_ci bf->bf_cap |= MT_EBF; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci mt7915_mcu_sta_sounding_rate(bf); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMER_FB, 18088c2ecf20Sopenharmony_ci pe->phy_cap_info[6]); 18098c2ecf20Sopenharmony_ci bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMER_FB, 18108c2ecf20Sopenharmony_ci pe->phy_cap_info[6]); 18118c2ecf20Sopenharmony_ci bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, 18128c2ecf20Sopenharmony_ci ve->phy_cap_info[5]); 18138c2ecf20Sopenharmony_ci bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, 18148c2ecf20Sopenharmony_ci pe->phy_cap_info[4]); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.tx_mcs_80); 18178c2ecf20Sopenharmony_ci nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci bf->nr = min_t(u8, bfer_nr, bfee_nr); 18208c2ecf20Sopenharmony_ci bf->nc = min_t(u8, nss_mcs, bf->nr); 18218c2ecf20Sopenharmony_ci bf->ibf_ncol = bf->nc; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (sta->bandwidth != IEEE80211_STA_RX_BW_160) 18248c2ecf20Sopenharmony_ci return; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci /* go over for 160MHz and 80p80 */ 18278c2ecf20Sopenharmony_ci if (pe->phy_cap_info[0] & 18288c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) { 18298c2ecf20Sopenharmony_ci mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); 18308c2ecf20Sopenharmony_ci nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci bf->nc_bw160 = nss_mcs; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (pe->phy_cap_info[0] & 18368c2ecf20Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { 18378c2ecf20Sopenharmony_ci mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); 18388c2ecf20Sopenharmony_ci nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (bf->nc_bw160) 18418c2ecf20Sopenharmony_ci bf->nc_bw160 = min_t(u8, bf->nc_bw160, nss_mcs); 18428c2ecf20Sopenharmony_ci else 18438c2ecf20Sopenharmony_ci bf->nc_bw160 = nss_mcs; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, 18478c2ecf20Sopenharmony_ci ve->phy_cap_info[5]); 18488c2ecf20Sopenharmony_ci bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, 18498c2ecf20Sopenharmony_ci pe->phy_cap_info[4]); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci bf->nr_bw160 = min_t(int, bfer_nr, bfee_nr); 18528c2ecf20Sopenharmony_ci} 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_cistatic void 18558c2ecf20Sopenharmony_cimt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 18568c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, struct mt7915_phy *phy, 18578c2ecf20Sopenharmony_ci bool enable) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci struct sta_rec_bf *bf; 18608c2ecf20Sopenharmony_ci struct tlv *tlv; 18618c2ecf20Sopenharmony_ci int tx_ant = hweight8(phy->chainmask) - 1; 18628c2ecf20Sopenharmony_ci const u8 matrix[4][4] = { 18638c2ecf20Sopenharmony_ci {0, 0, 0, 0}, 18648c2ecf20Sopenharmony_ci {1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */ 18658c2ecf20Sopenharmony_ci {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ 18668c2ecf20Sopenharmony_ci {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ 18678c2ecf20Sopenharmony_ci }; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci#define MT_BFER_FREE cpu_to_le16(GENMASK(15, 0)) 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf)); 18728c2ecf20Sopenharmony_ci bf = (struct sta_rec_bf *)tlv; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (!enable) { 18758c2ecf20Sopenharmony_ci bf->pfmu = MT_BFER_FREE; 18768c2ecf20Sopenharmony_ci return; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci bf->bw = sta->bandwidth; 18808c2ecf20Sopenharmony_ci bf->ibf_dbw = sta->bandwidth; 18818c2ecf20Sopenharmony_ci bf->ibf_nrow = tx_ant; 18828c2ecf20Sopenharmony_ci bf->ibf_timeout = 0x18; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci if (sta->he_cap.has_he) 18858c2ecf20Sopenharmony_ci mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); 18868c2ecf20Sopenharmony_ci else if (sta->vht_cap.vht_supported) 18878c2ecf20Sopenharmony_ci mt7915_mcu_sta_bfer_vht(sta, phy, bf); 18888c2ecf20Sopenharmony_ci else if (sta->ht_cap.ht_supported) 18898c2ecf20Sopenharmony_ci mt7915_mcu_sta_bfer_ht(sta, bf); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci if (bf->bf_cap & MT_EBF && bf->nr != tx_ant) 18928c2ecf20Sopenharmony_ci bf->mem_20m = matrix[tx_ant][bf->nc]; 18938c2ecf20Sopenharmony_ci else 18948c2ecf20Sopenharmony_ci bf->mem_20m = matrix[bf->nr][bf->nc]; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci switch (sta->bandwidth) { 18978c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 18988c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_80: 18998c2ecf20Sopenharmony_ci bf->mem_total = bf->mem_20m * 2; 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_40: 19028c2ecf20Sopenharmony_ci bf->mem_total = bf->mem_20m; 19038c2ecf20Sopenharmony_ci break; 19048c2ecf20Sopenharmony_ci case IEEE80211_STA_RX_BW_20: 19058c2ecf20Sopenharmony_ci default: 19068c2ecf20Sopenharmony_ci break; 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cistatic void 19118c2ecf20Sopenharmony_cimt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 19128c2ecf20Sopenharmony_ci struct mt7915_phy *phy) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci struct sta_rec_bfee *bfee; 19158c2ecf20Sopenharmony_ci struct tlv *tlv; 19168c2ecf20Sopenharmony_ci int tx_ant = hweight8(phy->chainmask) - 1; 19178c2ecf20Sopenharmony_ci u8 nr = 0; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee)); 19208c2ecf20Sopenharmony_ci bfee = (struct sta_rec_bfee *)tlv; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci if (sta->he_cap.has_he) { 19238c2ecf20Sopenharmony_ci struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, 19268c2ecf20Sopenharmony_ci pe->phy_cap_info[5]); 19278c2ecf20Sopenharmony_ci } else if (sta->vht_cap.vht_supported) { 19288c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *pc = &sta->vht_cap; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, 19318c2ecf20Sopenharmony_ci pc->cap); 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci /* reply with identity matrix to avoid 2x2 BF negative gain */ 19358c2ecf20Sopenharmony_ci if (nr == 1 && tx_ant == 2) 19368c2ecf20Sopenharmony_ci bfee->fb_identity_matrix = true; 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_cistatic u8 19408c2ecf20Sopenharmony_cimt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, 19418c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 19428c2ecf20Sopenharmony_ci{ 19438c2ecf20Sopenharmony_ci u8 type = 0; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION && 19468c2ecf20Sopenharmony_ci vif->type != NL80211_IFTYPE_AP) 19478c2ecf20Sopenharmony_ci return 0; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (sta->he_cap.has_he) { 19508c2ecf20Sopenharmony_ci struct ieee80211_he_cap_elem *pe; 19518c2ecf20Sopenharmony_ci const struct ieee80211_he_cap_elem *ve; 19528c2ecf20Sopenharmony_ci const struct ieee80211_sta_he_cap *vc; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci pe = &sta->he_cap.he_cap_elem; 19558c2ecf20Sopenharmony_ci vc = mt7915_get_he_phy_cap(phy, vif); 19568c2ecf20Sopenharmony_ci ve = &vc->he_cap_elem; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if ((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) || 19598c2ecf20Sopenharmony_ci HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) && 19608c2ecf20Sopenharmony_ci HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4])) 19618c2ecf20Sopenharmony_ci type |= MT_STA_BFEE; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if ((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) || 19648c2ecf20Sopenharmony_ci HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) && 19658c2ecf20Sopenharmony_ci HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])) 19668c2ecf20Sopenharmony_ci type |= MT_STA_BFER; 19678c2ecf20Sopenharmony_ci } else if (sta->vht_cap.vht_supported) { 19688c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *pc; 19698c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *vc; 19708c2ecf20Sopenharmony_ci u32 cr, ce; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci pc = &sta->vht_cap; 19738c2ecf20Sopenharmony_ci vc = &phy->mt76->sband_5g.sband.vht_cap; 19748c2ecf20Sopenharmony_ci cr = IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 19758c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; 19768c2ecf20Sopenharmony_ci ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 19778c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci if ((pc->cap & cr) && (vc->cap & ce)) 19808c2ecf20Sopenharmony_ci type |= MT_STA_BFEE; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci if ((vc->cap & cr) && (pc->cap & ce)) 19838c2ecf20Sopenharmony_ci type |= MT_STA_BFER; 19848c2ecf20Sopenharmony_ci } else if (sta->ht_cap.ht_supported) { 19858c2ecf20Sopenharmony_ci /* TODO: iBF */ 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci return type; 19898c2ecf20Sopenharmony_ci} 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_cistatic int 19928c2ecf20Sopenharmony_cimt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, 19938c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 19948c2ecf20Sopenharmony_ci{ 19958c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 19968c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 19978c2ecf20Sopenharmony_ci struct mt7915_phy *phy; 19988c2ecf20Sopenharmony_ci struct sk_buff *skb; 19998c2ecf20Sopenharmony_ci int r, len; 20008c2ecf20Sopenharmony_ci u8 type; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci type = mt7915_mcu_sta_txbf_type(phy, vif, sta); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci /* must keep each tag independent */ 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci /* starec bf */ 20098c2ecf20Sopenharmony_ci if (type & MT_STA_BFER) { 20108c2ecf20Sopenharmony_ci len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bf); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); 20138c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 20148c2ecf20Sopenharmony_ci return PTR_ERR(skb); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable); 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci r = __mt76_mcu_skb_send_msg(&dev->mt76, skb, 20198c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 20208c2ecf20Sopenharmony_ci if (r) 20218c2ecf20Sopenharmony_ci return r; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci /* starec bfee */ 20258c2ecf20Sopenharmony_ci if (type & MT_STA_BFEE) { 20268c2ecf20Sopenharmony_ci len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bfee); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); 20298c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 20308c2ecf20Sopenharmony_ci return PTR_ERR(skb); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci mt7915_mcu_sta_bfee_tlv(skb, sta, phy); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci r = __mt76_mcu_skb_send_msg(&dev->mt76, skb, 20358c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 20368c2ecf20Sopenharmony_ci if (r) 20378c2ecf20Sopenharmony_ci return r; 20388c2ecf20Sopenharmony_ci } 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci return 0; 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_cistatic void 20448c2ecf20Sopenharmony_cimt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, 20458c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 20468c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 20478c2ecf20Sopenharmony_ci{ 20488c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &dev->mphy.chandef; 20498c2ecf20Sopenharmony_ci struct sta_rec_ra *ra; 20508c2ecf20Sopenharmony_ci struct tlv *tlv; 20518c2ecf20Sopenharmony_ci enum nl80211_band band = chandef->chan->band; 20528c2ecf20Sopenharmony_ci u32 supp_rate = sta->supp_rates[band]; 20538c2ecf20Sopenharmony_ci int n_rates = hweight32(supp_rate); 20548c2ecf20Sopenharmony_ci u32 cap = sta->wme ? STA_CAP_WMM : 0; 20558c2ecf20Sopenharmony_ci u8 i, nss = sta->rx_nss, mcs = 0; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci ra = (struct sta_rec_ra *)tlv; 20608c2ecf20Sopenharmony_ci ra->valid = true; 20618c2ecf20Sopenharmony_ci ra->auto_rate = true; 20628c2ecf20Sopenharmony_ci ra->phy_mode = mt7915_get_phy_mode(dev, vif, band, sta); 20638c2ecf20Sopenharmony_ci ra->channel = chandef->chan->hw_value; 20648c2ecf20Sopenharmony_ci ra->bw = sta->bandwidth; 20658c2ecf20Sopenharmony_ci ra->rate_len = n_rates; 20668c2ecf20Sopenharmony_ci ra->phy.bw = sta->bandwidth; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci if (n_rates) { 20698c2ecf20Sopenharmony_ci if (band == NL80211_BAND_2GHZ) { 20708c2ecf20Sopenharmony_ci ra->supp_mode = MODE_CCK; 20718c2ecf20Sopenharmony_ci ra->supp_cck_rate = supp_rate & GENMASK(3, 0); 20728c2ecf20Sopenharmony_ci ra->phy.type = MT_PHY_TYPE_CCK; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (n_rates > 4) { 20758c2ecf20Sopenharmony_ci ra->supp_mode |= MODE_OFDM; 20768c2ecf20Sopenharmony_ci ra->supp_ofdm_rate = supp_rate >> 4; 20778c2ecf20Sopenharmony_ci ra->phy.type = MT_PHY_TYPE_OFDM; 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci } else { 20808c2ecf20Sopenharmony_ci ra->supp_mode = MODE_OFDM; 20818c2ecf20Sopenharmony_ci ra->supp_ofdm_rate = supp_rate; 20828c2ecf20Sopenharmony_ci ra->phy.type = MT_PHY_TYPE_OFDM; 20838c2ecf20Sopenharmony_ci } 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 20878c2ecf20Sopenharmony_ci for (i = 0; i < nss; i++) 20888c2ecf20Sopenharmony_ci ra->ht_mcs[i] = sta->ht_cap.mcs.rx_mask[i]; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; 20918c2ecf20Sopenharmony_ci ra->supp_mode |= MODE_HT; 20928c2ecf20Sopenharmony_ci mcs = hweight32(le32_to_cpu(ra->supp_ht_mcs)) - 1; 20938c2ecf20Sopenharmony_ci ra->af = sta->ht_cap.ampdu_factor; 20948c2ecf20Sopenharmony_ci ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci cap |= STA_CAP_HT; 20978c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) 20988c2ecf20Sopenharmony_ci cap |= STA_CAP_SGI_20; 20998c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) 21008c2ecf20Sopenharmony_ci cap |= STA_CAP_SGI_40; 21018c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) 21028c2ecf20Sopenharmony_ci cap |= STA_CAP_TX_STBC; 21038c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) 21048c2ecf20Sopenharmony_ci cap |= STA_CAP_RX_STBC; 21058c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) 21068c2ecf20Sopenharmony_ci cap |= STA_CAP_LDPC; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci if (sta->vht_cap.vht_supported) { 21108c2ecf20Sopenharmony_ci u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map); 21118c2ecf20Sopenharmony_ci u16 vht_mcs; 21128c2ecf20Sopenharmony_ci u8 af, mcs_prev; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, 21158c2ecf20Sopenharmony_ci sta->vht_cap.cap); 21168c2ecf20Sopenharmony_ci ra->af = max_t(u8, ra->af, af); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci cap |= STA_CAP_VHT; 21198c2ecf20Sopenharmony_ci if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) 21208c2ecf20Sopenharmony_ci cap |= STA_CAP_VHT_SGI_80; 21218c2ecf20Sopenharmony_ci if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) 21228c2ecf20Sopenharmony_ci cap |= STA_CAP_VHT_SGI_160; 21238c2ecf20Sopenharmony_ci if (sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) 21248c2ecf20Sopenharmony_ci cap |= STA_CAP_VHT_TX_STBC; 21258c2ecf20Sopenharmony_ci if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) 21268c2ecf20Sopenharmony_ci cap |= STA_CAP_VHT_RX_STBC; 21278c2ecf20Sopenharmony_ci if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) 21288c2ecf20Sopenharmony_ci cap |= STA_CAP_VHT_LDPC; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci ra->supp_mode |= MODE_VHT; 21318c2ecf20Sopenharmony_ci for (mcs = 0, i = 0; i < nss; i++, mcs_map >>= 2) { 21328c2ecf20Sopenharmony_ci switch (mcs_map & 0x3) { 21338c2ecf20Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_9: 21348c2ecf20Sopenharmony_ci vht_mcs = GENMASK(9, 0); 21358c2ecf20Sopenharmony_ci break; 21368c2ecf20Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_8: 21378c2ecf20Sopenharmony_ci vht_mcs = GENMASK(8, 0); 21388c2ecf20Sopenharmony_ci break; 21398c2ecf20Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_7: 21408c2ecf20Sopenharmony_ci vht_mcs = GENMASK(7, 0); 21418c2ecf20Sopenharmony_ci break; 21428c2ecf20Sopenharmony_ci default: 21438c2ecf20Sopenharmony_ci vht_mcs = 0; 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci ra->supp_vht_mcs[i] = cpu_to_le16(vht_mcs); 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci mcs_prev = hweight16(vht_mcs) - 1; 21498c2ecf20Sopenharmony_ci if (mcs_prev > mcs) 21508c2ecf20Sopenharmony_ci mcs = mcs_prev; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci /* only support 2ss on 160MHz */ 21538c2ecf20Sopenharmony_ci if (i > 1 && (ra->bw == CMD_CBW_160MHZ || 21548c2ecf20Sopenharmony_ci ra->bw == CMD_CBW_8080MHZ)) 21558c2ecf20Sopenharmony_ci break; 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci } 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci if (sta->he_cap.has_he) { 21608c2ecf20Sopenharmony_ci ra->supp_mode |= MODE_HE; 21618c2ecf20Sopenharmony_ci cap |= STA_CAP_HE; 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci ra->sta_status = cpu_to_le32(cap); 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci switch (BIT(fls(ra->supp_mode) - 1)) { 21678c2ecf20Sopenharmony_ci case MODE_VHT: 21688c2ecf20Sopenharmony_ci ra->phy.type = MT_PHY_TYPE_VHT; 21698c2ecf20Sopenharmony_ci ra->phy.mcs = mcs; 21708c2ecf20Sopenharmony_ci ra->phy.nss = nss; 21718c2ecf20Sopenharmony_ci ra->phy.stbc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC); 21728c2ecf20Sopenharmony_ci ra->phy.ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); 21738c2ecf20Sopenharmony_ci ra->phy.sgi = 21748c2ecf20Sopenharmony_ci !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); 21758c2ecf20Sopenharmony_ci break; 21768c2ecf20Sopenharmony_ci case MODE_HT: 21778c2ecf20Sopenharmony_ci ra->phy.type = MT_PHY_TYPE_HT; 21788c2ecf20Sopenharmony_ci ra->phy.mcs = mcs; 21798c2ecf20Sopenharmony_ci ra->phy.ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; 21808c2ecf20Sopenharmony_ci ra->phy.stbc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC); 21818c2ecf20Sopenharmony_ci ra->phy.sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); 21828c2ecf20Sopenharmony_ci break; 21838c2ecf20Sopenharmony_ci default: 21848c2ecf20Sopenharmony_ci break; 21858c2ecf20Sopenharmony_ci } 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ciint mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, 21898c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 21928c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 21938c2ecf20Sopenharmony_ci struct sk_buff *skb; 21948c2ecf20Sopenharmony_ci int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_ra); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); 21978c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 21988c2ecf20Sopenharmony_ci return PTR_ERR(skb); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 22038c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 22048c2ecf20Sopenharmony_ci} 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_cistatic int 22078c2ecf20Sopenharmony_cimt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, 22088c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 22098c2ecf20Sopenharmony_ci{ 22108c2ecf20Sopenharmony_ci#define MT_STA_BSS_GROUP 1 22118c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 22128c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 22138c2ecf20Sopenharmony_ci struct { 22148c2ecf20Sopenharmony_ci __le32 action; 22158c2ecf20Sopenharmony_ci u8 wlan_idx_lo; 22168c2ecf20Sopenharmony_ci u8 status; 22178c2ecf20Sopenharmony_ci u8 wlan_idx_hi; 22188c2ecf20Sopenharmony_ci u8 rsv0[5]; 22198c2ecf20Sopenharmony_ci __le32 val; 22208c2ecf20Sopenharmony_ci u8 rsv1[8]; 22218c2ecf20Sopenharmony_ci } __packed req = { 22228c2ecf20Sopenharmony_ci .action = cpu_to_le32(MT_STA_BSS_GROUP), 22238c2ecf20Sopenharmony_ci .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), 22248c2ecf20Sopenharmony_ci .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), 22258c2ecf20Sopenharmony_ci .val = cpu_to_le32(mvif->idx), 22268c2ecf20Sopenharmony_ci }; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_DRR_CTRL, 22298c2ecf20Sopenharmony_ci &req, sizeof(req), true); 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ciint mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, 22338c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci int ret; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci if (!sta) 22388c2ecf20Sopenharmony_ci return 0; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci /* must keep the order */ 22418c2ecf20Sopenharmony_ci ret = mt7915_mcu_add_group(dev, vif, sta); 22428c2ecf20Sopenharmony_ci if (ret) 22438c2ecf20Sopenharmony_ci return ret; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); 22468c2ecf20Sopenharmony_ci if (ret) 22478c2ecf20Sopenharmony_ci return ret; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci ret = mt7915_mcu_add_mu(dev, vif, sta); 22508c2ecf20Sopenharmony_ci if (ret) 22518c2ecf20Sopenharmony_ci return ret; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci if (enable) 22548c2ecf20Sopenharmony_ci return mt7915_mcu_add_rate_ctrl(dev, vif, sta); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci return 0; 22578c2ecf20Sopenharmony_ci} 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ciint mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, 22608c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 22618c2ecf20Sopenharmony_ci{ 22628c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 22638c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 22648c2ecf20Sopenharmony_ci struct mt7915_sta *msta; 22658c2ecf20Sopenharmony_ci struct tlv *sta_wtbl; 22668c2ecf20Sopenharmony_ci struct sk_buff *skb; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, 22718c2ecf20Sopenharmony_ci MT7915_STA_UPDATE_MAX_SIZE); 22728c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 22738c2ecf20Sopenharmony_ci return PTR_ERR(skb); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci mt7915_mcu_sta_basic_tlv(skb, vif, sta, enable); 22768c2ecf20Sopenharmony_ci if (enable && sta) 22778c2ecf20Sopenharmony_ci mt7915_mcu_sta_tlv(dev, skb, sta, vif); 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, 22828c2ecf20Sopenharmony_ci sta_wtbl, &skb); 22838c2ecf20Sopenharmony_ci if (enable) { 22848c2ecf20Sopenharmony_ci mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); 22858c2ecf20Sopenharmony_ci if (sta) 22868c2ecf20Sopenharmony_ci mt7915_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 22908c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 22918c2ecf20Sopenharmony_ci} 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ciint mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, 22948c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, u32 rate) 22958c2ecf20Sopenharmony_ci{ 22968c2ecf20Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 22978c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = msta->vif; 22988c2ecf20Sopenharmony_ci struct sta_rec_ra_fixed *ra; 22998c2ecf20Sopenharmony_ci struct sk_buff *skb; 23008c2ecf20Sopenharmony_ci struct tlv *tlv; 23018c2ecf20Sopenharmony_ci int len = sizeof(struct sta_req_hdr) + sizeof(*ra); 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); 23048c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 23058c2ecf20Sopenharmony_ci return PTR_ERR(skb); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); 23088c2ecf20Sopenharmony_ci ra = (struct sta_rec_ra_fixed *)tlv; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (!rate) { 23118c2ecf20Sopenharmony_ci ra->field = cpu_to_le32(RATE_PARAM_AUTO); 23128c2ecf20Sopenharmony_ci goto out; 23138c2ecf20Sopenharmony_ci } else { 23148c2ecf20Sopenharmony_ci ra->field = cpu_to_le32(RATE_PARAM_FIXED); 23158c2ecf20Sopenharmony_ci } 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci ra->phy.type = FIELD_GET(RATE_CFG_PHY_TYPE, rate); 23188c2ecf20Sopenharmony_ci ra->phy.bw = FIELD_GET(RATE_CFG_BW, rate); 23198c2ecf20Sopenharmony_ci ra->phy.nss = FIELD_GET(RATE_CFG_NSS, rate); 23208c2ecf20Sopenharmony_ci ra->phy.mcs = FIELD_GET(RATE_CFG_MCS, rate); 23218c2ecf20Sopenharmony_ci ra->phy.stbc = FIELD_GET(RATE_CFG_STBC, rate); 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci if (ra->phy.bw) 23248c2ecf20Sopenharmony_ci ra->phy.ldpc = 7; 23258c2ecf20Sopenharmony_ci else 23268c2ecf20Sopenharmony_ci ra->phy.ldpc = FIELD_GET(RATE_CFG_LDPC, rate) * 7; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci /* HT/VHT - SGI: 1, LGI: 0; HE - SGI: 0, MGI: 1, LGI: 2 */ 23298c2ecf20Sopenharmony_ci if (ra->phy.type > MT_PHY_TYPE_VHT) 23308c2ecf20Sopenharmony_ci ra->phy.sgi = ra->phy.mcs * 85; 23318c2ecf20Sopenharmony_ci else 23328c2ecf20Sopenharmony_ci ra->phy.sgi = ra->phy.mcs * 15; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ciout: 23358c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 23368c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 23378c2ecf20Sopenharmony_ci} 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ciint mt7915_mcu_add_dev_info(struct mt7915_dev *dev, 23408c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, bool enable) 23418c2ecf20Sopenharmony_ci{ 23428c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 23438c2ecf20Sopenharmony_ci struct { 23448c2ecf20Sopenharmony_ci struct req_hdr { 23458c2ecf20Sopenharmony_ci u8 omac_idx; 23468c2ecf20Sopenharmony_ci u8 dbdc_idx; 23478c2ecf20Sopenharmony_ci __le16 tlv_num; 23488c2ecf20Sopenharmony_ci u8 is_tlv_append; 23498c2ecf20Sopenharmony_ci u8 rsv[3]; 23508c2ecf20Sopenharmony_ci } __packed hdr; 23518c2ecf20Sopenharmony_ci struct req_tlv { 23528c2ecf20Sopenharmony_ci __le16 tag; 23538c2ecf20Sopenharmony_ci __le16 len; 23548c2ecf20Sopenharmony_ci u8 active; 23558c2ecf20Sopenharmony_ci u8 dbdc_idx; 23568c2ecf20Sopenharmony_ci u8 omac_addr[ETH_ALEN]; 23578c2ecf20Sopenharmony_ci } __packed tlv; 23588c2ecf20Sopenharmony_ci } data = { 23598c2ecf20Sopenharmony_ci .hdr = { 23608c2ecf20Sopenharmony_ci .omac_idx = mvif->omac_idx, 23618c2ecf20Sopenharmony_ci .dbdc_idx = mvif->band_idx, 23628c2ecf20Sopenharmony_ci .tlv_num = cpu_to_le16(1), 23638c2ecf20Sopenharmony_ci .is_tlv_append = 1, 23648c2ecf20Sopenharmony_ci }, 23658c2ecf20Sopenharmony_ci .tlv = { 23668c2ecf20Sopenharmony_ci .tag = cpu_to_le16(DEV_INFO_ACTIVE), 23678c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct req_tlv)), 23688c2ecf20Sopenharmony_ci .active = enable, 23698c2ecf20Sopenharmony_ci .dbdc_idx = mvif->band_idx, 23708c2ecf20Sopenharmony_ci }, 23718c2ecf20Sopenharmony_ci }; 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); 23748c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE, 23758c2ecf20Sopenharmony_ci &data, sizeof(data), true); 23768c2ecf20Sopenharmony_ci} 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_cistatic void 23798c2ecf20Sopenharmony_cimt7915_mcu_beacon_csa(struct sk_buff *rskb, struct sk_buff *skb, 23808c2ecf20Sopenharmony_ci struct bss_info_bcn *bcn, 23818c2ecf20Sopenharmony_ci struct ieee80211_mutable_offsets *offs) 23828c2ecf20Sopenharmony_ci{ 23838c2ecf20Sopenharmony_ci if (offs->cntdwn_counter_offs[0]) { 23848c2ecf20Sopenharmony_ci struct tlv *tlv; 23858c2ecf20Sopenharmony_ci struct bss_info_bcn_csa *csa; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CSA, 23888c2ecf20Sopenharmony_ci sizeof(*csa), &bcn->sub_ntlv, 23898c2ecf20Sopenharmony_ci &bcn->len); 23908c2ecf20Sopenharmony_ci csa = (struct bss_info_bcn_csa *)tlv; 23918c2ecf20Sopenharmony_ci csa->cnt = skb->data[offs->cntdwn_counter_offs[0]]; 23928c2ecf20Sopenharmony_ci } 23938c2ecf20Sopenharmony_ci} 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_cistatic void 23968c2ecf20Sopenharmony_cimt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, 23978c2ecf20Sopenharmony_ci struct sk_buff *skb, struct bss_info_bcn *bcn, 23988c2ecf20Sopenharmony_ci struct ieee80211_mutable_offsets *offs) 23998c2ecf20Sopenharmony_ci{ 24008c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = &dev->mt76.global_wcid; 24018c2ecf20Sopenharmony_ci struct bss_info_bcn_cont *cont; 24028c2ecf20Sopenharmony_ci struct tlv *tlv; 24038c2ecf20Sopenharmony_ci u8 *buf; 24048c2ecf20Sopenharmony_ci int len = sizeof(*cont) + MT_TXD_SIZE + skb->len; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT, 24078c2ecf20Sopenharmony_ci len, &bcn->sub_ntlv, &bcn->len); 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci cont = (struct bss_info_bcn_cont *)tlv; 24108c2ecf20Sopenharmony_ci cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); 24118c2ecf20Sopenharmony_ci cont->tim_ofs = cpu_to_le16(offs->tim_offset); 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci if (offs->cntdwn_counter_offs[0]) 24148c2ecf20Sopenharmony_ci cont->csa_ofs = cpu_to_le16(offs->cntdwn_counter_offs[0] - 4); 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci buf = (u8 *)tlv + sizeof(*cont); 24178c2ecf20Sopenharmony_ci mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 24188c2ecf20Sopenharmony_ci true); 24198c2ecf20Sopenharmony_ci memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); 24208c2ecf20Sopenharmony_ci} 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ciint mt7915_mcu_add_beacon(struct ieee80211_hw *hw, 24238c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, int en) 24248c2ecf20Sopenharmony_ci{ 24258c2ecf20Sopenharmony_ci#define MAX_BEACON_SIZE 512 24268c2ecf20Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 24278c2ecf20Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 24288c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 24298c2ecf20Sopenharmony_ci struct ieee80211_mutable_offsets offs; 24308c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 24318c2ecf20Sopenharmony_ci struct sk_buff *skb, *rskb; 24328c2ecf20Sopenharmony_ci struct tlv *tlv; 24338c2ecf20Sopenharmony_ci struct bss_info_bcn *bcn; 24348c2ecf20Sopenharmony_ci int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci skb = ieee80211_beacon_get_template(hw, vif, &offs); 24378c2ecf20Sopenharmony_ci if (!skb) 24388c2ecf20Sopenharmony_ci return -EINVAL; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci if (skb->len > MAX_BEACON_SIZE - MT_TXD_SIZE) { 24418c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); 24428c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 24438c2ecf20Sopenharmony_ci return -EINVAL; 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci rskb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len); 24478c2ecf20Sopenharmony_ci if (IS_ERR(rskb)) { 24488c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 24498c2ecf20Sopenharmony_ci return PTR_ERR(rskb); 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci tlv = mt7915_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn)); 24538c2ecf20Sopenharmony_ci bcn = (struct bss_info_bcn *)tlv; 24548c2ecf20Sopenharmony_ci bcn->enable = en; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci if (mvif->band_idx) { 24578c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 24588c2ecf20Sopenharmony_ci info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; 24598c2ecf20Sopenharmony_ci } 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci /* TODO: subtag - bss color count & 11v MBSSID */ 24628c2ecf20Sopenharmony_ci mt7915_mcu_beacon_csa(rskb, skb, bcn, &offs); 24638c2ecf20Sopenharmony_ci mt7915_mcu_beacon_cont(dev, rskb, skb, bcn, &offs); 24648c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, 24678c2ecf20Sopenharmony_ci MCU_EXT_CMD_BSS_INFO_UPDATE, true); 24688c2ecf20Sopenharmony_ci} 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_cistatic int mt7915_mcu_send_firmware(struct mt7915_dev *dev, const void *data, 24718c2ecf20Sopenharmony_ci int len) 24728c2ecf20Sopenharmony_ci{ 24738c2ecf20Sopenharmony_ci int ret = 0, cur_len; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci while (len > 0) { 24768c2ecf20Sopenharmony_ci cur_len = min_t(int, 4096 - sizeof(struct mt7915_mcu_txd), 24778c2ecf20Sopenharmony_ci len); 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER, 24808c2ecf20Sopenharmony_ci data, cur_len, false); 24818c2ecf20Sopenharmony_ci if (ret) 24828c2ecf20Sopenharmony_ci break; 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci data += cur_len; 24858c2ecf20Sopenharmony_ci len -= cur_len; 24868c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci return ret; 24908c2ecf20Sopenharmony_ci} 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_cistatic int mt7915_mcu_start_firmware(struct mt7915_dev *dev, u32 addr, 24938c2ecf20Sopenharmony_ci u32 option) 24948c2ecf20Sopenharmony_ci{ 24958c2ecf20Sopenharmony_ci struct { 24968c2ecf20Sopenharmony_ci __le32 option; 24978c2ecf20Sopenharmony_ci __le32 addr; 24988c2ecf20Sopenharmony_ci } req = { 24998c2ecf20Sopenharmony_ci .option = cpu_to_le32(option), 25008c2ecf20Sopenharmony_ci .addr = cpu_to_le32(addr), 25018c2ecf20Sopenharmony_ci }; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, 25048c2ecf20Sopenharmony_ci &req, sizeof(req), true); 25058c2ecf20Sopenharmony_ci} 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_cistatic int mt7915_mcu_restart(struct mt76_dev *dev) 25088c2ecf20Sopenharmony_ci{ 25098c2ecf20Sopenharmony_ci struct { 25108c2ecf20Sopenharmony_ci u8 power_mode; 25118c2ecf20Sopenharmony_ci u8 rsv[3]; 25128c2ecf20Sopenharmony_ci } req = { 25138c2ecf20Sopenharmony_ci .power_mode = 1, 25148c2ecf20Sopenharmony_ci }; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(dev, -MCU_CMD_NIC_POWER_CTRL, &req, 25178c2ecf20Sopenharmony_ci sizeof(req), false); 25188c2ecf20Sopenharmony_ci} 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_cistatic int mt7915_mcu_patch_sem_ctrl(struct mt7915_dev *dev, bool get) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci struct { 25238c2ecf20Sopenharmony_ci __le32 op; 25248c2ecf20Sopenharmony_ci } req = { 25258c2ecf20Sopenharmony_ci .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), 25268c2ecf20Sopenharmony_ci }; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL, 25298c2ecf20Sopenharmony_ci &req, sizeof(req), true); 25308c2ecf20Sopenharmony_ci} 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_cistatic int mt7915_mcu_start_patch(struct mt7915_dev *dev) 25338c2ecf20Sopenharmony_ci{ 25348c2ecf20Sopenharmony_ci struct { 25358c2ecf20Sopenharmony_ci u8 check_crc; 25368c2ecf20Sopenharmony_ci u8 reserved[3]; 25378c2ecf20Sopenharmony_ci } req = { 25388c2ecf20Sopenharmony_ci .check_crc = 0, 25398c2ecf20Sopenharmony_ci }; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ, 25428c2ecf20Sopenharmony_ci &req, sizeof(req), true); 25438c2ecf20Sopenharmony_ci} 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_cistatic int mt7915_driver_own(struct mt7915_dev *dev) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci u32 reg = mt7915_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); 25508c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, 25518c2ecf20Sopenharmony_ci 0, 500)) { 25528c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout for driver own\n"); 25538c2ecf20Sopenharmony_ci return -EIO; 25548c2ecf20Sopenharmony_ci } 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci return 0; 25578c2ecf20Sopenharmony_ci} 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_cistatic int mt7915_mcu_init_download(struct mt7915_dev *dev, u32 addr, 25608c2ecf20Sopenharmony_ci u32 len, u32 mode) 25618c2ecf20Sopenharmony_ci{ 25628c2ecf20Sopenharmony_ci struct { 25638c2ecf20Sopenharmony_ci __le32 addr; 25648c2ecf20Sopenharmony_ci __le32 len; 25658c2ecf20Sopenharmony_ci __le32 mode; 25668c2ecf20Sopenharmony_ci } req = { 25678c2ecf20Sopenharmony_ci .addr = cpu_to_le32(addr), 25688c2ecf20Sopenharmony_ci .len = cpu_to_le32(len), 25698c2ecf20Sopenharmony_ci .mode = cpu_to_le32(mode), 25708c2ecf20Sopenharmony_ci }; 25718c2ecf20Sopenharmony_ci int attr; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci if (req.addr == cpu_to_le32(MCU_PATCH_ADDRESS)) 25748c2ecf20Sopenharmony_ci attr = -MCU_CMD_PATCH_START_REQ; 25758c2ecf20Sopenharmony_ci else 25768c2ecf20Sopenharmony_ci attr = -MCU_CMD_TARGET_ADDRESS_LEN_REQ; 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true); 25798c2ecf20Sopenharmony_ci} 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_cistatic int mt7915_load_patch(struct mt7915_dev *dev) 25828c2ecf20Sopenharmony_ci{ 25838c2ecf20Sopenharmony_ci const struct mt7915_patch_hdr *hdr; 25848c2ecf20Sopenharmony_ci const struct firmware *fw = NULL; 25858c2ecf20Sopenharmony_ci int i, ret, sem; 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci sem = mt7915_mcu_patch_sem_ctrl(dev, 1); 25888c2ecf20Sopenharmony_ci switch (sem) { 25898c2ecf20Sopenharmony_ci case PATCH_IS_DL: 25908c2ecf20Sopenharmony_ci return 0; 25918c2ecf20Sopenharmony_ci case PATCH_NOT_DL_SEM_SUCCESS: 25928c2ecf20Sopenharmony_ci break; 25938c2ecf20Sopenharmony_ci default: 25948c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); 25958c2ecf20Sopenharmony_ci return -EAGAIN; 25968c2ecf20Sopenharmony_ci } 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci ret = request_firmware(&fw, MT7915_ROM_PATCH, dev->mt76.dev); 25998c2ecf20Sopenharmony_ci if (ret) 26008c2ecf20Sopenharmony_ci goto out; 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 26038c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 26048c2ecf20Sopenharmony_ci ret = -EINVAL; 26058c2ecf20Sopenharmony_ci goto out; 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci hdr = (const struct mt7915_patch_hdr *)(fw->data); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", 26118c2ecf20Sopenharmony_ci be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { 26148c2ecf20Sopenharmony_ci struct mt7915_patch_sec *sec; 26158c2ecf20Sopenharmony_ci const u8 *dl; 26168c2ecf20Sopenharmony_ci u32 len, addr; 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci sec = (struct mt7915_patch_sec *)(fw->data + sizeof(*hdr) + 26198c2ecf20Sopenharmony_ci i * sizeof(*sec)); 26208c2ecf20Sopenharmony_ci if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != 26218c2ecf20Sopenharmony_ci PATCH_SEC_TYPE_INFO) { 26228c2ecf20Sopenharmony_ci ret = -EINVAL; 26238c2ecf20Sopenharmony_ci goto out; 26248c2ecf20Sopenharmony_ci } 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci addr = be32_to_cpu(sec->info.addr); 26278c2ecf20Sopenharmony_ci len = be32_to_cpu(sec->info.len); 26288c2ecf20Sopenharmony_ci dl = fw->data + be32_to_cpu(sec->offs); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci ret = mt7915_mcu_init_download(dev, addr, len, 26318c2ecf20Sopenharmony_ci DL_MODE_NEED_RSP); 26328c2ecf20Sopenharmony_ci if (ret) { 26338c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Download request failed\n"); 26348c2ecf20Sopenharmony_ci goto out; 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci ret = mt7915_mcu_send_firmware(dev, dl, len); 26388c2ecf20Sopenharmony_ci if (ret) { 26398c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to send patch\n"); 26408c2ecf20Sopenharmony_ci goto out; 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci } 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci ret = mt7915_mcu_start_patch(dev); 26458c2ecf20Sopenharmony_ci if (ret) 26468c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start patch\n"); 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ciout: 26498c2ecf20Sopenharmony_ci sem = mt7915_mcu_patch_sem_ctrl(dev, 0); 26508c2ecf20Sopenharmony_ci switch (sem) { 26518c2ecf20Sopenharmony_ci case PATCH_REL_SEM_SUCCESS: 26528c2ecf20Sopenharmony_ci break; 26538c2ecf20Sopenharmony_ci default: 26548c2ecf20Sopenharmony_ci ret = -EAGAIN; 26558c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); 26568c2ecf20Sopenharmony_ci break; 26578c2ecf20Sopenharmony_ci } 26588c2ecf20Sopenharmony_ci release_firmware(fw); 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci return ret; 26618c2ecf20Sopenharmony_ci} 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_cistatic u32 mt7915_mcu_gen_dl_mode(u8 feature_set, bool is_wa) 26648c2ecf20Sopenharmony_ci{ 26658c2ecf20Sopenharmony_ci u32 ret = 0; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? 26688c2ecf20Sopenharmony_ci (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; 26698c2ecf20Sopenharmony_ci ret |= FIELD_PREP(DL_MODE_KEY_IDX, 26708c2ecf20Sopenharmony_ci FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); 26718c2ecf20Sopenharmony_ci ret |= DL_MODE_NEED_RSP; 26728c2ecf20Sopenharmony_ci ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci return ret; 26758c2ecf20Sopenharmony_ci} 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_cistatic int 26788c2ecf20Sopenharmony_cimt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, 26798c2ecf20Sopenharmony_ci const struct mt7915_fw_trailer *hdr, 26808c2ecf20Sopenharmony_ci const u8 *data, bool is_wa) 26818c2ecf20Sopenharmony_ci{ 26828c2ecf20Sopenharmony_ci int i, offset = 0; 26838c2ecf20Sopenharmony_ci u32 override = 0, option = 0; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci for (i = 0; i < hdr->n_region; i++) { 26868c2ecf20Sopenharmony_ci const struct mt7915_fw_region *region; 26878c2ecf20Sopenharmony_ci int err; 26888c2ecf20Sopenharmony_ci u32 len, addr, mode; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci region = (const struct mt7915_fw_region *)((const u8 *)hdr - 26918c2ecf20Sopenharmony_ci (hdr->n_region - i) * sizeof(*region)); 26928c2ecf20Sopenharmony_ci mode = mt7915_mcu_gen_dl_mode(region->feature_set, is_wa); 26938c2ecf20Sopenharmony_ci len = le32_to_cpu(region->len); 26948c2ecf20Sopenharmony_ci addr = le32_to_cpu(region->addr); 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) 26978c2ecf20Sopenharmony_ci override = addr; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci err = mt7915_mcu_init_download(dev, addr, len, mode); 27008c2ecf20Sopenharmony_ci if (err) { 27018c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Download request failed\n"); 27028c2ecf20Sopenharmony_ci return err; 27038c2ecf20Sopenharmony_ci } 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci err = mt7915_mcu_send_firmware(dev, data + offset, len); 27068c2ecf20Sopenharmony_ci if (err) { 27078c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to send firmware.\n"); 27088c2ecf20Sopenharmony_ci return err; 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci offset += len; 27128c2ecf20Sopenharmony_ci } 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci if (override) 27158c2ecf20Sopenharmony_ci option |= FW_START_OVERRIDE; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci if (is_wa) 27188c2ecf20Sopenharmony_ci option |= FW_START_WORKING_PDA_CR4; 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci return mt7915_mcu_start_firmware(dev, override, option); 27218c2ecf20Sopenharmony_ci} 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_cistatic int mt7915_load_ram(struct mt7915_dev *dev) 27248c2ecf20Sopenharmony_ci{ 27258c2ecf20Sopenharmony_ci const struct mt7915_fw_trailer *hdr; 27268c2ecf20Sopenharmony_ci const struct firmware *fw; 27278c2ecf20Sopenharmony_ci int ret; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci ret = request_firmware(&fw, MT7915_FIRMWARE_WM, dev->mt76.dev); 27308c2ecf20Sopenharmony_ci if (ret) 27318c2ecf20Sopenharmony_ci return ret; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 27348c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 27358c2ecf20Sopenharmony_ci ret = -EINVAL; 27368c2ecf20Sopenharmony_ci goto out; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - 27408c2ecf20Sopenharmony_ci sizeof(*hdr)); 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", 27438c2ecf20Sopenharmony_ci hdr->fw_ver, hdr->build_date); 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, false); 27468c2ecf20Sopenharmony_ci if (ret) { 27478c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); 27488c2ecf20Sopenharmony_ci goto out; 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci release_firmware(fw); 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci ret = request_firmware(&fw, MT7915_FIRMWARE_WA, dev->mt76.dev); 27548c2ecf20Sopenharmony_ci if (ret) 27558c2ecf20Sopenharmony_ci return ret; 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 27588c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 27598c2ecf20Sopenharmony_ci ret = -EINVAL; 27608c2ecf20Sopenharmony_ci goto out; 27618c2ecf20Sopenharmony_ci } 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - 27648c2ecf20Sopenharmony_ci sizeof(*hdr)); 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", 27678c2ecf20Sopenharmony_ci hdr->fw_ver, hdr->build_date); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, true); 27708c2ecf20Sopenharmony_ci if (ret) { 27718c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start WA firmware\n"); 27728c2ecf20Sopenharmony_ci goto out; 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci snprintf(dev->mt76.hw->wiphy->fw_version, 27768c2ecf20Sopenharmony_ci sizeof(dev->mt76.hw->wiphy->fw_version), 27778c2ecf20Sopenharmony_ci "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ciout: 27808c2ecf20Sopenharmony_ci release_firmware(fw); 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci return ret; 27838c2ecf20Sopenharmony_ci} 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_cistatic int mt7915_load_firmware(struct mt7915_dev *dev) 27868c2ecf20Sopenharmony_ci{ 27878c2ecf20Sopenharmony_ci int ret; 27888c2ecf20Sopenharmony_ci u32 val, reg = mt7915_reg_map_l1(dev, MT_TOP_MISC); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TOP_MISC_FW_STATE, FW_STATE_FW_DOWNLOAD); 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, val, 1000)) { 27938c2ecf20Sopenharmony_ci /* restart firmware once */ 27948c2ecf20Sopenharmony_ci __mt76_mcu_restart(&dev->mt76); 27958c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, 27968c2ecf20Sopenharmony_ci val, 1000)) { 27978c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, 27988c2ecf20Sopenharmony_ci "Firmware is not ready for download\n"); 27998c2ecf20Sopenharmony_ci return -EIO; 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci ret = mt7915_load_patch(dev); 28048c2ecf20Sopenharmony_ci if (ret) 28058c2ecf20Sopenharmony_ci return ret; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci ret = mt7915_load_ram(dev); 28088c2ecf20Sopenharmony_ci if (ret) 28098c2ecf20Sopenharmony_ci return ret; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, 28128c2ecf20Sopenharmony_ci FIELD_PREP(MT_TOP_MISC_FW_STATE, 28138c2ecf20Sopenharmony_ci FW_STATE_WACPU_RDY), 1000)) { 28148c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 28158c2ecf20Sopenharmony_ci return -EIO; 28168c2ecf20Sopenharmony_ci } 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci dev_dbg(dev->mt76.dev, "Firmware init done\n"); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci return 0; 28238c2ecf20Sopenharmony_ci} 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ciint mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl) 28268c2ecf20Sopenharmony_ci{ 28278c2ecf20Sopenharmony_ci struct { 28288c2ecf20Sopenharmony_ci u8 ctrl_val; 28298c2ecf20Sopenharmony_ci u8 pad[3]; 28308c2ecf20Sopenharmony_ci } data = { 28318c2ecf20Sopenharmony_ci .ctrl_val = ctrl 28328c2ecf20Sopenharmony_ci }; 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST, 28358c2ecf20Sopenharmony_ci &data, sizeof(data), true); 28368c2ecf20Sopenharmony_ci} 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ciint mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level) 28398c2ecf20Sopenharmony_ci{ 28408c2ecf20Sopenharmony_ci struct { 28418c2ecf20Sopenharmony_ci u8 ver; 28428c2ecf20Sopenharmony_ci u8 pad; 28438c2ecf20Sopenharmony_ci __le16 len; 28448c2ecf20Sopenharmony_ci u8 level; 28458c2ecf20Sopenharmony_ci u8 rsv[3]; 28468c2ecf20Sopenharmony_ci __le32 module_idx; 28478c2ecf20Sopenharmony_ci } data = { 28488c2ecf20Sopenharmony_ci .module_idx = cpu_to_le32(module), 28498c2ecf20Sopenharmony_ci .level = level, 28508c2ecf20Sopenharmony_ci }; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_DBG_CTRL, 28538c2ecf20Sopenharmony_ci &data, sizeof(data), false); 28548c2ecf20Sopenharmony_ci} 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ciint mt7915_mcu_init(struct mt7915_dev *dev) 28578c2ecf20Sopenharmony_ci{ 28588c2ecf20Sopenharmony_ci static const struct mt76_mcu_ops mt7915_mcu_ops = { 28598c2ecf20Sopenharmony_ci .headroom = sizeof(struct mt7915_mcu_txd), 28608c2ecf20Sopenharmony_ci .mcu_skb_send_msg = mt7915_mcu_send_message, 28618c2ecf20Sopenharmony_ci .mcu_send_msg = mt7915_mcu_msg_send, 28628c2ecf20Sopenharmony_ci .mcu_restart = mt7915_mcu_restart, 28638c2ecf20Sopenharmony_ci }; 28648c2ecf20Sopenharmony_ci int ret; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci dev->mt76.mcu_ops = &mt7915_mcu_ops, 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci ret = mt7915_driver_own(dev); 28698c2ecf20Sopenharmony_ci if (ret) 28708c2ecf20Sopenharmony_ci return ret; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci ret = mt7915_load_firmware(dev); 28738c2ecf20Sopenharmony_ci if (ret) 28748c2ecf20Sopenharmony_ci return ret; 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 28778c2ecf20Sopenharmony_ci mt7915_mcu_fw_log_2_host(dev, 0); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci return 0; 28808c2ecf20Sopenharmony_ci} 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_civoid mt7915_mcu_exit(struct mt7915_dev *dev) 28838c2ecf20Sopenharmony_ci{ 28848c2ecf20Sopenharmony_ci u32 reg = mt7915_reg_map_l1(dev, MT_TOP_MISC); 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci __mt76_mcu_restart(&dev->mt76); 28878c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, 28888c2ecf20Sopenharmony_ci FIELD_PREP(MT_TOP_MISC_FW_STATE, 28898c2ecf20Sopenharmony_ci FW_STATE_FW_DOWNLOAD), 1000)) { 28908c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to exit mcu\n"); 28918c2ecf20Sopenharmony_ci return; 28928c2ecf20Sopenharmony_ci } 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci reg = mt7915_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 28958c2ecf20Sopenharmony_ci mt76_wr(dev, reg, MT_TOP_LPCR_HOST_FW_OWN); 28968c2ecf20Sopenharmony_ci skb_queue_purge(&dev->mt76.mcu.res_q); 28978c2ecf20Sopenharmony_ci} 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ciint mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, 29008c2ecf20Sopenharmony_ci bool enable, bool hdr_trans) 29018c2ecf20Sopenharmony_ci{ 29028c2ecf20Sopenharmony_ci struct { 29038c2ecf20Sopenharmony_ci u8 operation; 29048c2ecf20Sopenharmony_ci u8 enable; 29058c2ecf20Sopenharmony_ci u8 check_bssid; 29068c2ecf20Sopenharmony_ci u8 insert_vlan; 29078c2ecf20Sopenharmony_ci u8 remove_vlan; 29088c2ecf20Sopenharmony_ci u8 tid; 29098c2ecf20Sopenharmony_ci u8 mode; 29108c2ecf20Sopenharmony_ci u8 rsv; 29118c2ecf20Sopenharmony_ci } __packed req_trans = { 29128c2ecf20Sopenharmony_ci .enable = hdr_trans, 29138c2ecf20Sopenharmony_ci }; 29148c2ecf20Sopenharmony_ci struct { 29158c2ecf20Sopenharmony_ci u8 enable; 29168c2ecf20Sopenharmony_ci u8 band; 29178c2ecf20Sopenharmony_ci u8 rsv[2]; 29188c2ecf20Sopenharmony_ci } __packed req_mac = { 29198c2ecf20Sopenharmony_ci .enable = enable, 29208c2ecf20Sopenharmony_ci .band = band, 29218c2ecf20Sopenharmony_ci }; 29228c2ecf20Sopenharmony_ci int ret; 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS, 29258c2ecf20Sopenharmony_ci &req_trans, sizeof(req_trans), false); 29268c2ecf20Sopenharmony_ci if (ret) 29278c2ecf20Sopenharmony_ci return ret; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, 29308c2ecf20Sopenharmony_ci &req_mac, sizeof(req_mac), true); 29318c2ecf20Sopenharmony_ci} 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ciint mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable) 29348c2ecf20Sopenharmony_ci{ 29358c2ecf20Sopenharmony_ci struct { 29368c2ecf20Sopenharmony_ci __le32 cmd; 29378c2ecf20Sopenharmony_ci u8 band; 29388c2ecf20Sopenharmony_ci u8 enable; 29398c2ecf20Sopenharmony_ci } __packed req = { 29408c2ecf20Sopenharmony_ci .cmd = cpu_to_le32(SCS_ENABLE), 29418c2ecf20Sopenharmony_ci .band = band, 29428c2ecf20Sopenharmony_ci .enable = enable + 1, 29438c2ecf20Sopenharmony_ci }; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SCS_CTRL, &req, 29468c2ecf20Sopenharmony_ci sizeof(req), false); 29478c2ecf20Sopenharmony_ci} 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ciint mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val) 29508c2ecf20Sopenharmony_ci{ 29518c2ecf20Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 29528c2ecf20Sopenharmony_ci struct { 29538c2ecf20Sopenharmony_ci u8 prot_idx; 29548c2ecf20Sopenharmony_ci u8 band; 29558c2ecf20Sopenharmony_ci u8 rsv[2]; 29568c2ecf20Sopenharmony_ci __le32 len_thresh; 29578c2ecf20Sopenharmony_ci __le32 pkt_thresh; 29588c2ecf20Sopenharmony_ci } __packed req = { 29598c2ecf20Sopenharmony_ci .prot_idx = 1, 29608c2ecf20Sopenharmony_ci .band = phy != &dev->phy, 29618c2ecf20Sopenharmony_ci .len_thresh = cpu_to_le32(val), 29628c2ecf20Sopenharmony_ci .pkt_thresh = cpu_to_le32(0x2), 29638c2ecf20Sopenharmony_ci }; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, 29668c2ecf20Sopenharmony_ci &req, sizeof(req), true); 29678c2ecf20Sopenharmony_ci} 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ciint mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) 29708c2ecf20Sopenharmony_ci{ 29718c2ecf20Sopenharmony_ci#define WMM_AIFS_SET BIT(0) 29728c2ecf20Sopenharmony_ci#define WMM_CW_MIN_SET BIT(1) 29738c2ecf20Sopenharmony_ci#define WMM_CW_MAX_SET BIT(2) 29748c2ecf20Sopenharmony_ci#define WMM_TXOP_SET BIT(3) 29758c2ecf20Sopenharmony_ci#define WMM_PARAM_SET GENMASK(3, 0) 29768c2ecf20Sopenharmony_ci#define TX_CMD_MODE 1 29778c2ecf20Sopenharmony_ci struct edca { 29788c2ecf20Sopenharmony_ci u8 queue; 29798c2ecf20Sopenharmony_ci u8 set; 29808c2ecf20Sopenharmony_ci u8 aifs; 29818c2ecf20Sopenharmony_ci u8 cw_min; 29828c2ecf20Sopenharmony_ci __le16 cw_max; 29838c2ecf20Sopenharmony_ci __le16 txop; 29848c2ecf20Sopenharmony_ci }; 29858c2ecf20Sopenharmony_ci struct mt7915_mcu_tx { 29868c2ecf20Sopenharmony_ci u8 total; 29878c2ecf20Sopenharmony_ci u8 action; 29888c2ecf20Sopenharmony_ci u8 valid; 29898c2ecf20Sopenharmony_ci u8 mode; 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci struct edca edca[IEEE80211_NUM_ACS]; 29928c2ecf20Sopenharmony_ci } __packed req = { 29938c2ecf20Sopenharmony_ci .valid = true, 29948c2ecf20Sopenharmony_ci .mode = TX_CMD_MODE, 29958c2ecf20Sopenharmony_ci .total = IEEE80211_NUM_ACS, 29968c2ecf20Sopenharmony_ci }; 29978c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 29988c2ecf20Sopenharmony_ci int ac; 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 30018c2ecf20Sopenharmony_ci struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 30028c2ecf20Sopenharmony_ci struct edca *e = &req.edca[ac]; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci e->set = WMM_PARAM_SET; 30058c2ecf20Sopenharmony_ci e->queue = ac + mvif->wmm_idx * MT7915_MAX_WMM_SETS; 30068c2ecf20Sopenharmony_ci e->aifs = q->aifs; 30078c2ecf20Sopenharmony_ci e->txop = cpu_to_le16(q->txop); 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci if (q->cw_min) 30108c2ecf20Sopenharmony_ci e->cw_min = fls(q->cw_min); 30118c2ecf20Sopenharmony_ci else 30128c2ecf20Sopenharmony_ci e->cw_min = 5; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci if (q->cw_max) 30158c2ecf20Sopenharmony_ci e->cw_max = cpu_to_le16(fls(q->cw_max)); 30168c2ecf20Sopenharmony_ci else 30178c2ecf20Sopenharmony_ci e->cw_max = cpu_to_le16(10); 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, 30208c2ecf20Sopenharmony_ci &req, sizeof(req), true); 30218c2ecf20Sopenharmony_ci} 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ciint mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter) 30248c2ecf20Sopenharmony_ci{ 30258c2ecf20Sopenharmony_ci#define ENTER_PM_STATE 1 30268c2ecf20Sopenharmony_ci#define EXIT_PM_STATE 2 30278c2ecf20Sopenharmony_ci struct { 30288c2ecf20Sopenharmony_ci u8 pm_number; 30298c2ecf20Sopenharmony_ci u8 pm_state; 30308c2ecf20Sopenharmony_ci u8 bssid[ETH_ALEN]; 30318c2ecf20Sopenharmony_ci u8 dtim_period; 30328c2ecf20Sopenharmony_ci u8 wlan_idx_lo; 30338c2ecf20Sopenharmony_ci __le16 bcn_interval; 30348c2ecf20Sopenharmony_ci __le32 aid; 30358c2ecf20Sopenharmony_ci __le32 rx_filter; 30368c2ecf20Sopenharmony_ci u8 band_idx; 30378c2ecf20Sopenharmony_ci u8 wlan_idx_hi; 30388c2ecf20Sopenharmony_ci u8 rsv[2]; 30398c2ecf20Sopenharmony_ci __le32 feature; 30408c2ecf20Sopenharmony_ci u8 omac_idx; 30418c2ecf20Sopenharmony_ci u8 wmm_idx; 30428c2ecf20Sopenharmony_ci u8 bcn_loss_cnt; 30438c2ecf20Sopenharmony_ci u8 bcn_sp_duration; 30448c2ecf20Sopenharmony_ci } __packed req = { 30458c2ecf20Sopenharmony_ci .pm_number = 5, 30468c2ecf20Sopenharmony_ci .pm_state = (enter) ? ENTER_PM_STATE : EXIT_PM_STATE, 30478c2ecf20Sopenharmony_ci .band_idx = band, 30488c2ecf20Sopenharmony_ci }; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, 30518c2ecf20Sopenharmony_ci &req, sizeof(req), true); 30528c2ecf20Sopenharmony_ci} 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ciint mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, 30558c2ecf20Sopenharmony_ci enum mt7915_rdd_cmd cmd, u8 index, 30568c2ecf20Sopenharmony_ci u8 rx_sel, u8 val) 30578c2ecf20Sopenharmony_ci{ 30588c2ecf20Sopenharmony_ci struct { 30598c2ecf20Sopenharmony_ci u8 ctrl; 30608c2ecf20Sopenharmony_ci u8 rdd_idx; 30618c2ecf20Sopenharmony_ci u8 rdd_rx_sel; 30628c2ecf20Sopenharmony_ci u8 val; 30638c2ecf20Sopenharmony_ci u8 rsv[4]; 30648c2ecf20Sopenharmony_ci } __packed req = { 30658c2ecf20Sopenharmony_ci .ctrl = cmd, 30668c2ecf20Sopenharmony_ci .rdd_idx = index, 30678c2ecf20Sopenharmony_ci .rdd_rx_sel = rx_sel, 30688c2ecf20Sopenharmony_ci .val = val, 30698c2ecf20Sopenharmony_ci }; 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, 30728c2ecf20Sopenharmony_ci &req, sizeof(req), true); 30738c2ecf20Sopenharmony_ci} 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ciint mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val) 30768c2ecf20Sopenharmony_ci{ 30778c2ecf20Sopenharmony_ci struct { 30788c2ecf20Sopenharmony_ci __le32 tag; 30798c2ecf20Sopenharmony_ci __le16 min_lpn; 30808c2ecf20Sopenharmony_ci u8 rsv[2]; 30818c2ecf20Sopenharmony_ci } __packed req = { 30828c2ecf20Sopenharmony_ci .tag = cpu_to_le32(0x1), 30838c2ecf20Sopenharmony_ci .min_lpn = cpu_to_le16(val), 30848c2ecf20Sopenharmony_ci }; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, 30878c2ecf20Sopenharmony_ci &req, sizeof(req), true); 30888c2ecf20Sopenharmony_ci} 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ciint mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, 30918c2ecf20Sopenharmony_ci const struct mt7915_dfs_pulse *pulse) 30928c2ecf20Sopenharmony_ci{ 30938c2ecf20Sopenharmony_ci struct { 30948c2ecf20Sopenharmony_ci __le32 tag; 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci __le32 max_width; /* us */ 30978c2ecf20Sopenharmony_ci __le32 max_pwr; /* dbm */ 30988c2ecf20Sopenharmony_ci __le32 min_pwr; /* dbm */ 30998c2ecf20Sopenharmony_ci __le32 min_stgr_pri; /* us */ 31008c2ecf20Sopenharmony_ci __le32 max_stgr_pri; /* us */ 31018c2ecf20Sopenharmony_ci __le32 min_cr_pri; /* us */ 31028c2ecf20Sopenharmony_ci __le32 max_cr_pri; /* us */ 31038c2ecf20Sopenharmony_ci } __packed req = { 31048c2ecf20Sopenharmony_ci .tag = cpu_to_le32(0x3), 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci#define __req_field(field) .field = cpu_to_le32(pulse->field) 31078c2ecf20Sopenharmony_ci __req_field(max_width), 31088c2ecf20Sopenharmony_ci __req_field(max_pwr), 31098c2ecf20Sopenharmony_ci __req_field(min_pwr), 31108c2ecf20Sopenharmony_ci __req_field(min_stgr_pri), 31118c2ecf20Sopenharmony_ci __req_field(max_stgr_pri), 31128c2ecf20Sopenharmony_ci __req_field(min_cr_pri), 31138c2ecf20Sopenharmony_ci __req_field(max_cr_pri), 31148c2ecf20Sopenharmony_ci#undef __req_field 31158c2ecf20Sopenharmony_ci }; 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, 31188c2ecf20Sopenharmony_ci &req, sizeof(req), true); 31198c2ecf20Sopenharmony_ci} 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ciint mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, 31228c2ecf20Sopenharmony_ci const struct mt7915_dfs_pattern *pattern) 31238c2ecf20Sopenharmony_ci{ 31248c2ecf20Sopenharmony_ci struct { 31258c2ecf20Sopenharmony_ci __le32 tag; 31268c2ecf20Sopenharmony_ci __le16 radar_type; 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci u8 enb; 31298c2ecf20Sopenharmony_ci u8 stgr; 31308c2ecf20Sopenharmony_ci u8 min_crpn; 31318c2ecf20Sopenharmony_ci u8 max_crpn; 31328c2ecf20Sopenharmony_ci u8 min_crpr; 31338c2ecf20Sopenharmony_ci u8 min_pw; 31348c2ecf20Sopenharmony_ci u32 min_pri; 31358c2ecf20Sopenharmony_ci u32 max_pri; 31368c2ecf20Sopenharmony_ci u8 max_pw; 31378c2ecf20Sopenharmony_ci u8 min_crbn; 31388c2ecf20Sopenharmony_ci u8 max_crbn; 31398c2ecf20Sopenharmony_ci u8 min_stgpn; 31408c2ecf20Sopenharmony_ci u8 max_stgpn; 31418c2ecf20Sopenharmony_ci u8 min_stgpr; 31428c2ecf20Sopenharmony_ci u8 rsv[2]; 31438c2ecf20Sopenharmony_ci u32 min_stgpr_diff; 31448c2ecf20Sopenharmony_ci } __packed req = { 31458c2ecf20Sopenharmony_ci .tag = cpu_to_le32(0x2), 31468c2ecf20Sopenharmony_ci .radar_type = cpu_to_le16(index), 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci#define __req_field_u8(field) .field = pattern->field 31498c2ecf20Sopenharmony_ci#define __req_field_u32(field) .field = cpu_to_le32(pattern->field) 31508c2ecf20Sopenharmony_ci __req_field_u8(enb), 31518c2ecf20Sopenharmony_ci __req_field_u8(stgr), 31528c2ecf20Sopenharmony_ci __req_field_u8(min_crpn), 31538c2ecf20Sopenharmony_ci __req_field_u8(max_crpn), 31548c2ecf20Sopenharmony_ci __req_field_u8(min_crpr), 31558c2ecf20Sopenharmony_ci __req_field_u8(min_pw), 31568c2ecf20Sopenharmony_ci __req_field_u32(min_pri), 31578c2ecf20Sopenharmony_ci __req_field_u32(max_pri), 31588c2ecf20Sopenharmony_ci __req_field_u8(max_pw), 31598c2ecf20Sopenharmony_ci __req_field_u8(min_crbn), 31608c2ecf20Sopenharmony_ci __req_field_u8(max_crbn), 31618c2ecf20Sopenharmony_ci __req_field_u8(min_stgpn), 31628c2ecf20Sopenharmony_ci __req_field_u8(max_stgpn), 31638c2ecf20Sopenharmony_ci __req_field_u8(min_stgpr), 31648c2ecf20Sopenharmony_ci __req_field_u32(min_stgpr_diff), 31658c2ecf20Sopenharmony_ci#undef __req_field_u8 31668c2ecf20Sopenharmony_ci#undef __req_field_u32 31678c2ecf20Sopenharmony_ci }; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, 31708c2ecf20Sopenharmony_ci &req, sizeof(req), true); 31718c2ecf20Sopenharmony_ci} 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ciint mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) 31748c2ecf20Sopenharmony_ci{ 31758c2ecf20Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 31768c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 31778c2ecf20Sopenharmony_ci int freq1 = chandef->center_freq1; 31788c2ecf20Sopenharmony_ci struct { 31798c2ecf20Sopenharmony_ci u8 control_ch; 31808c2ecf20Sopenharmony_ci u8 center_ch; 31818c2ecf20Sopenharmony_ci u8 bw; 31828c2ecf20Sopenharmony_ci u8 tx_streams_num; 31838c2ecf20Sopenharmony_ci u8 rx_streams; /* mask or num */ 31848c2ecf20Sopenharmony_ci u8 switch_reason; 31858c2ecf20Sopenharmony_ci u8 band_idx; 31868c2ecf20Sopenharmony_ci u8 center_ch2; /* for 80+80 only */ 31878c2ecf20Sopenharmony_ci __le16 cac_case; 31888c2ecf20Sopenharmony_ci u8 channel_band; 31898c2ecf20Sopenharmony_ci u8 rsv0; 31908c2ecf20Sopenharmony_ci __le32 outband_freq; 31918c2ecf20Sopenharmony_ci u8 txpower_drop; 31928c2ecf20Sopenharmony_ci u8 ap_bw; 31938c2ecf20Sopenharmony_ci u8 ap_center_ch; 31948c2ecf20Sopenharmony_ci u8 rsv1[57]; 31958c2ecf20Sopenharmony_ci } __packed req = { 31968c2ecf20Sopenharmony_ci .control_ch = chandef->chan->hw_value, 31978c2ecf20Sopenharmony_ci .center_ch = ieee80211_frequency_to_channel(freq1), 31988c2ecf20Sopenharmony_ci .bw = mt7915_mcu_chan_bw(chandef), 31998c2ecf20Sopenharmony_ci .tx_streams_num = hweight8(phy->mt76->antenna_mask), 32008c2ecf20Sopenharmony_ci .rx_streams = phy->chainmask, 32018c2ecf20Sopenharmony_ci .band_idx = phy != &dev->phy, 32028c2ecf20Sopenharmony_ci .channel_band = chandef->chan->band, 32038c2ecf20Sopenharmony_ci }; 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 32068c2ecf20Sopenharmony_ci req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 32078c2ecf20Sopenharmony_ci else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 32088c2ecf20Sopenharmony_ci chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 32098c2ecf20Sopenharmony_ci req.switch_reason = CH_SWITCH_DFS; 32108c2ecf20Sopenharmony_ci else 32118c2ecf20Sopenharmony_ci req.switch_reason = CH_SWITCH_NORMAL; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) 32148c2ecf20Sopenharmony_ci req.rx_streams = hweight8(req.rx_streams); 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 32178c2ecf20Sopenharmony_ci int freq2 = chandef->center_freq2; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci req.center_ch2 = ieee80211_frequency_to_channel(freq2); 32208c2ecf20Sopenharmony_ci } 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 32238c2ecf20Sopenharmony_ci} 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ciint mt7915_mcu_set_eeprom(struct mt7915_dev *dev) 32268c2ecf20Sopenharmony_ci{ 32278c2ecf20Sopenharmony_ci struct req_hdr { 32288c2ecf20Sopenharmony_ci u8 buffer_mode; 32298c2ecf20Sopenharmony_ci u8 format; 32308c2ecf20Sopenharmony_ci __le16 len; 32318c2ecf20Sopenharmony_ci } __packed req = { 32328c2ecf20Sopenharmony_ci .buffer_mode = EE_MODE_EFUSE, 32338c2ecf20Sopenharmony_ci .format = EE_FORMAT_WHOLE, 32348c2ecf20Sopenharmony_ci }; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 32378c2ecf20Sopenharmony_ci &req, sizeof(req), true); 32388c2ecf20Sopenharmony_ci} 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ciint mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) 32418c2ecf20Sopenharmony_ci{ 32428c2ecf20Sopenharmony_ci struct mt7915_mcu_eeprom_info req = { 32438c2ecf20Sopenharmony_ci .addr = cpu_to_le32(round_down(offset, 16)), 32448c2ecf20Sopenharmony_ci }; 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, 32478c2ecf20Sopenharmony_ci sizeof(req), true); 32488c2ecf20Sopenharmony_ci} 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ciint mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index) 32518c2ecf20Sopenharmony_ci{ 32528c2ecf20Sopenharmony_ci struct { 32538c2ecf20Sopenharmony_ci u8 ctrl_id; 32548c2ecf20Sopenharmony_ci u8 action; 32558c2ecf20Sopenharmony_ci u8 band; 32568c2ecf20Sopenharmony_ci u8 rsv[5]; 32578c2ecf20Sopenharmony_ci } req = { 32588c2ecf20Sopenharmony_ci .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, 32598c2ecf20Sopenharmony_ci .action = index, 32608c2ecf20Sopenharmony_ci }; 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_THERMAL_CTRL, &req, 32638c2ecf20Sopenharmony_ci sizeof(req), true); 32648c2ecf20Sopenharmony_ci} 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ciint mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) 32678c2ecf20Sopenharmony_ci{ 32688c2ecf20Sopenharmony_ci struct { 32698c2ecf20Sopenharmony_ci __le32 cmd; 32708c2ecf20Sopenharmony_ci __le16 wlan_idx; 32718c2ecf20Sopenharmony_ci __le16 ru_idx; 32728c2ecf20Sopenharmony_ci __le16 direction; 32738c2ecf20Sopenharmony_ci __le16 dump_group; 32748c2ecf20Sopenharmony_ci } req = { 32758c2ecf20Sopenharmony_ci .cmd = cpu_to_le32(cmd), 32768c2ecf20Sopenharmony_ci .wlan_idx = cpu_to_le16(wlan_idx), 32778c2ecf20Sopenharmony_ci .dump_group = cpu_to_le16(1), 32788c2ecf20Sopenharmony_ci }; 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RATE_CTRL, &req, 32818c2ecf20Sopenharmony_ci sizeof(req), false); 32828c2ecf20Sopenharmony_ci} 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ciint mt7915_mcu_set_sku(struct mt7915_phy *phy) 32858c2ecf20Sopenharmony_ci{ 32868c2ecf20Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 32878c2ecf20Sopenharmony_ci struct mt76_phy *mphy = phy->mt76; 32888c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = mphy->hw; 32898c2ecf20Sopenharmony_ci struct mt7915_sku_val { 32908c2ecf20Sopenharmony_ci u8 format_id; 32918c2ecf20Sopenharmony_ci u8 limit_type; 32928c2ecf20Sopenharmony_ci u8 dbdc_idx; 32938c2ecf20Sopenharmony_ci s8 val[MT7915_SKU_RATE_NUM]; 32948c2ecf20Sopenharmony_ci } __packed req = { 32958c2ecf20Sopenharmony_ci .format_id = 4, 32968c2ecf20Sopenharmony_ci .dbdc_idx = phy != &dev->phy, 32978c2ecf20Sopenharmony_ci }; 32988c2ecf20Sopenharmony_ci int i; 32998c2ecf20Sopenharmony_ci s8 *delta; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci delta = dev->rate_power[mphy->chandef.chan->band]; 33028c2ecf20Sopenharmony_ci mphy->txpower_cur = hw->conf.power_level * 2 + 33038c2ecf20Sopenharmony_ci delta[MT7915_SKU_MAX_DELTA_IDX]; 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci for (i = 0; i < MT7915_SKU_RATE_NUM; i++) 33068c2ecf20Sopenharmony_ci req.val[i] = hw->conf.power_level * 2 + delta[i]; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, 33098c2ecf20Sopenharmony_ci MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, 33108c2ecf20Sopenharmony_ci &req, sizeof(req), true); 33118c2ecf20Sopenharmony_ci} 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ciint mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) 33148c2ecf20Sopenharmony_ci{ 33158c2ecf20Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 33168c2ecf20Sopenharmony_ci struct mt7915_sku { 33178c2ecf20Sopenharmony_ci u8 format_id; 33188c2ecf20Sopenharmony_ci u8 sku_enable; 33198c2ecf20Sopenharmony_ci u8 dbdc_idx; 33208c2ecf20Sopenharmony_ci u8 rsv; 33218c2ecf20Sopenharmony_ci } __packed req = { 33228c2ecf20Sopenharmony_ci .format_id = 0, 33238c2ecf20Sopenharmony_ci .dbdc_idx = phy != &dev->phy, 33248c2ecf20Sopenharmony_ci .sku_enable = enable, 33258c2ecf20Sopenharmony_ci }; 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, 33288c2ecf20Sopenharmony_ci MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, 33298c2ecf20Sopenharmony_ci &req, sizeof(req), true); 33308c2ecf20Sopenharmony_ci} 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ciint mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) 33338c2ecf20Sopenharmony_ci{ 33348c2ecf20Sopenharmony_ci struct { 33358c2ecf20Sopenharmony_ci u8 action; 33368c2ecf20Sopenharmony_ci u8 set; 33378c2ecf20Sopenharmony_ci u8 band; 33388c2ecf20Sopenharmony_ci u8 rsv; 33398c2ecf20Sopenharmony_ci } req = { 33408c2ecf20Sopenharmony_ci .action = action, 33418c2ecf20Sopenharmony_ci .set = set, 33428c2ecf20Sopenharmony_ci .band = band, 33438c2ecf20Sopenharmony_ci }; 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SER_TRIGGER, 33468c2ecf20Sopenharmony_ci &req, sizeof(req), false); 33478c2ecf20Sopenharmony_ci} 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ciint mt7915_mcu_set_txbf_type(struct mt7915_dev *dev) 33508c2ecf20Sopenharmony_ci{ 33518c2ecf20Sopenharmony_ci#define MT_BF_TYPE_UPDATE 20 33528c2ecf20Sopenharmony_ci struct { 33538c2ecf20Sopenharmony_ci u8 action; 33548c2ecf20Sopenharmony_ci bool ebf; 33558c2ecf20Sopenharmony_ci bool ibf; 33568c2ecf20Sopenharmony_ci u8 rsv; 33578c2ecf20Sopenharmony_ci } __packed req = { 33588c2ecf20Sopenharmony_ci .action = MT_BF_TYPE_UPDATE, 33598c2ecf20Sopenharmony_ci .ebf = true, 33608c2ecf20Sopenharmony_ci .ibf = false, 33618c2ecf20Sopenharmony_ci }; 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, 33648c2ecf20Sopenharmony_ci &req, sizeof(req), true); 33658c2ecf20Sopenharmony_ci} 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ciint mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev) 33688c2ecf20Sopenharmony_ci{ 33698c2ecf20Sopenharmony_ci#define MT_BF_PROCESSING 4 33708c2ecf20Sopenharmony_ci struct { 33718c2ecf20Sopenharmony_ci u8 action; 33728c2ecf20Sopenharmony_ci u8 snd_mode; 33738c2ecf20Sopenharmony_ci u8 sta_num; 33748c2ecf20Sopenharmony_ci u8 rsv; 33758c2ecf20Sopenharmony_ci u8 wlan_idx[4]; 33768c2ecf20Sopenharmony_ci __le32 snd_period; /* ms */ 33778c2ecf20Sopenharmony_ci } __packed req = { 33788c2ecf20Sopenharmony_ci .action = true, 33798c2ecf20Sopenharmony_ci .snd_mode = MT_BF_PROCESSING, 33808c2ecf20Sopenharmony_ci }; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, 33838c2ecf20Sopenharmony_ci &req, sizeof(req), true); 33848c2ecf20Sopenharmony_ci} 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ciint mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, 33878c2ecf20Sopenharmony_ci bool enable) 33888c2ecf20Sopenharmony_ci{ 33898c2ecf20Sopenharmony_ci#define MT_SPR_ENABLE 1 33908c2ecf20Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 33918c2ecf20Sopenharmony_ci struct { 33928c2ecf20Sopenharmony_ci u8 action; 33938c2ecf20Sopenharmony_ci u8 arg_num; 33948c2ecf20Sopenharmony_ci u8 band_idx; 33958c2ecf20Sopenharmony_ci u8 status; 33968c2ecf20Sopenharmony_ci u8 drop_tx_idx; 33978c2ecf20Sopenharmony_ci u8 sta_idx; /* 256 sta */ 33988c2ecf20Sopenharmony_ci u8 rsv[2]; 33998c2ecf20Sopenharmony_ci __le32 val; 34008c2ecf20Sopenharmony_ci } __packed req = { 34018c2ecf20Sopenharmony_ci .action = MT_SPR_ENABLE, 34028c2ecf20Sopenharmony_ci .arg_num = 1, 34038c2ecf20Sopenharmony_ci .band_idx = mvif->band_idx, 34048c2ecf20Sopenharmony_ci .val = cpu_to_le32(enable), 34058c2ecf20Sopenharmony_ci }; 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SPR, 34088c2ecf20Sopenharmony_ci &req, sizeof(req), true); 34098c2ecf20Sopenharmony_ci} 3410