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 8568808872SDeren Wu #define PATCH_SEC_NOT_SUPPORT GENMASK(31, 0) 861c099ab4SSean Wang #define PATCH_SEC_TYPE_MASK GENMASK(15, 0) 871c099ab4SSean Wang #define PATCH_SEC_TYPE_INFO 0x2 881c099ab4SSean Wang 8968808872SDeren Wu #define PATCH_SEC_ENC_TYPE_MASK GENMASK(31, 24) 9068808872SDeren Wu #define PATCH_SEC_ENC_TYPE_PLAIN 0x00 9168808872SDeren Wu #define PATCH_SEC_ENC_TYPE_AES 0x01 9268808872SDeren Wu #define PATCH_SEC_ENC_TYPE_SCRAMBLE 0x02 9368808872SDeren Wu #define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0) 9468808872SDeren Wu #define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0) 9568808872SDeren Wu 961c099ab4SSean Wang #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) 971c099ab4SSean Wang #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) 981c099ab4SSean Wang 99c368362cSRyder Lee static enum mcu_cipher_type 1001c099ab4SSean Wang mt7921_mcu_get_cipher(int cipher) 1011c099ab4SSean Wang { 1021c099ab4SSean Wang switch (cipher) { 1031c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP40: 104c368362cSRyder Lee return MCU_CIPHER_WEP40; 1051c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP104: 106c368362cSRyder Lee return MCU_CIPHER_WEP104; 1071c099ab4SSean Wang case WLAN_CIPHER_SUITE_TKIP: 108c368362cSRyder Lee return MCU_CIPHER_TKIP; 1091c099ab4SSean Wang case WLAN_CIPHER_SUITE_AES_CMAC: 110c368362cSRyder Lee return MCU_CIPHER_BIP_CMAC_128; 1111c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP: 112c368362cSRyder Lee return MCU_CIPHER_AES_CCMP; 1131c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP_256: 114c368362cSRyder Lee return MCU_CIPHER_CCMP_256; 1151c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP: 116c368362cSRyder Lee return MCU_CIPHER_GCMP; 1171c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP_256: 118c368362cSRyder Lee return MCU_CIPHER_GCMP_256; 1191c099ab4SSean Wang case WLAN_CIPHER_SUITE_SMS4: 120c368362cSRyder Lee return MCU_CIPHER_WAPI; 1211c099ab4SSean Wang default: 122abf3d98dSArnd Bergmann return MCU_CIPHER_NONE; 1231c099ab4SSean Wang } 1241c099ab4SSean Wang } 1251c099ab4SSean Wang 1261c099ab4SSean Wang static u8 mt7921_mcu_chan_bw(struct cfg80211_chan_def *chandef) 1271c099ab4SSean Wang { 1281c099ab4SSean Wang static const u8 width_to_bw[] = { 1291c099ab4SSean Wang [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, 1301c099ab4SSean Wang [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, 1311c099ab4SSean Wang [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, 1321c099ab4SSean Wang [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, 1331c099ab4SSean Wang [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, 1341c099ab4SSean Wang [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, 1351c099ab4SSean Wang [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, 1361c099ab4SSean Wang [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, 1371c099ab4SSean Wang }; 1381c099ab4SSean Wang 1391c099ab4SSean Wang if (chandef->width >= ARRAY_SIZE(width_to_bw)) 1401c099ab4SSean Wang return 0; 1411c099ab4SSean Wang 1421c099ab4SSean Wang return width_to_bw[chandef->width]; 1431c099ab4SSean Wang } 1441c099ab4SSean Wang 1451c099ab4SSean Wang static int 1461c099ab4SSean Wang mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) 1471c099ab4SSean Wang { 1481c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 1491c099ab4SSean Wang u8 *buf; 1501c099ab4SSean Wang 1511c099ab4SSean Wang if (!skb) 1521c099ab4SSean Wang return -EINVAL; 1531c099ab4SSean Wang 1541c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 1551c099ab4SSean Wang 1561c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 1571c099ab4SSean Wang buf = dev->eeprom.data + le32_to_cpu(res->addr); 1581c099ab4SSean Wang memcpy(buf, res->data, 16); 1591c099ab4SSean Wang 1601c099ab4SSean Wang return 0; 1611c099ab4SSean Wang } 1621c099ab4SSean Wang 1631c099ab4SSean Wang static int 1641c099ab4SSean Wang mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, 1651c099ab4SSean Wang struct sk_buff *skb, int seq) 1661c099ab4SSean Wang { 1671c099ab4SSean Wang struct mt7921_mcu_rxd *rxd; 168cd3f3873SDeren Wu int mcu_cmd = cmd & MCU_CMD_MASK; 1691c099ab4SSean Wang int ret = 0; 1701c099ab4SSean Wang 1711c099ab4SSean Wang if (!skb) { 17253d35b1aSLorenzo Bianconi dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", 1731c099ab4SSean Wang cmd, seq); 174d43b3257SLorenzo Bianconi mt7921_reset(mdev); 175d43b3257SLorenzo Bianconi 1761c099ab4SSean Wang return -ETIMEDOUT; 1771c099ab4SSean Wang } 1781c099ab4SSean Wang 1791c099ab4SSean Wang rxd = (struct mt7921_mcu_rxd *)skb->data; 1801c099ab4SSean Wang if (seq != rxd->seq) 1811c099ab4SSean Wang return -EAGAIN; 1821c099ab4SSean Wang 1831c099ab4SSean Wang switch (cmd) { 1841c099ab4SSean Wang case MCU_CMD_PATCH_SEM_CONTROL: 1851c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) - 4); 1861c099ab4SSean Wang ret = *skb->data; 1871c099ab4SSean Wang break; 18867aa2743SLorenzo Bianconi case MCU_EXT_CMD_GET_TEMP: 1891c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) + 4); 1901c099ab4SSean Wang ret = le32_to_cpu(*(__le32 *)skb->data); 1911c099ab4SSean Wang break; 1921c099ab4SSean Wang case MCU_EXT_CMD_EFUSE_ACCESS: 1931c099ab4SSean Wang ret = mt7921_mcu_parse_eeprom(mdev, skb); 1941c099ab4SSean Wang break; 1951c099ab4SSean Wang case MCU_UNI_CMD_DEV_INFO_UPDATE: 1961c099ab4SSean Wang case MCU_UNI_CMD_BSS_INFO_UPDATE: 1971c099ab4SSean Wang case MCU_UNI_CMD_STA_REC_UPDATE: 1981c099ab4SSean Wang case MCU_UNI_CMD_HIF_CTRL: 1991c099ab4SSean Wang case MCU_UNI_CMD_OFFLOAD: 2001c099ab4SSean Wang case MCU_UNI_CMD_SUSPEND: { 2011c099ab4SSean Wang struct mt7921_mcu_uni_event *event; 2021c099ab4SSean Wang 2031c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 2041c099ab4SSean Wang event = (struct mt7921_mcu_uni_event *)skb->data; 2051c099ab4SSean Wang ret = le32_to_cpu(event->status); 206cd3f3873SDeren Wu /* skip invalid event */ 207cd3f3873SDeren Wu if (mcu_cmd != event->cid) 208cd3f3873SDeren Wu ret = -EAGAIN; 2091c099ab4SSean Wang break; 2101c099ab4SSean Wang } 2111c099ab4SSean Wang case MCU_CMD_REG_READ: { 2121c099ab4SSean Wang struct mt7921_mcu_reg_event *event; 2131c099ab4SSean Wang 2141c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 2151c099ab4SSean Wang event = (struct mt7921_mcu_reg_event *)skb->data; 2161c099ab4SSean Wang ret = (int)le32_to_cpu(event->val); 2171c099ab4SSean Wang break; 2181c099ab4SSean Wang } 2191c099ab4SSean Wang default: 2201c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 2211c099ab4SSean Wang break; 2221c099ab4SSean Wang } 2231c099ab4SSean Wang 2241c099ab4SSean Wang return ret; 2251c099ab4SSean Wang } 2261c099ab4SSean Wang 2271c099ab4SSean Wang static int 2281c099ab4SSean Wang mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 2291c099ab4SSean Wang int cmd, int *wait_seq) 2301c099ab4SSean Wang { 2311c099ab4SSean Wang struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 2321c099ab4SSean Wang int txd_len, mcu_cmd = cmd & MCU_CMD_MASK; 2331c099ab4SSean Wang enum mt76_mcuq_id txq = MT_MCUQ_WM; 2341c099ab4SSean Wang struct mt7921_uni_txd *uni_txd; 2351c099ab4SSean Wang struct mt7921_mcu_txd *mcu_txd; 2361c099ab4SSean Wang __le32 *txd; 2371c099ab4SSean Wang u32 val; 2381c099ab4SSean Wang u8 seq; 2391c099ab4SSean Wang 240a2a6cd54SLorenzo Bianconi switch (cmd) { 241a2a6cd54SLorenzo Bianconi case MCU_UNI_CMD_HIF_CTRL: 242a2a6cd54SLorenzo Bianconi case MCU_UNI_CMD_SUSPEND: 243a2a6cd54SLorenzo Bianconi case MCU_UNI_CMD_OFFLOAD: 244a2a6cd54SLorenzo Bianconi mdev->mcu.timeout = HZ / 3; 245a2a6cd54SLorenzo Bianconi break; 246a2a6cd54SLorenzo Bianconi default: 247a2a6cd54SLorenzo Bianconi mdev->mcu.timeout = 3 * HZ; 248a2a6cd54SLorenzo Bianconi break; 249a2a6cd54SLorenzo Bianconi } 2501c099ab4SSean Wang 2511c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2521c099ab4SSean Wang if (!seq) 2531c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2541c099ab4SSean Wang 2551c099ab4SSean Wang if (cmd == MCU_CMD_FW_SCATTER) { 2561c099ab4SSean Wang txq = MT_MCUQ_FWDL; 2571c099ab4SSean Wang goto exit; 2581c099ab4SSean Wang } 2591c099ab4SSean Wang 2601c099ab4SSean Wang txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd); 2611c099ab4SSean Wang txd = (__le32 *)skb_push(skb, txd_len); 2621c099ab4SSean Wang 2631c099ab4SSean Wang val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | 2641c099ab4SSean Wang FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | 2651c099ab4SSean Wang FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); 2661c099ab4SSean Wang txd[0] = cpu_to_le32(val); 2671c099ab4SSean Wang 2681c099ab4SSean Wang val = MT_TXD1_LONG_FORMAT | 2691c099ab4SSean Wang FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); 2701c099ab4SSean Wang txd[1] = cpu_to_le32(val); 2711c099ab4SSean Wang 2721c099ab4SSean Wang if (cmd & MCU_UNI_PREFIX) { 2731c099ab4SSean Wang uni_txd = (struct mt7921_uni_txd *)txd; 2741c099ab4SSean Wang uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); 2751c099ab4SSean Wang uni_txd->option = MCU_CMD_UNI_EXT_ACK; 2761c099ab4SSean Wang uni_txd->cid = cpu_to_le16(mcu_cmd); 2771c099ab4SSean Wang uni_txd->s2d_index = MCU_S2D_H2N; 2781c099ab4SSean Wang uni_txd->pkt_type = MCU_PKT_ID; 2791c099ab4SSean Wang uni_txd->seq = seq; 2801c099ab4SSean Wang 2811c099ab4SSean Wang goto exit; 2821c099ab4SSean Wang } 2831c099ab4SSean Wang 2841c099ab4SSean Wang mcu_txd = (struct mt7921_mcu_txd *)txd; 2851c099ab4SSean Wang mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); 2861c099ab4SSean Wang mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, 2871c099ab4SSean Wang MT_TX_MCU_PORT_RX_Q0)); 2881c099ab4SSean Wang mcu_txd->pkt_type = MCU_PKT_ID; 2891c099ab4SSean Wang mcu_txd->seq = seq; 2901c099ab4SSean Wang 2911c099ab4SSean Wang switch (cmd & ~MCU_CMD_MASK) { 2921c099ab4SSean Wang case MCU_FW_PREFIX: 2931c099ab4SSean Wang mcu_txd->set_query = MCU_Q_NA; 2941c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 2951c099ab4SSean Wang break; 2961c099ab4SSean Wang case MCU_CE_PREFIX: 2971c099ab4SSean Wang if (cmd & MCU_QUERY_MASK) 2981c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 2991c099ab4SSean Wang else 3001c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 3011c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 3021c099ab4SSean Wang break; 3031c099ab4SSean Wang default: 3041c099ab4SSean Wang mcu_txd->cid = MCU_CMD_EXT_CID; 3051c099ab4SSean Wang if (cmd & MCU_QUERY_PREFIX || cmd == MCU_EXT_CMD_EFUSE_ACCESS) 3061c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 3071c099ab4SSean Wang else 3081c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 3091c099ab4SSean Wang mcu_txd->ext_cid = mcu_cmd; 3101c099ab4SSean Wang mcu_txd->ext_cid_ack = 1; 3111c099ab4SSean Wang break; 3121c099ab4SSean Wang } 3131c099ab4SSean Wang 3141c099ab4SSean Wang mcu_txd->s2d_index = MCU_S2D_H2N; 3151c099ab4SSean Wang WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && 3161c099ab4SSean Wang mcu_txd->set_query != MCU_Q_QUERY); 3171c099ab4SSean Wang 3181c099ab4SSean Wang exit: 3191c099ab4SSean Wang if (wait_seq) 3201c099ab4SSean Wang *wait_seq = seq; 3211c099ab4SSean Wang 3221c099ab4SSean Wang return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); 3231c099ab4SSean Wang } 3241c099ab4SSean Wang 3251c099ab4SSean Wang static void 3261c099ab4SSean Wang mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) 3271c099ab4SSean Wang { 3281c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 3291c099ab4SSean Wang struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; 3301c099ab4SSean Wang 3311c099ab4SSean Wang spin_lock_bh(&dev->mt76.lock); 3321c099ab4SSean Wang __skb_queue_tail(&phy->scan_event_list, skb); 3331c099ab4SSean Wang spin_unlock_bh(&dev->mt76.lock); 3341c099ab4SSean Wang 3351c099ab4SSean Wang ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, 3361c099ab4SSean Wang MT7921_HW_SCAN_TIMEOUT); 3371c099ab4SSean Wang } 3381c099ab4SSean Wang 3391c099ab4SSean Wang static void 34010de032aSSean Wang mt7921_mcu_connection_loss_iter(void *priv, u8 *mac, 34110de032aSSean Wang struct ieee80211_vif *vif) 34210de032aSSean Wang { 34310de032aSSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 34410de032aSSean Wang struct mt76_connac_beacon_loss_event *event = priv; 34510de032aSSean Wang 34610de032aSSean Wang if (mvif->idx != event->bss_idx) 34710de032aSSean Wang return; 34810de032aSSean Wang 34910de032aSSean Wang if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) 35010de032aSSean Wang return; 35110de032aSSean Wang 35210de032aSSean Wang ieee80211_connection_loss(vif); 35310de032aSSean Wang } 35410de032aSSean Wang 35510de032aSSean Wang static void 35610de032aSSean Wang mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) 357b88f5c64SSean Wang { 35867aa2743SLorenzo Bianconi struct mt76_connac_beacon_loss_event *event; 35910de032aSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 360b88f5c64SSean Wang 361b88f5c64SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 36267aa2743SLorenzo Bianconi event = (struct mt76_connac_beacon_loss_event *)skb->data; 363b88f5c64SSean Wang 364b88f5c64SSean Wang ieee80211_iterate_active_interfaces_atomic(mphy->hw, 365b88f5c64SSean Wang IEEE80211_IFACE_ITER_RESUME_ALL, 36610de032aSSean Wang mt7921_mcu_connection_loss_iter, event); 367b88f5c64SSean Wang } 368b88f5c64SSean Wang 369b88f5c64SSean Wang static void 3701c099ab4SSean Wang mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb) 3711c099ab4SSean Wang { 3721c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 37367aa2743SLorenzo Bianconi struct mt76_connac_mcu_bss_event *event; 3741c099ab4SSean Wang 37567aa2743SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 37667aa2743SLorenzo Bianconi event = (struct mt76_connac_mcu_bss_event *)skb->data; 3771c099ab4SSean Wang if (event->is_absent) 3781c099ab4SSean Wang ieee80211_stop_queues(mphy->hw); 3791c099ab4SSean Wang else 3801c099ab4SSean Wang ieee80211_wake_queues(mphy->hw); 3811c099ab4SSean Wang } 3821c099ab4SSean Wang 3831c099ab4SSean Wang static void 3841c099ab4SSean Wang mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) 3851c099ab4SSean Wang { 386c7cc5ec5SLorenzo Bianconi struct mt7921_debug_msg { 3871c099ab4SSean Wang __le16 id; 3881c099ab4SSean Wang u8 type; 3891c099ab4SSean Wang u8 flag; 3901c099ab4SSean Wang __le32 value; 3911c099ab4SSean Wang __le16 len; 3921c099ab4SSean Wang u8 content[512]; 393c7cc5ec5SLorenzo Bianconi } __packed * msg; 394c7cc5ec5SLorenzo Bianconi 395c7cc5ec5SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 396c7cc5ec5SLorenzo Bianconi msg = (struct mt7921_debug_msg *)skb->data; 397c7cc5ec5SLorenzo Bianconi 398c7cc5ec5SLorenzo Bianconi if (msg->type == 3) { /* fw log */ 399c7cc5ec5SLorenzo Bianconi u16 len = min_t(u16, le16_to_cpu(msg->len), 512); 4001c099ab4SSean Wang int i; 4011c099ab4SSean Wang 402c7cc5ec5SLorenzo Bianconi for (i = 0 ; i < len; i++) { 403c7cc5ec5SLorenzo Bianconi if (!msg->content[i]) 404c7cc5ec5SLorenzo Bianconi msg->content[i] = ' '; 405c7cc5ec5SLorenzo Bianconi } 4062bf301bcSDan Carpenter wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content); 4071c099ab4SSean Wang } 4081c099ab4SSean Wang } 4091c099ab4SSean Wang 4101c099ab4SSean Wang static void 4112afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) 4122afd17b4SLorenzo Bianconi { 4132afd17b4SLorenzo Bianconi struct mt7921_mcu_lp_event { 4142afd17b4SLorenzo Bianconi u8 state; 4152afd17b4SLorenzo Bianconi u8 reserved[3]; 4162afd17b4SLorenzo Bianconi } __packed * event; 4172afd17b4SLorenzo Bianconi 4182afd17b4SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 4192afd17b4SLorenzo Bianconi event = (struct mt7921_mcu_lp_event *)skb->data; 4202afd17b4SLorenzo Bianconi 4212afd17b4SLorenzo Bianconi trace_lp_event(dev, event->state); 4222afd17b4SLorenzo Bianconi } 4232afd17b4SLorenzo Bianconi 4242afd17b4SLorenzo Bianconi static void 4251c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) 4261c099ab4SSean Wang { 4271c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 4281c099ab4SSean Wang 4291c099ab4SSean Wang switch (rxd->eid) { 4301c099ab4SSean Wang case MCU_EVENT_BSS_BEACON_LOSS: 43110de032aSSean Wang mt7921_mcu_connection_loss_event(dev, skb); 4321c099ab4SSean Wang break; 4331c099ab4SSean Wang case MCU_EVENT_SCHED_SCAN_DONE: 4341c099ab4SSean Wang case MCU_EVENT_SCAN_DONE: 4351c099ab4SSean Wang mt7921_mcu_scan_event(dev, skb); 4361c099ab4SSean Wang return; 4371c099ab4SSean Wang case MCU_EVENT_BSS_ABSENCE: 4381c099ab4SSean Wang mt7921_mcu_bss_event(dev, skb); 4391c099ab4SSean Wang break; 4401c099ab4SSean Wang case MCU_EVENT_DBG_MSG: 4411c099ab4SSean Wang mt7921_mcu_debug_msg_event(dev, skb); 4421c099ab4SSean Wang break; 4430da3c795SSean Wang case MCU_EVENT_COREDUMP: 4440da3c795SSean Wang mt76_connac_mcu_coredump_event(&dev->mt76, skb, 4450da3c795SSean Wang &dev->coredump); 4460da3c795SSean Wang return; 4472afd17b4SLorenzo Bianconi case MCU_EVENT_LP_INFO: 4482afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(dev, skb); 4492afd17b4SLorenzo Bianconi break; 4501c099ab4SSean Wang default: 4511c099ab4SSean Wang break; 4521c099ab4SSean Wang } 4531c099ab4SSean Wang dev_kfree_skb(skb); 4541c099ab4SSean Wang } 4551c099ab4SSean Wang 4561c099ab4SSean Wang void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) 4571c099ab4SSean Wang { 4581c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 4591c099ab4SSean Wang 4601c099ab4SSean Wang if (rxd->eid == 0x6) { 4611c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 4621c099ab4SSean Wang return; 4631c099ab4SSean Wang } 4641c099ab4SSean Wang 4651c099ab4SSean Wang if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || 4661c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || 4671c099ab4SSean Wang rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || 4681c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_ABSENCE || 4691c099ab4SSean Wang rxd->eid == MCU_EVENT_SCAN_DONE || 4703cce2b98SDeren Wu rxd->eid == MCU_EVENT_TX_DONE || 4711c099ab4SSean Wang rxd->eid == MCU_EVENT_DBG_MSG || 4720da3c795SSean Wang rxd->eid == MCU_EVENT_COREDUMP || 4732afd17b4SLorenzo Bianconi rxd->eid == MCU_EVENT_LP_INFO || 4741c099ab4SSean Wang !rxd->seq) 4751c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(dev, skb); 4761c099ab4SSean Wang else 4771c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 4781c099ab4SSean Wang } 4791c099ab4SSean Wang 4801c099ab4SSean Wang /** starec & wtbl **/ 4811c099ab4SSean Wang static int 4821c099ab4SSean Wang mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, 4831c099ab4SSean Wang struct ieee80211_key_conf *key, enum set_key_cmd cmd) 4841c099ab4SSean Wang { 4851c099ab4SSean Wang struct mt7921_sta_key_conf *bip = &msta->bip; 4861c099ab4SSean Wang struct sta_rec_sec *sec; 4871c099ab4SSean Wang struct tlv *tlv; 4881c099ab4SSean Wang u32 len = sizeof(*sec); 4891c099ab4SSean Wang 49067aa2743SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); 4911c099ab4SSean Wang 4921c099ab4SSean Wang sec = (struct sta_rec_sec *)tlv; 4931c099ab4SSean Wang sec->add = cmd; 4941c099ab4SSean Wang 4951c099ab4SSean Wang if (cmd == SET_KEY) { 4961c099ab4SSean Wang struct sec_key *sec_key; 4971c099ab4SSean Wang u8 cipher; 4981c099ab4SSean Wang 4991c099ab4SSean Wang cipher = mt7921_mcu_get_cipher(key->cipher); 500adedbc64SSean Wang if (cipher == MCU_CIPHER_NONE) 5011c099ab4SSean Wang return -EOPNOTSUPP; 5021c099ab4SSean Wang 5031c099ab4SSean Wang sec_key = &sec->key[0]; 5041c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 5051c099ab4SSean Wang 506c368362cSRyder Lee if (cipher == MCU_CIPHER_BIP_CMAC_128) { 507c368362cSRyder Lee sec_key->cipher_id = MCU_CIPHER_AES_CCMP; 5081c099ab4SSean Wang sec_key->key_id = bip->keyidx; 5091c099ab4SSean Wang sec_key->key_len = 16; 5101c099ab4SSean Wang memcpy(sec_key->key, bip->key, 16); 5111c099ab4SSean Wang 5121c099ab4SSean Wang sec_key = &sec->key[1]; 513c368362cSRyder Lee sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; 5141c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 5151c099ab4SSean Wang sec_key->key_len = 16; 5161c099ab4SSean Wang memcpy(sec_key->key, key->key, 16); 5171c099ab4SSean Wang 5181c099ab4SSean Wang sec->n_cipher = 2; 5191c099ab4SSean Wang } else { 5201c099ab4SSean Wang sec_key->cipher_id = cipher; 5211c099ab4SSean Wang sec_key->key_id = key->keyidx; 5221c099ab4SSean Wang sec_key->key_len = key->keylen; 5231c099ab4SSean Wang memcpy(sec_key->key, key->key, key->keylen); 5241c099ab4SSean Wang 525c368362cSRyder Lee if (cipher == MCU_CIPHER_TKIP) { 5261c099ab4SSean Wang /* Rx/Tx MIC keys are swapped */ 5271c099ab4SSean Wang memcpy(sec_key->key + 16, key->key + 24, 8); 5281c099ab4SSean Wang memcpy(sec_key->key + 24, key->key + 16, 8); 5291c099ab4SSean Wang } 5301c099ab4SSean Wang 5311c099ab4SSean Wang /* store key_conf for BIP batch update */ 532c368362cSRyder Lee if (cipher == MCU_CIPHER_AES_CCMP) { 5331c099ab4SSean Wang memcpy(bip->key, key->key, key->keylen); 5341c099ab4SSean Wang bip->keyidx = key->keyidx; 5351c099ab4SSean Wang } 5361c099ab4SSean Wang 5371c099ab4SSean Wang len -= sizeof(*sec_key); 5381c099ab4SSean Wang sec->n_cipher = 1; 5391c099ab4SSean Wang } 5401c099ab4SSean Wang } else { 5411c099ab4SSean Wang len -= sizeof(sec->key); 5421c099ab4SSean Wang sec->n_cipher = 0; 5431c099ab4SSean Wang } 5441c099ab4SSean Wang sec->len = cpu_to_le16(len); 5451c099ab4SSean Wang 5461c099ab4SSean Wang return 0; 5471c099ab4SSean Wang } 5481c099ab4SSean Wang 5491c099ab4SSean Wang int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, 5501c099ab4SSean Wang struct mt7921_sta *msta, struct ieee80211_key_conf *key, 5511c099ab4SSean Wang enum set_key_cmd cmd) 5521c099ab4SSean Wang { 5531c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 5541c099ab4SSean Wang struct sk_buff *skb; 5551c099ab4SSean Wang int ret; 5561c099ab4SSean Wang 55767aa2743SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 55867aa2743SLorenzo Bianconi &msta->wcid); 5591c099ab4SSean Wang if (IS_ERR(skb)) 5601c099ab4SSean Wang return PTR_ERR(skb); 5611c099ab4SSean Wang 5621c099ab4SSean Wang ret = mt7921_mcu_sta_key_tlv(msta, skb, key, cmd); 5631c099ab4SSean Wang if (ret) 5641c099ab4SSean Wang return ret; 5651c099ab4SSean Wang 5661c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, 5671c099ab4SSean Wang MCU_UNI_CMD_STA_REC_UPDATE, true); 5681c099ab4SSean Wang } 5691c099ab4SSean Wang 5701c099ab4SSean Wang int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, 5711c099ab4SSean Wang struct ieee80211_ampdu_params *params, 5721c099ab4SSean Wang bool enable) 5731c099ab4SSean Wang { 57467aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 57567aa2743SLorenzo Bianconi 57667aa2743SLorenzo Bianconi if (enable && !params->amsdu) 57767aa2743SLorenzo Bianconi msta->wcid.amsdu = false; 57867aa2743SLorenzo Bianconi 57967aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 58067aa2743SLorenzo Bianconi enable, true); 5811c099ab4SSean Wang } 5821c099ab4SSean Wang 5831c099ab4SSean Wang int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, 5841c099ab4SSean Wang struct ieee80211_ampdu_params *params, 5851c099ab4SSean Wang bool enable) 5861c099ab4SSean Wang { 58767aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 5881c099ab4SSean Wang 58967aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 59067aa2743SLorenzo Bianconi enable, false); 5911c099ab4SSean Wang } 5921c099ab4SSean Wang 5931c099ab4SSean Wang static int mt7921_mcu_restart(struct mt76_dev *dev) 5941c099ab4SSean Wang { 5951c099ab4SSean Wang struct { 5961c099ab4SSean Wang u8 power_mode; 5971c099ab4SSean Wang u8 rsv[3]; 5981c099ab4SSean Wang } req = { 5991c099ab4SSean Wang .power_mode = 1, 6001c099ab4SSean Wang }; 6011c099ab4SSean Wang 6021c099ab4SSean Wang return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req, 6031c099ab4SSean Wang sizeof(req), false); 6041c099ab4SSean Wang } 6051c099ab4SSean Wang 6061c099ab4SSean Wang static int mt7921_driver_own(struct mt7921_dev *dev) 6071c099ab4SSean Wang { 6081c099ab4SSean Wang u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 6091c099ab4SSean Wang 6101c099ab4SSean Wang mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); 6111c099ab4SSean Wang if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, 6121c099ab4SSean Wang 0, 500)) { 6131c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for driver own\n"); 6141c099ab4SSean Wang return -EIO; 6151c099ab4SSean Wang } 6161c099ab4SSean Wang 6171c099ab4SSean Wang return 0; 6181c099ab4SSean Wang } 6191c099ab4SSean Wang 62068808872SDeren Wu static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info) 62168808872SDeren Wu { 62268808872SDeren Wu u32 mode = DL_MODE_NEED_RSP; 62368808872SDeren Wu 62468808872SDeren Wu if (info == PATCH_SEC_NOT_SUPPORT) 62568808872SDeren Wu return mode; 62668808872SDeren Wu 62768808872SDeren Wu switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { 62868808872SDeren Wu case PATCH_SEC_ENC_TYPE_PLAIN: 62968808872SDeren Wu break; 63068808872SDeren Wu case PATCH_SEC_ENC_TYPE_AES: 63168808872SDeren Wu mode |= DL_MODE_ENCRYPT; 63268808872SDeren Wu mode |= FIELD_PREP(DL_MODE_KEY_IDX, 63368808872SDeren Wu (info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX; 63468808872SDeren Wu mode |= DL_MODE_RESET_SEC_IV; 63568808872SDeren Wu break; 63668808872SDeren Wu case PATCH_SEC_ENC_TYPE_SCRAMBLE: 63768808872SDeren Wu mode |= DL_MODE_ENCRYPT; 63868808872SDeren Wu mode |= DL_CONFIG_ENCRY_MODE_SEL; 63968808872SDeren Wu mode |= DL_MODE_RESET_SEC_IV; 64068808872SDeren Wu break; 64168808872SDeren Wu default: 64268808872SDeren Wu dev_err(dev->mt76.dev, "Encryption type not support!\n"); 64368808872SDeren Wu } 64468808872SDeren Wu 64568808872SDeren Wu return mode; 64668808872SDeren Wu } 64768808872SDeren Wu 64868808872SDeren Wu static char *mt7921_patch_name(struct mt7921_dev *dev) 64968808872SDeren Wu { 65068808872SDeren Wu char *ret; 65168808872SDeren Wu 65268808872SDeren Wu if (is_mt7922(&dev->mt76)) 65368808872SDeren Wu ret = MT7922_ROM_PATCH; 65468808872SDeren Wu else 65568808872SDeren Wu ret = MT7921_ROM_PATCH; 65668808872SDeren Wu 65768808872SDeren Wu return ret; 65868808872SDeren Wu } 65968808872SDeren Wu 6601c099ab4SSean Wang static int mt7921_load_patch(struct mt7921_dev *dev) 6611c099ab4SSean Wang { 6621c099ab4SSean Wang const struct mt7921_patch_hdr *hdr; 6631c099ab4SSean Wang const struct firmware *fw = NULL; 6641c099ab4SSean Wang int i, ret, sem; 6651c099ab4SSean Wang 66667aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); 6671c099ab4SSean Wang switch (sem) { 6681c099ab4SSean Wang case PATCH_IS_DL: 6691c099ab4SSean Wang return 0; 6701c099ab4SSean Wang case PATCH_NOT_DL_SEM_SUCCESS: 6711c099ab4SSean Wang break; 6721c099ab4SSean Wang default: 6731c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); 6741c099ab4SSean Wang return -EAGAIN; 6751c099ab4SSean Wang } 6761c099ab4SSean Wang 67768808872SDeren Wu ret = request_firmware(&fw, mt7921_patch_name(dev), dev->mt76.dev); 6781c099ab4SSean Wang if (ret) 6791c099ab4SSean Wang goto out; 6801c099ab4SSean Wang 6811c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 6821c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 6831c099ab4SSean Wang ret = -EINVAL; 6841c099ab4SSean Wang goto out; 6851c099ab4SSean Wang } 6861c099ab4SSean Wang 6871c099ab4SSean Wang hdr = (const struct mt7921_patch_hdr *)(fw->data); 6881c099ab4SSean Wang 6891c099ab4SSean Wang dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", 6901c099ab4SSean Wang be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); 6911c099ab4SSean Wang 6921c099ab4SSean Wang for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { 6931c099ab4SSean Wang struct mt7921_patch_sec *sec; 6941c099ab4SSean Wang const u8 *dl; 69568808872SDeren Wu u32 len, addr, mode; 69668808872SDeren Wu u32 sec_info = 0; 6971c099ab4SSean Wang 6981c099ab4SSean Wang sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + 6991c099ab4SSean Wang i * sizeof(*sec)); 7001c099ab4SSean Wang if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != 7011c099ab4SSean Wang PATCH_SEC_TYPE_INFO) { 7021c099ab4SSean Wang ret = -EINVAL; 7031c099ab4SSean Wang goto out; 7041c099ab4SSean Wang } 7051c099ab4SSean Wang 7061c099ab4SSean Wang addr = be32_to_cpu(sec->info.addr); 7071c099ab4SSean Wang len = be32_to_cpu(sec->info.len); 7081c099ab4SSean Wang dl = fw->data + be32_to_cpu(sec->offs); 70968808872SDeren Wu sec_info = be32_to_cpu(sec->info.sec_key_idx); 71068808872SDeren Wu mode = mt7921_get_data_mode(dev, sec_info); 7111c099ab4SSean Wang 71267aa2743SLorenzo Bianconi ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 71368808872SDeren Wu mode); 7141c099ab4SSean Wang if (ret) { 7151c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 7161c099ab4SSean Wang goto out; 7171c099ab4SSean Wang } 7181c099ab4SSean Wang 7191c099ab4SSean Wang ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 7201c099ab4SSean Wang dl, len); 7211c099ab4SSean Wang if (ret) { 7221c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send patch\n"); 7231c099ab4SSean Wang goto out; 7241c099ab4SSean Wang } 7251c099ab4SSean Wang } 7261c099ab4SSean Wang 72767aa2743SLorenzo Bianconi ret = mt76_connac_mcu_start_patch(&dev->mt76); 7281c099ab4SSean Wang if (ret) 7291c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start patch\n"); 7301c099ab4SSean Wang 7311c099ab4SSean Wang out: 73267aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); 7331c099ab4SSean Wang switch (sem) { 7341c099ab4SSean Wang case PATCH_REL_SEM_SUCCESS: 7351c099ab4SSean Wang break; 7361c099ab4SSean Wang default: 7371c099ab4SSean Wang ret = -EAGAIN; 7381c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); 739*02d1c7d4SSean Wang break; 7401c099ab4SSean Wang } 7411c099ab4SSean Wang release_firmware(fw); 7421c099ab4SSean Wang 7431c099ab4SSean Wang return ret; 7441c099ab4SSean Wang } 7451c099ab4SSean Wang 7461c099ab4SSean Wang static u32 mt7921_mcu_gen_dl_mode(u8 feature_set, bool is_wa) 7471c099ab4SSean Wang { 7481c099ab4SSean Wang u32 ret = 0; 7491c099ab4SSean Wang 7501c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? 7511c099ab4SSean Wang (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; 7521c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_ENCRY_MODE) ? 7531c099ab4SSean Wang DL_CONFIG_ENCRY_MODE_SEL : 0; 7541c099ab4SSean Wang ret |= FIELD_PREP(DL_MODE_KEY_IDX, 7551c099ab4SSean Wang FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); 7561c099ab4SSean Wang ret |= DL_MODE_NEED_RSP; 7571c099ab4SSean Wang ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; 7581c099ab4SSean Wang 7591c099ab4SSean Wang return ret; 7601c099ab4SSean Wang } 7611c099ab4SSean Wang 7621c099ab4SSean Wang static int 7631c099ab4SSean Wang mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, 7641c099ab4SSean Wang const struct mt7921_fw_trailer *hdr, 7651c099ab4SSean Wang const u8 *data, bool is_wa) 7661c099ab4SSean Wang { 7671c099ab4SSean Wang int i, offset = 0; 7681c099ab4SSean Wang u32 override = 0, option = 0; 7691c099ab4SSean Wang 7701c099ab4SSean Wang for (i = 0; i < hdr->n_region; i++) { 7711c099ab4SSean Wang const struct mt7921_fw_region *region; 7721c099ab4SSean Wang int err; 7731c099ab4SSean Wang u32 len, addr, mode; 7741c099ab4SSean Wang 7751c099ab4SSean Wang region = (const struct mt7921_fw_region *)((const u8 *)hdr - 7761c099ab4SSean Wang (hdr->n_region - i) * sizeof(*region)); 7771c099ab4SSean Wang mode = mt7921_mcu_gen_dl_mode(region->feature_set, is_wa); 7781c099ab4SSean Wang len = le32_to_cpu(region->len); 7791c099ab4SSean Wang addr = le32_to_cpu(region->addr); 7801c099ab4SSean Wang 7811c099ab4SSean Wang if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) 7821c099ab4SSean Wang override = addr; 7831c099ab4SSean Wang 78467aa2743SLorenzo Bianconi err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 78567aa2743SLorenzo Bianconi mode); 7861c099ab4SSean Wang if (err) { 7871c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 7881c099ab4SSean Wang return err; 7891c099ab4SSean Wang } 7901c099ab4SSean Wang 7911c099ab4SSean Wang err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 7921c099ab4SSean Wang data + offset, len); 7931c099ab4SSean Wang if (err) { 7941c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send firmware.\n"); 7951c099ab4SSean Wang return err; 7961c099ab4SSean Wang } 7971c099ab4SSean Wang 7981c099ab4SSean Wang offset += len; 7991c099ab4SSean Wang } 8001c099ab4SSean Wang 8011c099ab4SSean Wang if (override) 8021c099ab4SSean Wang option |= FW_START_OVERRIDE; 8031c099ab4SSean Wang 8041c099ab4SSean Wang if (is_wa) 8051c099ab4SSean Wang option |= FW_START_WORKING_PDA_CR4; 8061c099ab4SSean Wang 80767aa2743SLorenzo Bianconi return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); 8081c099ab4SSean Wang } 8091c099ab4SSean Wang 81068808872SDeren Wu static char *mt7921_ram_name(struct mt7921_dev *dev) 81168808872SDeren Wu { 81268808872SDeren Wu char *ret; 81368808872SDeren Wu 81468808872SDeren Wu if (is_mt7922(&dev->mt76)) 81568808872SDeren Wu ret = MT7922_FIRMWARE_WM; 81668808872SDeren Wu else 81768808872SDeren Wu ret = MT7921_FIRMWARE_WM; 81868808872SDeren Wu 81968808872SDeren Wu return ret; 82068808872SDeren Wu } 82168808872SDeren Wu 8221c099ab4SSean Wang static int mt7921_load_ram(struct mt7921_dev *dev) 8231c099ab4SSean Wang { 8241c099ab4SSean Wang const struct mt7921_fw_trailer *hdr; 8251c099ab4SSean Wang const struct firmware *fw; 8261c099ab4SSean Wang int ret; 8271c099ab4SSean Wang 82868808872SDeren Wu ret = request_firmware(&fw, mt7921_ram_name(dev), dev->mt76.dev); 8291c099ab4SSean Wang if (ret) 8301c099ab4SSean Wang return ret; 8311c099ab4SSean Wang 8321c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 8331c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 8341c099ab4SSean Wang ret = -EINVAL; 8351c099ab4SSean Wang goto out; 8361c099ab4SSean Wang } 8371c099ab4SSean Wang 8381c099ab4SSean Wang hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size - 8391c099ab4SSean Wang sizeof(*hdr)); 8401c099ab4SSean Wang 8411c099ab4SSean Wang dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", 8421c099ab4SSean Wang hdr->fw_ver, hdr->build_date); 8431c099ab4SSean Wang 8441c099ab4SSean Wang ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false); 8451c099ab4SSean Wang if (ret) { 8461c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); 8471c099ab4SSean Wang goto out; 8481c099ab4SSean Wang } 8491c099ab4SSean Wang 8501c099ab4SSean Wang snprintf(dev->mt76.hw->wiphy->fw_version, 8511c099ab4SSean Wang sizeof(dev->mt76.hw->wiphy->fw_version), 8521c099ab4SSean Wang "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 8531c099ab4SSean Wang 8541c099ab4SSean Wang out: 8551c099ab4SSean Wang release_firmware(fw); 8561c099ab4SSean Wang 8571c099ab4SSean Wang return ret; 8581c099ab4SSean Wang } 8591c099ab4SSean Wang 8601c099ab4SSean Wang static int mt7921_load_firmware(struct mt7921_dev *dev) 8611c099ab4SSean Wang { 8621c099ab4SSean Wang int ret; 8631c099ab4SSean Wang 8641c099ab4SSean Wang ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 8651c099ab4SSean Wang if (ret) { 8661c099ab4SSean Wang dev_dbg(dev->mt76.dev, "Firmware is already download\n"); 867c3426904SAaron Ma goto fw_loaded; 8681c099ab4SSean Wang } 8691c099ab4SSean Wang 8701c099ab4SSean Wang ret = mt7921_load_patch(dev); 8711c099ab4SSean Wang if (ret) 8721c099ab4SSean Wang return ret; 8731c099ab4SSean Wang 8741c099ab4SSean Wang ret = mt7921_load_ram(dev); 8751c099ab4SSean Wang if (ret) 8761c099ab4SSean Wang return ret; 8771c099ab4SSean Wang 8781c099ab4SSean Wang if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, 8791c099ab4SSean Wang MT_TOP_MISC2_FW_N9_RDY, 1500)) { 8801c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 8811c099ab4SSean Wang 8821c099ab4SSean Wang return -EIO; 8831c099ab4SSean Wang } 8841c099ab4SSean Wang 885c3426904SAaron Ma fw_loaded: 8861c099ab4SSean Wang mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); 8871c099ab4SSean Wang 888ffa1bf97SSean Wang #ifdef CONFIG_PM 889022159b0SLorenzo Bianconi dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; 890ffa1bf97SSean Wang #endif /* CONFIG_PM */ 891ffa1bf97SSean Wang 8921c099ab4SSean Wang dev_err(dev->mt76.dev, "Firmware init done\n"); 8931c099ab4SSean Wang 8941c099ab4SSean Wang return 0; 8951c099ab4SSean Wang } 8961c099ab4SSean Wang 8971c099ab4SSean Wang int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) 8981c099ab4SSean Wang { 8991c099ab4SSean Wang struct { 9001c099ab4SSean Wang u8 ctrl_val; 9011c099ab4SSean Wang u8 pad[3]; 9021c099ab4SSean Wang } data = { 9031c099ab4SSean Wang .ctrl_val = ctrl 9041c099ab4SSean Wang }; 9051c099ab4SSean Wang 9061c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FWLOG_2_HOST, &data, 9071c099ab4SSean Wang sizeof(data), false); 9081c099ab4SSean Wang } 9091c099ab4SSean Wang 910d32464e6SLorenzo Bianconi int mt7921_run_firmware(struct mt7921_dev *dev) 911d32464e6SLorenzo Bianconi { 912d32464e6SLorenzo Bianconi int err; 913d32464e6SLorenzo Bianconi 914d32464e6SLorenzo Bianconi err = mt7921_driver_own(dev); 915d32464e6SLorenzo Bianconi if (err) 916d32464e6SLorenzo Bianconi return err; 917d32464e6SLorenzo Bianconi 918d32464e6SLorenzo Bianconi err = mt7921_load_firmware(dev); 919d32464e6SLorenzo Bianconi if (err) 920d32464e6SLorenzo Bianconi return err; 921d32464e6SLorenzo Bianconi 922d32464e6SLorenzo Bianconi set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 923d32464e6SLorenzo Bianconi mt7921_mcu_fw_log_2_host(dev, 1); 924d32464e6SLorenzo Bianconi 925f7d2958cSLorenzo Bianconi return mt76_connac_mcu_get_nic_capability(&dev->mphy); 926d32464e6SLorenzo Bianconi } 927d32464e6SLorenzo Bianconi 9281c099ab4SSean Wang int mt7921_mcu_init(struct mt7921_dev *dev) 9291c099ab4SSean Wang { 9301c099ab4SSean Wang static const struct mt76_mcu_ops mt7921_mcu_ops = { 9311c099ab4SSean Wang .headroom = sizeof(struct mt7921_mcu_txd), 9321c099ab4SSean Wang .mcu_skb_send_msg = mt7921_mcu_send_message, 9331c099ab4SSean Wang .mcu_parse_response = mt7921_mcu_parse_response, 9341c099ab4SSean Wang .mcu_restart = mt7921_mcu_restart, 9351c099ab4SSean Wang }; 9361c099ab4SSean Wang 9371c099ab4SSean Wang dev->mt76.mcu_ops = &mt7921_mcu_ops; 9381c099ab4SSean Wang 939d32464e6SLorenzo Bianconi return mt7921_run_firmware(dev); 9401c099ab4SSean Wang } 9411c099ab4SSean Wang 9421c099ab4SSean Wang void mt7921_mcu_exit(struct mt7921_dev *dev) 9431c099ab4SSean Wang { 94449897c52SSean Wang mt7921_wfsys_reset(dev); 9451c099ab4SSean Wang skb_queue_purge(&dev->mt76.mcu.res_q); 9461c099ab4SSean Wang } 9471c099ab4SSean Wang 9481c099ab4SSean Wang int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) 9491c099ab4SSean Wang { 9501c099ab4SSean Wang #define WMM_AIFS_SET BIT(0) 9511c099ab4SSean Wang #define WMM_CW_MIN_SET BIT(1) 9521c099ab4SSean Wang #define WMM_CW_MAX_SET BIT(2) 9531c099ab4SSean Wang #define WMM_TXOP_SET BIT(3) 9541c099ab4SSean Wang #define WMM_PARAM_SET GENMASK(3, 0) 9551c099ab4SSean Wang #define TX_CMD_MODE 1 9561c099ab4SSean Wang struct edca { 9571c099ab4SSean Wang u8 queue; 9581c099ab4SSean Wang u8 set; 9591c099ab4SSean Wang u8 aifs; 9601c099ab4SSean Wang u8 cw_min; 9611c099ab4SSean Wang __le16 cw_max; 9621c099ab4SSean Wang __le16 txop; 9631c099ab4SSean Wang }; 9641c099ab4SSean Wang struct mt7921_mcu_tx { 9651c099ab4SSean Wang u8 total; 9661c099ab4SSean Wang u8 action; 9671c099ab4SSean Wang u8 valid; 9681c099ab4SSean Wang u8 mode; 9691c099ab4SSean Wang 9701c099ab4SSean Wang struct edca edca[IEEE80211_NUM_ACS]; 9711c099ab4SSean Wang } __packed req = { 9721c099ab4SSean Wang .valid = true, 9731c099ab4SSean Wang .mode = TX_CMD_MODE, 9741c099ab4SSean Wang .total = IEEE80211_NUM_ACS, 9751c099ab4SSean Wang }; 9761c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 9771c099ab4SSean Wang int ac; 9781c099ab4SSean Wang 9791c099ab4SSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 9801c099ab4SSean Wang struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 9811c099ab4SSean Wang struct edca *e = &req.edca[ac]; 9821c099ab4SSean Wang 9831c099ab4SSean Wang e->set = WMM_PARAM_SET; 9841c099ab4SSean Wang e->queue = ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS; 9851c099ab4SSean Wang e->aifs = q->aifs; 9861c099ab4SSean Wang e->txop = cpu_to_le16(q->txop); 9871c099ab4SSean Wang 9881c099ab4SSean Wang if (q->cw_min) 9891c099ab4SSean Wang e->cw_min = fls(q->cw_min); 9901c099ab4SSean Wang else 9911c099ab4SSean Wang e->cw_min = 5; 9921c099ab4SSean Wang 9931c099ab4SSean Wang if (q->cw_max) 9941c099ab4SSean Wang e->cw_max = cpu_to_le16(fls(q->cw_max)); 9951c099ab4SSean Wang else 9961c099ab4SSean Wang e->cw_max = cpu_to_le16(10); 9971c099ab4SSean Wang } 9981c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, 9991c099ab4SSean Wang sizeof(req), true); 10001c099ab4SSean Wang } 10011c099ab4SSean Wang 10021c099ab4SSean Wang int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) 10031c099ab4SSean Wang { 10041c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 10051c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 10061c099ab4SSean Wang int freq1 = chandef->center_freq1; 10071c099ab4SSean Wang struct { 10081c099ab4SSean Wang u8 control_ch; 10091c099ab4SSean Wang u8 center_ch; 10101c099ab4SSean Wang u8 bw; 10111c099ab4SSean Wang u8 tx_streams_num; 10121c099ab4SSean Wang u8 rx_streams; /* mask or num */ 10131c099ab4SSean Wang u8 switch_reason; 10141c099ab4SSean Wang u8 band_idx; 10151c099ab4SSean Wang u8 center_ch2; /* for 80+80 only */ 10161c099ab4SSean Wang __le16 cac_case; 10171c099ab4SSean Wang u8 channel_band; 10181c099ab4SSean Wang u8 rsv0; 10191c099ab4SSean Wang __le32 outband_freq; 10201c099ab4SSean Wang u8 txpower_drop; 10211c099ab4SSean Wang u8 ap_bw; 10221c099ab4SSean Wang u8 ap_center_ch; 10231c099ab4SSean Wang u8 rsv1[57]; 10241c099ab4SSean Wang } __packed req = { 10251c099ab4SSean Wang .control_ch = chandef->chan->hw_value, 10261c099ab4SSean Wang .center_ch = ieee80211_frequency_to_channel(freq1), 10271c099ab4SSean Wang .bw = mt7921_mcu_chan_bw(chandef), 10281c099ab4SSean Wang .tx_streams_num = hweight8(phy->mt76->antenna_mask), 10291c099ab4SSean Wang .rx_streams = phy->mt76->antenna_mask, 10301c099ab4SSean Wang .band_idx = phy != &dev->phy, 10311c099ab4SSean Wang .channel_band = chandef->chan->band, 10321c099ab4SSean Wang }; 10331c099ab4SSean Wang 10341c099ab4SSean Wang if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 10351c099ab4SSean Wang req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 10361c099ab4SSean Wang else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 10371c099ab4SSean Wang chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 10381c099ab4SSean Wang req.switch_reason = CH_SWITCH_DFS; 10391c099ab4SSean Wang else 10401c099ab4SSean Wang req.switch_reason = CH_SWITCH_NORMAL; 10411c099ab4SSean Wang 10421c099ab4SSean Wang if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) 10431c099ab4SSean Wang req.rx_streams = hweight8(req.rx_streams); 10441c099ab4SSean Wang 10451c099ab4SSean Wang if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 10461c099ab4SSean Wang int freq2 = chandef->center_freq2; 10471c099ab4SSean Wang 10481c099ab4SSean Wang req.center_ch2 = ieee80211_frequency_to_channel(freq2); 10491c099ab4SSean Wang } 10501c099ab4SSean Wang 10511c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 10521c099ab4SSean Wang } 10531c099ab4SSean Wang 10541c099ab4SSean Wang int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) 10551c099ab4SSean Wang { 10561c099ab4SSean Wang struct req_hdr { 10571c099ab4SSean Wang u8 buffer_mode; 10581c099ab4SSean Wang u8 format; 10591c099ab4SSean Wang __le16 len; 10601c099ab4SSean Wang } __packed req = { 10611c099ab4SSean Wang .buffer_mode = EE_MODE_EFUSE, 10621c099ab4SSean Wang .format = EE_FORMAT_WHOLE, 10631c099ab4SSean Wang }; 10641c099ab4SSean Wang 10651c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 10661c099ab4SSean Wang &req, sizeof(req), true); 10671c099ab4SSean Wang } 10681c099ab4SSean Wang 10691c099ab4SSean Wang int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) 10701c099ab4SSean Wang { 10711c099ab4SSean Wang struct mt7921_mcu_eeprom_info req = { 10721c099ab4SSean Wang .addr = cpu_to_le32(round_down(offset, 16)), 10731c099ab4SSean Wang }; 10741c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 10751c099ab4SSean Wang struct sk_buff *skb; 10761c099ab4SSean Wang int ret; 10771c099ab4SSean Wang u8 *buf; 10781c099ab4SSean Wang 10791c099ab4SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, 10801c099ab4SSean Wang sizeof(req), true, &skb); 10811c099ab4SSean Wang if (ret) 10821c099ab4SSean Wang return ret; 10831c099ab4SSean Wang 10841c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 10851c099ab4SSean Wang buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); 10861c099ab4SSean Wang memcpy(buf, res->data, 16); 10871c099ab4SSean Wang dev_kfree_skb(skb); 10881c099ab4SSean Wang 10891c099ab4SSean Wang return 0; 10901c099ab4SSean Wang } 10911c099ab4SSean Wang 109256d965daSSean Wang int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) 109356d965daSSean Wang { 109456d965daSSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 109556d965daSSean Wang struct { 109656d965daSSean Wang struct { 109756d965daSSean Wang u8 bss_idx; 109856d965daSSean Wang u8 pad[3]; 109956d965daSSean Wang } __packed hdr; 110056d965daSSean Wang struct ps_tlv { 110156d965daSSean Wang __le16 tag; 110256d965daSSean Wang __le16 len; 110356d965daSSean Wang u8 ps_state; /* 0: device awake 110456d965daSSean Wang * 1: static power save 110556d965daSSean Wang * 2: dynamic power saving 110656d965daSSean Wang * 3: enter TWT power saving 110756d965daSSean Wang * 4: leave TWT power saving 110856d965daSSean Wang */ 110956d965daSSean Wang u8 pad[3]; 111056d965daSSean Wang } __packed ps; 111156d965daSSean Wang } __packed ps_req = { 111256d965daSSean Wang .hdr = { 111356d965daSSean Wang .bss_idx = mvif->mt76.idx, 111456d965daSSean Wang }, 111556d965daSSean Wang .ps = { 111656d965daSSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_PS), 111756d965daSSean Wang .len = cpu_to_le16(sizeof(struct ps_tlv)), 111856d965daSSean Wang .ps_state = vif->bss_conf.ps ? 2 : 0, 111956d965daSSean Wang }, 112056d965daSSean Wang }; 112156d965daSSean Wang 112256d965daSSean Wang if (vif->type != NL80211_IFTYPE_STATION) 112356d965daSSean Wang return -EOPNOTSUPP; 112456d965daSSean Wang 112556d965daSSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 112656d965daSSean Wang &ps_req, sizeof(ps_req), true); 112756d965daSSean Wang } 11284086ee28SSean Wang 1129890809caSLorenzo Bianconi static int 1130890809caSLorenzo Bianconi mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, 11314086ee28SSean Wang bool enable) 11324086ee28SSean Wang { 11334086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 11344086ee28SSean Wang struct { 11354086ee28SSean Wang struct { 11364086ee28SSean Wang u8 bss_idx; 11374086ee28SSean Wang u8 pad[3]; 11384086ee28SSean Wang } __packed hdr; 11394086ee28SSean Wang struct bcnft_tlv { 11404086ee28SSean Wang __le16 tag; 11414086ee28SSean Wang __le16 len; 11424086ee28SSean Wang __le16 bcn_interval; 11434086ee28SSean Wang u8 dtim_period; 11444086ee28SSean Wang u8 pad; 11454086ee28SSean Wang } __packed bcnft; 11464086ee28SSean Wang } __packed bcnft_req = { 11474086ee28SSean Wang .hdr = { 11484086ee28SSean Wang .bss_idx = mvif->mt76.idx, 11494086ee28SSean Wang }, 11504086ee28SSean Wang .bcnft = { 11514086ee28SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), 11524086ee28SSean Wang .len = cpu_to_le16(sizeof(struct bcnft_tlv)), 11534086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 11544086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 11554086ee28SSean Wang }, 11564086ee28SSean Wang }; 11574086ee28SSean Wang 11584086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 11594086ee28SSean Wang return 0; 11604086ee28SSean Wang 11614086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 11624086ee28SSean Wang &bcnft_req, sizeof(bcnft_req), true); 11634086ee28SSean Wang } 11644086ee28SSean Wang 1165890809caSLorenzo Bianconi static int 1166890809caSLorenzo Bianconi mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, 11674086ee28SSean Wang bool enable) 11684086ee28SSean Wang { 11694086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 11704086ee28SSean Wang struct { 11714086ee28SSean Wang u8 bss_idx; 11724086ee28SSean Wang u8 dtim_period; 11734086ee28SSean Wang __le16 aid; 11744086ee28SSean Wang __le16 bcn_interval; 11754086ee28SSean Wang __le16 atim_window; 11764086ee28SSean Wang u8 uapsd; 11774086ee28SSean Wang u8 bmc_delivered_ac; 11784086ee28SSean Wang u8 bmc_triggered_ac; 11794086ee28SSean Wang u8 pad; 11804086ee28SSean Wang } req = { 11814086ee28SSean Wang .bss_idx = mvif->mt76.idx, 11824086ee28SSean Wang .aid = cpu_to_le16(vif->bss_conf.aid), 11834086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 11844086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 11854086ee28SSean Wang }; 11864086ee28SSean Wang struct { 11874086ee28SSean Wang u8 bss_idx; 11884086ee28SSean Wang u8 pad[3]; 11894086ee28SSean Wang } req_hdr = { 11904086ee28SSean Wang .bss_idx = mvif->mt76.idx, 11914086ee28SSean Wang }; 11924086ee28SSean Wang int err; 11934086ee28SSean Wang 11944086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 11954086ee28SSean Wang return 0; 11964086ee28SSean Wang 11974086ee28SSean Wang err = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, &req_hdr, 11984086ee28SSean Wang sizeof(req_hdr), false); 11994086ee28SSean Wang if (err < 0 || !enable) 12004086ee28SSean Wang return err; 12014086ee28SSean Wang 12024086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, &req, 12034086ee28SSean Wang sizeof(req), false); 12044086ee28SSean Wang } 12051d8efc74SSean Wang 1206f5056657SSean Wang int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, 1207f5056657SSean Wang struct ieee80211_vif *vif, bool enable, 1208f5056657SSean Wang enum mt76_sta_info_state state) 120936fcc8cfSLorenzo Bianconi { 121036fcc8cfSLorenzo Bianconi struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 121136fcc8cfSLorenzo Bianconi int rssi = -ewma_rssi_read(&mvif->rssi); 121236fcc8cfSLorenzo Bianconi struct mt76_sta_cmd_info info = { 121336fcc8cfSLorenzo Bianconi .sta = sta, 121436fcc8cfSLorenzo Bianconi .vif = vif, 121536fcc8cfSLorenzo Bianconi .enable = enable, 121636fcc8cfSLorenzo Bianconi .cmd = MCU_UNI_CMD_STA_REC_UPDATE, 1217f5056657SSean Wang .state = state, 121882453b1cSLorenzo Bianconi .offload_fw = true, 121936fcc8cfSLorenzo Bianconi .rcpi = to_rcpi(rssi), 122036fcc8cfSLorenzo Bianconi }; 122136fcc8cfSLorenzo Bianconi struct mt7921_sta *msta; 122236fcc8cfSLorenzo Bianconi 122336fcc8cfSLorenzo Bianconi msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL; 122436fcc8cfSLorenzo Bianconi info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; 1225f5056657SSean Wang info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; 122636fcc8cfSLorenzo Bianconi 1227f5056657SSean Wang return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); 122836fcc8cfSLorenzo Bianconi } 122936fcc8cfSLorenzo Bianconi 12307bf0a71eSSean Wang int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) 12311d8efc74SSean Wang { 12321d8efc74SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 123336873246SLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm; 1234fad90e43SLorenzo Bianconi int i, err = 0; 12351d8efc74SSean Wang 12361d8efc74SSean Wang for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { 12371d8efc74SSean Wang mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); 12381d8efc74SSean Wang if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, 12391d8efc74SSean Wang PCIE_LPCR_HOST_OWN_SYNC, 0, 50)) 12401d8efc74SSean Wang break; 12411d8efc74SSean Wang } 12421d8efc74SSean Wang 12431d8efc74SSean Wang if (i == MT7921_DRV_OWN_RETRY_COUNT) { 12441d8efc74SSean Wang dev_err(dev->mt76.dev, "driver own failed\n"); 1245fad90e43SLorenzo Bianconi err = -EIO; 1246fad90e43SLorenzo Bianconi goto out; 12471d8efc74SSean Wang } 12483df93214SLorenzo Bianconi 12493df93214SLorenzo Bianconi mt7921_wpdma_reinit_cond(dev); 1250fad90e43SLorenzo Bianconi clear_bit(MT76_STATE_PM, &mphy->state); 12511d8efc74SSean Wang 125236873246SLorenzo Bianconi pm->stats.last_wake_event = jiffies; 125336873246SLorenzo Bianconi pm->stats.doze_time += pm->stats.last_wake_event - 125436873246SLorenzo Bianconi pm->stats.last_doze_event; 12551d8efc74SSean Wang out: 12567bf0a71eSSean Wang return err; 12577bf0a71eSSean Wang } 12587bf0a71eSSean Wang 12597bf0a71eSSean Wang int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) 12607bf0a71eSSean Wang { 12617bf0a71eSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 12627bf0a71eSSean Wang struct mt76_connac_pm *pm = &dev->pm; 12637bf0a71eSSean Wang int err = 0; 12647bf0a71eSSean Wang 12657bf0a71eSSean Wang mutex_lock(&pm->mutex); 12667bf0a71eSSean Wang 12677bf0a71eSSean Wang if (!test_bit(MT76_STATE_PM, &mphy->state)) 12687bf0a71eSSean Wang goto out; 12697bf0a71eSSean Wang 12707bf0a71eSSean Wang err = __mt7921_mcu_drv_pmctrl(dev); 12717bf0a71eSSean Wang out: 127236873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 12731d8efc74SSean Wang 1274fad90e43SLorenzo Bianconi if (err) 1275fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 1276fad90e43SLorenzo Bianconi 1277fad90e43SLorenzo Bianconi return err; 12781d8efc74SSean Wang } 12791d8efc74SSean Wang 12801d8efc74SSean Wang int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev) 12811d8efc74SSean Wang { 12821d8efc74SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 128336873246SLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm; 1284fad90e43SLorenzo Bianconi int i, err = 0; 1285fad90e43SLorenzo Bianconi 128636873246SLorenzo Bianconi mutex_lock(&pm->mutex); 12871d8efc74SSean Wang 128836873246SLorenzo Bianconi if (mt76_connac_skip_fw_pmctrl(mphy, pm)) 1289fad90e43SLorenzo Bianconi goto out; 12901d8efc74SSean Wang 12911d8efc74SSean Wang for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { 12921d8efc74SSean Wang mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); 12931d8efc74SSean Wang if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, 12941d8efc74SSean Wang PCIE_LPCR_HOST_OWN_SYNC, 4, 50)) 12951d8efc74SSean Wang break; 12961d8efc74SSean Wang } 12971d8efc74SSean Wang 12981d8efc74SSean Wang if (i == MT7921_DRV_OWN_RETRY_COUNT) { 12991d8efc74SSean Wang dev_err(dev->mt76.dev, "firmware own failed\n"); 1300fad90e43SLorenzo Bianconi clear_bit(MT76_STATE_PM, &mphy->state); 1301fad90e43SLorenzo Bianconi err = -EIO; 13021d8efc74SSean Wang } 130336873246SLorenzo Bianconi 130436873246SLorenzo Bianconi pm->stats.last_doze_event = jiffies; 130536873246SLorenzo Bianconi pm->stats.awake_time += pm->stats.last_doze_event - 130636873246SLorenzo Bianconi pm->stats.last_wake_event; 1307fad90e43SLorenzo Bianconi out: 130836873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 13091d8efc74SSean Wang 1310fad90e43SLorenzo Bianconi if (err) 1311fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 1312fad90e43SLorenzo Bianconi 1313fad90e43SLorenzo Bianconi return err; 13141d8efc74SSean Wang } 13151d8efc74SSean Wang 1316890809caSLorenzo Bianconi int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, 1317890809caSLorenzo Bianconi struct ieee80211_vif *vif, 1318890809caSLorenzo Bianconi bool enable) 13191d8efc74SSean Wang { 132010de032aSSean Wang struct ieee80211_hw *hw = mt76_hw(dev); 1321890809caSLorenzo Bianconi int err; 13221d8efc74SSean Wang 1323890809caSLorenzo Bianconi if (enable) { 1324890809caSLorenzo Bianconi err = mt7921_mcu_uni_bss_bcnft(dev, vif, true); 1325890809caSLorenzo Bianconi if (err) 1326890809caSLorenzo Bianconi return err; 1327159f6dd6SSean Wang 13281d8efc74SSean Wang vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; 132910de032aSSean Wang ieee80211_hw_set(hw, CONNECTION_MONITOR); 13301d8efc74SSean Wang mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); 1331890809caSLorenzo Bianconi 1332890809caSLorenzo Bianconi return 0; 1333890809caSLorenzo Bianconi } 1334890809caSLorenzo Bianconi 1335890809caSLorenzo Bianconi err = mt7921_mcu_set_bss_pm(dev, vif, false); 1336890809caSLorenzo Bianconi if (err) 1337890809caSLorenzo Bianconi return err; 1338890809caSLorenzo Bianconi 13391d8efc74SSean Wang vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; 134010de032aSSean Wang __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); 13411d8efc74SSean Wang mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); 1342890809caSLorenzo Bianconi 1343890809caSLorenzo Bianconi return 0; 13441d8efc74SSean Wang } 13459c9d8321SSean Wang 1346ea29acc9SSean Wang int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr) 1347ea29acc9SSean Wang { 1348ea29acc9SSean Wang struct mt7921_txpwr_event *event; 1349ea29acc9SSean Wang struct mt7921_txpwr_req req = { 1350ea29acc9SSean Wang .dbdc_idx = 0, 1351ea29acc9SSean Wang }; 1352ea29acc9SSean Wang struct sk_buff *skb; 1353ea29acc9SSean Wang int ret; 1354ea29acc9SSean Wang 1355ea29acc9SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_TXPWR, 1356ea29acc9SSean Wang &req, sizeof(req), true, &skb); 1357ea29acc9SSean Wang if (ret) 1358ea29acc9SSean Wang return ret; 1359ea29acc9SSean Wang 1360ea29acc9SSean Wang event = (struct mt7921_txpwr_event *)skb->data; 1361ea29acc9SSean Wang WARN_ON(skb->len != le16_to_cpu(event->len)); 1362ea29acc9SSean Wang memcpy(txpwr, &event->txpwr, sizeof(event->txpwr)); 1363ea29acc9SSean Wang 1364ea29acc9SSean Wang dev_kfree_skb(skb); 1365ea29acc9SSean Wang 1366ea29acc9SSean Wang return 0; 1367ea29acc9SSean Wang } 1368