11c099ab4SSean Wang // SPDX-License-Identifier: ISC 21c099ab4SSean Wang /* Copyright (C) 2020 MediaTek Inc. */ 31c099ab4SSean Wang 41c099ab4SSean Wang #include <linux/firmware.h> 51c099ab4SSean Wang #include <linux/fs.h> 61c099ab4SSean Wang #include "mt7921.h" 71c099ab4SSean Wang #include "mcu.h" 81c099ab4SSean Wang #include "mac.h" 91c099ab4SSean Wang 101c099ab4SSean Wang struct mt7921_patch_hdr { 111c099ab4SSean Wang char build_date[16]; 121c099ab4SSean Wang char platform[4]; 131c099ab4SSean Wang __be32 hw_sw_ver; 141c099ab4SSean Wang __be32 patch_ver; 151c099ab4SSean Wang __be16 checksum; 161c099ab4SSean Wang u16 reserved; 171c099ab4SSean Wang struct { 181c099ab4SSean Wang __be32 patch_ver; 191c099ab4SSean Wang __be32 subsys; 201c099ab4SSean Wang __be32 feature; 211c099ab4SSean Wang __be32 n_region; 221c099ab4SSean Wang __be32 crc; 231c099ab4SSean Wang u32 reserved[11]; 241c099ab4SSean Wang } desc; 251c099ab4SSean Wang } __packed; 261c099ab4SSean Wang 271c099ab4SSean Wang struct mt7921_patch_sec { 281c099ab4SSean Wang __be32 type; 291c099ab4SSean Wang __be32 offs; 301c099ab4SSean Wang __be32 size; 311c099ab4SSean Wang union { 321c099ab4SSean Wang __be32 spec[13]; 331c099ab4SSean Wang struct { 341c099ab4SSean Wang __be32 addr; 351c099ab4SSean Wang __be32 len; 361c099ab4SSean Wang __be32 sec_key_idx; 371c099ab4SSean Wang __be32 align_len; 381c099ab4SSean Wang u32 reserved[9]; 391c099ab4SSean Wang } info; 401c099ab4SSean Wang }; 411c099ab4SSean Wang } __packed; 421c099ab4SSean Wang 431c099ab4SSean Wang struct mt7921_fw_trailer { 441c099ab4SSean Wang u8 chip_id; 451c099ab4SSean Wang u8 eco_code; 461c099ab4SSean Wang u8 n_region; 471c099ab4SSean Wang u8 format_ver; 481c099ab4SSean Wang u8 format_flag; 491c099ab4SSean Wang u8 reserved[2]; 501c099ab4SSean Wang char fw_ver[10]; 511c099ab4SSean Wang char build_date[15]; 521c099ab4SSean Wang u32 crc; 531c099ab4SSean Wang } __packed; 541c099ab4SSean Wang 551c099ab4SSean Wang struct mt7921_fw_region { 561c099ab4SSean Wang __le32 decomp_crc; 571c099ab4SSean Wang __le32 decomp_len; 581c099ab4SSean Wang __le32 decomp_blk_sz; 591c099ab4SSean Wang u8 reserved[4]; 601c099ab4SSean Wang __le32 addr; 611c099ab4SSean Wang __le32 len; 621c099ab4SSean Wang u8 feature_set; 631c099ab4SSean Wang u8 reserved1[15]; 641c099ab4SSean Wang } __packed; 651c099ab4SSean Wang 661c099ab4SSean Wang #define MCU_PATCH_ADDRESS 0x200000 671c099ab4SSean Wang 681c099ab4SSean Wang #define MT_STA_BFER BIT(0) 691c099ab4SSean Wang #define MT_STA_BFEE BIT(1) 701c099ab4SSean Wang 711c099ab4SSean Wang #define FW_FEATURE_SET_ENCRYPT BIT(0) 721c099ab4SSean Wang #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) 731c099ab4SSean Wang #define FW_FEATURE_ENCRY_MODE BIT(4) 741c099ab4SSean Wang #define FW_FEATURE_OVERRIDE_ADDR BIT(5) 751c099ab4SSean Wang 761c099ab4SSean Wang #define DL_MODE_ENCRYPT BIT(0) 771c099ab4SSean Wang #define DL_MODE_KEY_IDX GENMASK(2, 1) 781c099ab4SSean Wang #define DL_MODE_RESET_SEC_IV BIT(3) 791c099ab4SSean Wang #define DL_MODE_WORKING_PDA_CR4 BIT(4) 801c099ab4SSean Wang #define DL_CONFIG_ENCRY_MODE_SEL BIT(6) 811c099ab4SSean Wang #define DL_MODE_NEED_RSP BIT(31) 821c099ab4SSean Wang 831c099ab4SSean Wang #define FW_START_OVERRIDE BIT(0) 841c099ab4SSean Wang #define FW_START_WORKING_PDA_CR4 BIT(2) 851c099ab4SSean Wang 861c099ab4SSean Wang #define PATCH_SEC_TYPE_MASK GENMASK(15, 0) 871c099ab4SSean Wang #define PATCH_SEC_TYPE_INFO 0x2 881c099ab4SSean Wang 891c099ab4SSean Wang #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) 901c099ab4SSean Wang #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) 911c099ab4SSean Wang 921c099ab4SSean Wang #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) 931c099ab4SSean Wang #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) 941c099ab4SSean Wang 951c099ab4SSean Wang static enum mt7921_cipher_type 961c099ab4SSean Wang mt7921_mcu_get_cipher(int cipher) 971c099ab4SSean Wang { 981c099ab4SSean Wang switch (cipher) { 991c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP40: 1001c099ab4SSean Wang return MT_CIPHER_WEP40; 1011c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP104: 1021c099ab4SSean Wang return MT_CIPHER_WEP104; 1031c099ab4SSean Wang case WLAN_CIPHER_SUITE_TKIP: 1041c099ab4SSean Wang return MT_CIPHER_TKIP; 1051c099ab4SSean Wang case WLAN_CIPHER_SUITE_AES_CMAC: 1061c099ab4SSean Wang return MT_CIPHER_BIP_CMAC_128; 1071c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP: 1081c099ab4SSean Wang return MT_CIPHER_AES_CCMP; 1091c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP_256: 1101c099ab4SSean Wang return MT_CIPHER_CCMP_256; 1111c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP: 1121c099ab4SSean Wang return MT_CIPHER_GCMP; 1131c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP_256: 1141c099ab4SSean Wang return MT_CIPHER_GCMP_256; 1151c099ab4SSean Wang case WLAN_CIPHER_SUITE_SMS4: 1161c099ab4SSean Wang return MT_CIPHER_WAPI; 1171c099ab4SSean Wang default: 1181c099ab4SSean Wang return MT_CIPHER_NONE; 1191c099ab4SSean Wang } 1201c099ab4SSean Wang } 1211c099ab4SSean Wang 1221c099ab4SSean Wang static u8 mt7921_mcu_chan_bw(struct cfg80211_chan_def *chandef) 1231c099ab4SSean Wang { 1241c099ab4SSean Wang static const u8 width_to_bw[] = { 1251c099ab4SSean Wang [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, 1261c099ab4SSean Wang [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, 1271c099ab4SSean Wang [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, 1281c099ab4SSean Wang [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, 1291c099ab4SSean Wang [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, 1301c099ab4SSean Wang [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, 1311c099ab4SSean Wang [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, 1321c099ab4SSean Wang [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, 1331c099ab4SSean Wang }; 1341c099ab4SSean Wang 1351c099ab4SSean Wang if (chandef->width >= ARRAY_SIZE(width_to_bw)) 1361c099ab4SSean Wang return 0; 1371c099ab4SSean Wang 1381c099ab4SSean Wang return width_to_bw[chandef->width]; 1391c099ab4SSean Wang } 1401c099ab4SSean Wang 1411c099ab4SSean Wang static const struct ieee80211_sta_he_cap * 1421c099ab4SSean Wang mt7921_get_he_phy_cap(struct mt7921_phy *phy, struct ieee80211_vif *vif) 1431c099ab4SSean Wang { 1441c099ab4SSean Wang struct ieee80211_supported_band *sband; 1451c099ab4SSean Wang enum nl80211_band band; 1461c099ab4SSean Wang 1471c099ab4SSean Wang band = phy->mt76->chandef.chan->band; 1481c099ab4SSean Wang sband = phy->mt76->hw->wiphy->bands[band]; 1491c099ab4SSean Wang 1501c099ab4SSean Wang return ieee80211_get_he_iftype_cap(sband, vif->type); 1511c099ab4SSean Wang } 1521c099ab4SSean Wang 1531c099ab4SSean Wang static u8 1541c099ab4SSean Wang mt7921_get_phy_mode(struct mt7921_dev *dev, struct ieee80211_vif *vif, 1551c099ab4SSean Wang enum nl80211_band band, struct ieee80211_sta *sta) 1561c099ab4SSean Wang { 1571c099ab4SSean Wang struct ieee80211_sta_ht_cap *ht_cap; 1581c099ab4SSean Wang struct ieee80211_sta_vht_cap *vht_cap; 1591c099ab4SSean Wang const struct ieee80211_sta_he_cap *he_cap; 1601c099ab4SSean Wang u8 mode = 0; 1611c099ab4SSean Wang 1621c099ab4SSean Wang if (sta) { 1631c099ab4SSean Wang ht_cap = &sta->ht_cap; 1641c099ab4SSean Wang vht_cap = &sta->vht_cap; 1651c099ab4SSean Wang he_cap = &sta->he_cap; 1661c099ab4SSean Wang } else { 1671c099ab4SSean Wang struct ieee80211_supported_band *sband; 1681c099ab4SSean Wang struct mt7921_phy *phy = &dev->phy; 1691c099ab4SSean Wang 1701c099ab4SSean Wang sband = phy->mt76->hw->wiphy->bands[band]; 1711c099ab4SSean Wang ht_cap = &sband->ht_cap; 1721c099ab4SSean Wang vht_cap = &sband->vht_cap; 1731c099ab4SSean Wang he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); 1741c099ab4SSean Wang } 1751c099ab4SSean Wang 1761c099ab4SSean Wang if (band == NL80211_BAND_2GHZ) { 1771c099ab4SSean Wang mode |= PHY_MODE_B | PHY_MODE_G; 1781c099ab4SSean Wang 1791c099ab4SSean Wang if (ht_cap->ht_supported) 1801c099ab4SSean Wang mode |= PHY_MODE_GN; 1811c099ab4SSean Wang 1821c099ab4SSean Wang if (he_cap->has_he) 1831c099ab4SSean Wang mode |= PHY_MODE_AX_24G; 1841c099ab4SSean Wang } else if (band == NL80211_BAND_5GHZ) { 1851c099ab4SSean Wang mode |= PHY_MODE_A; 1861c099ab4SSean Wang 1871c099ab4SSean Wang if (ht_cap->ht_supported) 1881c099ab4SSean Wang mode |= PHY_MODE_AN; 1891c099ab4SSean Wang 1901c099ab4SSean Wang if (vht_cap->vht_supported) 1911c099ab4SSean Wang mode |= PHY_MODE_AC; 1921c099ab4SSean Wang 1931c099ab4SSean Wang if (he_cap->has_he) 1941c099ab4SSean Wang mode |= PHY_MODE_AX_5G; 1951c099ab4SSean Wang } 1961c099ab4SSean Wang 1971c099ab4SSean Wang return mode; 1981c099ab4SSean Wang } 1991c099ab4SSean Wang 2001c099ab4SSean Wang static u8 2011c099ab4SSean Wang mt7921_get_phy_mode_v2(struct mt7921_dev *dev, struct ieee80211_vif *vif, 2021c099ab4SSean Wang enum nl80211_band band, struct ieee80211_sta *sta) 2031c099ab4SSean Wang { 2041c099ab4SSean Wang struct ieee80211_sta_ht_cap *ht_cap; 2051c099ab4SSean Wang struct ieee80211_sta_vht_cap *vht_cap; 2061c099ab4SSean Wang const struct ieee80211_sta_he_cap *he_cap; 2071c099ab4SSean Wang u8 mode = 0; 2081c099ab4SSean Wang 2091c099ab4SSean Wang if (sta) { 2101c099ab4SSean Wang ht_cap = &sta->ht_cap; 2111c099ab4SSean Wang vht_cap = &sta->vht_cap; 2121c099ab4SSean Wang he_cap = &sta->he_cap; 2131c099ab4SSean Wang } else { 2141c099ab4SSean Wang struct ieee80211_supported_band *sband; 2151c099ab4SSean Wang struct mt7921_phy *phy = &dev->phy; 2161c099ab4SSean Wang 2171c099ab4SSean Wang sband = phy->mt76->hw->wiphy->bands[band]; 2181c099ab4SSean Wang ht_cap = &sband->ht_cap; 2191c099ab4SSean Wang vht_cap = &sband->vht_cap; 2201c099ab4SSean Wang he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); 2211c099ab4SSean Wang } 2221c099ab4SSean Wang 2231c099ab4SSean Wang if (band == NL80211_BAND_2GHZ) { 2241c099ab4SSean Wang mode |= PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP; 2251c099ab4SSean Wang 2261c099ab4SSean Wang if (ht_cap->ht_supported) 2271c099ab4SSean Wang mode |= PHY_TYPE_BIT_HT; 2281c099ab4SSean Wang 2291c099ab4SSean Wang if (he_cap->has_he) 2301c099ab4SSean Wang mode |= PHY_TYPE_BIT_HE; 2311c099ab4SSean Wang } else if (band == NL80211_BAND_5GHZ) { 2321c099ab4SSean Wang mode |= PHY_TYPE_BIT_OFDM; 2331c099ab4SSean Wang 2341c099ab4SSean Wang if (ht_cap->ht_supported) 2351c099ab4SSean Wang mode |= PHY_TYPE_BIT_HT; 2361c099ab4SSean Wang 2371c099ab4SSean Wang if (vht_cap->vht_supported) 2381c099ab4SSean Wang mode |= PHY_TYPE_BIT_VHT; 2391c099ab4SSean Wang 2401c099ab4SSean Wang if (he_cap->has_he) 2411c099ab4SSean Wang mode |= PHY_TYPE_BIT_HE; 2421c099ab4SSean Wang } 2431c099ab4SSean Wang 2441c099ab4SSean Wang return mode; 2451c099ab4SSean Wang } 2461c099ab4SSean Wang 2471c099ab4SSean Wang static int 2481c099ab4SSean Wang mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) 2491c099ab4SSean Wang { 2501c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 2511c099ab4SSean Wang u8 *buf; 2521c099ab4SSean Wang 2531c099ab4SSean Wang if (!skb) 2541c099ab4SSean Wang return -EINVAL; 2551c099ab4SSean Wang 2561c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 2571c099ab4SSean Wang 2581c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 2591c099ab4SSean Wang buf = dev->eeprom.data + le32_to_cpu(res->addr); 2601c099ab4SSean Wang memcpy(buf, res->data, 16); 2611c099ab4SSean Wang 2621c099ab4SSean Wang return 0; 2631c099ab4SSean Wang } 2641c099ab4SSean Wang 2651c099ab4SSean Wang static int 2661c099ab4SSean Wang mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, 2671c099ab4SSean Wang struct sk_buff *skb, int seq) 2681c099ab4SSean Wang { 2691c099ab4SSean Wang struct mt7921_mcu_rxd *rxd; 2701c099ab4SSean Wang int ret = 0; 2711c099ab4SSean Wang 2721c099ab4SSean Wang if (!skb) { 2731c099ab4SSean Wang dev_err(mdev->dev, "Message %d (seq %d) timeout\n", 2741c099ab4SSean Wang cmd, seq); 2751c099ab4SSean Wang return -ETIMEDOUT; 2761c099ab4SSean Wang } 2771c099ab4SSean Wang 2781c099ab4SSean Wang rxd = (struct mt7921_mcu_rxd *)skb->data; 2791c099ab4SSean Wang if (seq != rxd->seq) 2801c099ab4SSean Wang return -EAGAIN; 2811c099ab4SSean Wang 2821c099ab4SSean Wang switch (cmd) { 2831c099ab4SSean Wang case MCU_CMD_PATCH_SEM_CONTROL: 2841c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) - 4); 2851c099ab4SSean Wang ret = *skb->data; 2861c099ab4SSean Wang break; 2871c099ab4SSean Wang case MCU_EXT_CMD_THERMAL_CTRL: 2881c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) + 4); 2891c099ab4SSean Wang ret = le32_to_cpu(*(__le32 *)skb->data); 2901c099ab4SSean Wang break; 2911c099ab4SSean Wang case MCU_EXT_CMD_EFUSE_ACCESS: 2921c099ab4SSean Wang ret = mt7921_mcu_parse_eeprom(mdev, skb); 2931c099ab4SSean Wang break; 2941c099ab4SSean Wang case MCU_UNI_CMD_DEV_INFO_UPDATE: 2951c099ab4SSean Wang case MCU_UNI_CMD_BSS_INFO_UPDATE: 2961c099ab4SSean Wang case MCU_UNI_CMD_STA_REC_UPDATE: 2971c099ab4SSean Wang case MCU_UNI_CMD_HIF_CTRL: 2981c099ab4SSean Wang case MCU_UNI_CMD_OFFLOAD: 2991c099ab4SSean Wang case MCU_UNI_CMD_SUSPEND: { 3001c099ab4SSean Wang struct mt7921_mcu_uni_event *event; 3011c099ab4SSean Wang 3021c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 3031c099ab4SSean Wang event = (struct mt7921_mcu_uni_event *)skb->data; 3041c099ab4SSean Wang ret = le32_to_cpu(event->status); 3051c099ab4SSean Wang break; 3061c099ab4SSean Wang } 3071c099ab4SSean Wang case MCU_CMD_REG_READ: { 3081c099ab4SSean Wang struct mt7921_mcu_reg_event *event; 3091c099ab4SSean Wang 3101c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 3111c099ab4SSean Wang event = (struct mt7921_mcu_reg_event *)skb->data; 3121c099ab4SSean Wang ret = (int)le32_to_cpu(event->val); 3131c099ab4SSean Wang break; 3141c099ab4SSean Wang } 3151c099ab4SSean Wang default: 3161c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 3171c099ab4SSean Wang break; 3181c099ab4SSean Wang } 3191c099ab4SSean Wang 3201c099ab4SSean Wang return ret; 3211c099ab4SSean Wang } 3221c099ab4SSean Wang 3231c099ab4SSean Wang static int 3241c099ab4SSean Wang mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 3251c099ab4SSean Wang int cmd, int *wait_seq) 3261c099ab4SSean Wang { 3271c099ab4SSean Wang struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 3281c099ab4SSean Wang int txd_len, mcu_cmd = cmd & MCU_CMD_MASK; 3291c099ab4SSean Wang enum mt76_mcuq_id txq = MT_MCUQ_WM; 3301c099ab4SSean Wang struct mt7921_uni_txd *uni_txd; 3311c099ab4SSean Wang struct mt7921_mcu_txd *mcu_txd; 3321c099ab4SSean Wang __le32 *txd; 3331c099ab4SSean Wang u32 val; 3341c099ab4SSean Wang u8 seq; 3351c099ab4SSean Wang 3361c099ab4SSean Wang /* TODO: make dynamic based on msg type */ 3371c099ab4SSean Wang mdev->mcu.timeout = 20 * HZ; 3381c099ab4SSean Wang 3391c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 3401c099ab4SSean Wang if (!seq) 3411c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 3421c099ab4SSean Wang 3431c099ab4SSean Wang if (cmd == MCU_CMD_FW_SCATTER) { 3441c099ab4SSean Wang txq = MT_MCUQ_FWDL; 3451c099ab4SSean Wang goto exit; 3461c099ab4SSean Wang } 3471c099ab4SSean Wang 3481c099ab4SSean Wang txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd); 3491c099ab4SSean Wang txd = (__le32 *)skb_push(skb, txd_len); 3501c099ab4SSean Wang 3511c099ab4SSean Wang val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | 3521c099ab4SSean Wang FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | 3531c099ab4SSean Wang FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); 3541c099ab4SSean Wang txd[0] = cpu_to_le32(val); 3551c099ab4SSean Wang 3561c099ab4SSean Wang val = MT_TXD1_LONG_FORMAT | 3571c099ab4SSean Wang FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); 3581c099ab4SSean Wang txd[1] = cpu_to_le32(val); 3591c099ab4SSean Wang 3601c099ab4SSean Wang if (cmd & MCU_UNI_PREFIX) { 3611c099ab4SSean Wang uni_txd = (struct mt7921_uni_txd *)txd; 3621c099ab4SSean Wang uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); 3631c099ab4SSean Wang uni_txd->option = MCU_CMD_UNI_EXT_ACK; 3641c099ab4SSean Wang uni_txd->cid = cpu_to_le16(mcu_cmd); 3651c099ab4SSean Wang uni_txd->s2d_index = MCU_S2D_H2N; 3661c099ab4SSean Wang uni_txd->pkt_type = MCU_PKT_ID; 3671c099ab4SSean Wang uni_txd->seq = seq; 3681c099ab4SSean Wang 3691c099ab4SSean Wang goto exit; 3701c099ab4SSean Wang } 3711c099ab4SSean Wang 3721c099ab4SSean Wang mcu_txd = (struct mt7921_mcu_txd *)txd; 3731c099ab4SSean Wang mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); 3741c099ab4SSean Wang mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, 3751c099ab4SSean Wang MT_TX_MCU_PORT_RX_Q0)); 3761c099ab4SSean Wang mcu_txd->pkt_type = MCU_PKT_ID; 3771c099ab4SSean Wang mcu_txd->seq = seq; 3781c099ab4SSean Wang 3791c099ab4SSean Wang switch (cmd & ~MCU_CMD_MASK) { 3801c099ab4SSean Wang case MCU_FW_PREFIX: 3811c099ab4SSean Wang mcu_txd->set_query = MCU_Q_NA; 3821c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 3831c099ab4SSean Wang break; 3841c099ab4SSean Wang case MCU_CE_PREFIX: 3851c099ab4SSean Wang if (cmd & MCU_QUERY_MASK) 3861c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 3871c099ab4SSean Wang else 3881c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 3891c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 3901c099ab4SSean Wang break; 3911c099ab4SSean Wang default: 3921c099ab4SSean Wang mcu_txd->cid = MCU_CMD_EXT_CID; 3931c099ab4SSean Wang if (cmd & MCU_QUERY_PREFIX || cmd == MCU_EXT_CMD_EFUSE_ACCESS) 3941c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 3951c099ab4SSean Wang else 3961c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 3971c099ab4SSean Wang mcu_txd->ext_cid = mcu_cmd; 3981c099ab4SSean Wang mcu_txd->ext_cid_ack = 1; 3991c099ab4SSean Wang break; 4001c099ab4SSean Wang } 4011c099ab4SSean Wang 4021c099ab4SSean Wang mcu_txd->s2d_index = MCU_S2D_H2N; 4031c099ab4SSean Wang WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && 4041c099ab4SSean Wang mcu_txd->set_query != MCU_Q_QUERY); 4051c099ab4SSean Wang 4061c099ab4SSean Wang exit: 4071c099ab4SSean Wang if (wait_seq) 4081c099ab4SSean Wang *wait_seq = seq; 4091c099ab4SSean Wang 4101c099ab4SSean Wang return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); 4111c099ab4SSean Wang } 4121c099ab4SSean Wang 4131c099ab4SSean Wang static void 4141c099ab4SSean Wang mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, 4151c099ab4SSean Wang struct mt7921_mcu_peer_cap *peer, 4161c099ab4SSean Wang struct rate_info *rate, u16 r) 4171c099ab4SSean Wang { 4181c099ab4SSean Wang struct ieee80211_supported_band *sband; 4191c099ab4SSean Wang u16 flags = 0; 4201c099ab4SSean Wang u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r); 4211c099ab4SSean Wang u8 gi = 0; 4221c099ab4SSean Wang u8 bw = 0; 4231c099ab4SSean Wang 4241c099ab4SSean Wang rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r); 4251c099ab4SSean Wang rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1; 4261c099ab4SSean Wang 4271c099ab4SSean Wang switch (peer->bw) { 4281c099ab4SSean Wang case IEEE80211_STA_RX_BW_160: 4291c099ab4SSean Wang gi = peer->g16; 4301c099ab4SSean Wang break; 4311c099ab4SSean Wang case IEEE80211_STA_RX_BW_80: 4321c099ab4SSean Wang gi = peer->g8; 4331c099ab4SSean Wang break; 4341c099ab4SSean Wang case IEEE80211_STA_RX_BW_40: 4351c099ab4SSean Wang gi = peer->g4; 4361c099ab4SSean Wang break; 4371c099ab4SSean Wang default: 4381c099ab4SSean Wang gi = peer->g2; 4391c099ab4SSean Wang break; 4401c099ab4SSean Wang } 4411c099ab4SSean Wang 4421c099ab4SSean Wang gi = txmode >= MT_PHY_TYPE_HE_SU ? 4431c099ab4SSean Wang FIELD_GET(MT_WTBL_RATE_HE_GI, gi) : 4441c099ab4SSean Wang FIELD_GET(MT_WTBL_RATE_GI, gi); 4451c099ab4SSean Wang 4461c099ab4SSean Wang switch (txmode) { 4471c099ab4SSean Wang case MT_PHY_TYPE_CCK: 4481c099ab4SSean Wang case MT_PHY_TYPE_OFDM: 4491c099ab4SSean Wang if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 4501c099ab4SSean Wang sband = &mphy->sband_5g.sband; 4511c099ab4SSean Wang else 4521c099ab4SSean Wang sband = &mphy->sband_2g.sband; 4531c099ab4SSean Wang 4541c099ab4SSean Wang rate->legacy = sband->bitrates[rate->mcs].bitrate; 4551c099ab4SSean Wang break; 4561c099ab4SSean Wang case MT_PHY_TYPE_HT: 4571c099ab4SSean Wang case MT_PHY_TYPE_HT_GF: 4581c099ab4SSean Wang flags |= RATE_INFO_FLAGS_MCS; 4591c099ab4SSean Wang 4601c099ab4SSean Wang if (gi) 4611c099ab4SSean Wang flags |= RATE_INFO_FLAGS_SHORT_GI; 4621c099ab4SSean Wang break; 4631c099ab4SSean Wang case MT_PHY_TYPE_VHT: 4641c099ab4SSean Wang flags |= RATE_INFO_FLAGS_VHT_MCS; 4651c099ab4SSean Wang 4661c099ab4SSean Wang if (gi) 4671c099ab4SSean Wang flags |= RATE_INFO_FLAGS_SHORT_GI; 4681c099ab4SSean Wang break; 4691c099ab4SSean Wang case MT_PHY_TYPE_HE_SU: 4701c099ab4SSean Wang case MT_PHY_TYPE_HE_EXT_SU: 4711c099ab4SSean Wang case MT_PHY_TYPE_HE_TB: 4721c099ab4SSean Wang case MT_PHY_TYPE_HE_MU: 4731c099ab4SSean Wang rate->he_gi = gi; 4741c099ab4SSean Wang rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); 4751c099ab4SSean Wang 4761c099ab4SSean Wang flags |= RATE_INFO_FLAGS_HE_MCS; 4771c099ab4SSean Wang break; 4781c099ab4SSean Wang default: 4791c099ab4SSean Wang break; 4801c099ab4SSean Wang } 4811c099ab4SSean Wang rate->flags = flags; 4821c099ab4SSean Wang 4831c099ab4SSean Wang bw = mt7921_mcu_chan_bw(&mphy->chandef) - FIELD_GET(MT_RA_RATE_BW, r); 4841c099ab4SSean Wang 4851c099ab4SSean Wang switch (bw) { 4861c099ab4SSean Wang case IEEE80211_STA_RX_BW_160: 4871c099ab4SSean Wang rate->bw = RATE_INFO_BW_160; 4881c099ab4SSean Wang break; 4891c099ab4SSean Wang case IEEE80211_STA_RX_BW_80: 4901c099ab4SSean Wang rate->bw = RATE_INFO_BW_80; 4911c099ab4SSean Wang break; 4921c099ab4SSean Wang case IEEE80211_STA_RX_BW_40: 4931c099ab4SSean Wang rate->bw = RATE_INFO_BW_40; 4941c099ab4SSean Wang break; 4951c099ab4SSean Wang default: 4961c099ab4SSean Wang rate->bw = RATE_INFO_BW_20; 4971c099ab4SSean Wang break; 4981c099ab4SSean Wang } 4991c099ab4SSean Wang } 5001c099ab4SSean Wang 5011c099ab4SSean Wang static void 5021c099ab4SSean Wang mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb, 5031c099ab4SSean Wang u16 wlan_idx) 5041c099ab4SSean Wang { 5051c099ab4SSean Wang struct mt7921_mcu_wlan_info_event *wtbl_info = 5061c099ab4SSean Wang (struct mt7921_mcu_wlan_info_event *)(skb->data); 5071c099ab4SSean Wang struct rate_info rate = {}; 5081c099ab4SSean Wang u8 curr_idx = wtbl_info->rate_info.rate_idx; 5091c099ab4SSean Wang u16 curr = le16_to_cpu(wtbl_info->rate_info.rate[curr_idx]); 5101c099ab4SSean Wang struct mt7921_mcu_peer_cap peer = wtbl_info->peer_cap; 5111c099ab4SSean Wang struct mt76_phy *mphy = &dev->mphy; 5121c099ab4SSean Wang struct mt7921_sta_stats *stats; 5131c099ab4SSean Wang struct mt7921_sta *msta; 5141c099ab4SSean Wang struct mt76_wcid *wcid; 5151c099ab4SSean Wang 5161c099ab4SSean Wang if (wlan_idx >= MT76_N_WCIDS) 5171c099ab4SSean Wang return; 5181c099ab4SSean Wang wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); 5191c099ab4SSean Wang if (!wcid) { 5201c099ab4SSean Wang stats->tx_rate = rate; 5211c099ab4SSean Wang return; 5221c099ab4SSean Wang } 5231c099ab4SSean Wang 5241c099ab4SSean Wang msta = container_of(wcid, struct mt7921_sta, wcid); 5251c099ab4SSean Wang stats = &msta->stats; 5261c099ab4SSean Wang 5271c099ab4SSean Wang /* current rate */ 5281c099ab4SSean Wang mt7921_mcu_tx_rate_parse(mphy, &peer, &rate, curr); 5291c099ab4SSean Wang stats->tx_rate = rate; 5301c099ab4SSean Wang } 5311c099ab4SSean Wang 5321c099ab4SSean Wang static void 5331c099ab4SSean Wang mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) 5341c099ab4SSean Wang { 5351c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 5361c099ab4SSean Wang struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; 5371c099ab4SSean Wang 5381c099ab4SSean Wang spin_lock_bh(&dev->mt76.lock); 5391c099ab4SSean Wang __skb_queue_tail(&phy->scan_event_list, skb); 5401c099ab4SSean Wang spin_unlock_bh(&dev->mt76.lock); 5411c099ab4SSean Wang 5421c099ab4SSean Wang ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, 5431c099ab4SSean Wang MT7921_HW_SCAN_TIMEOUT); 5441c099ab4SSean Wang } 5451c099ab4SSean Wang 5461c099ab4SSean Wang static void 5471c099ab4SSean Wang mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb) 5481c099ab4SSean Wang { 5491c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 5501c099ab4SSean Wang struct mt7921_mcu_bss_event *event; 5511c099ab4SSean Wang 5521c099ab4SSean Wang event = (struct mt7921_mcu_bss_event *)(skb->data + 5531c099ab4SSean Wang sizeof(struct mt7921_mcu_rxd)); 5541c099ab4SSean Wang if (event->is_absent) 5551c099ab4SSean Wang ieee80211_stop_queues(mphy->hw); 5561c099ab4SSean Wang else 5571c099ab4SSean Wang ieee80211_wake_queues(mphy->hw); 5581c099ab4SSean Wang } 5591c099ab4SSean Wang 5601c099ab4SSean Wang static void 5611c099ab4SSean Wang mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) 5621c099ab4SSean Wang { 5631c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 5641c099ab4SSean Wang struct debug_msg { 5651c099ab4SSean Wang __le16 id; 5661c099ab4SSean Wang u8 type; 5671c099ab4SSean Wang u8 flag; 5681c099ab4SSean Wang __le32 value; 5691c099ab4SSean Wang __le16 len; 5701c099ab4SSean Wang u8 content[512]; 5711c099ab4SSean Wang } __packed * debug_msg; 5721c099ab4SSean Wang u16 cur_len; 5731c099ab4SSean Wang int i; 5741c099ab4SSean Wang 5751c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 5761c099ab4SSean Wang debug_msg = (struct debug_msg *)skb->data; 5771c099ab4SSean Wang 5781c099ab4SSean Wang cur_len = min_t(u16, le16_to_cpu(debug_msg->len), 512); 5791c099ab4SSean Wang 5801c099ab4SSean Wang if (debug_msg->type == 0x3) { 5811c099ab4SSean Wang for (i = 0 ; i < cur_len; i++) 5821c099ab4SSean Wang if (!debug_msg->content[i]) 5831c099ab4SSean Wang debug_msg->content[i] = ' '; 5841c099ab4SSean Wang 5851c099ab4SSean Wang dev_dbg(dev->mt76.dev, "%s", debug_msg->content); 5861c099ab4SSean Wang } 5871c099ab4SSean Wang } 5881c099ab4SSean Wang 5891c099ab4SSean Wang static void 5901c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) 5911c099ab4SSean Wang { 5921c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 5931c099ab4SSean Wang 5941c099ab4SSean Wang switch (rxd->eid) { 5951c099ab4SSean Wang case MCU_EVENT_BSS_BEACON_LOSS: 5961c099ab4SSean Wang break; 5971c099ab4SSean Wang case MCU_EVENT_SCHED_SCAN_DONE: 5981c099ab4SSean Wang case MCU_EVENT_SCAN_DONE: 5991c099ab4SSean Wang mt7921_mcu_scan_event(dev, skb); 6001c099ab4SSean Wang return; 6011c099ab4SSean Wang case MCU_EVENT_BSS_ABSENCE: 6021c099ab4SSean Wang mt7921_mcu_bss_event(dev, skb); 6031c099ab4SSean Wang break; 6041c099ab4SSean Wang case MCU_EVENT_DBG_MSG: 6051c099ab4SSean Wang mt7921_mcu_debug_msg_event(dev, skb); 6061c099ab4SSean Wang break; 6071c099ab4SSean Wang default: 6081c099ab4SSean Wang break; 6091c099ab4SSean Wang } 6101c099ab4SSean Wang dev_kfree_skb(skb); 6111c099ab4SSean Wang } 6121c099ab4SSean Wang 6131c099ab4SSean Wang void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) 6141c099ab4SSean Wang { 6151c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 6161c099ab4SSean Wang 6171c099ab4SSean Wang if (rxd->eid == 0x6) { 6181c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 6191c099ab4SSean Wang return; 6201c099ab4SSean Wang } 6211c099ab4SSean Wang 6221c099ab4SSean Wang if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || 6231c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || 6241c099ab4SSean Wang rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || 6251c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_ABSENCE || 6261c099ab4SSean Wang rxd->eid == MCU_EVENT_SCAN_DONE || 6271c099ab4SSean Wang rxd->eid == MCU_EVENT_DBG_MSG || 6281c099ab4SSean Wang !rxd->seq) 6291c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(dev, skb); 6301c099ab4SSean Wang else 6311c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 6321c099ab4SSean Wang } 6331c099ab4SSean Wang 6341c099ab4SSean Wang static struct sk_buff * 6351c099ab4SSean Wang mt7921_mcu_alloc_sta_req(struct mt7921_dev *dev, struct mt7921_vif *mvif, 6361c099ab4SSean Wang struct mt7921_sta *msta, int len) 6371c099ab4SSean Wang { 6381c099ab4SSean Wang struct sta_req_hdr hdr = { 6391c099ab4SSean Wang .bss_idx = mvif->mt76.idx, 6401c099ab4SSean Wang .wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0, 6411c099ab4SSean Wang .wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0, 6421c099ab4SSean Wang .muar_idx = msta ? mvif->mt76.omac_idx : 0, 6431c099ab4SSean Wang .is_tlv_append = 1, 6441c099ab4SSean Wang }; 6451c099ab4SSean Wang struct sk_buff *skb; 6461c099ab4SSean Wang 6471c099ab4SSean Wang skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); 6481c099ab4SSean Wang if (!skb) 6491c099ab4SSean Wang return ERR_PTR(-ENOMEM); 6501c099ab4SSean Wang 6511c099ab4SSean Wang skb_put_data(skb, &hdr, sizeof(hdr)); 6521c099ab4SSean Wang 6531c099ab4SSean Wang return skb; 6541c099ab4SSean Wang } 6551c099ab4SSean Wang 6561c099ab4SSean Wang static struct wtbl_req_hdr * 6571c099ab4SSean Wang mt7921_mcu_alloc_wtbl_req(struct mt7921_dev *dev, struct mt7921_sta *msta, 6581c099ab4SSean Wang int cmd, void *sta_wtbl, struct sk_buff **skb) 6591c099ab4SSean Wang { 6601c099ab4SSean Wang struct tlv *sta_hdr = sta_wtbl; 6611c099ab4SSean Wang struct wtbl_req_hdr hdr = { 6621c099ab4SSean Wang .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), 6631c099ab4SSean Wang .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), 6641c099ab4SSean Wang .operation = cmd, 6651c099ab4SSean Wang }; 6661c099ab4SSean Wang struct sk_buff *nskb = *skb; 6671c099ab4SSean Wang 6681c099ab4SSean Wang if (!nskb) { 6691c099ab4SSean Wang nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 6701c099ab4SSean Wang MT7921_WTBL_UPDATE_BA_SIZE); 6711c099ab4SSean Wang if (!nskb) 6721c099ab4SSean Wang return ERR_PTR(-ENOMEM); 6731c099ab4SSean Wang 6741c099ab4SSean Wang *skb = nskb; 6751c099ab4SSean Wang } 6761c099ab4SSean Wang 6771c099ab4SSean Wang if (sta_hdr) 6781c099ab4SSean Wang sta_hdr->len = cpu_to_le16(sizeof(hdr)); 6791c099ab4SSean Wang 6801c099ab4SSean Wang return skb_put_data(nskb, &hdr, sizeof(hdr)); 6811c099ab4SSean Wang } 6821c099ab4SSean Wang 6831c099ab4SSean Wang static struct tlv * 6841c099ab4SSean Wang mt7921_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, 6851c099ab4SSean Wang void *sta_ntlv, void *sta_wtbl) 6861c099ab4SSean Wang { 6871c099ab4SSean Wang struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; 6881c099ab4SSean Wang struct tlv *sta_hdr = sta_wtbl; 6891c099ab4SSean Wang struct tlv *ptlv, tlv = { 6901c099ab4SSean Wang .tag = cpu_to_le16(tag), 6911c099ab4SSean Wang .len = cpu_to_le16(len), 6921c099ab4SSean Wang }; 6931c099ab4SSean Wang u16 ntlv; 6941c099ab4SSean Wang 6951c099ab4SSean Wang ptlv = skb_put(skb, len); 6961c099ab4SSean Wang memcpy(ptlv, &tlv, sizeof(tlv)); 6971c099ab4SSean Wang 6981c099ab4SSean Wang ntlv = le16_to_cpu(ntlv_hdr->tlv_num); 6991c099ab4SSean Wang ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); 7001c099ab4SSean Wang 7011c099ab4SSean Wang if (sta_hdr) { 7021c099ab4SSean Wang u16 size = le16_to_cpu(sta_hdr->len); 7031c099ab4SSean Wang 7041c099ab4SSean Wang sta_hdr->len = cpu_to_le16(size + len); 7051c099ab4SSean Wang } 7061c099ab4SSean Wang 7071c099ab4SSean Wang return ptlv; 7081c099ab4SSean Wang } 7091c099ab4SSean Wang 7101c099ab4SSean Wang static struct tlv * 7111c099ab4SSean Wang mt7921_mcu_add_tlv(struct sk_buff *skb, int tag, int len) 7121c099ab4SSean Wang { 7131c099ab4SSean Wang return mt7921_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); 7141c099ab4SSean Wang } 7151c099ab4SSean Wang 7161c099ab4SSean Wang static void 7171c099ab4SSean Wang mt7921_mcu_uni_bss_he_tlv(struct tlv *tlv, struct ieee80211_vif *vif, 7181c099ab4SSean Wang struct mt7921_phy *phy) 7191c099ab4SSean Wang { 7201c099ab4SSean Wang #define DEFAULT_HE_PE_DURATION 4 7211c099ab4SSean Wang #define DEFAULT_HE_DURATION_RTS_THRES 1023 7221c099ab4SSean Wang const struct ieee80211_sta_he_cap *cap; 7231c099ab4SSean Wang struct bss_info_uni_he *he; 7241c099ab4SSean Wang 7251c099ab4SSean Wang cap = mt7921_get_he_phy_cap(phy, vif); 7261c099ab4SSean Wang 7271c099ab4SSean Wang he = (struct bss_info_uni_he *)tlv; 7281c099ab4SSean Wang he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; 7291c099ab4SSean Wang if (!he->he_pe_duration) 7301c099ab4SSean Wang he->he_pe_duration = DEFAULT_HE_PE_DURATION; 7311c099ab4SSean Wang 7321c099ab4SSean Wang he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); 7331c099ab4SSean Wang if (!he->he_rts_thres) 7341c099ab4SSean Wang he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); 7351c099ab4SSean Wang 7361c099ab4SSean Wang he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; 7371c099ab4SSean Wang he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; 7381c099ab4SSean Wang he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; 7391c099ab4SSean Wang } 7401c099ab4SSean Wang 7411c099ab4SSean Wang /** starec & wtbl **/ 7421c099ab4SSean Wang static int 7431c099ab4SSean Wang mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, 7441c099ab4SSean Wang struct ieee80211_key_conf *key, enum set_key_cmd cmd) 7451c099ab4SSean Wang { 7461c099ab4SSean Wang struct mt7921_sta_key_conf *bip = &msta->bip; 7471c099ab4SSean Wang struct sta_rec_sec *sec; 7481c099ab4SSean Wang struct tlv *tlv; 7491c099ab4SSean Wang u32 len = sizeof(*sec); 7501c099ab4SSean Wang 7511c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); 7521c099ab4SSean Wang 7531c099ab4SSean Wang sec = (struct sta_rec_sec *)tlv; 7541c099ab4SSean Wang sec->add = cmd; 7551c099ab4SSean Wang 7561c099ab4SSean Wang if (cmd == SET_KEY) { 7571c099ab4SSean Wang struct sec_key *sec_key; 7581c099ab4SSean Wang u8 cipher; 7591c099ab4SSean Wang 7601c099ab4SSean Wang cipher = mt7921_mcu_get_cipher(key->cipher); 7611c099ab4SSean Wang if (cipher == MT_CIPHER_NONE) 7621c099ab4SSean Wang return -EOPNOTSUPP; 7631c099ab4SSean Wang 7641c099ab4SSean Wang sec_key = &sec->key[0]; 7651c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 7661c099ab4SSean Wang 7671c099ab4SSean Wang if (cipher == MT_CIPHER_BIP_CMAC_128) { 7681c099ab4SSean Wang sec_key->cipher_id = MT_CIPHER_AES_CCMP; 7691c099ab4SSean Wang sec_key->key_id = bip->keyidx; 7701c099ab4SSean Wang sec_key->key_len = 16; 7711c099ab4SSean Wang memcpy(sec_key->key, bip->key, 16); 7721c099ab4SSean Wang 7731c099ab4SSean Wang sec_key = &sec->key[1]; 7741c099ab4SSean Wang sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; 7751c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 7761c099ab4SSean Wang sec_key->key_len = 16; 7771c099ab4SSean Wang memcpy(sec_key->key, key->key, 16); 7781c099ab4SSean Wang 7791c099ab4SSean Wang sec->n_cipher = 2; 7801c099ab4SSean Wang } else { 7811c099ab4SSean Wang sec_key->cipher_id = cipher; 7821c099ab4SSean Wang sec_key->key_id = key->keyidx; 7831c099ab4SSean Wang sec_key->key_len = key->keylen; 7841c099ab4SSean Wang memcpy(sec_key->key, key->key, key->keylen); 7851c099ab4SSean Wang 7861c099ab4SSean Wang if (cipher == MT_CIPHER_TKIP) { 7871c099ab4SSean Wang /* Rx/Tx MIC keys are swapped */ 7881c099ab4SSean Wang memcpy(sec_key->key + 16, key->key + 24, 8); 7891c099ab4SSean Wang memcpy(sec_key->key + 24, key->key + 16, 8); 7901c099ab4SSean Wang } 7911c099ab4SSean Wang 7921c099ab4SSean Wang /* store key_conf for BIP batch update */ 7931c099ab4SSean Wang if (cipher == MT_CIPHER_AES_CCMP) { 7941c099ab4SSean Wang memcpy(bip->key, key->key, key->keylen); 7951c099ab4SSean Wang bip->keyidx = key->keyidx; 7961c099ab4SSean Wang } 7971c099ab4SSean Wang 7981c099ab4SSean Wang len -= sizeof(*sec_key); 7991c099ab4SSean Wang sec->n_cipher = 1; 8001c099ab4SSean Wang } 8011c099ab4SSean Wang } else { 8021c099ab4SSean Wang len -= sizeof(sec->key); 8031c099ab4SSean Wang sec->n_cipher = 0; 8041c099ab4SSean Wang } 8051c099ab4SSean Wang sec->len = cpu_to_le16(len); 8061c099ab4SSean Wang 8071c099ab4SSean Wang return 0; 8081c099ab4SSean Wang } 8091c099ab4SSean Wang 8101c099ab4SSean Wang int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, 8111c099ab4SSean Wang struct mt7921_sta *msta, struct ieee80211_key_conf *key, 8121c099ab4SSean Wang enum set_key_cmd cmd) 8131c099ab4SSean Wang { 8141c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 8151c099ab4SSean Wang struct sk_buff *skb; 8161c099ab4SSean Wang int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_sec); 8171c099ab4SSean Wang int ret; 8181c099ab4SSean Wang 8191c099ab4SSean Wang skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta, len); 8201c099ab4SSean Wang if (IS_ERR(skb)) 8211c099ab4SSean Wang return PTR_ERR(skb); 8221c099ab4SSean Wang 8231c099ab4SSean Wang ret = mt7921_mcu_sta_key_tlv(msta, skb, key, cmd); 8241c099ab4SSean Wang if (ret) 8251c099ab4SSean Wang return ret; 8261c099ab4SSean Wang 8271c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, 8281c099ab4SSean Wang MCU_UNI_CMD_STA_REC_UPDATE, true); 8291c099ab4SSean Wang } 8301c099ab4SSean Wang 8311c099ab4SSean Wang static void 8321c099ab4SSean Wang mt7921_mcu_sta_ba_tlv(struct sk_buff *skb, 8331c099ab4SSean Wang struct ieee80211_ampdu_params *params, 8341c099ab4SSean Wang bool enable, bool tx) 8351c099ab4SSean Wang { 8361c099ab4SSean Wang struct sta_rec_ba *ba; 8371c099ab4SSean Wang struct tlv *tlv; 8381c099ab4SSean Wang 8391c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); 8401c099ab4SSean Wang 8411c099ab4SSean Wang ba = (struct sta_rec_ba *)tlv; 8421c099ab4SSean Wang ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT, 8431c099ab4SSean Wang ba->winsize = cpu_to_le16(params->buf_size); 8441c099ab4SSean Wang ba->ssn = cpu_to_le16(params->ssn); 8451c099ab4SSean Wang ba->ba_en = enable << params->tid; 8461c099ab4SSean Wang ba->amsdu = params->amsdu; 8471c099ab4SSean Wang ba->tid = params->tid; 8481c099ab4SSean Wang } 8491c099ab4SSean Wang 8501c099ab4SSean Wang static void 8511c099ab4SSean Wang mt7921_mcu_wtbl_ba_tlv(struct sk_buff *skb, 8521c099ab4SSean Wang struct ieee80211_ampdu_params *params, 8531c099ab4SSean Wang bool enable, bool tx, void *sta_wtbl, 8541c099ab4SSean Wang void *wtbl_tlv) 8551c099ab4SSean Wang { 8561c099ab4SSean Wang struct wtbl_ba *ba; 8571c099ab4SSean Wang struct tlv *tlv; 8581c099ab4SSean Wang 8591c099ab4SSean Wang tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), 8601c099ab4SSean Wang wtbl_tlv, sta_wtbl); 8611c099ab4SSean Wang 8621c099ab4SSean Wang ba = (struct wtbl_ba *)tlv; 8631c099ab4SSean Wang ba->tid = params->tid; 8641c099ab4SSean Wang 8651c099ab4SSean Wang if (tx) { 8661c099ab4SSean Wang ba->ba_type = MT_BA_TYPE_ORIGINATOR; 8671c099ab4SSean Wang ba->sn = enable ? cpu_to_le16(params->ssn) : 0; 8681c099ab4SSean Wang ba->ba_en = enable; 8691c099ab4SSean Wang } else { 8701c099ab4SSean Wang memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); 8711c099ab4SSean Wang ba->ba_type = MT_BA_TYPE_RECIPIENT; 8721c099ab4SSean Wang ba->rst_ba_tid = params->tid; 8731c099ab4SSean Wang ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; 8741c099ab4SSean Wang ba->rst_ba_sb = 1; 8751c099ab4SSean Wang } 8761c099ab4SSean Wang 8771c099ab4SSean Wang if (enable && tx) 8781c099ab4SSean Wang ba->ba_winsize = cpu_to_le16(params->buf_size); 8791c099ab4SSean Wang } 8801c099ab4SSean Wang 8811c099ab4SSean Wang static int 8821c099ab4SSean Wang mt7921_mcu_sta_ba(struct mt7921_dev *dev, 8831c099ab4SSean Wang struct ieee80211_ampdu_params *params, 8841c099ab4SSean Wang bool enable, bool tx, int cmd) 8851c099ab4SSean Wang { 8861c099ab4SSean Wang struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 8871c099ab4SSean Wang struct mt7921_vif *mvif = msta->vif; 8881c099ab4SSean Wang struct wtbl_req_hdr *wtbl_hdr; 8891c099ab4SSean Wang struct tlv *sta_wtbl; 8901c099ab4SSean Wang struct sk_buff *skb; 8911c099ab4SSean Wang int ret; 8921c099ab4SSean Wang 8931c099ab4SSean Wang if (enable && tx && !params->amsdu) 8941c099ab4SSean Wang msta->wcid.amsdu = false; 8951c099ab4SSean Wang 8961c099ab4SSean Wang skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta, 8971c099ab4SSean Wang MT7921_STA_UPDATE_MAX_SIZE); 8981c099ab4SSean Wang if (IS_ERR(skb)) 8991c099ab4SSean Wang return PTR_ERR(skb); 9001c099ab4SSean Wang 9011c099ab4SSean Wang sta_wtbl = mt7921_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 9021c099ab4SSean Wang 9031c099ab4SSean Wang wtbl_hdr = mt7921_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, 9041c099ab4SSean Wang &skb); 9051c099ab4SSean Wang mt7921_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); 9061c099ab4SSean Wang 9071c099ab4SSean Wang ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); 9081c099ab4SSean Wang if (ret) 9091c099ab4SSean Wang return ret; 9101c099ab4SSean Wang 9111c099ab4SSean Wang skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta, 9121c099ab4SSean Wang MT7921_STA_UPDATE_MAX_SIZE); 9131c099ab4SSean Wang if (IS_ERR(skb)) 9141c099ab4SSean Wang return PTR_ERR(skb); 9151c099ab4SSean Wang 9161c099ab4SSean Wang mt7921_mcu_sta_ba_tlv(skb, params, enable, tx); 9171c099ab4SSean Wang 9181c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); 9191c099ab4SSean Wang } 9201c099ab4SSean Wang 9211c099ab4SSean Wang int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, 9221c099ab4SSean Wang struct ieee80211_ampdu_params *params, 9231c099ab4SSean Wang bool enable) 9241c099ab4SSean Wang { 9251c099ab4SSean Wang return mt7921_mcu_sta_ba(dev, params, enable, true, MCU_UNI_CMD_STA_REC_UPDATE); 9261c099ab4SSean Wang } 9271c099ab4SSean Wang 9281c099ab4SSean Wang int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, 9291c099ab4SSean Wang struct ieee80211_ampdu_params *params, 9301c099ab4SSean Wang bool enable) 9311c099ab4SSean Wang { 9321c099ab4SSean Wang return mt7921_mcu_sta_ba(dev, params, enable, false, MCU_UNI_CMD_STA_REC_UPDATE); 9331c099ab4SSean Wang } 9341c099ab4SSean Wang 9351c099ab4SSean Wang static void 9361c099ab4SSean Wang mt7921_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 9371c099ab4SSean Wang struct ieee80211_sta *sta, void *sta_wtbl, 9381c099ab4SSean Wang void *wtbl_tlv) 9391c099ab4SSean Wang { 9401c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 9411c099ab4SSean Wang struct wtbl_generic *generic; 9421c099ab4SSean Wang struct wtbl_rx *rx; 9431c099ab4SSean Wang struct tlv *tlv; 9441c099ab4SSean Wang 9451c099ab4SSean Wang tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), 9461c099ab4SSean Wang wtbl_tlv, sta_wtbl); 9471c099ab4SSean Wang 9481c099ab4SSean Wang generic = (struct wtbl_generic *)tlv; 9491c099ab4SSean Wang 9501c099ab4SSean Wang if (sta) { 9511c099ab4SSean Wang if (vif->type == NL80211_IFTYPE_STATION) 9521c099ab4SSean Wang generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); 9531c099ab4SSean Wang else 9541c099ab4SSean Wang generic->partial_aid = cpu_to_le16(sta->aid); 9551c099ab4SSean Wang memcpy(generic->peer_addr, sta->addr, ETH_ALEN); 9561c099ab4SSean Wang generic->muar_idx = mvif->mt76.omac_idx; 9571c099ab4SSean Wang generic->qos = sta->wme; 9581c099ab4SSean Wang } else { 9591c099ab4SSean Wang /* use BSSID in station mode */ 9601c099ab4SSean Wang if (vif->type == NL80211_IFTYPE_STATION) 9611c099ab4SSean Wang memcpy(generic->peer_addr, vif->bss_conf.bssid, 9621c099ab4SSean Wang ETH_ALEN); 9631c099ab4SSean Wang else 9641c099ab4SSean Wang eth_broadcast_addr(generic->peer_addr); 9651c099ab4SSean Wang 9661c099ab4SSean Wang generic->muar_idx = 0xe; 9671c099ab4SSean Wang } 9681c099ab4SSean Wang 9691c099ab4SSean Wang tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), 9701c099ab4SSean Wang wtbl_tlv, sta_wtbl); 9711c099ab4SSean Wang 9721c099ab4SSean Wang rx = (struct wtbl_rx *)tlv; 9731c099ab4SSean Wang rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; 9741c099ab4SSean Wang rx->rca2 = 1; 9751c099ab4SSean Wang rx->rv = 1; 9761c099ab4SSean Wang } 9771c099ab4SSean Wang 9781c099ab4SSean Wang static void 9791c099ab4SSean Wang mt7921_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 9801c099ab4SSean Wang struct ieee80211_sta *sta, bool enable) 9811c099ab4SSean Wang { 9821c099ab4SSean Wang #define EXTRA_INFO_VER BIT(0) 9831c099ab4SSean Wang #define EXTRA_INFO_NEW BIT(1) 9841c099ab4SSean Wang struct sta_rec_basic *basic; 9851c099ab4SSean Wang struct tlv *tlv; 9861c099ab4SSean Wang int conn_type; 9871c099ab4SSean Wang 9881c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); 9891c099ab4SSean Wang 9901c099ab4SSean Wang basic = (struct sta_rec_basic *)tlv; 9911c099ab4SSean Wang basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); 9921c099ab4SSean Wang 9931c099ab4SSean Wang if (enable) { 9941c099ab4SSean Wang basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); 9951c099ab4SSean Wang basic->conn_state = CONN_STATE_PORT_SECURE; 9961c099ab4SSean Wang } else { 9971c099ab4SSean Wang basic->conn_state = CONN_STATE_DISCONNECT; 9981c099ab4SSean Wang } 9991c099ab4SSean Wang 10001c099ab4SSean Wang if (!sta) { 10011c099ab4SSean Wang basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); 10021c099ab4SSean Wang eth_broadcast_addr(basic->peer_addr); 10031c099ab4SSean Wang return; 10041c099ab4SSean Wang } 10051c099ab4SSean Wang 10061c099ab4SSean Wang switch (vif->type) { 10071c099ab4SSean Wang case NL80211_IFTYPE_MESH_POINT: 10081c099ab4SSean Wang case NL80211_IFTYPE_AP: 10091c099ab4SSean Wang if (vif->p2p) 10101c099ab4SSean Wang conn_type = CONNECTION_P2P_GC; 10111c099ab4SSean Wang else 10121c099ab4SSean Wang conn_type = CONNECTION_INFRA_STA; 10131c099ab4SSean Wang basic->conn_type = cpu_to_le32(conn_type); 10141c099ab4SSean Wang basic->aid = cpu_to_le16(sta->aid); 10151c099ab4SSean Wang break; 10161c099ab4SSean Wang case NL80211_IFTYPE_STATION: 10171c099ab4SSean Wang if (vif->p2p) 10181c099ab4SSean Wang conn_type = CONNECTION_P2P_GO; 10191c099ab4SSean Wang else 10201c099ab4SSean Wang conn_type = CONNECTION_INFRA_AP; 10211c099ab4SSean Wang basic->conn_type = cpu_to_le32(conn_type); 10221c099ab4SSean Wang basic->aid = cpu_to_le16(vif->bss_conf.aid); 10231c099ab4SSean Wang break; 10241c099ab4SSean Wang case NL80211_IFTYPE_ADHOC: 10251c099ab4SSean Wang basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); 10261c099ab4SSean Wang basic->aid = cpu_to_le16(sta->aid); 10271c099ab4SSean Wang break; 10281c099ab4SSean Wang default: 10291c099ab4SSean Wang WARN_ON(1); 10301c099ab4SSean Wang break; 10311c099ab4SSean Wang } 10321c099ab4SSean Wang 10331c099ab4SSean Wang memcpy(basic->peer_addr, sta->addr, ETH_ALEN); 10341c099ab4SSean Wang basic->qos = sta->wme; 10351c099ab4SSean Wang } 10361c099ab4SSean Wang 10371c099ab4SSean Wang static void 10381c099ab4SSean Wang mt7921_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 10391c099ab4SSean Wang { 10401c099ab4SSean Wang struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; 10411c099ab4SSean Wang struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; 10421c099ab4SSean Wang struct sta_rec_he *he; 10431c099ab4SSean Wang struct tlv *tlv; 10441c099ab4SSean Wang u32 cap = 0; 10451c099ab4SSean Wang 10461c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); 10471c099ab4SSean Wang 10481c099ab4SSean Wang he = (struct sta_rec_he *)tlv; 10491c099ab4SSean Wang 10501c099ab4SSean Wang if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) 10511c099ab4SSean Wang cap |= STA_REC_HE_CAP_HTC; 10521c099ab4SSean Wang 10531c099ab4SSean Wang if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) 10541c099ab4SSean Wang cap |= STA_REC_HE_CAP_BSR; 10551c099ab4SSean Wang 10561c099ab4SSean Wang if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) 10571c099ab4SSean Wang cap |= STA_REC_HE_CAP_OM; 10581c099ab4SSean Wang 10591c099ab4SSean Wang if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU) 10601c099ab4SSean Wang cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; 10611c099ab4SSean Wang 10621c099ab4SSean Wang if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) 10631c099ab4SSean Wang cap |= STA_REC_HE_CAP_BQR; 10641c099ab4SSean Wang 10651c099ab4SSean Wang if (elem->phy_cap_info[0] & 10661c099ab4SSean Wang (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | 10671c099ab4SSean Wang IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) 10681c099ab4SSean Wang cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; 10691c099ab4SSean Wang 10701c099ab4SSean Wang if (elem->phy_cap_info[1] & 10711c099ab4SSean Wang IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) 10721c099ab4SSean Wang cap |= STA_REC_HE_CAP_LDPC; 10731c099ab4SSean Wang 10741c099ab4SSean Wang if (elem->phy_cap_info[1] & 10751c099ab4SSean Wang IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) 10761c099ab4SSean Wang cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; 10771c099ab4SSean Wang 10781c099ab4SSean Wang if (elem->phy_cap_info[2] & 10791c099ab4SSean Wang IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) 10801c099ab4SSean Wang cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; 10811c099ab4SSean Wang 10821c099ab4SSean Wang if (elem->phy_cap_info[2] & 10831c099ab4SSean Wang IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) 10841c099ab4SSean Wang cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; 10851c099ab4SSean Wang 10861c099ab4SSean Wang if (elem->phy_cap_info[2] & 10871c099ab4SSean Wang IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) 10881c099ab4SSean Wang cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; 10891c099ab4SSean Wang 10901c099ab4SSean Wang if (elem->phy_cap_info[6] & 10911c099ab4SSean Wang IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) 10921c099ab4SSean Wang cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; 10931c099ab4SSean Wang 10941c099ab4SSean Wang if (elem->phy_cap_info[7] & 10951c099ab4SSean Wang IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) 10961c099ab4SSean Wang cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; 10971c099ab4SSean Wang 10981c099ab4SSean Wang if (elem->phy_cap_info[7] & 10991c099ab4SSean Wang IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) 11001c099ab4SSean Wang cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; 11011c099ab4SSean Wang 11021c099ab4SSean Wang if (elem->phy_cap_info[7] & 11031c099ab4SSean Wang IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) 11041c099ab4SSean Wang cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; 11051c099ab4SSean Wang 11061c099ab4SSean Wang if (elem->phy_cap_info[8] & 11071c099ab4SSean Wang IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) 11081c099ab4SSean Wang cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; 11091c099ab4SSean Wang 11101c099ab4SSean Wang if (elem->phy_cap_info[8] & 11111c099ab4SSean Wang IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) 11121c099ab4SSean Wang cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; 11131c099ab4SSean Wang 11141c099ab4SSean Wang if (elem->phy_cap_info[9] & 11151c099ab4SSean Wang IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK) 11161c099ab4SSean Wang cap |= STA_REC_HE_CAP_TRIG_CQI_FK; 11171c099ab4SSean Wang 11181c099ab4SSean Wang if (elem->phy_cap_info[9] & 11191c099ab4SSean Wang IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) 11201c099ab4SSean Wang cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; 11211c099ab4SSean Wang 11221c099ab4SSean Wang if (elem->phy_cap_info[9] & 11231c099ab4SSean Wang IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) 11241c099ab4SSean Wang cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; 11251c099ab4SSean Wang 11261c099ab4SSean Wang he->he_cap = cpu_to_le32(cap); 11271c099ab4SSean Wang 11281c099ab4SSean Wang switch (sta->bandwidth) { 11291c099ab4SSean Wang case IEEE80211_STA_RX_BW_160: 11301c099ab4SSean Wang if (elem->phy_cap_info[0] & 11311c099ab4SSean Wang IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) 11321c099ab4SSean Wang he->max_nss_mcs[CMD_HE_MCS_BW8080] = 11331c099ab4SSean Wang he_cap->he_mcs_nss_supp.rx_mcs_80p80; 11341c099ab4SSean Wang 11351c099ab4SSean Wang he->max_nss_mcs[CMD_HE_MCS_BW160] = 11361c099ab4SSean Wang he_cap->he_mcs_nss_supp.rx_mcs_160; 11371c099ab4SSean Wang fallthrough; 11381c099ab4SSean Wang default: 11391c099ab4SSean Wang he->max_nss_mcs[CMD_HE_MCS_BW80] = 11401c099ab4SSean Wang he_cap->he_mcs_nss_supp.rx_mcs_80; 11411c099ab4SSean Wang break; 11421c099ab4SSean Wang } 11431c099ab4SSean Wang 11441c099ab4SSean Wang he->t_frame_dur = 11451c099ab4SSean Wang HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); 11461c099ab4SSean Wang he->max_ampdu_exp = 11471c099ab4SSean Wang HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); 11481c099ab4SSean Wang 11491c099ab4SSean Wang he->bw_set = 11501c099ab4SSean Wang HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); 11511c099ab4SSean Wang he->device_class = 11521c099ab4SSean Wang HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); 11531c099ab4SSean Wang he->punc_pream_rx = 11541c099ab4SSean Wang HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); 11551c099ab4SSean Wang 11561c099ab4SSean Wang he->dcm_tx_mode = 11571c099ab4SSean Wang HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); 11581c099ab4SSean Wang he->dcm_tx_max_nss = 11591c099ab4SSean Wang HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); 11601c099ab4SSean Wang he->dcm_rx_mode = 11611c099ab4SSean Wang HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); 11621c099ab4SSean Wang he->dcm_rx_max_nss = 11631c099ab4SSean Wang HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); 11641c099ab4SSean Wang he->dcm_rx_max_nss = 11651c099ab4SSean Wang HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); 11661c099ab4SSean Wang 11671c099ab4SSean Wang he->pkt_ext = 2; 11681c099ab4SSean Wang } 11691c099ab4SSean Wang 11701c099ab4SSean Wang static void 11711c099ab4SSean Wang mt7921_mcu_sta_uapsd_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 11721c099ab4SSean Wang struct ieee80211_vif *vif) 11731c099ab4SSean Wang { 11741c099ab4SSean Wang struct sta_rec_uapsd *uapsd; 11751c099ab4SSean Wang struct tlv *tlv; 11761c099ab4SSean Wang 11771c099ab4SSean Wang if (vif->type != NL80211_IFTYPE_AP || !sta->wme) 11781c099ab4SSean Wang return; 11791c099ab4SSean Wang 11801c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); 11811c099ab4SSean Wang uapsd = (struct sta_rec_uapsd *)tlv; 11821c099ab4SSean Wang 11831c099ab4SSean Wang if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { 11841c099ab4SSean Wang uapsd->dac_map |= BIT(3); 11851c099ab4SSean Wang uapsd->tac_map |= BIT(3); 11861c099ab4SSean Wang } 11871c099ab4SSean Wang if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { 11881c099ab4SSean Wang uapsd->dac_map |= BIT(2); 11891c099ab4SSean Wang uapsd->tac_map |= BIT(2); 11901c099ab4SSean Wang } 11911c099ab4SSean Wang if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { 11921c099ab4SSean Wang uapsd->dac_map |= BIT(1); 11931c099ab4SSean Wang uapsd->tac_map |= BIT(1); 11941c099ab4SSean Wang } 11951c099ab4SSean Wang if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { 11961c099ab4SSean Wang uapsd->dac_map |= BIT(0); 11971c099ab4SSean Wang uapsd->tac_map |= BIT(0); 11981c099ab4SSean Wang } 11991c099ab4SSean Wang uapsd->max_sp = sta->max_sp; 12001c099ab4SSean Wang } 12011c099ab4SSean Wang 12021c099ab4SSean Wang static void 12031c099ab4SSean Wang mt7921_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 12041c099ab4SSean Wang { 12051c099ab4SSean Wang struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; 12061c099ab4SSean Wang struct sta_rec_amsdu *amsdu; 12071c099ab4SSean Wang struct tlv *tlv; 12081c099ab4SSean Wang 12091c099ab4SSean Wang if (!sta->max_amsdu_len) 12101c099ab4SSean Wang return; 12111c099ab4SSean Wang 12121c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); 12131c099ab4SSean Wang amsdu = (struct sta_rec_amsdu *)tlv; 12141c099ab4SSean Wang amsdu->max_amsdu_num = 8; 12151c099ab4SSean Wang amsdu->amsdu_en = true; 12161c099ab4SSean Wang amsdu->max_mpdu_size = sta->max_amsdu_len >= 12171c099ab4SSean Wang IEEE80211_MAX_MPDU_LEN_VHT_7991; 12181c099ab4SSean Wang msta->wcid.amsdu = true; 12191c099ab4SSean Wang } 12201c099ab4SSean Wang 12211c099ab4SSean Wang static bool 12221c099ab4SSean Wang mt7921_hw_amsdu_supported(struct ieee80211_vif *vif) 12231c099ab4SSean Wang { 12241c099ab4SSean Wang switch (vif->type) { 12251c099ab4SSean Wang case NL80211_IFTYPE_AP: 12261c099ab4SSean Wang case NL80211_IFTYPE_STATION: 12271c099ab4SSean Wang return true; 12281c099ab4SSean Wang default: 12291c099ab4SSean Wang return false; 12301c099ab4SSean Wang } 12311c099ab4SSean Wang } 12321c099ab4SSean Wang 12331c099ab4SSean Wang static void 12341c099ab4SSean Wang mt7921_mcu_sta_tlv(struct mt7921_dev *dev, struct sk_buff *skb, 12351c099ab4SSean Wang struct ieee80211_sta *sta, struct ieee80211_vif *vif) 12361c099ab4SSean Wang { 12371c099ab4SSean Wang struct tlv *tlv; 12381c099ab4SSean Wang struct sta_rec_state *state; 12391c099ab4SSean Wang struct sta_rec_phy *phy; 12401c099ab4SSean Wang struct sta_rec_ra_info *ra_info; 12411c099ab4SSean Wang struct cfg80211_chan_def *chandef = &dev->mphy.chandef; 12421c099ab4SSean Wang enum nl80211_band band = chandef->chan->band; 12431c099ab4SSean Wang 12441c099ab4SSean Wang /* starec ht */ 12451c099ab4SSean Wang if (sta->ht_cap.ht_supported) { 12461c099ab4SSean Wang struct sta_rec_ht *ht; 12471c099ab4SSean Wang 12481c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); 12491c099ab4SSean Wang ht = (struct sta_rec_ht *)tlv; 12501c099ab4SSean Wang ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); 12511c099ab4SSean Wang 12521c099ab4SSean Wang if (mt7921_hw_amsdu_supported(vif)) 12531c099ab4SSean Wang mt7921_mcu_sta_amsdu_tlv(skb, sta); 12541c099ab4SSean Wang } 12551c099ab4SSean Wang 12561c099ab4SSean Wang /* starec vht */ 12571c099ab4SSean Wang if (sta->vht_cap.vht_supported) { 12581c099ab4SSean Wang struct sta_rec_vht *vht; 12591c099ab4SSean Wang 12601c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); 12611c099ab4SSean Wang vht = (struct sta_rec_vht *)tlv; 12621c099ab4SSean Wang vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); 12631c099ab4SSean Wang vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; 12641c099ab4SSean Wang vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; 12651c099ab4SSean Wang } 12661c099ab4SSean Wang 12671c099ab4SSean Wang /* starec he */ 12681c099ab4SSean Wang if (sta->he_cap.has_he) 12691c099ab4SSean Wang mt7921_mcu_sta_he_tlv(skb, sta); 12701c099ab4SSean Wang 12711c099ab4SSean Wang /* starec uapsd */ 12721c099ab4SSean Wang mt7921_mcu_sta_uapsd_tlv(skb, sta, vif); 12731c099ab4SSean Wang 12741c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); 12751c099ab4SSean Wang phy = (struct sta_rec_phy *)tlv; 12761c099ab4SSean Wang phy->phy_type = mt7921_get_phy_mode_v2(dev, vif, band, sta); 12771c099ab4SSean Wang phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); 12781c099ab4SSean Wang 12791c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); 12801c099ab4SSean Wang ra_info = (struct sta_rec_ra_info *)tlv; 12811c099ab4SSean Wang ra_info->legacy = cpu_to_le16((u16)sta->supp_rates[band]); 12821c099ab4SSean Wang 12831c099ab4SSean Wang if (sta->ht_cap.ht_supported) { 12841c099ab4SSean Wang memcpy(ra_info->rx_mcs_bitmask, sta->ht_cap.mcs.rx_mask, 12851c099ab4SSean Wang HT_MCS_MASK_NUM); 12861c099ab4SSean Wang } 12871c099ab4SSean Wang 12881c099ab4SSean Wang tlv = mt7921_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state)); 12891c099ab4SSean Wang state = (struct sta_rec_state *)tlv; 12901c099ab4SSean Wang state->state = 2; 12911c099ab4SSean Wang 12921c099ab4SSean Wang if (sta->vht_cap.vht_supported) { 12931c099ab4SSean Wang state->vht_opmode = sta->bandwidth; 12941c099ab4SSean Wang state->vht_opmode |= (sta->rx_nss - 1) << 12951c099ab4SSean Wang IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; 12961c099ab4SSean Wang } 12971c099ab4SSean Wang } 12981c099ab4SSean Wang 12991c099ab4SSean Wang static void 13001c099ab4SSean Wang mt7921_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 13011c099ab4SSean Wang void *sta_wtbl, void *wtbl_tlv) 13021c099ab4SSean Wang { 13031c099ab4SSean Wang struct wtbl_smps *smps; 13041c099ab4SSean Wang struct tlv *tlv; 13051c099ab4SSean Wang 13061c099ab4SSean Wang tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), 13071c099ab4SSean Wang wtbl_tlv, sta_wtbl); 13081c099ab4SSean Wang smps = (struct wtbl_smps *)tlv; 13091c099ab4SSean Wang 13101c099ab4SSean Wang if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) 13111c099ab4SSean Wang smps->smps = true; 13121c099ab4SSean Wang } 13131c099ab4SSean Wang 13141c099ab4SSean Wang static void 13151c099ab4SSean Wang mt7921_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 13161c099ab4SSean Wang void *sta_wtbl, void *wtbl_tlv) 13171c099ab4SSean Wang { 13181c099ab4SSean Wang struct wtbl_ht *ht = NULL; 13191c099ab4SSean Wang struct tlv *tlv; 13201c099ab4SSean Wang 13211c099ab4SSean Wang /* wtbl ht */ 13221c099ab4SSean Wang if (sta->ht_cap.ht_supported) { 13231c099ab4SSean Wang tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), 13241c099ab4SSean Wang wtbl_tlv, sta_wtbl); 13251c099ab4SSean Wang ht = (struct wtbl_ht *)tlv; 13261c099ab4SSean Wang ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING); 13271c099ab4SSean Wang ht->af = sta->ht_cap.ampdu_factor; 13281c099ab4SSean Wang ht->mm = sta->ht_cap.ampdu_density; 13291c099ab4SSean Wang ht->ht = true; 13301c099ab4SSean Wang } 13311c099ab4SSean Wang 13321c099ab4SSean Wang /* wtbl vht */ 13331c099ab4SSean Wang if (sta->vht_cap.vht_supported) { 13341c099ab4SSean Wang struct wtbl_vht *vht; 13351c099ab4SSean Wang u8 af; 13361c099ab4SSean Wang 13371c099ab4SSean Wang tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), 13381c099ab4SSean Wang wtbl_tlv, sta_wtbl); 13391c099ab4SSean Wang vht = (struct wtbl_vht *)tlv; 13401c099ab4SSean Wang vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); 13411c099ab4SSean Wang vht->vht = true; 13421c099ab4SSean Wang 13431c099ab4SSean Wang af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, 13441c099ab4SSean Wang sta->vht_cap.cap); 13451c099ab4SSean Wang if (ht) 13461c099ab4SSean Wang ht->af = max_t(u8, ht->af, af); 13471c099ab4SSean Wang } 13481c099ab4SSean Wang 13491c099ab4SSean Wang mt7921_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv); 13501c099ab4SSean Wang } 13511c099ab4SSean Wang 13521c099ab4SSean Wang static int mt7921_mcu_start_firmware(struct mt7921_dev *dev, u32 addr, 13531c099ab4SSean Wang u32 option) 13541c099ab4SSean Wang { 13551c099ab4SSean Wang struct { 13561c099ab4SSean Wang __le32 option; 13571c099ab4SSean Wang __le32 addr; 13581c099ab4SSean Wang } req = { 13591c099ab4SSean Wang .option = cpu_to_le32(option), 13601c099ab4SSean Wang .addr = cpu_to_le32(addr), 13611c099ab4SSean Wang }; 13621c099ab4SSean Wang 13631c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_START_REQ, &req, 13641c099ab4SSean Wang sizeof(req), true); 13651c099ab4SSean Wang } 13661c099ab4SSean Wang 13671c099ab4SSean Wang static int mt7921_mcu_restart(struct mt76_dev *dev) 13681c099ab4SSean Wang { 13691c099ab4SSean Wang struct { 13701c099ab4SSean Wang u8 power_mode; 13711c099ab4SSean Wang u8 rsv[3]; 13721c099ab4SSean Wang } req = { 13731c099ab4SSean Wang .power_mode = 1, 13741c099ab4SSean Wang }; 13751c099ab4SSean Wang 13761c099ab4SSean Wang return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req, 13771c099ab4SSean Wang sizeof(req), false); 13781c099ab4SSean Wang } 13791c099ab4SSean Wang 13801c099ab4SSean Wang static int mt7921_mcu_patch_sem_ctrl(struct mt7921_dev *dev, bool get) 13811c099ab4SSean Wang { 13821c099ab4SSean Wang struct { 13831c099ab4SSean Wang __le32 op; 13841c099ab4SSean Wang } req = { 13851c099ab4SSean Wang .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), 13861c099ab4SSean Wang }; 13871c099ab4SSean Wang 13881c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_SEM_CONTROL, &req, 13891c099ab4SSean Wang sizeof(req), true); 13901c099ab4SSean Wang } 13911c099ab4SSean Wang 13921c099ab4SSean Wang static int mt7921_mcu_start_patch(struct mt7921_dev *dev) 13931c099ab4SSean Wang { 13941c099ab4SSean Wang struct { 13951c099ab4SSean Wang u8 check_crc; 13961c099ab4SSean Wang u8 reserved[3]; 13971c099ab4SSean Wang } req = { 13981c099ab4SSean Wang .check_crc = 0, 13991c099ab4SSean Wang }; 14001c099ab4SSean Wang 14011c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_FINISH_REQ, &req, 14021c099ab4SSean Wang sizeof(req), true); 14031c099ab4SSean Wang } 14041c099ab4SSean Wang 14051c099ab4SSean Wang static int mt7921_driver_own(struct mt7921_dev *dev) 14061c099ab4SSean Wang { 14071c099ab4SSean Wang u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 14081c099ab4SSean Wang 14091c099ab4SSean Wang mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); 14101c099ab4SSean Wang if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, 14111c099ab4SSean Wang 0, 500)) { 14121c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for driver own\n"); 14131c099ab4SSean Wang return -EIO; 14141c099ab4SSean Wang } 14151c099ab4SSean Wang 14161c099ab4SSean Wang return 0; 14171c099ab4SSean Wang } 14181c099ab4SSean Wang 14191c099ab4SSean Wang static int mt7921_mcu_init_download(struct mt7921_dev *dev, u32 addr, 14201c099ab4SSean Wang u32 len, u32 mode) 14211c099ab4SSean Wang { 14221c099ab4SSean Wang struct { 14231c099ab4SSean Wang __le32 addr; 14241c099ab4SSean Wang __le32 len; 14251c099ab4SSean Wang __le32 mode; 14261c099ab4SSean Wang } req = { 14271c099ab4SSean Wang .addr = cpu_to_le32(addr), 14281c099ab4SSean Wang .len = cpu_to_le32(len), 14291c099ab4SSean Wang .mode = cpu_to_le32(mode), 14301c099ab4SSean Wang }; 14311c099ab4SSean Wang int attr; 14321c099ab4SSean Wang 14331c099ab4SSean Wang if (req.addr == cpu_to_le32(MCU_PATCH_ADDRESS) || addr == 0x900000) 14341c099ab4SSean Wang attr = MCU_CMD_PATCH_START_REQ; 14351c099ab4SSean Wang else 14361c099ab4SSean Wang attr = MCU_CMD_TARGET_ADDRESS_LEN_REQ; 14371c099ab4SSean Wang 14381c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true); 14391c099ab4SSean Wang } 14401c099ab4SSean Wang 14411c099ab4SSean Wang static int mt7921_load_patch(struct mt7921_dev *dev) 14421c099ab4SSean Wang { 14431c099ab4SSean Wang const struct mt7921_patch_hdr *hdr; 14441c099ab4SSean Wang const struct firmware *fw = NULL; 14451c099ab4SSean Wang int i, ret, sem; 14461c099ab4SSean Wang 14471c099ab4SSean Wang sem = mt7921_mcu_patch_sem_ctrl(dev, 1); 14481c099ab4SSean Wang switch (sem) { 14491c099ab4SSean Wang case PATCH_IS_DL: 14501c099ab4SSean Wang return 0; 14511c099ab4SSean Wang case PATCH_NOT_DL_SEM_SUCCESS: 14521c099ab4SSean Wang break; 14531c099ab4SSean Wang default: 14541c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); 14551c099ab4SSean Wang return -EAGAIN; 14561c099ab4SSean Wang } 14571c099ab4SSean Wang 14581c099ab4SSean Wang ret = request_firmware(&fw, MT7921_ROM_PATCH, dev->mt76.dev); 14591c099ab4SSean Wang if (ret) 14601c099ab4SSean Wang goto out; 14611c099ab4SSean Wang 14621c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 14631c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 14641c099ab4SSean Wang ret = -EINVAL; 14651c099ab4SSean Wang goto out; 14661c099ab4SSean Wang } 14671c099ab4SSean Wang 14681c099ab4SSean Wang hdr = (const struct mt7921_patch_hdr *)(fw->data); 14691c099ab4SSean Wang 14701c099ab4SSean Wang dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", 14711c099ab4SSean Wang be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); 14721c099ab4SSean Wang 14731c099ab4SSean Wang for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { 14741c099ab4SSean Wang struct mt7921_patch_sec *sec; 14751c099ab4SSean Wang const u8 *dl; 14761c099ab4SSean Wang u32 len, addr; 14771c099ab4SSean Wang 14781c099ab4SSean Wang sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + 14791c099ab4SSean Wang i * sizeof(*sec)); 14801c099ab4SSean Wang if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != 14811c099ab4SSean Wang PATCH_SEC_TYPE_INFO) { 14821c099ab4SSean Wang ret = -EINVAL; 14831c099ab4SSean Wang goto out; 14841c099ab4SSean Wang } 14851c099ab4SSean Wang 14861c099ab4SSean Wang addr = be32_to_cpu(sec->info.addr); 14871c099ab4SSean Wang len = be32_to_cpu(sec->info.len); 14881c099ab4SSean Wang dl = fw->data + be32_to_cpu(sec->offs); 14891c099ab4SSean Wang 14901c099ab4SSean Wang ret = mt7921_mcu_init_download(dev, addr, len, 14911c099ab4SSean Wang DL_MODE_NEED_RSP); 14921c099ab4SSean Wang if (ret) { 14931c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 14941c099ab4SSean Wang goto out; 14951c099ab4SSean Wang } 14961c099ab4SSean Wang 14971c099ab4SSean Wang ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 14981c099ab4SSean Wang dl, len); 14991c099ab4SSean Wang if (ret) { 15001c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send patch\n"); 15011c099ab4SSean Wang goto out; 15021c099ab4SSean Wang } 15031c099ab4SSean Wang } 15041c099ab4SSean Wang 15051c099ab4SSean Wang ret = mt7921_mcu_start_patch(dev); 15061c099ab4SSean Wang if (ret) 15071c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start patch\n"); 15081c099ab4SSean Wang 15091c099ab4SSean Wang out: 15101c099ab4SSean Wang sem = mt7921_mcu_patch_sem_ctrl(dev, 0); 15111c099ab4SSean Wang switch (sem) { 15121c099ab4SSean Wang case PATCH_REL_SEM_SUCCESS: 15131c099ab4SSean Wang break; 15141c099ab4SSean Wang default: 15151c099ab4SSean Wang ret = -EAGAIN; 15161c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); 15171c099ab4SSean Wang goto out; 15181c099ab4SSean Wang } 15191c099ab4SSean Wang release_firmware(fw); 15201c099ab4SSean Wang 15211c099ab4SSean Wang return ret; 15221c099ab4SSean Wang } 15231c099ab4SSean Wang 15241c099ab4SSean Wang static u32 mt7921_mcu_gen_dl_mode(u8 feature_set, bool is_wa) 15251c099ab4SSean Wang { 15261c099ab4SSean Wang u32 ret = 0; 15271c099ab4SSean Wang 15281c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? 15291c099ab4SSean Wang (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; 15301c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_ENCRY_MODE) ? 15311c099ab4SSean Wang DL_CONFIG_ENCRY_MODE_SEL : 0; 15321c099ab4SSean Wang ret |= FIELD_PREP(DL_MODE_KEY_IDX, 15331c099ab4SSean Wang FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); 15341c099ab4SSean Wang ret |= DL_MODE_NEED_RSP; 15351c099ab4SSean Wang ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; 15361c099ab4SSean Wang 15371c099ab4SSean Wang return ret; 15381c099ab4SSean Wang } 15391c099ab4SSean Wang 15401c099ab4SSean Wang static int 15411c099ab4SSean Wang mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, 15421c099ab4SSean Wang const struct mt7921_fw_trailer *hdr, 15431c099ab4SSean Wang const u8 *data, bool is_wa) 15441c099ab4SSean Wang { 15451c099ab4SSean Wang int i, offset = 0; 15461c099ab4SSean Wang u32 override = 0, option = 0; 15471c099ab4SSean Wang 15481c099ab4SSean Wang for (i = 0; i < hdr->n_region; i++) { 15491c099ab4SSean Wang const struct mt7921_fw_region *region; 15501c099ab4SSean Wang int err; 15511c099ab4SSean Wang u32 len, addr, mode; 15521c099ab4SSean Wang 15531c099ab4SSean Wang region = (const struct mt7921_fw_region *)((const u8 *)hdr - 15541c099ab4SSean Wang (hdr->n_region - i) * sizeof(*region)); 15551c099ab4SSean Wang mode = mt7921_mcu_gen_dl_mode(region->feature_set, is_wa); 15561c099ab4SSean Wang len = le32_to_cpu(region->len); 15571c099ab4SSean Wang addr = le32_to_cpu(region->addr); 15581c099ab4SSean Wang 15591c099ab4SSean Wang if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) 15601c099ab4SSean Wang override = addr; 15611c099ab4SSean Wang 15621c099ab4SSean Wang err = mt7921_mcu_init_download(dev, addr, len, mode); 15631c099ab4SSean Wang if (err) { 15641c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 15651c099ab4SSean Wang return err; 15661c099ab4SSean Wang } 15671c099ab4SSean Wang 15681c099ab4SSean Wang err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 15691c099ab4SSean Wang data + offset, len); 15701c099ab4SSean Wang if (err) { 15711c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send firmware.\n"); 15721c099ab4SSean Wang return err; 15731c099ab4SSean Wang } 15741c099ab4SSean Wang 15751c099ab4SSean Wang offset += len; 15761c099ab4SSean Wang } 15771c099ab4SSean Wang 15781c099ab4SSean Wang if (override) 15791c099ab4SSean Wang option |= FW_START_OVERRIDE; 15801c099ab4SSean Wang 15811c099ab4SSean Wang if (is_wa) 15821c099ab4SSean Wang option |= FW_START_WORKING_PDA_CR4; 15831c099ab4SSean Wang 15841c099ab4SSean Wang return mt7921_mcu_start_firmware(dev, override, option); 15851c099ab4SSean Wang } 15861c099ab4SSean Wang 15871c099ab4SSean Wang static int mt7921_load_ram(struct mt7921_dev *dev) 15881c099ab4SSean Wang { 15891c099ab4SSean Wang const struct mt7921_fw_trailer *hdr; 15901c099ab4SSean Wang const struct firmware *fw; 15911c099ab4SSean Wang int ret; 15921c099ab4SSean Wang 15931c099ab4SSean Wang ret = request_firmware(&fw, MT7921_FIRMWARE_WM, dev->mt76.dev); 15941c099ab4SSean Wang if (ret) 15951c099ab4SSean Wang return ret; 15961c099ab4SSean Wang 15971c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 15981c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 15991c099ab4SSean Wang ret = -EINVAL; 16001c099ab4SSean Wang goto out; 16011c099ab4SSean Wang } 16021c099ab4SSean Wang 16031c099ab4SSean Wang hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size - 16041c099ab4SSean Wang sizeof(*hdr)); 16051c099ab4SSean Wang 16061c099ab4SSean Wang dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", 16071c099ab4SSean Wang hdr->fw_ver, hdr->build_date); 16081c099ab4SSean Wang 16091c099ab4SSean Wang ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false); 16101c099ab4SSean Wang if (ret) { 16111c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); 16121c099ab4SSean Wang goto out; 16131c099ab4SSean Wang } 16141c099ab4SSean Wang 16151c099ab4SSean Wang snprintf(dev->mt76.hw->wiphy->fw_version, 16161c099ab4SSean Wang sizeof(dev->mt76.hw->wiphy->fw_version), 16171c099ab4SSean Wang "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 16181c099ab4SSean Wang 16191c099ab4SSean Wang out: 16201c099ab4SSean Wang release_firmware(fw); 16211c099ab4SSean Wang 16221c099ab4SSean Wang return ret; 16231c099ab4SSean Wang } 16241c099ab4SSean Wang 16251c099ab4SSean Wang static int mt7921_load_firmware(struct mt7921_dev *dev) 16261c099ab4SSean Wang { 16271c099ab4SSean Wang int ret; 16281c099ab4SSean Wang 16291c099ab4SSean Wang ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 16301c099ab4SSean Wang if (ret) { 16311c099ab4SSean Wang dev_dbg(dev->mt76.dev, "Firmware is already download\n"); 16321c099ab4SSean Wang return -EIO; 16331c099ab4SSean Wang } 16341c099ab4SSean Wang 16351c099ab4SSean Wang ret = mt7921_load_patch(dev); 16361c099ab4SSean Wang if (ret) 16371c099ab4SSean Wang return ret; 16381c099ab4SSean Wang 16391c099ab4SSean Wang ret = mt7921_load_ram(dev); 16401c099ab4SSean Wang if (ret) 16411c099ab4SSean Wang return ret; 16421c099ab4SSean Wang 16431c099ab4SSean Wang if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, 16441c099ab4SSean Wang MT_TOP_MISC2_FW_N9_RDY, 1500)) { 16451c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 16461c099ab4SSean Wang 16471c099ab4SSean Wang return -EIO; 16481c099ab4SSean Wang } 16491c099ab4SSean Wang 16501c099ab4SSean Wang mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); 16511c099ab4SSean Wang 16521c099ab4SSean Wang dev_err(dev->mt76.dev, "Firmware init done\n"); 16531c099ab4SSean Wang 16541c099ab4SSean Wang return 0; 16551c099ab4SSean Wang } 16561c099ab4SSean Wang 16571c099ab4SSean Wang int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) 16581c099ab4SSean Wang { 16591c099ab4SSean Wang struct { 16601c099ab4SSean Wang u8 ctrl_val; 16611c099ab4SSean Wang u8 pad[3]; 16621c099ab4SSean Wang } data = { 16631c099ab4SSean Wang .ctrl_val = ctrl 16641c099ab4SSean Wang }; 16651c099ab4SSean Wang 16661c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FWLOG_2_HOST, &data, 16671c099ab4SSean Wang sizeof(data), false); 16681c099ab4SSean Wang } 16691c099ab4SSean Wang 16701c099ab4SSean Wang int mt7921_mcu_init(struct mt7921_dev *dev) 16711c099ab4SSean Wang { 16721c099ab4SSean Wang static const struct mt76_mcu_ops mt7921_mcu_ops = { 16731c099ab4SSean Wang .headroom = sizeof(struct mt7921_mcu_txd), 16741c099ab4SSean Wang .mcu_skb_send_msg = mt7921_mcu_send_message, 16751c099ab4SSean Wang .mcu_parse_response = mt7921_mcu_parse_response, 16761c099ab4SSean Wang .mcu_restart = mt7921_mcu_restart, 16771c099ab4SSean Wang }; 16781c099ab4SSean Wang int ret; 16791c099ab4SSean Wang 16801c099ab4SSean Wang dev->mt76.mcu_ops = &mt7921_mcu_ops; 16811c099ab4SSean Wang 16821c099ab4SSean Wang ret = mt7921_driver_own(dev); 16831c099ab4SSean Wang if (ret) 16841c099ab4SSean Wang return ret; 16851c099ab4SSean Wang 16861c099ab4SSean Wang ret = mt7921_load_firmware(dev); 16871c099ab4SSean Wang if (ret) 16881c099ab4SSean Wang return ret; 16891c099ab4SSean Wang 16901c099ab4SSean Wang set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 16911c099ab4SSean Wang mt7921_mcu_fw_log_2_host(dev, 1); 16921c099ab4SSean Wang 16931c099ab4SSean Wang return 0; 16941c099ab4SSean Wang } 16951c099ab4SSean Wang 16961c099ab4SSean Wang void mt7921_mcu_exit(struct mt7921_dev *dev) 16971c099ab4SSean Wang { 16981c099ab4SSean Wang u32 reg = mt7921_reg_map_l1(dev, MT_TOP_MISC); 16991c099ab4SSean Wang 17001c099ab4SSean Wang __mt76_mcu_restart(&dev->mt76); 17011c099ab4SSean Wang if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, 17021c099ab4SSean Wang FIELD_PREP(MT_TOP_MISC_FW_STATE, 17031c099ab4SSean Wang FW_STATE_FW_DOWNLOAD), 1000)) { 17041c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to exit mcu\n"); 17051c099ab4SSean Wang return; 17061c099ab4SSean Wang } 17071c099ab4SSean Wang 17081c099ab4SSean Wang reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 17091c099ab4SSean Wang mt76_wr(dev, reg, MT_TOP_LPCR_HOST_FW_OWN); 17101c099ab4SSean Wang skb_queue_purge(&dev->mt76.mcu.res_q); 17111c099ab4SSean Wang } 17121c099ab4SSean Wang 17131c099ab4SSean Wang int mt7921_mcu_set_mac(struct mt7921_dev *dev, int band, 17141c099ab4SSean Wang bool enable, bool hdr_trans) 17151c099ab4SSean Wang { 17161c099ab4SSean Wang struct { 17171c099ab4SSean Wang u8 enable; 17181c099ab4SSean Wang u8 band; 17191c099ab4SSean Wang u8 rsv[2]; 17201c099ab4SSean Wang } __packed req_mac = { 17211c099ab4SSean Wang .enable = enable, 17221c099ab4SSean Wang .band = band, 17231c099ab4SSean Wang }; 17241c099ab4SSean Wang 17251c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, 17261c099ab4SSean Wang &req_mac, sizeof(req_mac), true); 17271c099ab4SSean Wang } 17281c099ab4SSean Wang 17291c099ab4SSean Wang int mt7921_mcu_set_rts_thresh(struct mt7921_phy *phy, u32 val) 17301c099ab4SSean Wang { 17311c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 17321c099ab4SSean Wang struct { 17331c099ab4SSean Wang u8 prot_idx; 17341c099ab4SSean Wang u8 band; 17351c099ab4SSean Wang u8 rsv[2]; 17361c099ab4SSean Wang __le32 len_thresh; 17371c099ab4SSean Wang __le32 pkt_thresh; 17381c099ab4SSean Wang } __packed req = { 17391c099ab4SSean Wang .prot_idx = 1, 17401c099ab4SSean Wang .band = phy != &dev->phy, 17411c099ab4SSean Wang .len_thresh = cpu_to_le32(val), 17421c099ab4SSean Wang .pkt_thresh = cpu_to_le32(0x2), 17431c099ab4SSean Wang }; 17441c099ab4SSean Wang 17451c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, &req, 17461c099ab4SSean Wang sizeof(req), true); 17471c099ab4SSean Wang } 17481c099ab4SSean Wang 17491c099ab4SSean Wang int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) 17501c099ab4SSean Wang { 17511c099ab4SSean Wang #define WMM_AIFS_SET BIT(0) 17521c099ab4SSean Wang #define WMM_CW_MIN_SET BIT(1) 17531c099ab4SSean Wang #define WMM_CW_MAX_SET BIT(2) 17541c099ab4SSean Wang #define WMM_TXOP_SET BIT(3) 17551c099ab4SSean Wang #define WMM_PARAM_SET GENMASK(3, 0) 17561c099ab4SSean Wang #define TX_CMD_MODE 1 17571c099ab4SSean Wang struct edca { 17581c099ab4SSean Wang u8 queue; 17591c099ab4SSean Wang u8 set; 17601c099ab4SSean Wang u8 aifs; 17611c099ab4SSean Wang u8 cw_min; 17621c099ab4SSean Wang __le16 cw_max; 17631c099ab4SSean Wang __le16 txop; 17641c099ab4SSean Wang }; 17651c099ab4SSean Wang struct mt7921_mcu_tx { 17661c099ab4SSean Wang u8 total; 17671c099ab4SSean Wang u8 action; 17681c099ab4SSean Wang u8 valid; 17691c099ab4SSean Wang u8 mode; 17701c099ab4SSean Wang 17711c099ab4SSean Wang struct edca edca[IEEE80211_NUM_ACS]; 17721c099ab4SSean Wang } __packed req = { 17731c099ab4SSean Wang .valid = true, 17741c099ab4SSean Wang .mode = TX_CMD_MODE, 17751c099ab4SSean Wang .total = IEEE80211_NUM_ACS, 17761c099ab4SSean Wang }; 17771c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 17781c099ab4SSean Wang int ac; 17791c099ab4SSean Wang 17801c099ab4SSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 17811c099ab4SSean Wang struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 17821c099ab4SSean Wang struct edca *e = &req.edca[ac]; 17831c099ab4SSean Wang 17841c099ab4SSean Wang e->set = WMM_PARAM_SET; 17851c099ab4SSean Wang e->queue = ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS; 17861c099ab4SSean Wang e->aifs = q->aifs; 17871c099ab4SSean Wang e->txop = cpu_to_le16(q->txop); 17881c099ab4SSean Wang 17891c099ab4SSean Wang if (q->cw_min) 17901c099ab4SSean Wang e->cw_min = fls(q->cw_min); 17911c099ab4SSean Wang else 17921c099ab4SSean Wang e->cw_min = 5; 17931c099ab4SSean Wang 17941c099ab4SSean Wang if (q->cw_max) 17951c099ab4SSean Wang e->cw_max = cpu_to_le16(fls(q->cw_max)); 17961c099ab4SSean Wang else 17971c099ab4SSean Wang e->cw_max = cpu_to_le16(10); 17981c099ab4SSean Wang } 17991c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, 18001c099ab4SSean Wang sizeof(req), true); 18011c099ab4SSean Wang } 18021c099ab4SSean Wang 18031c099ab4SSean Wang int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) 18041c099ab4SSean Wang { 18051c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 18061c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 18071c099ab4SSean Wang int freq1 = chandef->center_freq1; 18081c099ab4SSean Wang struct { 18091c099ab4SSean Wang u8 control_ch; 18101c099ab4SSean Wang u8 center_ch; 18111c099ab4SSean Wang u8 bw; 18121c099ab4SSean Wang u8 tx_streams_num; 18131c099ab4SSean Wang u8 rx_streams; /* mask or num */ 18141c099ab4SSean Wang u8 switch_reason; 18151c099ab4SSean Wang u8 band_idx; 18161c099ab4SSean Wang u8 center_ch2; /* for 80+80 only */ 18171c099ab4SSean Wang __le16 cac_case; 18181c099ab4SSean Wang u8 channel_band; 18191c099ab4SSean Wang u8 rsv0; 18201c099ab4SSean Wang __le32 outband_freq; 18211c099ab4SSean Wang u8 txpower_drop; 18221c099ab4SSean Wang u8 ap_bw; 18231c099ab4SSean Wang u8 ap_center_ch; 18241c099ab4SSean Wang u8 rsv1[57]; 18251c099ab4SSean Wang } __packed req = { 18261c099ab4SSean Wang .control_ch = chandef->chan->hw_value, 18271c099ab4SSean Wang .center_ch = ieee80211_frequency_to_channel(freq1), 18281c099ab4SSean Wang .bw = mt7921_mcu_chan_bw(chandef), 18291c099ab4SSean Wang .tx_streams_num = hweight8(phy->mt76->antenna_mask), 18301c099ab4SSean Wang .rx_streams = phy->mt76->antenna_mask, 18311c099ab4SSean Wang .band_idx = phy != &dev->phy, 18321c099ab4SSean Wang .channel_band = chandef->chan->band, 18331c099ab4SSean Wang }; 18341c099ab4SSean Wang 18351c099ab4SSean Wang if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 18361c099ab4SSean Wang req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 18371c099ab4SSean Wang else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 18381c099ab4SSean Wang chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 18391c099ab4SSean Wang req.switch_reason = CH_SWITCH_DFS; 18401c099ab4SSean Wang else 18411c099ab4SSean Wang req.switch_reason = CH_SWITCH_NORMAL; 18421c099ab4SSean Wang 18431c099ab4SSean Wang if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) 18441c099ab4SSean Wang req.rx_streams = hweight8(req.rx_streams); 18451c099ab4SSean Wang 18461c099ab4SSean Wang if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 18471c099ab4SSean Wang int freq2 = chandef->center_freq2; 18481c099ab4SSean Wang 18491c099ab4SSean Wang req.center_ch2 = ieee80211_frequency_to_channel(freq2); 18501c099ab4SSean Wang } 18511c099ab4SSean Wang 18521c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 18531c099ab4SSean Wang } 18541c099ab4SSean Wang 18551c099ab4SSean Wang int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) 18561c099ab4SSean Wang { 18571c099ab4SSean Wang struct req_hdr { 18581c099ab4SSean Wang u8 buffer_mode; 18591c099ab4SSean Wang u8 format; 18601c099ab4SSean Wang __le16 len; 18611c099ab4SSean Wang } __packed req = { 18621c099ab4SSean Wang .buffer_mode = EE_MODE_EFUSE, 18631c099ab4SSean Wang .format = EE_FORMAT_WHOLE, 18641c099ab4SSean Wang }; 18651c099ab4SSean Wang 18661c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 18671c099ab4SSean Wang &req, sizeof(req), true); 18681c099ab4SSean Wang } 18691c099ab4SSean Wang 18701c099ab4SSean Wang int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) 18711c099ab4SSean Wang { 18721c099ab4SSean Wang struct mt7921_mcu_eeprom_info req = { 18731c099ab4SSean Wang .addr = cpu_to_le32(round_down(offset, 16)), 18741c099ab4SSean Wang }; 18751c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 18761c099ab4SSean Wang struct sk_buff *skb; 18771c099ab4SSean Wang int ret; 18781c099ab4SSean Wang u8 *buf; 18791c099ab4SSean Wang 18801c099ab4SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, 18811c099ab4SSean Wang sizeof(req), true, &skb); 18821c099ab4SSean Wang if (ret) 18831c099ab4SSean Wang return ret; 18841c099ab4SSean Wang 18851c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 18861c099ab4SSean Wang buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); 18871c099ab4SSean Wang memcpy(buf, res->data, 16); 18881c099ab4SSean Wang dev_kfree_skb(skb); 18891c099ab4SSean Wang 18901c099ab4SSean Wang return 0; 18911c099ab4SSean Wang } 18921c099ab4SSean Wang 18931c099ab4SSean Wang int 18941c099ab4SSean Wang mt7921_mcu_uni_add_dev(struct mt7921_dev *dev, 18951c099ab4SSean Wang struct ieee80211_vif *vif, bool enable) 18961c099ab4SSean Wang { 18971c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 18981c099ab4SSean Wang u8 omac_idx = mvif->mt76.omac_idx; 18991c099ab4SSean Wang struct { 19001c099ab4SSean Wang struct { 19011c099ab4SSean Wang u8 omac_idx; 19021c099ab4SSean Wang u8 band_idx; 19031c099ab4SSean Wang __le16 pad; 19041c099ab4SSean Wang } __packed hdr; 19051c099ab4SSean Wang struct req_tlv { 19061c099ab4SSean Wang __le16 tag; 19071c099ab4SSean Wang __le16 len; 19081c099ab4SSean Wang u8 active; 19091c099ab4SSean Wang u8 pad; 19101c099ab4SSean Wang u8 omac_addr[ETH_ALEN]; 19111c099ab4SSean Wang } __packed tlv; 19121c099ab4SSean Wang } dev_req = { 19131c099ab4SSean Wang .hdr = { 19141c099ab4SSean Wang .omac_idx = omac_idx, 19151c099ab4SSean Wang .band_idx = mvif->mt76.band_idx, 19161c099ab4SSean Wang }, 19171c099ab4SSean Wang .tlv = { 19181c099ab4SSean Wang .tag = cpu_to_le16(DEV_INFO_ACTIVE), 19191c099ab4SSean Wang .len = cpu_to_le16(sizeof(struct req_tlv)), 19201c099ab4SSean Wang .active = enable, 19211c099ab4SSean Wang }, 19221c099ab4SSean Wang }; 19231c099ab4SSean Wang struct { 19241c099ab4SSean Wang struct { 19251c099ab4SSean Wang u8 bss_idx; 19261c099ab4SSean Wang u8 pad[3]; 19271c099ab4SSean Wang } __packed hdr; 19281c099ab4SSean Wang struct mt7921_bss_basic_tlv basic; 19291c099ab4SSean Wang } basic_req = { 19301c099ab4SSean Wang .hdr = { 19311c099ab4SSean Wang .bss_idx = mvif->mt76.idx, 19321c099ab4SSean Wang }, 19331c099ab4SSean Wang .basic = { 19341c099ab4SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), 19351c099ab4SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_bss_basic_tlv)), 19361c099ab4SSean Wang .omac_idx = omac_idx, 19371c099ab4SSean Wang .band_idx = mvif->mt76.band_idx, 19381c099ab4SSean Wang .wmm_idx = mvif->mt76.wmm_idx, 19391c099ab4SSean Wang .active = enable, 19401c099ab4SSean Wang .bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx), 19411c099ab4SSean Wang .sta_idx = cpu_to_le16(mvif->sta.wcid.idx), 19421c099ab4SSean Wang .conn_state = 1, 19431c099ab4SSean Wang }, 19441c099ab4SSean Wang }; 19451c099ab4SSean Wang int err, idx, cmd, len; 19461c099ab4SSean Wang void *data; 19471c099ab4SSean Wang 19481c099ab4SSean Wang switch (vif->type) { 19491c099ab4SSean Wang case NL80211_IFTYPE_MESH_POINT: 19501c099ab4SSean Wang case NL80211_IFTYPE_AP: 19511c099ab4SSean Wang basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); 19521c099ab4SSean Wang break; 19531c099ab4SSean Wang case NL80211_IFTYPE_STATION: 19541c099ab4SSean Wang basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); 19551c099ab4SSean Wang break; 19561c099ab4SSean Wang case NL80211_IFTYPE_ADHOC: 19571c099ab4SSean Wang basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); 19581c099ab4SSean Wang break; 19591c099ab4SSean Wang default: 19601c099ab4SSean Wang WARN_ON(1); 19611c099ab4SSean Wang break; 19621c099ab4SSean Wang } 19631c099ab4SSean Wang 19641c099ab4SSean Wang idx = omac_idx > EXT_BSSID_START ? HW_BSSID_0 : omac_idx; 19651c099ab4SSean Wang basic_req.basic.hw_bss_idx = idx; 19661c099ab4SSean Wang 19671c099ab4SSean Wang memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); 19681c099ab4SSean Wang 19691c099ab4SSean Wang cmd = enable ? MCU_UNI_CMD_DEV_INFO_UPDATE : MCU_UNI_CMD_BSS_INFO_UPDATE; 19701c099ab4SSean Wang data = enable ? (void *)&dev_req : (void *)&basic_req; 19711c099ab4SSean Wang len = enable ? sizeof(dev_req) : sizeof(basic_req); 19721c099ab4SSean Wang 19731c099ab4SSean Wang err = mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); 19741c099ab4SSean Wang if (err < 0) 19751c099ab4SSean Wang return err; 19761c099ab4SSean Wang 19771c099ab4SSean Wang cmd = enable ? MCU_UNI_CMD_BSS_INFO_UPDATE : MCU_UNI_CMD_DEV_INFO_UPDATE; 19781c099ab4SSean Wang data = enable ? (void *)&basic_req : (void *)&dev_req; 19791c099ab4SSean Wang len = enable ? sizeof(basic_req) : sizeof(dev_req); 19801c099ab4SSean Wang 19811c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); 19821c099ab4SSean Wang } 19831c099ab4SSean Wang 19841c099ab4SSean Wang int 19851c099ab4SSean Wang mt7921_mcu_uni_add_bss(struct mt7921_phy *phy, struct ieee80211_vif *vif, 19861c099ab4SSean Wang bool enable) 19871c099ab4SSean Wang { 19881c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 19891c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 19901c099ab4SSean Wang int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; 19911c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 19921c099ab4SSean Wang enum nl80211_band band = chandef->chan->band; 19931c099ab4SSean Wang u8 omac_idx = mvif->mt76.omac_idx; 19941c099ab4SSean Wang struct { 19951c099ab4SSean Wang struct { 19961c099ab4SSean Wang u8 bss_idx; 19971c099ab4SSean Wang u8 pad[3]; 19981c099ab4SSean Wang } __packed hdr; 19991c099ab4SSean Wang struct mt7921_bss_basic_tlv basic; 20001c099ab4SSean Wang struct mt7921_bss_qos_tlv qos; 20011c099ab4SSean Wang } basic_req = { 20021c099ab4SSean Wang .hdr = { 20031c099ab4SSean Wang .bss_idx = mvif->mt76.idx, 20041c099ab4SSean Wang }, 20051c099ab4SSean Wang .basic = { 20061c099ab4SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), 20071c099ab4SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_bss_basic_tlv)), 20081c099ab4SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 20091c099ab4SSean Wang .dtim_period = vif->bss_conf.dtim_period, 20101c099ab4SSean Wang .omac_idx = omac_idx, 20111c099ab4SSean Wang .band_idx = mvif->mt76.band_idx, 20121c099ab4SSean Wang .wmm_idx = mvif->mt76.wmm_idx, 20131c099ab4SSean Wang .active = true, /* keep bss deactivated */ 20141c099ab4SSean Wang .phymode = mt7921_get_phy_mode(phy->dev, vif, band, NULL), 20151c099ab4SSean Wang }, 20161c099ab4SSean Wang .qos = { 20171c099ab4SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_QBSS), 20181c099ab4SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_bss_qos_tlv)), 20191c099ab4SSean Wang .qos = vif->bss_conf.qos, 20201c099ab4SSean Wang }, 20211c099ab4SSean Wang }; 20221c099ab4SSean Wang 20231c099ab4SSean Wang struct { 20241c099ab4SSean Wang struct { 20251c099ab4SSean Wang u8 bss_idx; 20261c099ab4SSean Wang u8 pad[3]; 20271c099ab4SSean Wang } __packed hdr; 20281c099ab4SSean Wang struct bss_info_uni_he he; 20291c099ab4SSean Wang } he_req = { 20301c099ab4SSean Wang .hdr = { 20311c099ab4SSean Wang .bss_idx = mvif->mt76.idx, 20321c099ab4SSean Wang }, 20331c099ab4SSean Wang .he = { 20341c099ab4SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC), 20351c099ab4SSean Wang .len = cpu_to_le16(sizeof(struct bss_info_uni_he)), 20361c099ab4SSean Wang }, 20371c099ab4SSean Wang }; 20381c099ab4SSean Wang 20391c099ab4SSean Wang struct { 20401c099ab4SSean Wang struct { 20411c099ab4SSean Wang u8 bss_idx; 20421c099ab4SSean Wang u8 pad[3]; 20431c099ab4SSean Wang } __packed hdr; 20441c099ab4SSean Wang struct rlm_tlv { 20451c099ab4SSean Wang __le16 tag; 20461c099ab4SSean Wang __le16 len; 20471c099ab4SSean Wang u8 control_channel; 20481c099ab4SSean Wang u8 center_chan; 20491c099ab4SSean Wang u8 center_chan2; 20501c099ab4SSean Wang u8 bw; 20511c099ab4SSean Wang u8 tx_streams; 20521c099ab4SSean Wang u8 rx_streams; 20531c099ab4SSean Wang u8 short_st; 20541c099ab4SSean Wang u8 ht_op_info; 20551c099ab4SSean Wang u8 sco; 20561c099ab4SSean Wang u8 pad[3]; 20571c099ab4SSean Wang } __packed rlm; 20581c099ab4SSean Wang } __packed rlm_req = { 20591c099ab4SSean Wang .hdr = { 20601c099ab4SSean Wang .bss_idx = mvif->mt76.idx, 20611c099ab4SSean Wang }, 20621c099ab4SSean Wang .rlm = { 20631c099ab4SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_RLM), 20641c099ab4SSean Wang .len = cpu_to_le16(sizeof(struct rlm_tlv)), 20651c099ab4SSean Wang .control_channel = chandef->chan->hw_value, 20661c099ab4SSean Wang .center_chan = ieee80211_frequency_to_channel(freq1), 20671c099ab4SSean Wang .center_chan2 = ieee80211_frequency_to_channel(freq2), 20681c099ab4SSean Wang .tx_streams = hweight8(phy->mt76->antenna_mask), 20691c099ab4SSean Wang .rx_streams = phy->mt76->chainmask, 20701c099ab4SSean Wang .short_st = true, 20711c099ab4SSean Wang }, 20721c099ab4SSean Wang }; 20731c099ab4SSean Wang int err, conn_type; 20741c099ab4SSean Wang u8 idx; 20751c099ab4SSean Wang 20761c099ab4SSean Wang idx = omac_idx > EXT_BSSID_START ? HW_BSSID_0 : omac_idx; 20771c099ab4SSean Wang basic_req.basic.hw_bss_idx = idx; 20781c099ab4SSean Wang 20791c099ab4SSean Wang switch (vif->type) { 20801c099ab4SSean Wang case NL80211_IFTYPE_MESH_POINT: 20811c099ab4SSean Wang case NL80211_IFTYPE_AP: 20821c099ab4SSean Wang if (vif->p2p) 20831c099ab4SSean Wang conn_type = CONNECTION_P2P_GO; 20841c099ab4SSean Wang else 20851c099ab4SSean Wang conn_type = CONNECTION_INFRA_AP; 20861c099ab4SSean Wang basic_req.basic.conn_type = cpu_to_le32(conn_type); 20871c099ab4SSean Wang break; 20881c099ab4SSean Wang case NL80211_IFTYPE_STATION: 20891c099ab4SSean Wang if (vif->p2p) 20901c099ab4SSean Wang conn_type = CONNECTION_P2P_GC; 20911c099ab4SSean Wang else 20921c099ab4SSean Wang conn_type = CONNECTION_INFRA_STA; 20931c099ab4SSean Wang basic_req.basic.conn_type = cpu_to_le32(conn_type); 20941c099ab4SSean Wang break; 20951c099ab4SSean Wang case NL80211_IFTYPE_ADHOC: 20961c099ab4SSean Wang basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); 20971c099ab4SSean Wang break; 20981c099ab4SSean Wang default: 20991c099ab4SSean Wang WARN_ON(1); 21001c099ab4SSean Wang break; 21011c099ab4SSean Wang } 21021c099ab4SSean Wang 21031c099ab4SSean Wang memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); 21041c099ab4SSean Wang basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx); 21051c099ab4SSean Wang basic_req.basic.sta_idx = cpu_to_le16(mvif->sta.wcid.idx); 21061c099ab4SSean Wang basic_req.basic.conn_state = !enable; 21071c099ab4SSean Wang 21081c099ab4SSean Wang err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 21091c099ab4SSean Wang &basic_req, sizeof(basic_req), true); 21101c099ab4SSean Wang if (err < 0) 21111c099ab4SSean Wang return err; 21121c099ab4SSean Wang 21131c099ab4SSean Wang if (vif->bss_conf.he_support) { 21141c099ab4SSean Wang mt7921_mcu_uni_bss_he_tlv((struct tlv *)&he_req.he, vif, phy); 21151c099ab4SSean Wang 21161c099ab4SSean Wang err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 21171c099ab4SSean Wang &he_req, sizeof(he_req), true); 21181c099ab4SSean Wang if (err < 0) 21191c099ab4SSean Wang return err; 21201c099ab4SSean Wang } 21211c099ab4SSean Wang 21221c099ab4SSean Wang switch (chandef->width) { 21231c099ab4SSean Wang case NL80211_CHAN_WIDTH_40: 21241c099ab4SSean Wang rlm_req.rlm.bw = CMD_CBW_40MHZ; 21251c099ab4SSean Wang break; 21261c099ab4SSean Wang case NL80211_CHAN_WIDTH_80: 21271c099ab4SSean Wang rlm_req.rlm.bw = CMD_CBW_80MHZ; 21281c099ab4SSean Wang break; 21291c099ab4SSean Wang case NL80211_CHAN_WIDTH_80P80: 21301c099ab4SSean Wang rlm_req.rlm.bw = CMD_CBW_8080MHZ; 21311c099ab4SSean Wang break; 21321c099ab4SSean Wang case NL80211_CHAN_WIDTH_160: 21331c099ab4SSean Wang rlm_req.rlm.bw = CMD_CBW_160MHZ; 21341c099ab4SSean Wang break; 21351c099ab4SSean Wang case NL80211_CHAN_WIDTH_5: 21361c099ab4SSean Wang rlm_req.rlm.bw = CMD_CBW_5MHZ; 21371c099ab4SSean Wang break; 21381c099ab4SSean Wang case NL80211_CHAN_WIDTH_10: 21391c099ab4SSean Wang rlm_req.rlm.bw = CMD_CBW_10MHZ; 21401c099ab4SSean Wang break; 21411c099ab4SSean Wang case NL80211_CHAN_WIDTH_20_NOHT: 21421c099ab4SSean Wang case NL80211_CHAN_WIDTH_20: 21431c099ab4SSean Wang default: 21441c099ab4SSean Wang rlm_req.rlm.bw = CMD_CBW_20MHZ; 21451c099ab4SSean Wang break; 21461c099ab4SSean Wang } 21471c099ab4SSean Wang 21481c099ab4SSean Wang if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan) 21491c099ab4SSean Wang rlm_req.rlm.sco = 1; /* SCA */ 21501c099ab4SSean Wang else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan) 21511c099ab4SSean Wang rlm_req.rlm.sco = 3; /* SCB */ 21521c099ab4SSean Wang 21531c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 21541c099ab4SSean Wang &rlm_req, sizeof(rlm_req), true); 21551c099ab4SSean Wang } 21561c099ab4SSean Wang 21571c099ab4SSean Wang static int 21581c099ab4SSean Wang mt7921_mcu_add_sta_cmd(struct mt7921_dev *dev, struct ieee80211_vif *vif, 21591c099ab4SSean Wang struct ieee80211_sta *sta, bool enable, int cmd) 21601c099ab4SSean Wang { 21611c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 21621c099ab4SSean Wang struct wtbl_req_hdr *wtbl_hdr; 21631c099ab4SSean Wang struct mt7921_sta *msta; 21641c099ab4SSean Wang struct tlv *sta_wtbl; 21651c099ab4SSean Wang struct sk_buff *skb; 21661c099ab4SSean Wang 21671c099ab4SSean Wang msta = sta ? (struct mt7921_sta *)sta->drv_priv : &mvif->sta; 21681c099ab4SSean Wang 21691c099ab4SSean Wang skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta, 21701c099ab4SSean Wang MT7921_STA_UPDATE_MAX_SIZE); 21711c099ab4SSean Wang if (IS_ERR(skb)) 21721c099ab4SSean Wang return PTR_ERR(skb); 21731c099ab4SSean Wang 21741c099ab4SSean Wang mt7921_mcu_sta_basic_tlv(skb, vif, sta, enable); 21751c099ab4SSean Wang if (enable && sta) 21761c099ab4SSean Wang mt7921_mcu_sta_tlv(dev, skb, sta, vif); 21771c099ab4SSean Wang 21781c099ab4SSean Wang sta_wtbl = mt7921_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 21791c099ab4SSean Wang 21801c099ab4SSean Wang wtbl_hdr = mt7921_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, 21811c099ab4SSean Wang sta_wtbl, &skb); 21821c099ab4SSean Wang if (enable) { 21831c099ab4SSean Wang mt7921_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); 21841c099ab4SSean Wang if (sta) 21851c099ab4SSean Wang mt7921_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); 21861c099ab4SSean Wang } 21871c099ab4SSean Wang 21881c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); 21891c099ab4SSean Wang } 21901c099ab4SSean Wang 21911c099ab4SSean Wang int 21921c099ab4SSean Wang mt7921_mcu_uni_add_sta(struct mt7921_dev *dev, struct ieee80211_vif *vif, 21931c099ab4SSean Wang struct ieee80211_sta *sta, bool enable) 21941c099ab4SSean Wang { 21951c099ab4SSean Wang return mt7921_mcu_add_sta_cmd(dev, vif, sta, enable, 21961c099ab4SSean Wang MCU_UNI_CMD_STA_REC_UPDATE); 21971c099ab4SSean Wang } 21981c099ab4SSean Wang 21991c099ab4SSean Wang int mt7921_mcu_set_channel_domain(struct mt7921_phy *phy) 22001c099ab4SSean Wang { 22011c099ab4SSean Wang struct mt76_phy *mphy = phy->mt76; 22021c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 22031c099ab4SSean Wang struct mt7921_mcu_channel_domain { 22041c099ab4SSean Wang __le32 country_code; /* regulatory_request.alpha2 */ 22051c099ab4SSean Wang u8 bw_2g; /* BW_20_40M 0 22061c099ab4SSean Wang * BW_20M 1 22071c099ab4SSean Wang * BW_20_40_80M 2 22081c099ab4SSean Wang * BW_20_40_80_160M 3 22091c099ab4SSean Wang * BW_20_40_80_8080M 4 22101c099ab4SSean Wang */ 22111c099ab4SSean Wang u8 bw_5g; 22121c099ab4SSean Wang __le16 pad; 22131c099ab4SSean Wang u8 n_2ch; 22141c099ab4SSean Wang u8 n_5ch; 22151c099ab4SSean Wang __le16 pad2; 22161c099ab4SSean Wang } __packed hdr = { 22171c099ab4SSean Wang .bw_2g = 0, 22181c099ab4SSean Wang .bw_5g = 3, 22191c099ab4SSean Wang .n_2ch = mphy->sband_2g.sband.n_channels, 22201c099ab4SSean Wang .n_5ch = mphy->sband_5g.sband.n_channels, 22211c099ab4SSean Wang }; 22221c099ab4SSean Wang struct mt7921_mcu_chan { 22231c099ab4SSean Wang __le16 hw_value; 22241c099ab4SSean Wang __le16 pad; 22251c099ab4SSean Wang __le32 flags; 22261c099ab4SSean Wang } __packed; 22271c099ab4SSean Wang int i, n_channels = hdr.n_2ch + hdr.n_5ch; 22281c099ab4SSean Wang int len = sizeof(hdr) + n_channels * sizeof(struct mt7921_mcu_chan); 22291c099ab4SSean Wang struct sk_buff *skb; 22301c099ab4SSean Wang 22311c099ab4SSean Wang skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); 22321c099ab4SSean Wang if (!skb) 22331c099ab4SSean Wang return -ENOMEM; 22341c099ab4SSean Wang 22351c099ab4SSean Wang skb_put_data(skb, &hdr, sizeof(hdr)); 22361c099ab4SSean Wang 22371c099ab4SSean Wang for (i = 0; i < n_channels; i++) { 22381c099ab4SSean Wang struct ieee80211_channel *chan; 22391c099ab4SSean Wang struct mt7921_mcu_chan channel; 22401c099ab4SSean Wang 22411c099ab4SSean Wang if (i < hdr.n_2ch) 22421c099ab4SSean Wang chan = &mphy->sband_2g.sband.channels[i]; 22431c099ab4SSean Wang else 22441c099ab4SSean Wang chan = &mphy->sband_5g.sband.channels[i - hdr.n_2ch]; 22451c099ab4SSean Wang 22461c099ab4SSean Wang channel.hw_value = cpu_to_le16(chan->hw_value); 22471c099ab4SSean Wang channel.flags = cpu_to_le32(chan->flags); 22481c099ab4SSean Wang channel.pad = 0; 22491c099ab4SSean Wang 22501c099ab4SSean Wang skb_put_data(skb, &channel, sizeof(channel)); 22511c099ab4SSean Wang } 22521c099ab4SSean Wang 22531c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SET_CHAN_DOMAIN, 22541c099ab4SSean Wang false); 22551c099ab4SSean Wang } 22561c099ab4SSean Wang 22571c099ab4SSean Wang #define MT7921_SCAN_CHANNEL_TIME 60 22581c099ab4SSean Wang int mt7921_mcu_hw_scan(struct mt7921_phy *phy, struct ieee80211_vif *vif, 22591c099ab4SSean Wang struct ieee80211_scan_request *scan_req) 22601c099ab4SSean Wang { 22611c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 22621c099ab4SSean Wang struct cfg80211_scan_request *sreq = &scan_req->req; 22631c099ab4SSean Wang int n_ssids = 0, err, i, duration = MT7921_SCAN_CHANNEL_TIME; 22641c099ab4SSean Wang int ext_channels_num = max_t(int, sreq->n_channels - 32, 0); 22651c099ab4SSean Wang struct ieee80211_channel **scan_list = sreq->channels; 22661c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 22671c099ab4SSean Wang struct mt7921_mcu_scan_channel *chan; 22681c099ab4SSean Wang struct mt7921_hw_scan_req *req; 22691c099ab4SSean Wang struct sk_buff *skb; 22701c099ab4SSean Wang 22711c099ab4SSean Wang skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(*req)); 22721c099ab4SSean Wang if (!skb) 22731c099ab4SSean Wang return -ENOMEM; 22741c099ab4SSean Wang 22751c099ab4SSean Wang set_bit(MT76_HW_SCANNING, &phy->mt76->state); 22761c099ab4SSean Wang mvif->mt76.scan_seq_num = (mvif->mt76.scan_seq_num + 1) & 0x7f; 22771c099ab4SSean Wang 22781c099ab4SSean Wang req = (struct mt7921_hw_scan_req *)skb_put(skb, sizeof(*req)); 22791c099ab4SSean Wang 22801c099ab4SSean Wang req->seq_num = mvif->mt76.scan_seq_num; 22811c099ab4SSean Wang req->bss_idx = mvif->mt76.idx; 22821c099ab4SSean Wang req->scan_type = sreq->n_ssids ? 1 : 0; 22831c099ab4SSean Wang req->probe_req_num = sreq->n_ssids ? 2 : 0; 22841c099ab4SSean Wang req->version = 1; 22851c099ab4SSean Wang 22861c099ab4SSean Wang for (i = 0; i < sreq->n_ssids; i++) { 22871c099ab4SSean Wang if (!sreq->ssids[i].ssid_len) 22881c099ab4SSean Wang continue; 22891c099ab4SSean Wang 22901c099ab4SSean Wang req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); 22911c099ab4SSean Wang memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, 22921c099ab4SSean Wang sreq->ssids[i].ssid_len); 22931c099ab4SSean Wang n_ssids++; 22941c099ab4SSean Wang } 22951c099ab4SSean Wang req->ssid_type = n_ssids ? BIT(2) : BIT(0); 22961c099ab4SSean Wang req->ssid_type_ext = n_ssids ? BIT(0) : 0; 22971c099ab4SSean Wang req->ssids_num = n_ssids; 22981c099ab4SSean Wang 22991c099ab4SSean Wang /* increase channel time for passive scan */ 23001c099ab4SSean Wang if (!sreq->n_ssids) 23011c099ab4SSean Wang duration *= 2; 23021c099ab4SSean Wang req->timeout_value = cpu_to_le16(sreq->n_channels * duration); 23031c099ab4SSean Wang req->channel_min_dwell_time = cpu_to_le16(duration); 23041c099ab4SSean Wang req->channel_dwell_time = cpu_to_le16(duration); 23051c099ab4SSean Wang 23061c099ab4SSean Wang req->channels_num = min_t(u8, sreq->n_channels, 32); 23071c099ab4SSean Wang req->ext_channels_num = min_t(u8, ext_channels_num, 32); 23081c099ab4SSean Wang for (i = 0; i < req->channels_num + req->ext_channels_num; i++) { 23091c099ab4SSean Wang if (i >= 32) 23101c099ab4SSean Wang chan = &req->ext_channels[i - 32]; 23111c099ab4SSean Wang else 23121c099ab4SSean Wang chan = &req->channels[i]; 23131c099ab4SSean Wang 23141c099ab4SSean Wang chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; 23151c099ab4SSean Wang chan->channel_num = scan_list[i]->hw_value; 23161c099ab4SSean Wang } 23171c099ab4SSean Wang req->channel_type = sreq->n_channels ? 4 : 0; 23181c099ab4SSean Wang 23191c099ab4SSean Wang if (sreq->ie_len > 0) { 23201c099ab4SSean Wang memcpy(req->ies, sreq->ie, sreq->ie_len); 23211c099ab4SSean Wang req->ies_len = cpu_to_le16(sreq->ie_len); 23221c099ab4SSean Wang } 23231c099ab4SSean Wang 23241c099ab4SSean Wang memcpy(req->bssid, sreq->bssid, ETH_ALEN); 23251c099ab4SSean Wang if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { 23261c099ab4SSean Wang get_random_mask_addr(req->random_mac, sreq->mac_addr, 23271c099ab4SSean Wang sreq->mac_addr_mask); 23281c099ab4SSean Wang req->scan_func = 1; 23291c099ab4SSean Wang } 23301c099ab4SSean Wang 23311c099ab4SSean Wang err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_START_HW_SCAN, 23321c099ab4SSean Wang false); 23331c099ab4SSean Wang if (err < 0) 23341c099ab4SSean Wang clear_bit(MT76_HW_SCANNING, &phy->mt76->state); 23351c099ab4SSean Wang 23361c099ab4SSean Wang return err; 23371c099ab4SSean Wang } 23381c099ab4SSean Wang 23391c099ab4SSean Wang int mt7921_mcu_cancel_hw_scan(struct mt7921_phy *phy, 23401c099ab4SSean Wang struct ieee80211_vif *vif) 23411c099ab4SSean Wang { 23421c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 23431c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 23441c099ab4SSean Wang struct { 23451c099ab4SSean Wang u8 seq_num; 23461c099ab4SSean Wang u8 is_ext_channel; 23471c099ab4SSean Wang u8 rsv[2]; 23481c099ab4SSean Wang } __packed req = { 23491c099ab4SSean Wang .seq_num = mvif->mt76.scan_seq_num, 23501c099ab4SSean Wang }; 23511c099ab4SSean Wang 23521c099ab4SSean Wang if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) { 23531c099ab4SSean Wang struct cfg80211_scan_info info = { 23541c099ab4SSean Wang .aborted = true, 23551c099ab4SSean Wang }; 23561c099ab4SSean Wang 23571c099ab4SSean Wang ieee80211_scan_completed(phy->mt76->hw, &info); 23581c099ab4SSean Wang } 23591c099ab4SSean Wang 23601c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req, 23611c099ab4SSean Wang sizeof(req), false); 23621c099ab4SSean Wang } 23631c099ab4SSean Wang 236429f9d8b0SSean Wang int mt7921_mcu_sched_scan_req(struct mt7921_phy *phy, 236529f9d8b0SSean Wang struct ieee80211_vif *vif, 236629f9d8b0SSean Wang struct cfg80211_sched_scan_request *sreq) 236729f9d8b0SSean Wang { 236829f9d8b0SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 236929f9d8b0SSean Wang struct ieee80211_channel **scan_list = sreq->channels; 237029f9d8b0SSean Wang struct mt7921_dev *dev = phy->dev; 237129f9d8b0SSean Wang struct mt7921_mcu_scan_channel *chan; 237229f9d8b0SSean Wang struct mt7921_sched_scan_req *req; 237329f9d8b0SSean Wang struct cfg80211_match_set *match; 237429f9d8b0SSean Wang struct cfg80211_ssid *ssid; 237529f9d8b0SSean Wang struct sk_buff *skb; 237629f9d8b0SSean Wang int i; 237729f9d8b0SSean Wang 237829f9d8b0SSean Wang skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 237929f9d8b0SSean Wang sizeof(*req) + sreq->ie_len); 238029f9d8b0SSean Wang if (!skb) 238129f9d8b0SSean Wang return -ENOMEM; 238229f9d8b0SSean Wang 238329f9d8b0SSean Wang mvif->mt76.scan_seq_num = (mvif->mt76.scan_seq_num + 1) & 0x7f; 238429f9d8b0SSean Wang 238529f9d8b0SSean Wang req = (struct mt7921_sched_scan_req *)skb_put(skb, sizeof(*req)); 238629f9d8b0SSean Wang req->version = 1; 238729f9d8b0SSean Wang req->seq_num = mvif->mt76.scan_seq_num; 238829f9d8b0SSean Wang 238929f9d8b0SSean Wang req->ssids_num = sreq->n_ssids; 239029f9d8b0SSean Wang for (i = 0; i < req->ssids_num; i++) { 239129f9d8b0SSean Wang ssid = &sreq->ssids[i]; 239229f9d8b0SSean Wang memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len); 239329f9d8b0SSean Wang req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len); 239429f9d8b0SSean Wang } 239529f9d8b0SSean Wang 239629f9d8b0SSean Wang req->match_num = sreq->n_match_sets; 239729f9d8b0SSean Wang for (i = 0; i < req->match_num; i++) { 239829f9d8b0SSean Wang match = &sreq->match_sets[i]; 239929f9d8b0SSean Wang memcpy(req->match[i].ssid, match->ssid.ssid, 240029f9d8b0SSean Wang match->ssid.ssid_len); 240129f9d8b0SSean Wang req->match[i].rssi_th = cpu_to_le32(match->rssi_thold); 240229f9d8b0SSean Wang req->match[i].ssid_len = match->ssid.ssid_len; 240329f9d8b0SSean Wang } 240429f9d8b0SSean Wang 240529f9d8b0SSean Wang req->channel_type = sreq->n_channels ? 4 : 0; 240629f9d8b0SSean Wang req->channels_num = min_t(u8, sreq->n_channels, 64); 240729f9d8b0SSean Wang for (i = 0; i < req->channels_num; i++) { 240829f9d8b0SSean Wang chan = &req->channels[i]; 240929f9d8b0SSean Wang chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; 241029f9d8b0SSean Wang chan->channel_num = scan_list[i]->hw_value; 241129f9d8b0SSean Wang } 241229f9d8b0SSean Wang 241329f9d8b0SSean Wang req->intervals_num = sreq->n_scan_plans; 241429f9d8b0SSean Wang for (i = 0; i < req->intervals_num; i++) 241529f9d8b0SSean Wang req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval); 241629f9d8b0SSean Wang 241729f9d8b0SSean Wang if (sreq->ie_len > 0) { 241829f9d8b0SSean Wang req->ie_len = cpu_to_le16(sreq->ie_len); 241929f9d8b0SSean Wang memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len); 242029f9d8b0SSean Wang } 242129f9d8b0SSean Wang 242229f9d8b0SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SCHED_SCAN_REQ, 242329f9d8b0SSean Wang false); 242429f9d8b0SSean Wang } 242529f9d8b0SSean Wang 242629f9d8b0SSean Wang int mt7921_mcu_sched_scan_enable(struct mt7921_phy *phy, 242729f9d8b0SSean Wang struct ieee80211_vif *vif, 242829f9d8b0SSean Wang bool enable) 242929f9d8b0SSean Wang { 243029f9d8b0SSean Wang struct mt7921_dev *dev = phy->dev; 243129f9d8b0SSean Wang struct { 243229f9d8b0SSean Wang u8 active; /* 0: enabled 1: disabled */ 243329f9d8b0SSean Wang u8 rsv[3]; 243429f9d8b0SSean Wang } __packed req = { 243529f9d8b0SSean Wang .active = !enable, 243629f9d8b0SSean Wang }; 243729f9d8b0SSean Wang 243829f9d8b0SSean Wang if (enable) 243929f9d8b0SSean Wang set_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); 244029f9d8b0SSean Wang else 244129f9d8b0SSean Wang clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); 244229f9d8b0SSean Wang 244329f9d8b0SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, &req, 244429f9d8b0SSean Wang sizeof(req), false); 244529f9d8b0SSean Wang } 244629f9d8b0SSean Wang 24471c099ab4SSean Wang u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u16 wlan_idx) 24481c099ab4SSean Wang { 24491c099ab4SSean Wang struct mt7921_mcu_wlan_info wtbl_info = { 24501c099ab4SSean Wang .wlan_idx = cpu_to_le32(wlan_idx), 24511c099ab4SSean Wang }; 24521c099ab4SSean Wang struct sk_buff *skb; 24531c099ab4SSean Wang int ret; 24541c099ab4SSean Wang 24551c099ab4SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_WTBL, 24561c099ab4SSean Wang &wtbl_info, sizeof(wtbl_info), true, 24571c099ab4SSean Wang &skb); 24581c099ab4SSean Wang if (ret) 24591c099ab4SSean Wang return ret; 24601c099ab4SSean Wang 24611c099ab4SSean Wang mt7921_mcu_tx_rate_report(dev, skb, wlan_idx); 24621c099ab4SSean Wang dev_kfree_skb(skb); 24631c099ab4SSean Wang 24641c099ab4SSean Wang return 0; 24651c099ab4SSean Wang } 246656d965daSSean Wang 246756d965daSSean Wang int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) 246856d965daSSean Wang { 246956d965daSSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 247056d965daSSean Wang struct { 247156d965daSSean Wang struct { 247256d965daSSean Wang u8 bss_idx; 247356d965daSSean Wang u8 pad[3]; 247456d965daSSean Wang } __packed hdr; 247556d965daSSean Wang struct ps_tlv { 247656d965daSSean Wang __le16 tag; 247756d965daSSean Wang __le16 len; 247856d965daSSean Wang u8 ps_state; /* 0: device awake 247956d965daSSean Wang * 1: static power save 248056d965daSSean Wang * 2: dynamic power saving 248156d965daSSean Wang * 3: enter TWT power saving 248256d965daSSean Wang * 4: leave TWT power saving 248356d965daSSean Wang */ 248456d965daSSean Wang u8 pad[3]; 248556d965daSSean Wang } __packed ps; 248656d965daSSean Wang } __packed ps_req = { 248756d965daSSean Wang .hdr = { 248856d965daSSean Wang .bss_idx = mvif->mt76.idx, 248956d965daSSean Wang }, 249056d965daSSean Wang .ps = { 249156d965daSSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_PS), 249256d965daSSean Wang .len = cpu_to_le16(sizeof(struct ps_tlv)), 249356d965daSSean Wang .ps_state = vif->bss_conf.ps ? 2 : 0, 249456d965daSSean Wang }, 249556d965daSSean Wang }; 249656d965daSSean Wang 249756d965daSSean Wang if (vif->type != NL80211_IFTYPE_STATION) 249856d965daSSean Wang return -EOPNOTSUPP; 249956d965daSSean Wang 250056d965daSSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 250156d965daSSean Wang &ps_req, sizeof(ps_req), true); 250256d965daSSean Wang } 2503*4086ee28SSean Wang 2504*4086ee28SSean Wang int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, 2505*4086ee28SSean Wang bool enable) 2506*4086ee28SSean Wang { 2507*4086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 2508*4086ee28SSean Wang struct { 2509*4086ee28SSean Wang struct { 2510*4086ee28SSean Wang u8 bss_idx; 2511*4086ee28SSean Wang u8 pad[3]; 2512*4086ee28SSean Wang } __packed hdr; 2513*4086ee28SSean Wang struct bcnft_tlv { 2514*4086ee28SSean Wang __le16 tag; 2515*4086ee28SSean Wang __le16 len; 2516*4086ee28SSean Wang __le16 bcn_interval; 2517*4086ee28SSean Wang u8 dtim_period; 2518*4086ee28SSean Wang u8 pad; 2519*4086ee28SSean Wang } __packed bcnft; 2520*4086ee28SSean Wang } __packed bcnft_req = { 2521*4086ee28SSean Wang .hdr = { 2522*4086ee28SSean Wang .bss_idx = mvif->mt76.idx, 2523*4086ee28SSean Wang }, 2524*4086ee28SSean Wang .bcnft = { 2525*4086ee28SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), 2526*4086ee28SSean Wang .len = cpu_to_le16(sizeof(struct bcnft_tlv)), 2527*4086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 2528*4086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 2529*4086ee28SSean Wang }, 2530*4086ee28SSean Wang }; 2531*4086ee28SSean Wang 2532*4086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 2533*4086ee28SSean Wang return 0; 2534*4086ee28SSean Wang 2535*4086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 2536*4086ee28SSean Wang &bcnft_req, sizeof(bcnft_req), true); 2537*4086ee28SSean Wang } 2538*4086ee28SSean Wang 2539*4086ee28SSean Wang int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, 2540*4086ee28SSean Wang bool enable) 2541*4086ee28SSean Wang { 2542*4086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 2543*4086ee28SSean Wang struct { 2544*4086ee28SSean Wang u8 bss_idx; 2545*4086ee28SSean Wang u8 dtim_period; 2546*4086ee28SSean Wang __le16 aid; 2547*4086ee28SSean Wang __le16 bcn_interval; 2548*4086ee28SSean Wang __le16 atim_window; 2549*4086ee28SSean Wang u8 uapsd; 2550*4086ee28SSean Wang u8 bmc_delivered_ac; 2551*4086ee28SSean Wang u8 bmc_triggered_ac; 2552*4086ee28SSean Wang u8 pad; 2553*4086ee28SSean Wang } req = { 2554*4086ee28SSean Wang .bss_idx = mvif->mt76.idx, 2555*4086ee28SSean Wang .aid = cpu_to_le16(vif->bss_conf.aid), 2556*4086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 2557*4086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 2558*4086ee28SSean Wang }; 2559*4086ee28SSean Wang struct { 2560*4086ee28SSean Wang u8 bss_idx; 2561*4086ee28SSean Wang u8 pad[3]; 2562*4086ee28SSean Wang } req_hdr = { 2563*4086ee28SSean Wang .bss_idx = mvif->mt76.idx, 2564*4086ee28SSean Wang }; 2565*4086ee28SSean Wang int err; 2566*4086ee28SSean Wang 2567*4086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 2568*4086ee28SSean Wang return 0; 2569*4086ee28SSean Wang 2570*4086ee28SSean Wang err = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, &req_hdr, 2571*4086ee28SSean Wang sizeof(req_hdr), false); 2572*4086ee28SSean Wang if (err < 0 || !enable) 2573*4086ee28SSean Wang return err; 2574*4086ee28SSean Wang 2575*4086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, &req, 2576*4086ee28SSean Wang sizeof(req), false); 2577*4086ee28SSean Wang } 2578