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" 72afd17b4SLorenzo Bianconi #include "mt7921_trace.h" 81c099ab4SSean Wang #include "mcu.h" 91c099ab4SSean Wang #include "mac.h" 101c099ab4SSean Wang 111c099ab4SSean Wang struct mt7921_patch_hdr { 121c099ab4SSean Wang char build_date[16]; 131c099ab4SSean Wang char platform[4]; 141c099ab4SSean Wang __be32 hw_sw_ver; 151c099ab4SSean Wang __be32 patch_ver; 161c099ab4SSean Wang __be16 checksum; 171c099ab4SSean Wang u16 reserved; 181c099ab4SSean Wang struct { 191c099ab4SSean Wang __be32 patch_ver; 201c099ab4SSean Wang __be32 subsys; 211c099ab4SSean Wang __be32 feature; 221c099ab4SSean Wang __be32 n_region; 231c099ab4SSean Wang __be32 crc; 241c099ab4SSean Wang u32 reserved[11]; 251c099ab4SSean Wang } desc; 261c099ab4SSean Wang } __packed; 271c099ab4SSean Wang 281c099ab4SSean Wang struct mt7921_patch_sec { 291c099ab4SSean Wang __be32 type; 301c099ab4SSean Wang __be32 offs; 311c099ab4SSean Wang __be32 size; 321c099ab4SSean Wang union { 331c099ab4SSean Wang __be32 spec[13]; 341c099ab4SSean Wang struct { 351c099ab4SSean Wang __be32 addr; 361c099ab4SSean Wang __be32 len; 371c099ab4SSean Wang __be32 sec_key_idx; 381c099ab4SSean Wang __be32 align_len; 391c099ab4SSean Wang u32 reserved[9]; 401c099ab4SSean Wang } info; 411c099ab4SSean Wang }; 421c099ab4SSean Wang } __packed; 431c099ab4SSean Wang 441c099ab4SSean Wang struct mt7921_fw_trailer { 451c099ab4SSean Wang u8 chip_id; 461c099ab4SSean Wang u8 eco_code; 471c099ab4SSean Wang u8 n_region; 481c099ab4SSean Wang u8 format_ver; 491c099ab4SSean Wang u8 format_flag; 501c099ab4SSean Wang u8 reserved[2]; 511c099ab4SSean Wang char fw_ver[10]; 521c099ab4SSean Wang char build_date[15]; 531c099ab4SSean Wang u32 crc; 541c099ab4SSean Wang } __packed; 551c099ab4SSean Wang 561c099ab4SSean Wang struct mt7921_fw_region { 571c099ab4SSean Wang __le32 decomp_crc; 581c099ab4SSean Wang __le32 decomp_len; 591c099ab4SSean Wang __le32 decomp_blk_sz; 601c099ab4SSean Wang u8 reserved[4]; 611c099ab4SSean Wang __le32 addr; 621c099ab4SSean Wang __le32 len; 631c099ab4SSean Wang u8 feature_set; 641c099ab4SSean Wang u8 reserved1[15]; 651c099ab4SSean Wang } __packed; 661c099ab4SSean Wang 671c099ab4SSean Wang #define MT_STA_BFER BIT(0) 681c099ab4SSean Wang #define MT_STA_BFEE BIT(1) 691c099ab4SSean Wang 701c099ab4SSean Wang #define FW_FEATURE_SET_ENCRYPT BIT(0) 711c099ab4SSean Wang #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) 721c099ab4SSean Wang #define FW_FEATURE_ENCRY_MODE BIT(4) 731c099ab4SSean Wang #define FW_FEATURE_OVERRIDE_ADDR BIT(5) 741c099ab4SSean Wang 751c099ab4SSean Wang #define DL_MODE_ENCRYPT BIT(0) 761c099ab4SSean Wang #define DL_MODE_KEY_IDX GENMASK(2, 1) 771c099ab4SSean Wang #define DL_MODE_RESET_SEC_IV BIT(3) 781c099ab4SSean Wang #define DL_MODE_WORKING_PDA_CR4 BIT(4) 791c099ab4SSean Wang #define DL_CONFIG_ENCRY_MODE_SEL BIT(6) 801c099ab4SSean Wang #define DL_MODE_NEED_RSP BIT(31) 811c099ab4SSean Wang 821c099ab4SSean Wang #define FW_START_OVERRIDE BIT(0) 831c099ab4SSean Wang #define FW_START_WORKING_PDA_CR4 BIT(2) 841c099ab4SSean Wang 851c099ab4SSean Wang #define PATCH_SEC_TYPE_MASK GENMASK(15, 0) 861c099ab4SSean Wang #define PATCH_SEC_TYPE_INFO 0x2 871c099ab4SSean Wang 881c099ab4SSean Wang #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) 891c099ab4SSean Wang #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) 901c099ab4SSean Wang 911c099ab4SSean Wang static enum mt7921_cipher_type 921c099ab4SSean Wang mt7921_mcu_get_cipher(int cipher) 931c099ab4SSean Wang { 941c099ab4SSean Wang switch (cipher) { 951c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP40: 961c099ab4SSean Wang return MT_CIPHER_WEP40; 971c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP104: 981c099ab4SSean Wang return MT_CIPHER_WEP104; 991c099ab4SSean Wang case WLAN_CIPHER_SUITE_TKIP: 1001c099ab4SSean Wang return MT_CIPHER_TKIP; 1011c099ab4SSean Wang case WLAN_CIPHER_SUITE_AES_CMAC: 1021c099ab4SSean Wang return MT_CIPHER_BIP_CMAC_128; 1031c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP: 1041c099ab4SSean Wang return MT_CIPHER_AES_CCMP; 1051c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP_256: 1061c099ab4SSean Wang return MT_CIPHER_CCMP_256; 1071c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP: 1081c099ab4SSean Wang return MT_CIPHER_GCMP; 1091c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP_256: 1101c099ab4SSean Wang return MT_CIPHER_GCMP_256; 1111c099ab4SSean Wang case WLAN_CIPHER_SUITE_SMS4: 1121c099ab4SSean Wang return MT_CIPHER_WAPI; 1131c099ab4SSean Wang default: 1141c099ab4SSean Wang return MT_CIPHER_NONE; 1151c099ab4SSean Wang } 1161c099ab4SSean Wang } 1171c099ab4SSean Wang 1181c099ab4SSean Wang static u8 mt7921_mcu_chan_bw(struct cfg80211_chan_def *chandef) 1191c099ab4SSean Wang { 1201c099ab4SSean Wang static const u8 width_to_bw[] = { 1211c099ab4SSean Wang [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, 1221c099ab4SSean Wang [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, 1231c099ab4SSean Wang [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, 1241c099ab4SSean Wang [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, 1251c099ab4SSean Wang [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, 1261c099ab4SSean Wang [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, 1271c099ab4SSean Wang [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, 1281c099ab4SSean Wang [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, 1291c099ab4SSean Wang }; 1301c099ab4SSean Wang 1311c099ab4SSean Wang if (chandef->width >= ARRAY_SIZE(width_to_bw)) 1321c099ab4SSean Wang return 0; 1331c099ab4SSean Wang 1341c099ab4SSean Wang return width_to_bw[chandef->width]; 1351c099ab4SSean Wang } 1361c099ab4SSean Wang 1371c099ab4SSean Wang static int 1381c099ab4SSean Wang mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) 1391c099ab4SSean Wang { 1401c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 1411c099ab4SSean Wang u8 *buf; 1421c099ab4SSean Wang 1431c099ab4SSean Wang if (!skb) 1441c099ab4SSean Wang return -EINVAL; 1451c099ab4SSean Wang 1461c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 1471c099ab4SSean Wang 1481c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 1491c099ab4SSean Wang buf = dev->eeprom.data + le32_to_cpu(res->addr); 1501c099ab4SSean Wang memcpy(buf, res->data, 16); 1511c099ab4SSean Wang 1521c099ab4SSean Wang return 0; 1531c099ab4SSean Wang } 1541c099ab4SSean Wang 1551c099ab4SSean Wang static int 1561c099ab4SSean Wang mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, 1571c099ab4SSean Wang struct sk_buff *skb, int seq) 1581c099ab4SSean Wang { 1591c099ab4SSean Wang struct mt7921_mcu_rxd *rxd; 1601c099ab4SSean Wang int ret = 0; 1611c099ab4SSean Wang 1621c099ab4SSean Wang if (!skb) { 16353d35b1aSLorenzo Bianconi dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", 1641c099ab4SSean Wang cmd, seq); 165d43b3257SLorenzo Bianconi mt7921_reset(mdev); 166d43b3257SLorenzo Bianconi 1671c099ab4SSean Wang return -ETIMEDOUT; 1681c099ab4SSean Wang } 1691c099ab4SSean Wang 1701c099ab4SSean Wang rxd = (struct mt7921_mcu_rxd *)skb->data; 1711c099ab4SSean Wang if (seq != rxd->seq) 1721c099ab4SSean Wang return -EAGAIN; 1731c099ab4SSean Wang 1741c099ab4SSean Wang switch (cmd) { 1751c099ab4SSean Wang case MCU_CMD_PATCH_SEM_CONTROL: 1761c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) - 4); 1771c099ab4SSean Wang ret = *skb->data; 1781c099ab4SSean Wang break; 17967aa2743SLorenzo Bianconi case MCU_EXT_CMD_GET_TEMP: 1801c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) + 4); 1811c099ab4SSean Wang ret = le32_to_cpu(*(__le32 *)skb->data); 1821c099ab4SSean Wang break; 1831c099ab4SSean Wang case MCU_EXT_CMD_EFUSE_ACCESS: 1841c099ab4SSean Wang ret = mt7921_mcu_parse_eeprom(mdev, skb); 1851c099ab4SSean Wang break; 1861c099ab4SSean Wang case MCU_UNI_CMD_DEV_INFO_UPDATE: 1871c099ab4SSean Wang case MCU_UNI_CMD_BSS_INFO_UPDATE: 1881c099ab4SSean Wang case MCU_UNI_CMD_STA_REC_UPDATE: 1891c099ab4SSean Wang case MCU_UNI_CMD_HIF_CTRL: 1901c099ab4SSean Wang case MCU_UNI_CMD_OFFLOAD: 1911c099ab4SSean Wang case MCU_UNI_CMD_SUSPEND: { 1921c099ab4SSean Wang struct mt7921_mcu_uni_event *event; 1931c099ab4SSean Wang 1941c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 1951c099ab4SSean Wang event = (struct mt7921_mcu_uni_event *)skb->data; 1961c099ab4SSean Wang ret = le32_to_cpu(event->status); 1971c099ab4SSean Wang break; 1981c099ab4SSean Wang } 1991c099ab4SSean Wang case MCU_CMD_REG_READ: { 2001c099ab4SSean Wang struct mt7921_mcu_reg_event *event; 2011c099ab4SSean Wang 2021c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 2031c099ab4SSean Wang event = (struct mt7921_mcu_reg_event *)skb->data; 2041c099ab4SSean Wang ret = (int)le32_to_cpu(event->val); 2051c099ab4SSean Wang break; 2061c099ab4SSean Wang } 2071c099ab4SSean Wang default: 2081c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 2091c099ab4SSean Wang break; 2101c099ab4SSean Wang } 2111c099ab4SSean Wang 2121c099ab4SSean Wang return ret; 2131c099ab4SSean Wang } 2141c099ab4SSean Wang 2151c099ab4SSean Wang static int 2161c099ab4SSean Wang mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 2171c099ab4SSean Wang int cmd, int *wait_seq) 2181c099ab4SSean Wang { 2191c099ab4SSean Wang struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 2201c099ab4SSean Wang int txd_len, mcu_cmd = cmd & MCU_CMD_MASK; 2211c099ab4SSean Wang enum mt76_mcuq_id txq = MT_MCUQ_WM; 2221c099ab4SSean Wang struct mt7921_uni_txd *uni_txd; 2231c099ab4SSean Wang struct mt7921_mcu_txd *mcu_txd; 2241c099ab4SSean Wang __le32 *txd; 2251c099ab4SSean Wang u32 val; 2261c099ab4SSean Wang u8 seq; 2271c099ab4SSean Wang 228a2a6cd54SLorenzo Bianconi switch (cmd) { 229a2a6cd54SLorenzo Bianconi case MCU_UNI_CMD_HIF_CTRL: 230a2a6cd54SLorenzo Bianconi case MCU_UNI_CMD_SUSPEND: 231a2a6cd54SLorenzo Bianconi case MCU_UNI_CMD_OFFLOAD: 232a2a6cd54SLorenzo Bianconi mdev->mcu.timeout = HZ / 3; 233a2a6cd54SLorenzo Bianconi break; 234a2a6cd54SLorenzo Bianconi default: 235a2a6cd54SLorenzo Bianconi mdev->mcu.timeout = 3 * HZ; 236a2a6cd54SLorenzo Bianconi break; 237a2a6cd54SLorenzo Bianconi } 2381c099ab4SSean Wang 2391c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2401c099ab4SSean Wang if (!seq) 2411c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2421c099ab4SSean Wang 2431c099ab4SSean Wang if (cmd == MCU_CMD_FW_SCATTER) { 2441c099ab4SSean Wang txq = MT_MCUQ_FWDL; 2451c099ab4SSean Wang goto exit; 2461c099ab4SSean Wang } 2471c099ab4SSean Wang 2481c099ab4SSean Wang txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd); 2491c099ab4SSean Wang txd = (__le32 *)skb_push(skb, txd_len); 2501c099ab4SSean Wang 2511c099ab4SSean Wang val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | 2521c099ab4SSean Wang FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | 2531c099ab4SSean Wang FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); 2541c099ab4SSean Wang txd[0] = cpu_to_le32(val); 2551c099ab4SSean Wang 2561c099ab4SSean Wang val = MT_TXD1_LONG_FORMAT | 2571c099ab4SSean Wang FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); 2581c099ab4SSean Wang txd[1] = cpu_to_le32(val); 2591c099ab4SSean Wang 2601c099ab4SSean Wang if (cmd & MCU_UNI_PREFIX) { 2611c099ab4SSean Wang uni_txd = (struct mt7921_uni_txd *)txd; 2621c099ab4SSean Wang uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); 2631c099ab4SSean Wang uni_txd->option = MCU_CMD_UNI_EXT_ACK; 2641c099ab4SSean Wang uni_txd->cid = cpu_to_le16(mcu_cmd); 2651c099ab4SSean Wang uni_txd->s2d_index = MCU_S2D_H2N; 2661c099ab4SSean Wang uni_txd->pkt_type = MCU_PKT_ID; 2671c099ab4SSean Wang uni_txd->seq = seq; 2681c099ab4SSean Wang 2691c099ab4SSean Wang goto exit; 2701c099ab4SSean Wang } 2711c099ab4SSean Wang 2721c099ab4SSean Wang mcu_txd = (struct mt7921_mcu_txd *)txd; 2731c099ab4SSean Wang mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); 2741c099ab4SSean Wang mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, 2751c099ab4SSean Wang MT_TX_MCU_PORT_RX_Q0)); 2761c099ab4SSean Wang mcu_txd->pkt_type = MCU_PKT_ID; 2771c099ab4SSean Wang mcu_txd->seq = seq; 2781c099ab4SSean Wang 2791c099ab4SSean Wang switch (cmd & ~MCU_CMD_MASK) { 2801c099ab4SSean Wang case MCU_FW_PREFIX: 2811c099ab4SSean Wang mcu_txd->set_query = MCU_Q_NA; 2821c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 2831c099ab4SSean Wang break; 2841c099ab4SSean Wang case MCU_CE_PREFIX: 2851c099ab4SSean Wang if (cmd & MCU_QUERY_MASK) 2861c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 2871c099ab4SSean Wang else 2881c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 2891c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 2901c099ab4SSean Wang break; 2911c099ab4SSean Wang default: 2921c099ab4SSean Wang mcu_txd->cid = MCU_CMD_EXT_CID; 2931c099ab4SSean Wang if (cmd & MCU_QUERY_PREFIX || cmd == MCU_EXT_CMD_EFUSE_ACCESS) 2941c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 2951c099ab4SSean Wang else 2961c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 2971c099ab4SSean Wang mcu_txd->ext_cid = mcu_cmd; 2981c099ab4SSean Wang mcu_txd->ext_cid_ack = 1; 2991c099ab4SSean Wang break; 3001c099ab4SSean Wang } 3011c099ab4SSean Wang 3021c099ab4SSean Wang mcu_txd->s2d_index = MCU_S2D_H2N; 3031c099ab4SSean Wang WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && 3041c099ab4SSean Wang mcu_txd->set_query != MCU_Q_QUERY); 3051c099ab4SSean Wang 3061c099ab4SSean Wang exit: 3071c099ab4SSean Wang if (wait_seq) 3081c099ab4SSean Wang *wait_seq = seq; 3091c099ab4SSean Wang 3101c099ab4SSean Wang return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); 3111c099ab4SSean Wang } 3121c099ab4SSean Wang 3131c099ab4SSean Wang static void 3141c099ab4SSean Wang mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, 3151c099ab4SSean Wang struct mt7921_mcu_peer_cap *peer, 3161c099ab4SSean Wang struct rate_info *rate, u16 r) 3171c099ab4SSean Wang { 3181c099ab4SSean Wang struct ieee80211_supported_band *sband; 3191c099ab4SSean Wang u16 flags = 0; 3201c099ab4SSean Wang u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r); 3211c099ab4SSean Wang u8 gi = 0; 3221c099ab4SSean Wang u8 bw = 0; 3231c099ab4SSean Wang 3241c099ab4SSean Wang rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r); 3251c099ab4SSean Wang rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1; 3261c099ab4SSean Wang 3271c099ab4SSean Wang switch (peer->bw) { 3281c099ab4SSean Wang case IEEE80211_STA_RX_BW_160: 3291c099ab4SSean Wang gi = peer->g16; 3301c099ab4SSean Wang break; 3311c099ab4SSean Wang case IEEE80211_STA_RX_BW_80: 3321c099ab4SSean Wang gi = peer->g8; 3331c099ab4SSean Wang break; 3341c099ab4SSean Wang case IEEE80211_STA_RX_BW_40: 3351c099ab4SSean Wang gi = peer->g4; 3361c099ab4SSean Wang break; 3371c099ab4SSean Wang default: 3381c099ab4SSean Wang gi = peer->g2; 3391c099ab4SSean Wang break; 3401c099ab4SSean Wang } 3411c099ab4SSean Wang 3421c099ab4SSean Wang gi = txmode >= MT_PHY_TYPE_HE_SU ? 3431c099ab4SSean Wang FIELD_GET(MT_WTBL_RATE_HE_GI, gi) : 3441c099ab4SSean Wang FIELD_GET(MT_WTBL_RATE_GI, gi); 3451c099ab4SSean Wang 3461c099ab4SSean Wang switch (txmode) { 3471c099ab4SSean Wang case MT_PHY_TYPE_CCK: 3481c099ab4SSean Wang case MT_PHY_TYPE_OFDM: 3491c099ab4SSean Wang if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 3501c099ab4SSean Wang sband = &mphy->sband_5g.sband; 3511c099ab4SSean Wang else 3521c099ab4SSean Wang sband = &mphy->sband_2g.sband; 3531c099ab4SSean Wang 3541c099ab4SSean Wang rate->legacy = sband->bitrates[rate->mcs].bitrate; 3551c099ab4SSean Wang break; 3561c099ab4SSean Wang case MT_PHY_TYPE_HT: 3571c099ab4SSean Wang case MT_PHY_TYPE_HT_GF: 3581c099ab4SSean Wang flags |= RATE_INFO_FLAGS_MCS; 3591c099ab4SSean Wang 3601c099ab4SSean Wang if (gi) 3611c099ab4SSean Wang flags |= RATE_INFO_FLAGS_SHORT_GI; 3621c099ab4SSean Wang break; 3631c099ab4SSean Wang case MT_PHY_TYPE_VHT: 3641c099ab4SSean Wang flags |= RATE_INFO_FLAGS_VHT_MCS; 3651c099ab4SSean Wang 3661c099ab4SSean Wang if (gi) 3671c099ab4SSean Wang flags |= RATE_INFO_FLAGS_SHORT_GI; 3681c099ab4SSean Wang break; 3691c099ab4SSean Wang case MT_PHY_TYPE_HE_SU: 3701c099ab4SSean Wang case MT_PHY_TYPE_HE_EXT_SU: 3711c099ab4SSean Wang case MT_PHY_TYPE_HE_TB: 3721c099ab4SSean Wang case MT_PHY_TYPE_HE_MU: 3731c099ab4SSean Wang rate->he_gi = gi; 3741c099ab4SSean Wang rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); 3751c099ab4SSean Wang 3761c099ab4SSean Wang flags |= RATE_INFO_FLAGS_HE_MCS; 3771c099ab4SSean Wang break; 3781c099ab4SSean Wang default: 3791c099ab4SSean Wang break; 3801c099ab4SSean Wang } 3811c099ab4SSean Wang rate->flags = flags; 3821c099ab4SSean Wang 3831c099ab4SSean Wang bw = mt7921_mcu_chan_bw(&mphy->chandef) - FIELD_GET(MT_RA_RATE_BW, r); 3841c099ab4SSean Wang 3851c099ab4SSean Wang switch (bw) { 3861c099ab4SSean Wang case IEEE80211_STA_RX_BW_160: 3871c099ab4SSean Wang rate->bw = RATE_INFO_BW_160; 3881c099ab4SSean Wang break; 3891c099ab4SSean Wang case IEEE80211_STA_RX_BW_80: 3901c099ab4SSean Wang rate->bw = RATE_INFO_BW_80; 3911c099ab4SSean Wang break; 3921c099ab4SSean Wang case IEEE80211_STA_RX_BW_40: 3931c099ab4SSean Wang rate->bw = RATE_INFO_BW_40; 3941c099ab4SSean Wang break; 3951c099ab4SSean Wang default: 3961c099ab4SSean Wang rate->bw = RATE_INFO_BW_20; 3971c099ab4SSean Wang break; 3981c099ab4SSean Wang } 3991c099ab4SSean Wang } 4001c099ab4SSean Wang 4011c099ab4SSean Wang static void 4021c099ab4SSean Wang mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) 4031c099ab4SSean Wang { 4041c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 4051c099ab4SSean Wang struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; 4061c099ab4SSean Wang 4071c099ab4SSean Wang spin_lock_bh(&dev->mt76.lock); 4081c099ab4SSean Wang __skb_queue_tail(&phy->scan_event_list, skb); 4091c099ab4SSean Wang spin_unlock_bh(&dev->mt76.lock); 4101c099ab4SSean Wang 4111c099ab4SSean Wang ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, 4121c099ab4SSean Wang MT7921_HW_SCAN_TIMEOUT); 4131c099ab4SSean Wang } 4141c099ab4SSean Wang 4151c099ab4SSean Wang static void 41610de032aSSean Wang mt7921_mcu_connection_loss_iter(void *priv, u8 *mac, 41710de032aSSean Wang struct ieee80211_vif *vif) 41810de032aSSean Wang { 41910de032aSSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 42010de032aSSean Wang struct mt76_connac_beacon_loss_event *event = priv; 42110de032aSSean Wang 42210de032aSSean Wang if (mvif->idx != event->bss_idx) 42310de032aSSean Wang return; 42410de032aSSean Wang 42510de032aSSean Wang if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) 42610de032aSSean Wang return; 42710de032aSSean Wang 42810de032aSSean Wang ieee80211_connection_loss(vif); 42910de032aSSean Wang } 43010de032aSSean Wang 43110de032aSSean Wang static void 43210de032aSSean Wang mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) 433b88f5c64SSean Wang { 43467aa2743SLorenzo Bianconi struct mt76_connac_beacon_loss_event *event; 43510de032aSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 436b88f5c64SSean Wang 437b88f5c64SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 43867aa2743SLorenzo Bianconi event = (struct mt76_connac_beacon_loss_event *)skb->data; 439b88f5c64SSean Wang 440b88f5c64SSean Wang ieee80211_iterate_active_interfaces_atomic(mphy->hw, 441b88f5c64SSean Wang IEEE80211_IFACE_ITER_RESUME_ALL, 44210de032aSSean Wang mt7921_mcu_connection_loss_iter, event); 443b88f5c64SSean Wang } 444b88f5c64SSean Wang 445b88f5c64SSean Wang static void 4461c099ab4SSean Wang mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb) 4471c099ab4SSean Wang { 4481c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 44967aa2743SLorenzo Bianconi struct mt76_connac_mcu_bss_event *event; 4501c099ab4SSean Wang 45167aa2743SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 45267aa2743SLorenzo Bianconi event = (struct mt76_connac_mcu_bss_event *)skb->data; 4531c099ab4SSean Wang if (event->is_absent) 4541c099ab4SSean Wang ieee80211_stop_queues(mphy->hw); 4551c099ab4SSean Wang else 4561c099ab4SSean Wang ieee80211_wake_queues(mphy->hw); 4571c099ab4SSean Wang } 4581c099ab4SSean Wang 4591c099ab4SSean Wang static void 4601c099ab4SSean Wang mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) 4611c099ab4SSean Wang { 462c7cc5ec5SLorenzo Bianconi struct mt7921_debug_msg { 4631c099ab4SSean Wang __le16 id; 4641c099ab4SSean Wang u8 type; 4651c099ab4SSean Wang u8 flag; 4661c099ab4SSean Wang __le32 value; 4671c099ab4SSean Wang __le16 len; 4681c099ab4SSean Wang u8 content[512]; 469c7cc5ec5SLorenzo Bianconi } __packed * msg; 470c7cc5ec5SLorenzo Bianconi 471c7cc5ec5SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 472c7cc5ec5SLorenzo Bianconi msg = (struct mt7921_debug_msg *)skb->data; 473c7cc5ec5SLorenzo Bianconi 474c7cc5ec5SLorenzo Bianconi if (msg->type == 3) { /* fw log */ 475c7cc5ec5SLorenzo Bianconi u16 len = min_t(u16, le16_to_cpu(msg->len), 512); 4761c099ab4SSean Wang int i; 4771c099ab4SSean Wang 478c7cc5ec5SLorenzo Bianconi for (i = 0 ; i < len; i++) { 479c7cc5ec5SLorenzo Bianconi if (!msg->content[i]) 480c7cc5ec5SLorenzo Bianconi msg->content[i] = ' '; 481c7cc5ec5SLorenzo Bianconi } 4822bf301bcSDan Carpenter wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content); 4831c099ab4SSean Wang } 4841c099ab4SSean Wang } 4851c099ab4SSean Wang 4861c099ab4SSean Wang static void 4872afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) 4882afd17b4SLorenzo Bianconi { 4892afd17b4SLorenzo Bianconi struct mt7921_mcu_lp_event { 4902afd17b4SLorenzo Bianconi u8 state; 4912afd17b4SLorenzo Bianconi u8 reserved[3]; 4922afd17b4SLorenzo Bianconi } __packed * event; 4932afd17b4SLorenzo Bianconi 4942afd17b4SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 4952afd17b4SLorenzo Bianconi event = (struct mt7921_mcu_lp_event *)skb->data; 4962afd17b4SLorenzo Bianconi 4972afd17b4SLorenzo Bianconi trace_lp_event(dev, event->state); 4982afd17b4SLorenzo Bianconi } 4992afd17b4SLorenzo Bianconi 5002afd17b4SLorenzo Bianconi static void 5013cce2b98SDeren Wu mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) 5023cce2b98SDeren Wu { 5033cce2b98SDeren Wu struct mt7921_mcu_tx_done_event *event; 5043cce2b98SDeren Wu struct mt7921_sta *msta; 5053cce2b98SDeren Wu struct mt7921_phy *mphy = &dev->phy; 5063cce2b98SDeren Wu struct mt7921_mcu_peer_cap peer; 5073cce2b98SDeren Wu struct ieee80211_sta *sta; 5083cce2b98SDeren Wu LIST_HEAD(list); 5093cce2b98SDeren Wu 5103cce2b98SDeren Wu skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 5113cce2b98SDeren Wu event = (struct mt7921_mcu_tx_done_event *)skb->data; 5123cce2b98SDeren Wu 5133cce2b98SDeren Wu spin_lock_bh(&dev->sta_poll_lock); 5143cce2b98SDeren Wu list_splice_init(&mphy->stats_list, &list); 5153cce2b98SDeren Wu 5163cce2b98SDeren Wu while (!list_empty(&list)) { 5173cce2b98SDeren Wu msta = list_first_entry(&list, struct mt7921_sta, stats_list); 5183cce2b98SDeren Wu list_del_init(&msta->stats_list); 5193cce2b98SDeren Wu 5203cce2b98SDeren Wu if (msta->wcid.idx != event->wlan_idx) 5213cce2b98SDeren Wu continue; 5223cce2b98SDeren Wu 5233cce2b98SDeren Wu spin_unlock_bh(&dev->sta_poll_lock); 5243cce2b98SDeren Wu 5253cce2b98SDeren Wu sta = wcid_to_sta(&msta->wcid); 5263cce2b98SDeren Wu 5273cce2b98SDeren Wu /* peer config based on IEEE SPEC */ 5283cce2b98SDeren Wu memset(&peer, 0x0, sizeof(peer)); 5293cce2b98SDeren Wu peer.bw = event->bw; 5303cce2b98SDeren Wu peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); 5313cce2b98SDeren Wu peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); 5323cce2b98SDeren Wu peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); 5333cce2b98SDeren Wu peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); 5343cce2b98SDeren Wu mt7921_mcu_tx_rate_parse(mphy->mt76, &peer, 5353cce2b98SDeren Wu &msta->stats.tx_rate, event->tx_rate); 5363cce2b98SDeren Wu 5373cce2b98SDeren Wu spin_lock_bh(&dev->sta_poll_lock); 5383cce2b98SDeren Wu break; 5393cce2b98SDeren Wu } 5403cce2b98SDeren Wu spin_unlock_bh(&dev->sta_poll_lock); 5413cce2b98SDeren Wu } 5423cce2b98SDeren Wu 5433cce2b98SDeren Wu static void 5441c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) 5451c099ab4SSean Wang { 5461c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 5471c099ab4SSean Wang 5481c099ab4SSean Wang switch (rxd->eid) { 5491c099ab4SSean Wang case MCU_EVENT_BSS_BEACON_LOSS: 55010de032aSSean Wang mt7921_mcu_connection_loss_event(dev, skb); 5511c099ab4SSean Wang break; 5521c099ab4SSean Wang case MCU_EVENT_SCHED_SCAN_DONE: 5531c099ab4SSean Wang case MCU_EVENT_SCAN_DONE: 5541c099ab4SSean Wang mt7921_mcu_scan_event(dev, skb); 5551c099ab4SSean Wang return; 5561c099ab4SSean Wang case MCU_EVENT_BSS_ABSENCE: 5571c099ab4SSean Wang mt7921_mcu_bss_event(dev, skb); 5581c099ab4SSean Wang break; 5591c099ab4SSean Wang case MCU_EVENT_DBG_MSG: 5601c099ab4SSean Wang mt7921_mcu_debug_msg_event(dev, skb); 5611c099ab4SSean Wang break; 5620da3c795SSean Wang case MCU_EVENT_COREDUMP: 5630da3c795SSean Wang mt76_connac_mcu_coredump_event(&dev->mt76, skb, 5640da3c795SSean Wang &dev->coredump); 5650da3c795SSean Wang return; 5662afd17b4SLorenzo Bianconi case MCU_EVENT_LP_INFO: 5672afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(dev, skb); 5682afd17b4SLorenzo Bianconi break; 5693cce2b98SDeren Wu case MCU_EVENT_TX_DONE: 5703cce2b98SDeren Wu mt7921_mcu_tx_done_event(dev, skb); 5713cce2b98SDeren Wu break; 5721c099ab4SSean Wang default: 5731c099ab4SSean Wang break; 5741c099ab4SSean Wang } 5751c099ab4SSean Wang dev_kfree_skb(skb); 5761c099ab4SSean Wang } 5771c099ab4SSean Wang 5781c099ab4SSean Wang void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) 5791c099ab4SSean Wang { 5801c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 5811c099ab4SSean Wang 5821c099ab4SSean Wang if (rxd->eid == 0x6) { 5831c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 5841c099ab4SSean Wang return; 5851c099ab4SSean Wang } 5861c099ab4SSean Wang 5871c099ab4SSean Wang if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || 5881c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || 5891c099ab4SSean Wang rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || 5901c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_ABSENCE || 5911c099ab4SSean Wang rxd->eid == MCU_EVENT_SCAN_DONE || 5923cce2b98SDeren Wu rxd->eid == MCU_EVENT_TX_DONE || 5931c099ab4SSean Wang rxd->eid == MCU_EVENT_DBG_MSG || 5940da3c795SSean Wang rxd->eid == MCU_EVENT_COREDUMP || 5952afd17b4SLorenzo Bianconi rxd->eid == MCU_EVENT_LP_INFO || 5961c099ab4SSean Wang !rxd->seq) 5971c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(dev, skb); 5981c099ab4SSean Wang else 5991c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 6001c099ab4SSean Wang } 6011c099ab4SSean Wang 6021c099ab4SSean Wang /** starec & wtbl **/ 6031c099ab4SSean Wang static int 6041c099ab4SSean Wang mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, 6051c099ab4SSean Wang struct ieee80211_key_conf *key, enum set_key_cmd cmd) 6061c099ab4SSean Wang { 6071c099ab4SSean Wang struct mt7921_sta_key_conf *bip = &msta->bip; 6081c099ab4SSean Wang struct sta_rec_sec *sec; 6091c099ab4SSean Wang struct tlv *tlv; 6101c099ab4SSean Wang u32 len = sizeof(*sec); 6111c099ab4SSean Wang 61267aa2743SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); 6131c099ab4SSean Wang 6141c099ab4SSean Wang sec = (struct sta_rec_sec *)tlv; 6151c099ab4SSean Wang sec->add = cmd; 6161c099ab4SSean Wang 6171c099ab4SSean Wang if (cmd == SET_KEY) { 6181c099ab4SSean Wang struct sec_key *sec_key; 6191c099ab4SSean Wang u8 cipher; 6201c099ab4SSean Wang 6211c099ab4SSean Wang cipher = mt7921_mcu_get_cipher(key->cipher); 6221c099ab4SSean Wang if (cipher == MT_CIPHER_NONE) 6231c099ab4SSean Wang return -EOPNOTSUPP; 6241c099ab4SSean Wang 6251c099ab4SSean Wang sec_key = &sec->key[0]; 6261c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 6271c099ab4SSean Wang 6281c099ab4SSean Wang if (cipher == MT_CIPHER_BIP_CMAC_128) { 6291c099ab4SSean Wang sec_key->cipher_id = MT_CIPHER_AES_CCMP; 6301c099ab4SSean Wang sec_key->key_id = bip->keyidx; 6311c099ab4SSean Wang sec_key->key_len = 16; 6321c099ab4SSean Wang memcpy(sec_key->key, bip->key, 16); 6331c099ab4SSean Wang 6341c099ab4SSean Wang sec_key = &sec->key[1]; 6351c099ab4SSean Wang sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; 6361c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 6371c099ab4SSean Wang sec_key->key_len = 16; 6381c099ab4SSean Wang memcpy(sec_key->key, key->key, 16); 6391c099ab4SSean Wang 6401c099ab4SSean Wang sec->n_cipher = 2; 6411c099ab4SSean Wang } else { 6421c099ab4SSean Wang sec_key->cipher_id = cipher; 6431c099ab4SSean Wang sec_key->key_id = key->keyidx; 6441c099ab4SSean Wang sec_key->key_len = key->keylen; 6451c099ab4SSean Wang memcpy(sec_key->key, key->key, key->keylen); 6461c099ab4SSean Wang 6471c099ab4SSean Wang if (cipher == MT_CIPHER_TKIP) { 6481c099ab4SSean Wang /* Rx/Tx MIC keys are swapped */ 6491c099ab4SSean Wang memcpy(sec_key->key + 16, key->key + 24, 8); 6501c099ab4SSean Wang memcpy(sec_key->key + 24, key->key + 16, 8); 6511c099ab4SSean Wang } 6521c099ab4SSean Wang 6531c099ab4SSean Wang /* store key_conf for BIP batch update */ 6541c099ab4SSean Wang if (cipher == MT_CIPHER_AES_CCMP) { 6551c099ab4SSean Wang memcpy(bip->key, key->key, key->keylen); 6561c099ab4SSean Wang bip->keyidx = key->keyidx; 6571c099ab4SSean Wang } 6581c099ab4SSean Wang 6591c099ab4SSean Wang len -= sizeof(*sec_key); 6601c099ab4SSean Wang sec->n_cipher = 1; 6611c099ab4SSean Wang } 6621c099ab4SSean Wang } else { 6631c099ab4SSean Wang len -= sizeof(sec->key); 6641c099ab4SSean Wang sec->n_cipher = 0; 6651c099ab4SSean Wang } 6661c099ab4SSean Wang sec->len = cpu_to_le16(len); 6671c099ab4SSean Wang 6681c099ab4SSean Wang return 0; 6691c099ab4SSean Wang } 6701c099ab4SSean Wang 6711c099ab4SSean Wang int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, 6721c099ab4SSean Wang struct mt7921_sta *msta, struct ieee80211_key_conf *key, 6731c099ab4SSean Wang enum set_key_cmd cmd) 6741c099ab4SSean Wang { 6751c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 6761c099ab4SSean Wang struct sk_buff *skb; 6771c099ab4SSean Wang int ret; 6781c099ab4SSean Wang 67967aa2743SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 68067aa2743SLorenzo Bianconi &msta->wcid); 6811c099ab4SSean Wang if (IS_ERR(skb)) 6821c099ab4SSean Wang return PTR_ERR(skb); 6831c099ab4SSean Wang 6841c099ab4SSean Wang ret = mt7921_mcu_sta_key_tlv(msta, skb, key, cmd); 6851c099ab4SSean Wang if (ret) 6861c099ab4SSean Wang return ret; 6871c099ab4SSean Wang 6881c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, 6891c099ab4SSean Wang MCU_UNI_CMD_STA_REC_UPDATE, true); 6901c099ab4SSean Wang } 6911c099ab4SSean Wang 6921c099ab4SSean Wang int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, 6931c099ab4SSean Wang struct ieee80211_ampdu_params *params, 6941c099ab4SSean Wang bool enable) 6951c099ab4SSean Wang { 69667aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 69767aa2743SLorenzo Bianconi 69867aa2743SLorenzo Bianconi if (enable && !params->amsdu) 69967aa2743SLorenzo Bianconi msta->wcid.amsdu = false; 70067aa2743SLorenzo Bianconi 70167aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 70267aa2743SLorenzo Bianconi enable, true); 7031c099ab4SSean Wang } 7041c099ab4SSean Wang 7051c099ab4SSean Wang int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, 7061c099ab4SSean Wang struct ieee80211_ampdu_params *params, 7071c099ab4SSean Wang bool enable) 7081c099ab4SSean Wang { 70967aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 7101c099ab4SSean Wang 71167aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 71267aa2743SLorenzo Bianconi enable, false); 7131c099ab4SSean Wang } 7141c099ab4SSean Wang 7151c099ab4SSean Wang static int mt7921_mcu_restart(struct mt76_dev *dev) 7161c099ab4SSean Wang { 7171c099ab4SSean Wang struct { 7181c099ab4SSean Wang u8 power_mode; 7191c099ab4SSean Wang u8 rsv[3]; 7201c099ab4SSean Wang } req = { 7211c099ab4SSean Wang .power_mode = 1, 7221c099ab4SSean Wang }; 7231c099ab4SSean Wang 7241c099ab4SSean Wang return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req, 7251c099ab4SSean Wang sizeof(req), false); 7261c099ab4SSean Wang } 7271c099ab4SSean Wang 7281c099ab4SSean Wang static int mt7921_driver_own(struct mt7921_dev *dev) 7291c099ab4SSean Wang { 7301c099ab4SSean Wang u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 7311c099ab4SSean Wang 7321c099ab4SSean Wang mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); 7331c099ab4SSean Wang if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, 7341c099ab4SSean Wang 0, 500)) { 7351c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for driver own\n"); 7361c099ab4SSean Wang return -EIO; 7371c099ab4SSean Wang } 7381c099ab4SSean Wang 7391c099ab4SSean Wang return 0; 7401c099ab4SSean Wang } 7411c099ab4SSean Wang 7421c099ab4SSean Wang static int mt7921_load_patch(struct mt7921_dev *dev) 7431c099ab4SSean Wang { 7441c099ab4SSean Wang const struct mt7921_patch_hdr *hdr; 7451c099ab4SSean Wang const struct firmware *fw = NULL; 7461c099ab4SSean Wang int i, ret, sem; 7471c099ab4SSean Wang 74867aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); 7491c099ab4SSean Wang switch (sem) { 7501c099ab4SSean Wang case PATCH_IS_DL: 7511c099ab4SSean Wang return 0; 7521c099ab4SSean Wang case PATCH_NOT_DL_SEM_SUCCESS: 7531c099ab4SSean Wang break; 7541c099ab4SSean Wang default: 7551c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); 7561c099ab4SSean Wang return -EAGAIN; 7571c099ab4SSean Wang } 7581c099ab4SSean Wang 7591c099ab4SSean Wang ret = request_firmware(&fw, MT7921_ROM_PATCH, dev->mt76.dev); 7601c099ab4SSean Wang if (ret) 7611c099ab4SSean Wang goto out; 7621c099ab4SSean Wang 7631c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 7641c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 7651c099ab4SSean Wang ret = -EINVAL; 7661c099ab4SSean Wang goto out; 7671c099ab4SSean Wang } 7681c099ab4SSean Wang 7691c099ab4SSean Wang hdr = (const struct mt7921_patch_hdr *)(fw->data); 7701c099ab4SSean Wang 7711c099ab4SSean Wang dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", 7721c099ab4SSean Wang be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); 7731c099ab4SSean Wang 7741c099ab4SSean Wang for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { 7751c099ab4SSean Wang struct mt7921_patch_sec *sec; 7761c099ab4SSean Wang const u8 *dl; 7771c099ab4SSean Wang u32 len, addr; 7781c099ab4SSean Wang 7791c099ab4SSean Wang sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + 7801c099ab4SSean Wang i * sizeof(*sec)); 7811c099ab4SSean Wang if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != 7821c099ab4SSean Wang PATCH_SEC_TYPE_INFO) { 7831c099ab4SSean Wang ret = -EINVAL; 7841c099ab4SSean Wang goto out; 7851c099ab4SSean Wang } 7861c099ab4SSean Wang 7871c099ab4SSean Wang addr = be32_to_cpu(sec->info.addr); 7881c099ab4SSean Wang len = be32_to_cpu(sec->info.len); 7891c099ab4SSean Wang dl = fw->data + be32_to_cpu(sec->offs); 7901c099ab4SSean Wang 79167aa2743SLorenzo Bianconi ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 7921c099ab4SSean Wang DL_MODE_NEED_RSP); 7931c099ab4SSean Wang if (ret) { 7941c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 7951c099ab4SSean Wang goto out; 7961c099ab4SSean Wang } 7971c099ab4SSean Wang 7981c099ab4SSean Wang ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 7991c099ab4SSean Wang dl, len); 8001c099ab4SSean Wang if (ret) { 8011c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send patch\n"); 8021c099ab4SSean Wang goto out; 8031c099ab4SSean Wang } 8041c099ab4SSean Wang } 8051c099ab4SSean Wang 80667aa2743SLorenzo Bianconi ret = mt76_connac_mcu_start_patch(&dev->mt76); 8071c099ab4SSean Wang if (ret) 8081c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start patch\n"); 8091c099ab4SSean Wang 8101c099ab4SSean Wang out: 81167aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); 8121c099ab4SSean Wang switch (sem) { 8131c099ab4SSean Wang case PATCH_REL_SEM_SUCCESS: 8141c099ab4SSean Wang break; 8151c099ab4SSean Wang default: 8161c099ab4SSean Wang ret = -EAGAIN; 8171c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); 8181c099ab4SSean Wang goto out; 8191c099ab4SSean Wang } 8201c099ab4SSean Wang release_firmware(fw); 8211c099ab4SSean Wang 8221c099ab4SSean Wang return ret; 8231c099ab4SSean Wang } 8241c099ab4SSean Wang 8251c099ab4SSean Wang static u32 mt7921_mcu_gen_dl_mode(u8 feature_set, bool is_wa) 8261c099ab4SSean Wang { 8271c099ab4SSean Wang u32 ret = 0; 8281c099ab4SSean Wang 8291c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? 8301c099ab4SSean Wang (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; 8311c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_ENCRY_MODE) ? 8321c099ab4SSean Wang DL_CONFIG_ENCRY_MODE_SEL : 0; 8331c099ab4SSean Wang ret |= FIELD_PREP(DL_MODE_KEY_IDX, 8341c099ab4SSean Wang FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); 8351c099ab4SSean Wang ret |= DL_MODE_NEED_RSP; 8361c099ab4SSean Wang ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; 8371c099ab4SSean Wang 8381c099ab4SSean Wang return ret; 8391c099ab4SSean Wang } 8401c099ab4SSean Wang 8411c099ab4SSean Wang static int 8421c099ab4SSean Wang mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, 8431c099ab4SSean Wang const struct mt7921_fw_trailer *hdr, 8441c099ab4SSean Wang const u8 *data, bool is_wa) 8451c099ab4SSean Wang { 8461c099ab4SSean Wang int i, offset = 0; 8471c099ab4SSean Wang u32 override = 0, option = 0; 8481c099ab4SSean Wang 8491c099ab4SSean Wang for (i = 0; i < hdr->n_region; i++) { 8501c099ab4SSean Wang const struct mt7921_fw_region *region; 8511c099ab4SSean Wang int err; 8521c099ab4SSean Wang u32 len, addr, mode; 8531c099ab4SSean Wang 8541c099ab4SSean Wang region = (const struct mt7921_fw_region *)((const u8 *)hdr - 8551c099ab4SSean Wang (hdr->n_region - i) * sizeof(*region)); 8561c099ab4SSean Wang mode = mt7921_mcu_gen_dl_mode(region->feature_set, is_wa); 8571c099ab4SSean Wang len = le32_to_cpu(region->len); 8581c099ab4SSean Wang addr = le32_to_cpu(region->addr); 8591c099ab4SSean Wang 8601c099ab4SSean Wang if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) 8611c099ab4SSean Wang override = addr; 8621c099ab4SSean Wang 86367aa2743SLorenzo Bianconi err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 86467aa2743SLorenzo Bianconi mode); 8651c099ab4SSean Wang if (err) { 8661c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 8671c099ab4SSean Wang return err; 8681c099ab4SSean Wang } 8691c099ab4SSean Wang 8701c099ab4SSean Wang err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 8711c099ab4SSean Wang data + offset, len); 8721c099ab4SSean Wang if (err) { 8731c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send firmware.\n"); 8741c099ab4SSean Wang return err; 8751c099ab4SSean Wang } 8761c099ab4SSean Wang 8771c099ab4SSean Wang offset += len; 8781c099ab4SSean Wang } 8791c099ab4SSean Wang 8801c099ab4SSean Wang if (override) 8811c099ab4SSean Wang option |= FW_START_OVERRIDE; 8821c099ab4SSean Wang 8831c099ab4SSean Wang if (is_wa) 8841c099ab4SSean Wang option |= FW_START_WORKING_PDA_CR4; 8851c099ab4SSean Wang 88667aa2743SLorenzo Bianconi return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); 8871c099ab4SSean Wang } 8881c099ab4SSean Wang 8891c099ab4SSean Wang static int mt7921_load_ram(struct mt7921_dev *dev) 8901c099ab4SSean Wang { 8911c099ab4SSean Wang const struct mt7921_fw_trailer *hdr; 8921c099ab4SSean Wang const struct firmware *fw; 8931c099ab4SSean Wang int ret; 8941c099ab4SSean Wang 8951c099ab4SSean Wang ret = request_firmware(&fw, MT7921_FIRMWARE_WM, dev->mt76.dev); 8961c099ab4SSean Wang if (ret) 8971c099ab4SSean Wang return ret; 8981c099ab4SSean Wang 8991c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 9001c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 9011c099ab4SSean Wang ret = -EINVAL; 9021c099ab4SSean Wang goto out; 9031c099ab4SSean Wang } 9041c099ab4SSean Wang 9051c099ab4SSean Wang hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size - 9061c099ab4SSean Wang sizeof(*hdr)); 9071c099ab4SSean Wang 9081c099ab4SSean Wang dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", 9091c099ab4SSean Wang hdr->fw_ver, hdr->build_date); 9101c099ab4SSean Wang 9111c099ab4SSean Wang ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false); 9121c099ab4SSean Wang if (ret) { 9131c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); 9141c099ab4SSean Wang goto out; 9151c099ab4SSean Wang } 9161c099ab4SSean Wang 9171c099ab4SSean Wang snprintf(dev->mt76.hw->wiphy->fw_version, 9181c099ab4SSean Wang sizeof(dev->mt76.hw->wiphy->fw_version), 9191c099ab4SSean Wang "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 9201c099ab4SSean Wang 9211c099ab4SSean Wang out: 9221c099ab4SSean Wang release_firmware(fw); 9231c099ab4SSean Wang 9241c099ab4SSean Wang return ret; 9251c099ab4SSean Wang } 9261c099ab4SSean Wang 9271c099ab4SSean Wang static int mt7921_load_firmware(struct mt7921_dev *dev) 9281c099ab4SSean Wang { 9291c099ab4SSean Wang int ret; 9301c099ab4SSean Wang 9311c099ab4SSean Wang ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 9321c099ab4SSean Wang if (ret) { 9331c099ab4SSean Wang dev_dbg(dev->mt76.dev, "Firmware is already download\n"); 9341c099ab4SSean Wang return -EIO; 9351c099ab4SSean Wang } 9361c099ab4SSean Wang 9371c099ab4SSean Wang ret = mt7921_load_patch(dev); 9381c099ab4SSean Wang if (ret) 9391c099ab4SSean Wang return ret; 9401c099ab4SSean Wang 9411c099ab4SSean Wang ret = mt7921_load_ram(dev); 9421c099ab4SSean Wang if (ret) 9431c099ab4SSean Wang return ret; 9441c099ab4SSean Wang 9451c099ab4SSean Wang if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, 9461c099ab4SSean Wang MT_TOP_MISC2_FW_N9_RDY, 1500)) { 9471c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 9481c099ab4SSean Wang 9491c099ab4SSean Wang return -EIO; 9501c099ab4SSean Wang } 9511c099ab4SSean Wang 9521c099ab4SSean Wang mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); 9531c099ab4SSean Wang 954ffa1bf97SSean Wang #ifdef CONFIG_PM 955022159b0SLorenzo Bianconi dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; 956ffa1bf97SSean Wang #endif /* CONFIG_PM */ 957ffa1bf97SSean Wang 9581c099ab4SSean Wang dev_err(dev->mt76.dev, "Firmware init done\n"); 9591c099ab4SSean Wang 9601c099ab4SSean Wang return 0; 9611c099ab4SSean Wang } 9621c099ab4SSean Wang 9631c099ab4SSean Wang int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) 9641c099ab4SSean Wang { 9651c099ab4SSean Wang struct { 9661c099ab4SSean Wang u8 ctrl_val; 9671c099ab4SSean Wang u8 pad[3]; 9681c099ab4SSean Wang } data = { 9691c099ab4SSean Wang .ctrl_val = ctrl 9701c099ab4SSean Wang }; 9711c099ab4SSean Wang 9721c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FWLOG_2_HOST, &data, 9731c099ab4SSean Wang sizeof(data), false); 9741c099ab4SSean Wang } 9751c099ab4SSean Wang 976d32464e6SLorenzo Bianconi int mt7921_run_firmware(struct mt7921_dev *dev) 977d32464e6SLorenzo Bianconi { 978d32464e6SLorenzo Bianconi int err; 979d32464e6SLorenzo Bianconi 980d32464e6SLorenzo Bianconi err = mt7921_driver_own(dev); 981d32464e6SLorenzo Bianconi if (err) 982d32464e6SLorenzo Bianconi return err; 983d32464e6SLorenzo Bianconi 984d32464e6SLorenzo Bianconi err = mt7921_load_firmware(dev); 985d32464e6SLorenzo Bianconi if (err) 986d32464e6SLorenzo Bianconi return err; 987d32464e6SLorenzo Bianconi 988d32464e6SLorenzo Bianconi set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 989d32464e6SLorenzo Bianconi mt7921_mcu_fw_log_2_host(dev, 1); 990d32464e6SLorenzo Bianconi 991*f7d2958cSLorenzo Bianconi return mt76_connac_mcu_get_nic_capability(&dev->mphy); 992d32464e6SLorenzo Bianconi } 993d32464e6SLorenzo Bianconi 9941c099ab4SSean Wang int mt7921_mcu_init(struct mt7921_dev *dev) 9951c099ab4SSean Wang { 9961c099ab4SSean Wang static const struct mt76_mcu_ops mt7921_mcu_ops = { 9971c099ab4SSean Wang .headroom = sizeof(struct mt7921_mcu_txd), 9981c099ab4SSean Wang .mcu_skb_send_msg = mt7921_mcu_send_message, 9991c099ab4SSean Wang .mcu_parse_response = mt7921_mcu_parse_response, 10001c099ab4SSean Wang .mcu_restart = mt7921_mcu_restart, 10011c099ab4SSean Wang }; 10021c099ab4SSean Wang 10031c099ab4SSean Wang dev->mt76.mcu_ops = &mt7921_mcu_ops; 10041c099ab4SSean Wang 1005d32464e6SLorenzo Bianconi return mt7921_run_firmware(dev); 10061c099ab4SSean Wang } 10071c099ab4SSean Wang 10081c099ab4SSean Wang void mt7921_mcu_exit(struct mt7921_dev *dev) 10091c099ab4SSean Wang { 101049897c52SSean Wang mt7921_wfsys_reset(dev); 10111c099ab4SSean Wang skb_queue_purge(&dev->mt76.mcu.res_q); 10121c099ab4SSean Wang } 10131c099ab4SSean Wang 10141c099ab4SSean Wang int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) 10151c099ab4SSean Wang { 10161c099ab4SSean Wang #define WMM_AIFS_SET BIT(0) 10171c099ab4SSean Wang #define WMM_CW_MIN_SET BIT(1) 10181c099ab4SSean Wang #define WMM_CW_MAX_SET BIT(2) 10191c099ab4SSean Wang #define WMM_TXOP_SET BIT(3) 10201c099ab4SSean Wang #define WMM_PARAM_SET GENMASK(3, 0) 10211c099ab4SSean Wang #define TX_CMD_MODE 1 10221c099ab4SSean Wang struct edca { 10231c099ab4SSean Wang u8 queue; 10241c099ab4SSean Wang u8 set; 10251c099ab4SSean Wang u8 aifs; 10261c099ab4SSean Wang u8 cw_min; 10271c099ab4SSean Wang __le16 cw_max; 10281c099ab4SSean Wang __le16 txop; 10291c099ab4SSean Wang }; 10301c099ab4SSean Wang struct mt7921_mcu_tx { 10311c099ab4SSean Wang u8 total; 10321c099ab4SSean Wang u8 action; 10331c099ab4SSean Wang u8 valid; 10341c099ab4SSean Wang u8 mode; 10351c099ab4SSean Wang 10361c099ab4SSean Wang struct edca edca[IEEE80211_NUM_ACS]; 10371c099ab4SSean Wang } __packed req = { 10381c099ab4SSean Wang .valid = true, 10391c099ab4SSean Wang .mode = TX_CMD_MODE, 10401c099ab4SSean Wang .total = IEEE80211_NUM_ACS, 10411c099ab4SSean Wang }; 10421c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 10431c099ab4SSean Wang int ac; 10441c099ab4SSean Wang 10451c099ab4SSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 10461c099ab4SSean Wang struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 10471c099ab4SSean Wang struct edca *e = &req.edca[ac]; 10481c099ab4SSean Wang 10491c099ab4SSean Wang e->set = WMM_PARAM_SET; 10501c099ab4SSean Wang e->queue = ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS; 10511c099ab4SSean Wang e->aifs = q->aifs; 10521c099ab4SSean Wang e->txop = cpu_to_le16(q->txop); 10531c099ab4SSean Wang 10541c099ab4SSean Wang if (q->cw_min) 10551c099ab4SSean Wang e->cw_min = fls(q->cw_min); 10561c099ab4SSean Wang else 10571c099ab4SSean Wang e->cw_min = 5; 10581c099ab4SSean Wang 10591c099ab4SSean Wang if (q->cw_max) 10601c099ab4SSean Wang e->cw_max = cpu_to_le16(fls(q->cw_max)); 10611c099ab4SSean Wang else 10621c099ab4SSean Wang e->cw_max = cpu_to_le16(10); 10631c099ab4SSean Wang } 10641c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, 10651c099ab4SSean Wang sizeof(req), true); 10661c099ab4SSean Wang } 10671c099ab4SSean Wang 10681c099ab4SSean Wang int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) 10691c099ab4SSean Wang { 10701c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 10711c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 10721c099ab4SSean Wang int freq1 = chandef->center_freq1; 10731c099ab4SSean Wang struct { 10741c099ab4SSean Wang u8 control_ch; 10751c099ab4SSean Wang u8 center_ch; 10761c099ab4SSean Wang u8 bw; 10771c099ab4SSean Wang u8 tx_streams_num; 10781c099ab4SSean Wang u8 rx_streams; /* mask or num */ 10791c099ab4SSean Wang u8 switch_reason; 10801c099ab4SSean Wang u8 band_idx; 10811c099ab4SSean Wang u8 center_ch2; /* for 80+80 only */ 10821c099ab4SSean Wang __le16 cac_case; 10831c099ab4SSean Wang u8 channel_band; 10841c099ab4SSean Wang u8 rsv0; 10851c099ab4SSean Wang __le32 outband_freq; 10861c099ab4SSean Wang u8 txpower_drop; 10871c099ab4SSean Wang u8 ap_bw; 10881c099ab4SSean Wang u8 ap_center_ch; 10891c099ab4SSean Wang u8 rsv1[57]; 10901c099ab4SSean Wang } __packed req = { 10911c099ab4SSean Wang .control_ch = chandef->chan->hw_value, 10921c099ab4SSean Wang .center_ch = ieee80211_frequency_to_channel(freq1), 10931c099ab4SSean Wang .bw = mt7921_mcu_chan_bw(chandef), 10941c099ab4SSean Wang .tx_streams_num = hweight8(phy->mt76->antenna_mask), 10951c099ab4SSean Wang .rx_streams = phy->mt76->antenna_mask, 10961c099ab4SSean Wang .band_idx = phy != &dev->phy, 10971c099ab4SSean Wang .channel_band = chandef->chan->band, 10981c099ab4SSean Wang }; 10991c099ab4SSean Wang 11001c099ab4SSean Wang if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 11011c099ab4SSean Wang req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 11021c099ab4SSean Wang else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 11031c099ab4SSean Wang chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 11041c099ab4SSean Wang req.switch_reason = CH_SWITCH_DFS; 11051c099ab4SSean Wang else 11061c099ab4SSean Wang req.switch_reason = CH_SWITCH_NORMAL; 11071c099ab4SSean Wang 11081c099ab4SSean Wang if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) 11091c099ab4SSean Wang req.rx_streams = hweight8(req.rx_streams); 11101c099ab4SSean Wang 11111c099ab4SSean Wang if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 11121c099ab4SSean Wang int freq2 = chandef->center_freq2; 11131c099ab4SSean Wang 11141c099ab4SSean Wang req.center_ch2 = ieee80211_frequency_to_channel(freq2); 11151c099ab4SSean Wang } 11161c099ab4SSean Wang 11171c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 11181c099ab4SSean Wang } 11191c099ab4SSean Wang 11201c099ab4SSean Wang int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) 11211c099ab4SSean Wang { 11221c099ab4SSean Wang struct req_hdr { 11231c099ab4SSean Wang u8 buffer_mode; 11241c099ab4SSean Wang u8 format; 11251c099ab4SSean Wang __le16 len; 11261c099ab4SSean Wang } __packed req = { 11271c099ab4SSean Wang .buffer_mode = EE_MODE_EFUSE, 11281c099ab4SSean Wang .format = EE_FORMAT_WHOLE, 11291c099ab4SSean Wang }; 11301c099ab4SSean Wang 11311c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 11321c099ab4SSean Wang &req, sizeof(req), true); 11331c099ab4SSean Wang } 11341c099ab4SSean Wang 11351c099ab4SSean Wang int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) 11361c099ab4SSean Wang { 11371c099ab4SSean Wang struct mt7921_mcu_eeprom_info req = { 11381c099ab4SSean Wang .addr = cpu_to_le32(round_down(offset, 16)), 11391c099ab4SSean Wang }; 11401c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 11411c099ab4SSean Wang struct sk_buff *skb; 11421c099ab4SSean Wang int ret; 11431c099ab4SSean Wang u8 *buf; 11441c099ab4SSean Wang 11451c099ab4SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, 11461c099ab4SSean Wang sizeof(req), true, &skb); 11471c099ab4SSean Wang if (ret) 11481c099ab4SSean Wang return ret; 11491c099ab4SSean Wang 11501c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 11511c099ab4SSean Wang buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); 11521c099ab4SSean Wang memcpy(buf, res->data, 16); 11531c099ab4SSean Wang dev_kfree_skb(skb); 11541c099ab4SSean Wang 11551c099ab4SSean Wang return 0; 11561c099ab4SSean Wang } 11571c099ab4SSean Wang 115856d965daSSean Wang int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) 115956d965daSSean Wang { 116056d965daSSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 116156d965daSSean Wang struct { 116256d965daSSean Wang struct { 116356d965daSSean Wang u8 bss_idx; 116456d965daSSean Wang u8 pad[3]; 116556d965daSSean Wang } __packed hdr; 116656d965daSSean Wang struct ps_tlv { 116756d965daSSean Wang __le16 tag; 116856d965daSSean Wang __le16 len; 116956d965daSSean Wang u8 ps_state; /* 0: device awake 117056d965daSSean Wang * 1: static power save 117156d965daSSean Wang * 2: dynamic power saving 117256d965daSSean Wang * 3: enter TWT power saving 117356d965daSSean Wang * 4: leave TWT power saving 117456d965daSSean Wang */ 117556d965daSSean Wang u8 pad[3]; 117656d965daSSean Wang } __packed ps; 117756d965daSSean Wang } __packed ps_req = { 117856d965daSSean Wang .hdr = { 117956d965daSSean Wang .bss_idx = mvif->mt76.idx, 118056d965daSSean Wang }, 118156d965daSSean Wang .ps = { 118256d965daSSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_PS), 118356d965daSSean Wang .len = cpu_to_le16(sizeof(struct ps_tlv)), 118456d965daSSean Wang .ps_state = vif->bss_conf.ps ? 2 : 0, 118556d965daSSean Wang }, 118656d965daSSean Wang }; 118756d965daSSean Wang 118856d965daSSean Wang if (vif->type != NL80211_IFTYPE_STATION) 118956d965daSSean Wang return -EOPNOTSUPP; 119056d965daSSean Wang 119156d965daSSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 119256d965daSSean Wang &ps_req, sizeof(ps_req), true); 119356d965daSSean Wang } 11944086ee28SSean Wang 11954086ee28SSean Wang int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, 11964086ee28SSean Wang bool enable) 11974086ee28SSean Wang { 11984086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 11994086ee28SSean Wang struct { 12004086ee28SSean Wang struct { 12014086ee28SSean Wang u8 bss_idx; 12024086ee28SSean Wang u8 pad[3]; 12034086ee28SSean Wang } __packed hdr; 12044086ee28SSean Wang struct bcnft_tlv { 12054086ee28SSean Wang __le16 tag; 12064086ee28SSean Wang __le16 len; 12074086ee28SSean Wang __le16 bcn_interval; 12084086ee28SSean Wang u8 dtim_period; 12094086ee28SSean Wang u8 pad; 12104086ee28SSean Wang } __packed bcnft; 12114086ee28SSean Wang } __packed bcnft_req = { 12124086ee28SSean Wang .hdr = { 12134086ee28SSean Wang .bss_idx = mvif->mt76.idx, 12144086ee28SSean Wang }, 12154086ee28SSean Wang .bcnft = { 12164086ee28SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), 12174086ee28SSean Wang .len = cpu_to_le16(sizeof(struct bcnft_tlv)), 12184086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 12194086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 12204086ee28SSean Wang }, 12214086ee28SSean Wang }; 12224086ee28SSean Wang 12234086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 12244086ee28SSean Wang return 0; 12254086ee28SSean Wang 12264086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 12274086ee28SSean Wang &bcnft_req, sizeof(bcnft_req), true); 12284086ee28SSean Wang } 12294086ee28SSean Wang 12304086ee28SSean Wang int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, 12314086ee28SSean Wang bool enable) 12324086ee28SSean Wang { 12334086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 12344086ee28SSean Wang struct { 12354086ee28SSean Wang u8 bss_idx; 12364086ee28SSean Wang u8 dtim_period; 12374086ee28SSean Wang __le16 aid; 12384086ee28SSean Wang __le16 bcn_interval; 12394086ee28SSean Wang __le16 atim_window; 12404086ee28SSean Wang u8 uapsd; 12414086ee28SSean Wang u8 bmc_delivered_ac; 12424086ee28SSean Wang u8 bmc_triggered_ac; 12434086ee28SSean Wang u8 pad; 12444086ee28SSean Wang } req = { 12454086ee28SSean Wang .bss_idx = mvif->mt76.idx, 12464086ee28SSean Wang .aid = cpu_to_le16(vif->bss_conf.aid), 12474086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 12484086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 12494086ee28SSean Wang }; 12504086ee28SSean Wang struct { 12514086ee28SSean Wang u8 bss_idx; 12524086ee28SSean Wang u8 pad[3]; 12534086ee28SSean Wang } req_hdr = { 12544086ee28SSean Wang .bss_idx = mvif->mt76.idx, 12554086ee28SSean Wang }; 12564086ee28SSean Wang int err; 12574086ee28SSean Wang 12584086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 12594086ee28SSean Wang return 0; 12604086ee28SSean Wang 12614086ee28SSean Wang err = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, &req_hdr, 12624086ee28SSean Wang sizeof(req_hdr), false); 12634086ee28SSean Wang if (err < 0 || !enable) 12644086ee28SSean Wang return err; 12654086ee28SSean Wang 12664086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, &req, 12674086ee28SSean Wang sizeof(req), false); 12684086ee28SSean Wang } 12691d8efc74SSean Wang 127036fcc8cfSLorenzo Bianconi int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, 127136fcc8cfSLorenzo Bianconi struct ieee80211_vif *vif, bool enable) 127236fcc8cfSLorenzo Bianconi { 127336fcc8cfSLorenzo Bianconi struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 127436fcc8cfSLorenzo Bianconi int rssi = -ewma_rssi_read(&mvif->rssi); 127536fcc8cfSLorenzo Bianconi struct mt76_sta_cmd_info info = { 127636fcc8cfSLorenzo Bianconi .sta = sta, 127736fcc8cfSLorenzo Bianconi .vif = vif, 127836fcc8cfSLorenzo Bianconi .enable = enable, 127936fcc8cfSLorenzo Bianconi .cmd = MCU_UNI_CMD_STA_REC_UPDATE, 128082453b1cSLorenzo Bianconi .offload_fw = true, 128136fcc8cfSLorenzo Bianconi .rcpi = to_rcpi(rssi), 128236fcc8cfSLorenzo Bianconi }; 128336fcc8cfSLorenzo Bianconi struct mt7921_sta *msta; 128436fcc8cfSLorenzo Bianconi 128536fcc8cfSLorenzo Bianconi msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL; 128636fcc8cfSLorenzo Bianconi info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; 128736fcc8cfSLorenzo Bianconi 128836fcc8cfSLorenzo Bianconi return mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info); 128936fcc8cfSLorenzo Bianconi } 129036fcc8cfSLorenzo Bianconi 12917bf0a71eSSean Wang int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) 12921d8efc74SSean Wang { 12931d8efc74SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 129436873246SLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm; 1295fad90e43SLorenzo Bianconi int i, err = 0; 12961d8efc74SSean Wang 12971d8efc74SSean Wang for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { 12981d8efc74SSean Wang mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); 12991d8efc74SSean Wang if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, 13001d8efc74SSean Wang PCIE_LPCR_HOST_OWN_SYNC, 0, 50)) 13011d8efc74SSean Wang break; 13021d8efc74SSean Wang } 13031d8efc74SSean Wang 13041d8efc74SSean Wang if (i == MT7921_DRV_OWN_RETRY_COUNT) { 13051d8efc74SSean Wang dev_err(dev->mt76.dev, "driver own failed\n"); 1306fad90e43SLorenzo Bianconi err = -EIO; 1307fad90e43SLorenzo Bianconi goto out; 13081d8efc74SSean Wang } 13093df93214SLorenzo Bianconi 13103df93214SLorenzo Bianconi mt7921_wpdma_reinit_cond(dev); 1311fad90e43SLorenzo Bianconi clear_bit(MT76_STATE_PM, &mphy->state); 13121d8efc74SSean Wang 131336873246SLorenzo Bianconi pm->stats.last_wake_event = jiffies; 131436873246SLorenzo Bianconi pm->stats.doze_time += pm->stats.last_wake_event - 131536873246SLorenzo Bianconi pm->stats.last_doze_event; 13161d8efc74SSean Wang out: 13177bf0a71eSSean Wang return err; 13187bf0a71eSSean Wang } 13197bf0a71eSSean Wang 13207bf0a71eSSean Wang int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) 13217bf0a71eSSean Wang { 13227bf0a71eSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 13237bf0a71eSSean Wang struct mt76_connac_pm *pm = &dev->pm; 13247bf0a71eSSean Wang int err = 0; 13257bf0a71eSSean Wang 13267bf0a71eSSean Wang mutex_lock(&pm->mutex); 13277bf0a71eSSean Wang 13287bf0a71eSSean Wang if (!test_bit(MT76_STATE_PM, &mphy->state)) 13297bf0a71eSSean Wang goto out; 13307bf0a71eSSean Wang 13317bf0a71eSSean Wang err = __mt7921_mcu_drv_pmctrl(dev); 13327bf0a71eSSean Wang out: 133336873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 13341d8efc74SSean Wang 1335fad90e43SLorenzo Bianconi if (err) 1336fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 1337fad90e43SLorenzo Bianconi 1338fad90e43SLorenzo Bianconi return err; 13391d8efc74SSean Wang } 13401d8efc74SSean Wang 13411d8efc74SSean Wang int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev) 13421d8efc74SSean Wang { 13431d8efc74SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 134436873246SLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm; 1345fad90e43SLorenzo Bianconi int i, err = 0; 1346fad90e43SLorenzo Bianconi 134736873246SLorenzo Bianconi mutex_lock(&pm->mutex); 13481d8efc74SSean Wang 134936873246SLorenzo Bianconi if (mt76_connac_skip_fw_pmctrl(mphy, pm)) 1350fad90e43SLorenzo Bianconi goto out; 13511d8efc74SSean Wang 13521d8efc74SSean Wang for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { 13531d8efc74SSean Wang mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); 13541d8efc74SSean Wang if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, 13551d8efc74SSean Wang PCIE_LPCR_HOST_OWN_SYNC, 4, 50)) 13561d8efc74SSean Wang break; 13571d8efc74SSean Wang } 13581d8efc74SSean Wang 13591d8efc74SSean Wang if (i == MT7921_DRV_OWN_RETRY_COUNT) { 13601d8efc74SSean Wang dev_err(dev->mt76.dev, "firmware own failed\n"); 1361fad90e43SLorenzo Bianconi clear_bit(MT76_STATE_PM, &mphy->state); 1362fad90e43SLorenzo Bianconi err = -EIO; 13631d8efc74SSean Wang } 136436873246SLorenzo Bianconi 136536873246SLorenzo Bianconi pm->stats.last_doze_event = jiffies; 136636873246SLorenzo Bianconi pm->stats.awake_time += pm->stats.last_doze_event - 136736873246SLorenzo Bianconi pm->stats.last_wake_event; 1368fad90e43SLorenzo Bianconi out: 136936873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 13701d8efc74SSean Wang 1371fad90e43SLorenzo Bianconi if (err) 1372fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 1373fad90e43SLorenzo Bianconi 1374fad90e43SLorenzo Bianconi return err; 13751d8efc74SSean Wang } 13761d8efc74SSean Wang 13771d8efc74SSean Wang void 13781d8efc74SSean Wang mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) 13791d8efc74SSean Wang { 13801d8efc74SSean Wang struct mt7921_phy *phy = priv; 13811d8efc74SSean Wang struct mt7921_dev *dev = phy->dev; 138210de032aSSean Wang struct ieee80211_hw *hw = mt76_hw(dev); 1383159f6dd6SSean Wang int ret; 13841d8efc74SSean Wang 1385159f6dd6SSean Wang if (dev->pm.enable) 1386159f6dd6SSean Wang ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true); 1387159f6dd6SSean Wang else 1388159f6dd6SSean Wang ret = mt7921_mcu_set_bss_pm(dev, vif, false); 1389159f6dd6SSean Wang 1390159f6dd6SSean Wang if (ret) 13911d8efc74SSean Wang return; 13921d8efc74SSean Wang 13931d8efc74SSean Wang if (dev->pm.enable) { 13941d8efc74SSean Wang vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; 139510de032aSSean Wang ieee80211_hw_set(hw, CONNECTION_MONITOR); 13961d8efc74SSean Wang mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); 13971d8efc74SSean Wang } else { 13981d8efc74SSean Wang vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; 139910de032aSSean Wang __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); 14001d8efc74SSean Wang mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); 14011d8efc74SSean Wang } 14021d8efc74SSean Wang } 14039c9d8321SSean Wang 1404ea29acc9SSean Wang int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr) 1405ea29acc9SSean Wang { 1406ea29acc9SSean Wang struct mt7921_txpwr_event *event; 1407ea29acc9SSean Wang struct mt7921_txpwr_req req = { 1408ea29acc9SSean Wang .dbdc_idx = 0, 1409ea29acc9SSean Wang }; 1410ea29acc9SSean Wang struct sk_buff *skb; 1411ea29acc9SSean Wang int ret; 1412ea29acc9SSean Wang 1413ea29acc9SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_TXPWR, 1414ea29acc9SSean Wang &req, sizeof(req), true, &skb); 1415ea29acc9SSean Wang if (ret) 1416ea29acc9SSean Wang return ret; 1417ea29acc9SSean Wang 1418ea29acc9SSean Wang event = (struct mt7921_txpwr_event *)skb->data; 1419ea29acc9SSean Wang WARN_ON(skb->len != le16_to_cpu(event->len)); 1420ea29acc9SSean Wang memcpy(txpwr, &event->txpwr, sizeof(event->txpwr)); 1421ea29acc9SSean Wang 1422ea29acc9SSean Wang dev_kfree_skb(skb); 1423ea29acc9SSean Wang 1424ea29acc9SSean Wang return 0; 1425ea29acc9SSean Wang } 1426