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 96c368362cSRyder Lee static enum mcu_cipher_type 971c099ab4SSean Wang mt7921_mcu_get_cipher(int cipher) 981c099ab4SSean Wang { 991c099ab4SSean Wang switch (cipher) { 1001c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP40: 101c368362cSRyder Lee return MCU_CIPHER_WEP40; 1021c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP104: 103c368362cSRyder Lee return MCU_CIPHER_WEP104; 1041c099ab4SSean Wang case WLAN_CIPHER_SUITE_TKIP: 105c368362cSRyder Lee return MCU_CIPHER_TKIP; 1061c099ab4SSean Wang case WLAN_CIPHER_SUITE_AES_CMAC: 107c368362cSRyder Lee return MCU_CIPHER_BIP_CMAC_128; 1081c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP: 109c368362cSRyder Lee return MCU_CIPHER_AES_CCMP; 1101c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP_256: 111c368362cSRyder Lee return MCU_CIPHER_CCMP_256; 1121c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP: 113c368362cSRyder Lee return MCU_CIPHER_GCMP; 1141c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP_256: 115c368362cSRyder Lee return MCU_CIPHER_GCMP_256; 1161c099ab4SSean Wang case WLAN_CIPHER_SUITE_SMS4: 117c368362cSRyder Lee return MCU_CIPHER_WAPI; 1181c099ab4SSean Wang default: 119abf3d98dSArnd Bergmann return MCU_CIPHER_NONE; 1201c099ab4SSean Wang } 1211c099ab4SSean Wang } 1221c099ab4SSean Wang 1231c099ab4SSean Wang static u8 mt7921_mcu_chan_bw(struct cfg80211_chan_def *chandef) 1241c099ab4SSean Wang { 1251c099ab4SSean Wang static const u8 width_to_bw[] = { 1261c099ab4SSean Wang [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, 1271c099ab4SSean Wang [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, 1281c099ab4SSean Wang [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, 1291c099ab4SSean Wang [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, 1301c099ab4SSean Wang [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, 1311c099ab4SSean Wang [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, 1321c099ab4SSean Wang [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, 1331c099ab4SSean Wang [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, 1341c099ab4SSean Wang }; 1351c099ab4SSean Wang 1361c099ab4SSean Wang if (chandef->width >= ARRAY_SIZE(width_to_bw)) 1371c099ab4SSean Wang return 0; 1381c099ab4SSean Wang 1391c099ab4SSean Wang return width_to_bw[chandef->width]; 1401c099ab4SSean Wang } 1411c099ab4SSean Wang 1421c099ab4SSean Wang static int 1431c099ab4SSean Wang mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) 1441c099ab4SSean Wang { 1451c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 1461c099ab4SSean Wang u8 *buf; 1471c099ab4SSean Wang 1481c099ab4SSean Wang if (!skb) 1491c099ab4SSean Wang return -EINVAL; 1501c099ab4SSean Wang 1511c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 1521c099ab4SSean Wang 1531c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 1541c099ab4SSean Wang buf = dev->eeprom.data + le32_to_cpu(res->addr); 1551c099ab4SSean Wang memcpy(buf, res->data, 16); 1561c099ab4SSean Wang 1571c099ab4SSean Wang return 0; 1581c099ab4SSean Wang } 1591c099ab4SSean Wang 160dfc7743dSSean Wang int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, 1611c099ab4SSean Wang struct sk_buff *skb, int seq) 1621c099ab4SSean Wang { 163680a2eadSLorenzo Bianconi int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); 1641c099ab4SSean Wang struct mt7921_mcu_rxd *rxd; 1651c099ab4SSean Wang int ret = 0; 1661c099ab4SSean Wang 1671c099ab4SSean Wang if (!skb) { 16853d35b1aSLorenzo Bianconi dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", 1691c099ab4SSean Wang cmd, seq); 170d43b3257SLorenzo Bianconi mt7921_reset(mdev); 171d43b3257SLorenzo Bianconi 1721c099ab4SSean Wang return -ETIMEDOUT; 1731c099ab4SSean Wang } 1741c099ab4SSean Wang 1751c099ab4SSean Wang rxd = (struct mt7921_mcu_rxd *)skb->data; 1761c099ab4SSean Wang if (seq != rxd->seq) 1771c099ab4SSean Wang return -EAGAIN; 1781c099ab4SSean Wang 179ffc2198dSLorenzo Bianconi if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { 1801c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) - 4); 1811c099ab4SSean Wang ret = *skb->data; 1829d8d136cSLorenzo Bianconi } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { 1831c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) + 4); 1841c099ab4SSean Wang ret = le32_to_cpu(*(__le32 *)skb->data); 185e6d2070dSLorenzo Bianconi } else if (cmd == MCU_EXT_CMD(EFUSE_ACCESS)) { 1861c099ab4SSean Wang ret = mt7921_mcu_parse_eeprom(mdev, skb); 18754722402SLorenzo Bianconi } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) || 18854722402SLorenzo Bianconi cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) || 18954722402SLorenzo Bianconi cmd == MCU_UNI_CMD(STA_REC_UPDATE) || 19054722402SLorenzo Bianconi cmd == MCU_UNI_CMD(HIF_CTRL) || 19154722402SLorenzo Bianconi cmd == MCU_UNI_CMD(OFFLOAD) || 19254722402SLorenzo Bianconi cmd == MCU_UNI_CMD(SUSPEND)) { 1931c099ab4SSean Wang struct mt7921_mcu_uni_event *event; 1941c099ab4SSean Wang 1951c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 1961c099ab4SSean Wang event = (struct mt7921_mcu_uni_event *)skb->data; 1971c099ab4SSean Wang ret = le32_to_cpu(event->status); 198cd3f3873SDeren Wu /* skip invalid event */ 199cd3f3873SDeren Wu if (mcu_cmd != event->cid) 200cd3f3873SDeren Wu ret = -EAGAIN; 201680a2eadSLorenzo Bianconi } else if (cmd == MCU_CE_QUERY(REG_READ)) { 2021c099ab4SSean Wang struct mt7921_mcu_reg_event *event; 2031c099ab4SSean Wang 2041c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 2051c099ab4SSean Wang event = (struct mt7921_mcu_reg_event *)skb->data; 2061c099ab4SSean Wang ret = (int)le32_to_cpu(event->val); 207e6d2070dSLorenzo Bianconi } else { 2081c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 2091c099ab4SSean Wang } 2101c099ab4SSean Wang 2111c099ab4SSean Wang return ret; 2121c099ab4SSean Wang } 2138910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response); 2141c099ab4SSean Wang 215fe0195f7SSean Wang int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, 2161c099ab4SSean Wang int cmd, int *wait_seq) 2171c099ab4SSean Wang { 2181c099ab4SSean Wang struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 219e6d2070dSLorenzo Bianconi int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); 2201c099ab4SSean Wang struct mt7921_uni_txd *uni_txd; 2211c099ab4SSean Wang struct mt7921_mcu_txd *mcu_txd; 2221c099ab4SSean Wang __le32 *txd; 2231c099ab4SSean Wang u32 val; 2241c099ab4SSean Wang u8 seq; 2251c099ab4SSean Wang 22654722402SLorenzo Bianconi if (cmd == MCU_UNI_CMD(HIF_CTRL) || 22754722402SLorenzo Bianconi cmd == MCU_UNI_CMD(SUSPEND) || 22854722402SLorenzo Bianconi cmd == MCU_UNI_CMD(OFFLOAD)) 229*1bb42a35SSean Wang mdev->mcu.timeout = HZ; 23054722402SLorenzo Bianconi else 231a2a6cd54SLorenzo Bianconi mdev->mcu.timeout = 3 * HZ; 2321c099ab4SSean Wang 2331c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2341c099ab4SSean Wang if (!seq) 2351c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2361c099ab4SSean Wang 237ffc2198dSLorenzo Bianconi if (cmd == MCU_CMD(FW_SCATTER)) 2381c099ab4SSean Wang goto exit; 2391c099ab4SSean Wang 24054722402SLorenzo Bianconi txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); 2411c099ab4SSean Wang txd = (__le32 *)skb_push(skb, txd_len); 2421c099ab4SSean Wang 2431c099ab4SSean Wang val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | 2441c099ab4SSean Wang FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | 2451c099ab4SSean Wang FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); 2461c099ab4SSean Wang txd[0] = cpu_to_le32(val); 2471c099ab4SSean Wang 2481c099ab4SSean Wang val = MT_TXD1_LONG_FORMAT | 2491c099ab4SSean Wang FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); 2501c099ab4SSean Wang txd[1] = cpu_to_le32(val); 2511c099ab4SSean Wang 25254722402SLorenzo Bianconi if (cmd & __MCU_CMD_FIELD_UNI) { 2531c099ab4SSean Wang uni_txd = (struct mt7921_uni_txd *)txd; 2541c099ab4SSean Wang uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); 2551c099ab4SSean Wang uni_txd->option = MCU_CMD_UNI_EXT_ACK; 2561c099ab4SSean Wang uni_txd->cid = cpu_to_le16(mcu_cmd); 2571c099ab4SSean Wang uni_txd->s2d_index = MCU_S2D_H2N; 2581c099ab4SSean Wang uni_txd->pkt_type = MCU_PKT_ID; 2591c099ab4SSean Wang uni_txd->seq = seq; 2601c099ab4SSean Wang 2611c099ab4SSean Wang goto exit; 2621c099ab4SSean Wang } 2631c099ab4SSean Wang 2641c099ab4SSean Wang mcu_txd = (struct mt7921_mcu_txd *)txd; 2651c099ab4SSean Wang mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); 2661c099ab4SSean Wang mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, 2671c099ab4SSean Wang MT_TX_MCU_PORT_RX_Q0)); 2681c099ab4SSean Wang mcu_txd->pkt_type = MCU_PKT_ID; 2691c099ab4SSean Wang mcu_txd->seq = seq; 2701c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 2711c099ab4SSean Wang mcu_txd->s2d_index = MCU_S2D_H2N; 272e6d2070dSLorenzo Bianconi mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); 273e6d2070dSLorenzo Bianconi 274680a2eadSLorenzo Bianconi if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) { 275e6d2070dSLorenzo Bianconi if (cmd & __MCU_CMD_FIELD_QUERY) 276e6d2070dSLorenzo Bianconi mcu_txd->set_query = MCU_Q_QUERY; 277e6d2070dSLorenzo Bianconi else 278e6d2070dSLorenzo Bianconi mcu_txd->set_query = MCU_Q_SET; 279e6d2070dSLorenzo Bianconi mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid; 280e6d2070dSLorenzo Bianconi } else { 281e6d2070dSLorenzo Bianconi mcu_txd->set_query = MCU_Q_NA; 282e6d2070dSLorenzo Bianconi } 2831c099ab4SSean Wang 2841c099ab4SSean Wang exit: 2851c099ab4SSean Wang if (wait_seq) 2861c099ab4SSean Wang *wait_seq = seq; 2871c099ab4SSean Wang 288fe0195f7SSean Wang return 0; 2891c099ab4SSean Wang } 290fe0195f7SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_fill_message); 2911c099ab4SSean Wang 2921c099ab4SSean Wang static void 2931c099ab4SSean Wang mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) 2941c099ab4SSean Wang { 2951c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 2961c099ab4SSean Wang struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; 2971c099ab4SSean Wang 2981c099ab4SSean Wang spin_lock_bh(&dev->mt76.lock); 2991c099ab4SSean Wang __skb_queue_tail(&phy->scan_event_list, skb); 3001c099ab4SSean Wang spin_unlock_bh(&dev->mt76.lock); 3011c099ab4SSean Wang 3021c099ab4SSean Wang ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, 3031c099ab4SSean Wang MT7921_HW_SCAN_TIMEOUT); 3041c099ab4SSean Wang } 3051c099ab4SSean Wang 3061c099ab4SSean Wang static void 30710de032aSSean Wang mt7921_mcu_connection_loss_iter(void *priv, u8 *mac, 30810de032aSSean Wang struct ieee80211_vif *vif) 30910de032aSSean Wang { 31010de032aSSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 31110de032aSSean Wang struct mt76_connac_beacon_loss_event *event = priv; 31210de032aSSean Wang 31310de032aSSean Wang if (mvif->idx != event->bss_idx) 31410de032aSSean Wang return; 31510de032aSSean Wang 31610de032aSSean Wang if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) 31710de032aSSean Wang return; 31810de032aSSean Wang 31910de032aSSean Wang ieee80211_connection_loss(vif); 32010de032aSSean Wang } 32110de032aSSean Wang 32210de032aSSean Wang static void 32310de032aSSean Wang mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) 324b88f5c64SSean Wang { 32567aa2743SLorenzo Bianconi struct mt76_connac_beacon_loss_event *event; 32610de032aSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 327b88f5c64SSean Wang 328b88f5c64SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 32967aa2743SLorenzo Bianconi event = (struct mt76_connac_beacon_loss_event *)skb->data; 330b88f5c64SSean Wang 331b88f5c64SSean Wang ieee80211_iterate_active_interfaces_atomic(mphy->hw, 332b88f5c64SSean Wang IEEE80211_IFACE_ITER_RESUME_ALL, 33310de032aSSean Wang mt7921_mcu_connection_loss_iter, event); 334b88f5c64SSean Wang } 335b88f5c64SSean Wang 336b88f5c64SSean Wang static void 3371c099ab4SSean Wang mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb) 3381c099ab4SSean Wang { 3391c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 34067aa2743SLorenzo Bianconi struct mt76_connac_mcu_bss_event *event; 3411c099ab4SSean Wang 34267aa2743SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 34367aa2743SLorenzo Bianconi event = (struct mt76_connac_mcu_bss_event *)skb->data; 3441c099ab4SSean Wang if (event->is_absent) 3451c099ab4SSean Wang ieee80211_stop_queues(mphy->hw); 3461c099ab4SSean Wang else 3471c099ab4SSean Wang ieee80211_wake_queues(mphy->hw); 3481c099ab4SSean Wang } 3491c099ab4SSean Wang 3501c099ab4SSean Wang static void 3511c099ab4SSean Wang mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) 3521c099ab4SSean Wang { 353c7cc5ec5SLorenzo Bianconi struct mt7921_debug_msg { 3541c099ab4SSean Wang __le16 id; 3551c099ab4SSean Wang u8 type; 3561c099ab4SSean Wang u8 flag; 3571c099ab4SSean Wang __le32 value; 3581c099ab4SSean Wang __le16 len; 3591c099ab4SSean Wang u8 content[512]; 360c7cc5ec5SLorenzo Bianconi } __packed * msg; 361c7cc5ec5SLorenzo Bianconi 362c7cc5ec5SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 363c7cc5ec5SLorenzo Bianconi msg = (struct mt7921_debug_msg *)skb->data; 364c7cc5ec5SLorenzo Bianconi 365c7cc5ec5SLorenzo Bianconi if (msg->type == 3) { /* fw log */ 366c7cc5ec5SLorenzo Bianconi u16 len = min_t(u16, le16_to_cpu(msg->len), 512); 3671c099ab4SSean Wang int i; 3681c099ab4SSean Wang 369c7cc5ec5SLorenzo Bianconi for (i = 0 ; i < len; i++) { 370c7cc5ec5SLorenzo Bianconi if (!msg->content[i]) 371c7cc5ec5SLorenzo Bianconi msg->content[i] = ' '; 372c7cc5ec5SLorenzo Bianconi } 3732bf301bcSDan Carpenter wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content); 3741c099ab4SSean Wang } 3751c099ab4SSean Wang } 3761c099ab4SSean Wang 3771c099ab4SSean Wang static void 3782afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) 3792afd17b4SLorenzo Bianconi { 3802afd17b4SLorenzo Bianconi struct mt7921_mcu_lp_event { 3812afd17b4SLorenzo Bianconi u8 state; 3822afd17b4SLorenzo Bianconi u8 reserved[3]; 3832afd17b4SLorenzo Bianconi } __packed * event; 3842afd17b4SLorenzo Bianconi 3852afd17b4SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 3862afd17b4SLorenzo Bianconi event = (struct mt7921_mcu_lp_event *)skb->data; 3872afd17b4SLorenzo Bianconi 3882afd17b4SLorenzo Bianconi trace_lp_event(dev, event->state); 3892afd17b4SLorenzo Bianconi } 3902afd17b4SLorenzo Bianconi 3912afd17b4SLorenzo Bianconi static void 392e0bf699aSDeren Wu mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) 393e0bf699aSDeren Wu { 394e0bf699aSDeren Wu struct mt7921_mcu_tx_done_event *event; 395e0bf699aSDeren Wu 396e0bf699aSDeren Wu skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 397e0bf699aSDeren Wu event = (struct mt7921_mcu_tx_done_event *)skb->data; 398e0bf699aSDeren Wu 399e0bf699aSDeren Wu mt7921_mac_add_txs(dev, event->txs); 400e0bf699aSDeren Wu } 401e0bf699aSDeren Wu 402e0bf699aSDeren Wu static void 4031c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) 4041c099ab4SSean Wang { 4051c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 4061c099ab4SSean Wang 4071c099ab4SSean Wang switch (rxd->eid) { 4081c099ab4SSean Wang case MCU_EVENT_BSS_BEACON_LOSS: 40910de032aSSean Wang mt7921_mcu_connection_loss_event(dev, skb); 4101c099ab4SSean Wang break; 4111c099ab4SSean Wang case MCU_EVENT_SCHED_SCAN_DONE: 4121c099ab4SSean Wang case MCU_EVENT_SCAN_DONE: 4131c099ab4SSean Wang mt7921_mcu_scan_event(dev, skb); 4141c099ab4SSean Wang return; 4151c099ab4SSean Wang case MCU_EVENT_BSS_ABSENCE: 4161c099ab4SSean Wang mt7921_mcu_bss_event(dev, skb); 4171c099ab4SSean Wang break; 4181c099ab4SSean Wang case MCU_EVENT_DBG_MSG: 4191c099ab4SSean Wang mt7921_mcu_debug_msg_event(dev, skb); 4201c099ab4SSean Wang break; 4210da3c795SSean Wang case MCU_EVENT_COREDUMP: 422ca74b9b9SSean Wang dev->fw_assert = true; 4230da3c795SSean Wang mt76_connac_mcu_coredump_event(&dev->mt76, skb, 4240da3c795SSean Wang &dev->coredump); 4250da3c795SSean Wang return; 4262afd17b4SLorenzo Bianconi case MCU_EVENT_LP_INFO: 4272afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(dev, skb); 4282afd17b4SLorenzo Bianconi break; 429e0bf699aSDeren Wu case MCU_EVENT_TX_DONE: 430e0bf699aSDeren Wu mt7921_mcu_tx_done_event(dev, skb); 431e0bf699aSDeren Wu break; 4321c099ab4SSean Wang default: 4331c099ab4SSean Wang break; 4341c099ab4SSean Wang } 4351c099ab4SSean Wang dev_kfree_skb(skb); 4361c099ab4SSean Wang } 4371c099ab4SSean Wang 4381c099ab4SSean Wang void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) 4391c099ab4SSean Wang { 440f0ff5d3aSSean Wang struct mt7921_mcu_rxd *rxd; 441f0ff5d3aSSean Wang 442f0ff5d3aSSean Wang if (skb_linearize(skb)) 443f0ff5d3aSSean Wang return; 444f0ff5d3aSSean Wang 445f0ff5d3aSSean Wang rxd = (struct mt7921_mcu_rxd *)skb->data; 4461c099ab4SSean Wang 4471c099ab4SSean Wang if (rxd->eid == 0x6) { 4481c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 4491c099ab4SSean Wang return; 4501c099ab4SSean Wang } 4511c099ab4SSean Wang 4521c099ab4SSean Wang if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || 4531c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || 4541c099ab4SSean Wang rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || 4551c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_ABSENCE || 4561c099ab4SSean Wang rxd->eid == MCU_EVENT_SCAN_DONE || 4573cce2b98SDeren Wu rxd->eid == MCU_EVENT_TX_DONE || 4581c099ab4SSean Wang rxd->eid == MCU_EVENT_DBG_MSG || 4590da3c795SSean Wang rxd->eid == MCU_EVENT_COREDUMP || 4602afd17b4SLorenzo Bianconi rxd->eid == MCU_EVENT_LP_INFO || 4611c099ab4SSean Wang !rxd->seq) 4621c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(dev, skb); 4631c099ab4SSean Wang else 4641c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 4651c099ab4SSean Wang } 4661c099ab4SSean Wang 4671c099ab4SSean Wang /** starec & wtbl **/ 4681c099ab4SSean Wang static int 4691c099ab4SSean Wang mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, 4701c099ab4SSean Wang struct ieee80211_key_conf *key, enum set_key_cmd cmd) 4711c099ab4SSean Wang { 4721c099ab4SSean Wang struct mt7921_sta_key_conf *bip = &msta->bip; 4731c099ab4SSean Wang struct sta_rec_sec *sec; 4741c099ab4SSean Wang struct tlv *tlv; 4751c099ab4SSean Wang u32 len = sizeof(*sec); 4761c099ab4SSean Wang 47767aa2743SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); 4781c099ab4SSean Wang 4791c099ab4SSean Wang sec = (struct sta_rec_sec *)tlv; 4801c099ab4SSean Wang sec->add = cmd; 4811c099ab4SSean Wang 4821c099ab4SSean Wang if (cmd == SET_KEY) { 4831c099ab4SSean Wang struct sec_key *sec_key; 4841c099ab4SSean Wang u8 cipher; 4851c099ab4SSean Wang 4861c099ab4SSean Wang cipher = mt7921_mcu_get_cipher(key->cipher); 487adedbc64SSean Wang if (cipher == MCU_CIPHER_NONE) 4881c099ab4SSean Wang return -EOPNOTSUPP; 4891c099ab4SSean Wang 4901c099ab4SSean Wang sec_key = &sec->key[0]; 4911c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 4921c099ab4SSean Wang 493c368362cSRyder Lee if (cipher == MCU_CIPHER_BIP_CMAC_128) { 494c368362cSRyder Lee sec_key->cipher_id = MCU_CIPHER_AES_CCMP; 4951c099ab4SSean Wang sec_key->key_id = bip->keyidx; 4961c099ab4SSean Wang sec_key->key_len = 16; 4971c099ab4SSean Wang memcpy(sec_key->key, bip->key, 16); 4981c099ab4SSean Wang 4991c099ab4SSean Wang sec_key = &sec->key[1]; 500c368362cSRyder Lee sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; 5011c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 5021c099ab4SSean Wang sec_key->key_len = 16; 5031c099ab4SSean Wang memcpy(sec_key->key, key->key, 16); 5041c099ab4SSean Wang 5051c099ab4SSean Wang sec->n_cipher = 2; 5061c099ab4SSean Wang } else { 5071c099ab4SSean Wang sec_key->cipher_id = cipher; 5081c099ab4SSean Wang sec_key->key_id = key->keyidx; 5091c099ab4SSean Wang sec_key->key_len = key->keylen; 5101c099ab4SSean Wang memcpy(sec_key->key, key->key, key->keylen); 5111c099ab4SSean Wang 512c368362cSRyder Lee if (cipher == MCU_CIPHER_TKIP) { 5131c099ab4SSean Wang /* Rx/Tx MIC keys are swapped */ 5141c099ab4SSean Wang memcpy(sec_key->key + 16, key->key + 24, 8); 5151c099ab4SSean Wang memcpy(sec_key->key + 24, key->key + 16, 8); 5161c099ab4SSean Wang } 5171c099ab4SSean Wang 5181c099ab4SSean Wang /* store key_conf for BIP batch update */ 519c368362cSRyder Lee if (cipher == MCU_CIPHER_AES_CCMP) { 5201c099ab4SSean Wang memcpy(bip->key, key->key, key->keylen); 5211c099ab4SSean Wang bip->keyidx = key->keyidx; 5221c099ab4SSean Wang } 5231c099ab4SSean Wang 5241c099ab4SSean Wang len -= sizeof(*sec_key); 5251c099ab4SSean Wang sec->n_cipher = 1; 5261c099ab4SSean Wang } 5271c099ab4SSean Wang } else { 5281c099ab4SSean Wang len -= sizeof(sec->key); 5291c099ab4SSean Wang sec->n_cipher = 0; 5301c099ab4SSean Wang } 5311c099ab4SSean Wang sec->len = cpu_to_le16(len); 5321c099ab4SSean Wang 5331c099ab4SSean Wang return 0; 5341c099ab4SSean Wang } 5351c099ab4SSean Wang 5361c099ab4SSean Wang int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, 5371c099ab4SSean Wang struct mt7921_sta *msta, struct ieee80211_key_conf *key, 5381c099ab4SSean Wang enum set_key_cmd cmd) 5391c099ab4SSean Wang { 5401c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 5411c099ab4SSean Wang struct sk_buff *skb; 5421c099ab4SSean Wang int ret; 5431c099ab4SSean Wang 54467aa2743SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 54567aa2743SLorenzo Bianconi &msta->wcid); 5461c099ab4SSean Wang if (IS_ERR(skb)) 5471c099ab4SSean Wang return PTR_ERR(skb); 5481c099ab4SSean Wang 5491c099ab4SSean Wang ret = mt7921_mcu_sta_key_tlv(msta, skb, key, cmd); 5501c099ab4SSean Wang if (ret) 5511c099ab4SSean Wang return ret; 5521c099ab4SSean Wang 5531c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, 55454722402SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE), true); 5551c099ab4SSean Wang } 5561c099ab4SSean Wang 5571c099ab4SSean Wang int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, 5581c099ab4SSean Wang struct ieee80211_ampdu_params *params, 5591c099ab4SSean Wang bool enable) 5601c099ab4SSean Wang { 56167aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 56267aa2743SLorenzo Bianconi 56367aa2743SLorenzo Bianconi if (enable && !params->amsdu) 56467aa2743SLorenzo Bianconi msta->wcid.amsdu = false; 56567aa2743SLorenzo Bianconi 56667aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 56767aa2743SLorenzo Bianconi enable, true); 5681c099ab4SSean Wang } 5691c099ab4SSean Wang 5701c099ab4SSean Wang int mt7921_mcu_uni_rx_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; 5751c099ab4SSean Wang 57667aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 57767aa2743SLorenzo Bianconi enable, false); 5781c099ab4SSean Wang } 5791c099ab4SSean Wang 580dfc7743dSSean Wang int mt7921_mcu_restart(struct mt76_dev *dev) 5811c099ab4SSean Wang { 5821c099ab4SSean Wang struct { 5831c099ab4SSean Wang u8 power_mode; 5841c099ab4SSean Wang u8 rsv[3]; 5851c099ab4SSean Wang } req = { 5861c099ab4SSean Wang .power_mode = 1, 5871c099ab4SSean Wang }; 5881c099ab4SSean Wang 589ffc2198dSLorenzo Bianconi return mt76_mcu_send_msg(dev, MCU_CMD(NIC_POWER_CTRL), &req, 5901c099ab4SSean Wang sizeof(req), false); 5911c099ab4SSean Wang } 5928910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_restart); 5931c099ab4SSean Wang 59468808872SDeren Wu static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info) 59568808872SDeren Wu { 59668808872SDeren Wu u32 mode = DL_MODE_NEED_RSP; 59768808872SDeren Wu 59868808872SDeren Wu if (info == PATCH_SEC_NOT_SUPPORT) 59968808872SDeren Wu return mode; 60068808872SDeren Wu 60168808872SDeren Wu switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { 60268808872SDeren Wu case PATCH_SEC_ENC_TYPE_PLAIN: 60368808872SDeren Wu break; 60468808872SDeren Wu case PATCH_SEC_ENC_TYPE_AES: 60568808872SDeren Wu mode |= DL_MODE_ENCRYPT; 60668808872SDeren Wu mode |= FIELD_PREP(DL_MODE_KEY_IDX, 60768808872SDeren Wu (info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX; 60868808872SDeren Wu mode |= DL_MODE_RESET_SEC_IV; 60968808872SDeren Wu break; 61068808872SDeren Wu case PATCH_SEC_ENC_TYPE_SCRAMBLE: 61168808872SDeren Wu mode |= DL_MODE_ENCRYPT; 61268808872SDeren Wu mode |= DL_CONFIG_ENCRY_MODE_SEL; 61368808872SDeren Wu mode |= DL_MODE_RESET_SEC_IV; 61468808872SDeren Wu break; 61568808872SDeren Wu default: 61668808872SDeren Wu dev_err(dev->mt76.dev, "Encryption type not support!\n"); 61768808872SDeren Wu } 61868808872SDeren Wu 61968808872SDeren Wu return mode; 62068808872SDeren Wu } 62168808872SDeren Wu 62268808872SDeren Wu static char *mt7921_patch_name(struct mt7921_dev *dev) 62368808872SDeren Wu { 62468808872SDeren Wu char *ret; 62568808872SDeren Wu 62668808872SDeren Wu if (is_mt7922(&dev->mt76)) 62768808872SDeren Wu ret = MT7922_ROM_PATCH; 62868808872SDeren Wu else 62968808872SDeren Wu ret = MT7921_ROM_PATCH; 63068808872SDeren Wu 63168808872SDeren Wu return ret; 63268808872SDeren Wu } 63368808872SDeren Wu 6341c099ab4SSean Wang static int mt7921_load_patch(struct mt7921_dev *dev) 6351c099ab4SSean Wang { 6361c099ab4SSean Wang const struct mt7921_patch_hdr *hdr; 6371c099ab4SSean Wang const struct firmware *fw = NULL; 63848fab5bbSSean Wang int i, ret, sem, max_len; 63948fab5bbSSean Wang 64048fab5bbSSean Wang max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096; 6411c099ab4SSean Wang 64267aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); 6431c099ab4SSean Wang switch (sem) { 6441c099ab4SSean Wang case PATCH_IS_DL: 6451c099ab4SSean Wang return 0; 6461c099ab4SSean Wang case PATCH_NOT_DL_SEM_SUCCESS: 6471c099ab4SSean Wang break; 6481c099ab4SSean Wang default: 6491c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); 6501c099ab4SSean Wang return -EAGAIN; 6511c099ab4SSean Wang } 6521c099ab4SSean Wang 65368808872SDeren Wu ret = request_firmware(&fw, mt7921_patch_name(dev), dev->mt76.dev); 6541c099ab4SSean Wang if (ret) 6551c099ab4SSean Wang goto out; 6561c099ab4SSean Wang 6571c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 6581c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 6591c099ab4SSean Wang ret = -EINVAL; 6601c099ab4SSean Wang goto out; 6611c099ab4SSean Wang } 6621c099ab4SSean Wang 6631c099ab4SSean Wang hdr = (const struct mt7921_patch_hdr *)(fw->data); 6641c099ab4SSean Wang 6651c099ab4SSean Wang dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", 6661c099ab4SSean Wang be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); 6671c099ab4SSean Wang 6681c099ab4SSean Wang for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { 6691c099ab4SSean Wang struct mt7921_patch_sec *sec; 6701c099ab4SSean Wang const u8 *dl; 67168808872SDeren Wu u32 len, addr, mode; 67268808872SDeren Wu u32 sec_info = 0; 6731c099ab4SSean Wang 6741c099ab4SSean Wang sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + 6751c099ab4SSean Wang i * sizeof(*sec)); 6761c099ab4SSean Wang if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != 6771c099ab4SSean Wang PATCH_SEC_TYPE_INFO) { 6781c099ab4SSean Wang ret = -EINVAL; 6791c099ab4SSean Wang goto out; 6801c099ab4SSean Wang } 6811c099ab4SSean Wang 6821c099ab4SSean Wang addr = be32_to_cpu(sec->info.addr); 6831c099ab4SSean Wang len = be32_to_cpu(sec->info.len); 6841c099ab4SSean Wang dl = fw->data + be32_to_cpu(sec->offs); 68568808872SDeren Wu sec_info = be32_to_cpu(sec->info.sec_key_idx); 68668808872SDeren Wu mode = mt7921_get_data_mode(dev, sec_info); 6871c099ab4SSean Wang 68867aa2743SLorenzo Bianconi ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 68968808872SDeren Wu mode); 6901c099ab4SSean Wang if (ret) { 6911c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 6921c099ab4SSean Wang goto out; 6931c099ab4SSean Wang } 6941c099ab4SSean Wang 695ffc2198dSLorenzo Bianconi ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), 69648fab5bbSSean Wang dl, len, max_len); 6971c099ab4SSean Wang if (ret) { 6981c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send patch\n"); 6991c099ab4SSean Wang goto out; 7001c099ab4SSean Wang } 7011c099ab4SSean Wang } 7021c099ab4SSean Wang 70367aa2743SLorenzo Bianconi ret = mt76_connac_mcu_start_patch(&dev->mt76); 7041c099ab4SSean Wang if (ret) 7051c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start patch\n"); 7061c099ab4SSean Wang 70778b21758SDeren Wu if (mt76_is_sdio(&dev->mt76)) { 70878b21758SDeren Wu /* activate again */ 70978b21758SDeren Wu ret = __mt7921_mcu_fw_pmctrl(dev); 71078b21758SDeren Wu if (ret) 71178b21758SDeren Wu return ret; 71278b21758SDeren Wu 71378b21758SDeren Wu ret = __mt7921_mcu_drv_pmctrl(dev); 71478b21758SDeren Wu if (ret) 71578b21758SDeren Wu return ret; 71678b21758SDeren Wu } 71778b21758SDeren Wu 7181c099ab4SSean Wang out: 71967aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); 7201c099ab4SSean Wang switch (sem) { 7211c099ab4SSean Wang case PATCH_REL_SEM_SUCCESS: 7221c099ab4SSean Wang break; 7231c099ab4SSean Wang default: 7241c099ab4SSean Wang ret = -EAGAIN; 7251c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); 72602d1c7d4SSean Wang break; 7271c099ab4SSean Wang } 7281c099ab4SSean Wang release_firmware(fw); 7291c099ab4SSean Wang 7301c099ab4SSean Wang return ret; 7311c099ab4SSean Wang } 7321c099ab4SSean Wang 7331c099ab4SSean Wang static u32 mt7921_mcu_gen_dl_mode(u8 feature_set, bool is_wa) 7341c099ab4SSean Wang { 7351c099ab4SSean Wang u32 ret = 0; 7361c099ab4SSean Wang 7371c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? 7381c099ab4SSean Wang (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; 7391c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_ENCRY_MODE) ? 7401c099ab4SSean Wang DL_CONFIG_ENCRY_MODE_SEL : 0; 7411c099ab4SSean Wang ret |= FIELD_PREP(DL_MODE_KEY_IDX, 7421c099ab4SSean Wang FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); 7431c099ab4SSean Wang ret |= DL_MODE_NEED_RSP; 7441c099ab4SSean Wang ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; 7451c099ab4SSean Wang 7461c099ab4SSean Wang return ret; 7471c099ab4SSean Wang } 7481c099ab4SSean Wang 7491c099ab4SSean Wang static int 7501c099ab4SSean Wang mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, 7511c099ab4SSean Wang const struct mt7921_fw_trailer *hdr, 7521c099ab4SSean Wang const u8 *data, bool is_wa) 7531c099ab4SSean Wang { 75448fab5bbSSean Wang int i, offset = 0, max_len; 7551c099ab4SSean Wang u32 override = 0, option = 0; 7561c099ab4SSean Wang 75748fab5bbSSean Wang max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096; 75848fab5bbSSean Wang 7591c099ab4SSean Wang for (i = 0; i < hdr->n_region; i++) { 7601c099ab4SSean Wang const struct mt7921_fw_region *region; 7611c099ab4SSean Wang int err; 7621c099ab4SSean Wang u32 len, addr, mode; 7631c099ab4SSean Wang 7641c099ab4SSean Wang region = (const struct mt7921_fw_region *)((const u8 *)hdr - 7651c099ab4SSean Wang (hdr->n_region - i) * sizeof(*region)); 7661c099ab4SSean Wang mode = mt7921_mcu_gen_dl_mode(region->feature_set, is_wa); 7671c099ab4SSean Wang len = le32_to_cpu(region->len); 7681c099ab4SSean Wang addr = le32_to_cpu(region->addr); 7691c099ab4SSean Wang 7701c099ab4SSean Wang if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) 7711c099ab4SSean Wang override = addr; 7721c099ab4SSean Wang 77367aa2743SLorenzo Bianconi err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 77467aa2743SLorenzo Bianconi mode); 7751c099ab4SSean Wang if (err) { 7761c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 7771c099ab4SSean Wang return err; 7781c099ab4SSean Wang } 7791c099ab4SSean Wang 780ffc2198dSLorenzo Bianconi err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), 78148fab5bbSSean Wang data + offset, len, max_len); 7821c099ab4SSean Wang if (err) { 7831c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send firmware.\n"); 7841c099ab4SSean Wang return err; 7851c099ab4SSean Wang } 7861c099ab4SSean Wang 7871c099ab4SSean Wang offset += len; 7881c099ab4SSean Wang } 7891c099ab4SSean Wang 7901c099ab4SSean Wang if (override) 7911c099ab4SSean Wang option |= FW_START_OVERRIDE; 7921c099ab4SSean Wang 7931c099ab4SSean Wang if (is_wa) 7941c099ab4SSean Wang option |= FW_START_WORKING_PDA_CR4; 7951c099ab4SSean Wang 79667aa2743SLorenzo Bianconi return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); 7971c099ab4SSean Wang } 7981c099ab4SSean Wang 79968808872SDeren Wu static char *mt7921_ram_name(struct mt7921_dev *dev) 80068808872SDeren Wu { 80168808872SDeren Wu char *ret; 80268808872SDeren Wu 80368808872SDeren Wu if (is_mt7922(&dev->mt76)) 80468808872SDeren Wu ret = MT7922_FIRMWARE_WM; 80568808872SDeren Wu else 80668808872SDeren Wu ret = MT7921_FIRMWARE_WM; 80768808872SDeren Wu 80868808872SDeren Wu return ret; 80968808872SDeren Wu } 81068808872SDeren Wu 8111c099ab4SSean Wang static int mt7921_load_ram(struct mt7921_dev *dev) 8121c099ab4SSean Wang { 8131c099ab4SSean Wang const struct mt7921_fw_trailer *hdr; 8141c099ab4SSean Wang const struct firmware *fw; 8151c099ab4SSean Wang int ret; 8161c099ab4SSean Wang 81768808872SDeren Wu ret = request_firmware(&fw, mt7921_ram_name(dev), dev->mt76.dev); 8181c099ab4SSean Wang if (ret) 8191c099ab4SSean Wang return ret; 8201c099ab4SSean Wang 8211c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 8221c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 8231c099ab4SSean Wang ret = -EINVAL; 8241c099ab4SSean Wang goto out; 8251c099ab4SSean Wang } 8261c099ab4SSean Wang 8271c099ab4SSean Wang hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size - 8281c099ab4SSean Wang sizeof(*hdr)); 8291c099ab4SSean Wang 8301c099ab4SSean Wang dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", 8311c099ab4SSean Wang hdr->fw_ver, hdr->build_date); 8321c099ab4SSean Wang 8331c099ab4SSean Wang ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false); 8341c099ab4SSean Wang if (ret) { 8351c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); 8361c099ab4SSean Wang goto out; 8371c099ab4SSean Wang } 8381c099ab4SSean Wang 8391c099ab4SSean Wang snprintf(dev->mt76.hw->wiphy->fw_version, 8401c099ab4SSean Wang sizeof(dev->mt76.hw->wiphy->fw_version), 8411c099ab4SSean Wang "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 8421c099ab4SSean Wang 8431c099ab4SSean Wang out: 8441c099ab4SSean Wang release_firmware(fw); 8451c099ab4SSean Wang 8461c099ab4SSean Wang return ret; 8471c099ab4SSean Wang } 8481c099ab4SSean Wang 8491c099ab4SSean Wang static int mt7921_load_firmware(struct mt7921_dev *dev) 8501c099ab4SSean Wang { 8511c099ab4SSean Wang int ret; 8521c099ab4SSean Wang 8531c099ab4SSean Wang ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 85448fab5bbSSean Wang if (ret && mt76_is_mmio(&dev->mt76)) { 8551c099ab4SSean Wang dev_dbg(dev->mt76.dev, "Firmware is already download\n"); 856c3426904SAaron Ma goto fw_loaded; 8571c099ab4SSean Wang } 8581c099ab4SSean Wang 8591c099ab4SSean Wang ret = mt7921_load_patch(dev); 8601c099ab4SSean Wang if (ret) 8611c099ab4SSean Wang return ret; 8621c099ab4SSean Wang 8631c099ab4SSean Wang ret = mt7921_load_ram(dev); 8641c099ab4SSean Wang if (ret) 8651c099ab4SSean Wang return ret; 8661c099ab4SSean Wang 8671c099ab4SSean Wang if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, 8681c099ab4SSean Wang MT_TOP_MISC2_FW_N9_RDY, 1500)) { 8691c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 8701c099ab4SSean Wang 8711c099ab4SSean Wang return -EIO; 8721c099ab4SSean Wang } 8731c099ab4SSean Wang 874c3426904SAaron Ma fw_loaded: 8751c099ab4SSean Wang 876ffa1bf97SSean Wang #ifdef CONFIG_PM 877022159b0SLorenzo Bianconi dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; 878ffa1bf97SSean Wang #endif /* CONFIG_PM */ 879ffa1bf97SSean Wang 88081a88b1eSTzung-Bi Shih dev_dbg(dev->mt76.dev, "Firmware init done\n"); 8811c099ab4SSean Wang 8821c099ab4SSean Wang return 0; 8831c099ab4SSean Wang } 8841c099ab4SSean Wang 8851c099ab4SSean Wang int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) 8861c099ab4SSean Wang { 8871c099ab4SSean Wang struct { 8881c099ab4SSean Wang u8 ctrl_val; 8891c099ab4SSean Wang u8 pad[3]; 8901c099ab4SSean Wang } data = { 8911c099ab4SSean Wang .ctrl_val = ctrl 8921c099ab4SSean Wang }; 8931c099ab4SSean Wang 894680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(FWLOG_2_HOST), 895680a2eadSLorenzo Bianconi &data, sizeof(data), false); 8961c099ab4SSean Wang } 8971c099ab4SSean Wang 898d32464e6SLorenzo Bianconi int mt7921_run_firmware(struct mt7921_dev *dev) 899d32464e6SLorenzo Bianconi { 900d32464e6SLorenzo Bianconi int err; 901d32464e6SLorenzo Bianconi 902d32464e6SLorenzo Bianconi err = mt7921_load_firmware(dev); 903d32464e6SLorenzo Bianconi if (err) 904d32464e6SLorenzo Bianconi return err; 905d32464e6SLorenzo Bianconi 90616d98b54SSean Wang err = mt76_connac_mcu_get_nic_capability(&dev->mphy); 90716d98b54SSean Wang if (err) 90816d98b54SSean Wang return err; 909d32464e6SLorenzo Bianconi 91016d98b54SSean Wang set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 91116d98b54SSean Wang return mt7921_mcu_fw_log_2_host(dev, 1); 912d32464e6SLorenzo Bianconi } 9138910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_run_firmware); 914d32464e6SLorenzo Bianconi 9151c099ab4SSean Wang void mt7921_mcu_exit(struct mt7921_dev *dev) 9161c099ab4SSean Wang { 9171c099ab4SSean Wang skb_queue_purge(&dev->mt76.mcu.res_q); 9181c099ab4SSean Wang } 9198910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_exit); 9201c099ab4SSean Wang 9211c099ab4SSean Wang int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) 9221c099ab4SSean Wang { 9231c099ab4SSean Wang #define WMM_AIFS_SET BIT(0) 9241c099ab4SSean Wang #define WMM_CW_MIN_SET BIT(1) 9251c099ab4SSean Wang #define WMM_CW_MAX_SET BIT(2) 9261c099ab4SSean Wang #define WMM_TXOP_SET BIT(3) 9271c099ab4SSean Wang #define WMM_PARAM_SET GENMASK(3, 0) 9281c099ab4SSean Wang #define TX_CMD_MODE 1 9291c099ab4SSean Wang struct edca { 9301c099ab4SSean Wang u8 queue; 9311c099ab4SSean Wang u8 set; 9321c099ab4SSean Wang u8 aifs; 9331c099ab4SSean Wang u8 cw_min; 9341c099ab4SSean Wang __le16 cw_max; 9351c099ab4SSean Wang __le16 txop; 9361c099ab4SSean Wang }; 9371c099ab4SSean Wang struct mt7921_mcu_tx { 9381c099ab4SSean Wang u8 total; 9391c099ab4SSean Wang u8 action; 9401c099ab4SSean Wang u8 valid; 9411c099ab4SSean Wang u8 mode; 9421c099ab4SSean Wang 9431c099ab4SSean Wang struct edca edca[IEEE80211_NUM_ACS]; 9441c099ab4SSean Wang } __packed req = { 9451c099ab4SSean Wang .valid = true, 9461c099ab4SSean Wang .mode = TX_CMD_MODE, 9471c099ab4SSean Wang .total = IEEE80211_NUM_ACS, 9481c099ab4SSean Wang }; 9491c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 950bb0ae4cfSSean Wang struct mu_edca { 951bb0ae4cfSSean Wang u8 cw_min; 952bb0ae4cfSSean Wang u8 cw_max; 953bb0ae4cfSSean Wang u8 aifsn; 954bb0ae4cfSSean Wang u8 acm; 955bb0ae4cfSSean Wang u8 timer; 956bb0ae4cfSSean Wang u8 padding[3]; 957bb0ae4cfSSean Wang }; 958bb0ae4cfSSean Wang struct mt7921_mcu_mu_tx { 959bb0ae4cfSSean Wang u8 ver; 960bb0ae4cfSSean Wang u8 pad0; 961bb0ae4cfSSean Wang __le16 len; 962bb0ae4cfSSean Wang u8 bss_idx; 963bb0ae4cfSSean Wang u8 qos; 964bb0ae4cfSSean Wang u8 wmm_idx; 965bb0ae4cfSSean Wang u8 pad1; 966bb0ae4cfSSean Wang struct mu_edca edca[IEEE80211_NUM_ACS]; 967bb0ae4cfSSean Wang u8 pad3[32]; 968bb0ae4cfSSean Wang } __packed req_mu = { 969bb0ae4cfSSean Wang .bss_idx = mvif->mt76.idx, 970bb0ae4cfSSean Wang .qos = vif->bss_conf.qos, 971bb0ae4cfSSean Wang .wmm_idx = mvif->mt76.wmm_idx, 972bb0ae4cfSSean Wang }; 973bb0ae4cfSSean Wang int ac, ret; 9741c099ab4SSean Wang 9751c099ab4SSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 9761c099ab4SSean Wang struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 9771c099ab4SSean Wang struct edca *e = &req.edca[ac]; 9781c099ab4SSean Wang 9791c099ab4SSean Wang e->set = WMM_PARAM_SET; 9801c099ab4SSean Wang e->queue = ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS; 9811c099ab4SSean Wang e->aifs = q->aifs; 9821c099ab4SSean Wang e->txop = cpu_to_le16(q->txop); 9831c099ab4SSean Wang 9841c099ab4SSean Wang if (q->cw_min) 9851c099ab4SSean Wang e->cw_min = fls(q->cw_min); 9861c099ab4SSean Wang else 9871c099ab4SSean Wang e->cw_min = 5; 9881c099ab4SSean Wang 9891c099ab4SSean Wang if (q->cw_max) 9901c099ab4SSean Wang e->cw_max = cpu_to_le16(fls(q->cw_max)); 9911c099ab4SSean Wang else 9921c099ab4SSean Wang e->cw_max = cpu_to_le16(10); 9931c099ab4SSean Wang } 994bb0ae4cfSSean Wang 995e6d2070dSLorenzo Bianconi ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), 996e6d2070dSLorenzo Bianconi &req, sizeof(req), true); 997bb0ae4cfSSean Wang if (ret) 998bb0ae4cfSSean Wang return ret; 999bb0ae4cfSSean Wang 1000bb0ae4cfSSean Wang if (!vif->bss_conf.he_support) 1001bb0ae4cfSSean Wang return 0; 1002bb0ae4cfSSean Wang 1003bb0ae4cfSSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 1004bb0ae4cfSSean Wang struct ieee80211_he_mu_edca_param_ac_rec *q; 1005bb0ae4cfSSean Wang struct mu_edca *e; 1006bb0ae4cfSSean Wang int to_aci[] = {1, 0, 2, 3}; 1007bb0ae4cfSSean Wang 1008bb0ae4cfSSean Wang if (!mvif->queue_params[ac].mu_edca) 1009bb0ae4cfSSean Wang break; 1010bb0ae4cfSSean Wang 1011bb0ae4cfSSean Wang q = &mvif->queue_params[ac].mu_edca_param_rec; 1012bb0ae4cfSSean Wang e = &(req_mu.edca[to_aci[ac]]); 1013bb0ae4cfSSean Wang 1014bb0ae4cfSSean Wang e->cw_min = q->ecw_min_max & 0xf; 1015bb0ae4cfSSean Wang e->cw_max = (q->ecw_min_max & 0xf0) >> 4; 1016bb0ae4cfSSean Wang e->aifsn = q->aifsn; 1017bb0ae4cfSSean Wang e->timer = q->mu_edca_timer; 1018bb0ae4cfSSean Wang } 1019bb0ae4cfSSean Wang 1020680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_MU_EDCA_PARMS), 1021680a2eadSLorenzo Bianconi &req_mu, sizeof(req_mu), false); 10221c099ab4SSean Wang } 10231c099ab4SSean Wang 10241c099ab4SSean Wang int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) 10251c099ab4SSean Wang { 10261c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 10271c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 10281c099ab4SSean Wang int freq1 = chandef->center_freq1; 10291c099ab4SSean Wang struct { 10301c099ab4SSean Wang u8 control_ch; 10311c099ab4SSean Wang u8 center_ch; 10321c099ab4SSean Wang u8 bw; 10331c099ab4SSean Wang u8 tx_streams_num; 10341c099ab4SSean Wang u8 rx_streams; /* mask or num */ 10351c099ab4SSean Wang u8 switch_reason; 10361c099ab4SSean Wang u8 band_idx; 10371c099ab4SSean Wang u8 center_ch2; /* for 80+80 only */ 10381c099ab4SSean Wang __le16 cac_case; 10391c099ab4SSean Wang u8 channel_band; 10401c099ab4SSean Wang u8 rsv0; 10411c099ab4SSean Wang __le32 outband_freq; 10421c099ab4SSean Wang u8 txpower_drop; 10431c099ab4SSean Wang u8 ap_bw; 10441c099ab4SSean Wang u8 ap_center_ch; 10451c099ab4SSean Wang u8 rsv1[57]; 10461c099ab4SSean Wang } __packed req = { 10471c099ab4SSean Wang .control_ch = chandef->chan->hw_value, 10481c099ab4SSean Wang .center_ch = ieee80211_frequency_to_channel(freq1), 10491c099ab4SSean Wang .bw = mt7921_mcu_chan_bw(chandef), 10501c099ab4SSean Wang .tx_streams_num = hweight8(phy->mt76->antenna_mask), 10511c099ab4SSean Wang .rx_streams = phy->mt76->antenna_mask, 10521c099ab4SSean Wang .band_idx = phy != &dev->phy, 10531c099ab4SSean Wang }; 10541c099ab4SSean Wang 105550ac15a5SLorenzo Bianconi if (chandef->chan->band == NL80211_BAND_6GHZ) 105650ac15a5SLorenzo Bianconi req.channel_band = 2; 105750ac15a5SLorenzo Bianconi else 105850ac15a5SLorenzo Bianconi req.channel_band = chandef->chan->band; 105950ac15a5SLorenzo Bianconi 10601c099ab4SSean Wang if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 10611c099ab4SSean Wang req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 10621c099ab4SSean Wang else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 10631c099ab4SSean Wang chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 10641c099ab4SSean Wang req.switch_reason = CH_SWITCH_DFS; 10651c099ab4SSean Wang else 10661c099ab4SSean Wang req.switch_reason = CH_SWITCH_NORMAL; 10671c099ab4SSean Wang 1068e6d2070dSLorenzo Bianconi if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) 10691c099ab4SSean Wang req.rx_streams = hweight8(req.rx_streams); 10701c099ab4SSean Wang 10711c099ab4SSean Wang if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 10721c099ab4SSean Wang int freq2 = chandef->center_freq2; 10731c099ab4SSean Wang 10741c099ab4SSean Wang req.center_ch2 = ieee80211_frequency_to_channel(freq2); 10751c099ab4SSean Wang } 10761c099ab4SSean Wang 10771c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 10781c099ab4SSean Wang } 10791c099ab4SSean Wang 10801c099ab4SSean Wang int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) 10811c099ab4SSean Wang { 10821c099ab4SSean Wang struct req_hdr { 10831c099ab4SSean Wang u8 buffer_mode; 10841c099ab4SSean Wang u8 format; 10851c099ab4SSean Wang __le16 len; 10861c099ab4SSean Wang } __packed req = { 10871c099ab4SSean Wang .buffer_mode = EE_MODE_EFUSE, 10881c099ab4SSean Wang .format = EE_FORMAT_WHOLE, 10891c099ab4SSean Wang }; 10901c099ab4SSean Wang 1091e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE), 10921c099ab4SSean Wang &req, sizeof(req), true); 10931c099ab4SSean Wang } 10948910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom); 10951c099ab4SSean Wang 10961c099ab4SSean Wang int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) 10971c099ab4SSean Wang { 10981c099ab4SSean Wang struct mt7921_mcu_eeprom_info req = { 10991c099ab4SSean Wang .addr = cpu_to_le32(round_down(offset, 16)), 11001c099ab4SSean Wang }; 11011c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 11021c099ab4SSean Wang struct sk_buff *skb; 11031c099ab4SSean Wang int ret; 11041c099ab4SSean Wang u8 *buf; 11051c099ab4SSean Wang 1106e6d2070dSLorenzo Bianconi ret = mt76_mcu_send_and_get_msg(&dev->mt76, 1107e6d2070dSLorenzo Bianconi MCU_EXT_QUERY(EFUSE_ACCESS), 1108e6d2070dSLorenzo Bianconi &req, sizeof(req), true, &skb); 11091c099ab4SSean Wang if (ret) 11101c099ab4SSean Wang return ret; 11111c099ab4SSean Wang 11121c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 11131c099ab4SSean Wang buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); 11141c099ab4SSean Wang memcpy(buf, res->data, 16); 11151c099ab4SSean Wang dev_kfree_skb(skb); 11161c099ab4SSean Wang 11171c099ab4SSean Wang return 0; 11181c099ab4SSean Wang } 11191c099ab4SSean Wang 112056d965daSSean Wang int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) 112156d965daSSean Wang { 112256d965daSSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 112356d965daSSean Wang struct { 112456d965daSSean Wang struct { 112556d965daSSean Wang u8 bss_idx; 112656d965daSSean Wang u8 pad[3]; 112756d965daSSean Wang } __packed hdr; 112856d965daSSean Wang struct ps_tlv { 112956d965daSSean Wang __le16 tag; 113056d965daSSean Wang __le16 len; 113156d965daSSean Wang u8 ps_state; /* 0: device awake 113256d965daSSean Wang * 1: static power save 113356d965daSSean Wang * 2: dynamic power saving 113456d965daSSean Wang * 3: enter TWT power saving 113556d965daSSean Wang * 4: leave TWT power saving 113656d965daSSean Wang */ 113756d965daSSean Wang u8 pad[3]; 113856d965daSSean Wang } __packed ps; 113956d965daSSean Wang } __packed ps_req = { 114056d965daSSean Wang .hdr = { 114156d965daSSean Wang .bss_idx = mvif->mt76.idx, 114256d965daSSean Wang }, 114356d965daSSean Wang .ps = { 114456d965daSSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_PS), 114556d965daSSean Wang .len = cpu_to_le16(sizeof(struct ps_tlv)), 114656d965daSSean Wang .ps_state = vif->bss_conf.ps ? 2 : 0, 114756d965daSSean Wang }, 114856d965daSSean Wang }; 114956d965daSSean Wang 115056d965daSSean Wang if (vif->type != NL80211_IFTYPE_STATION) 115156d965daSSean Wang return -EOPNOTSUPP; 115256d965daSSean Wang 115354722402SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), 115456d965daSSean Wang &ps_req, sizeof(ps_req), true); 115556d965daSSean Wang } 11564086ee28SSean Wang 1157890809caSLorenzo Bianconi static int 1158890809caSLorenzo Bianconi mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, 11594086ee28SSean Wang bool enable) 11604086ee28SSean Wang { 11614086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 11624086ee28SSean Wang struct { 11634086ee28SSean Wang struct { 11644086ee28SSean Wang u8 bss_idx; 11654086ee28SSean Wang u8 pad[3]; 11664086ee28SSean Wang } __packed hdr; 11674086ee28SSean Wang struct bcnft_tlv { 11684086ee28SSean Wang __le16 tag; 11694086ee28SSean Wang __le16 len; 11704086ee28SSean Wang __le16 bcn_interval; 11714086ee28SSean Wang u8 dtim_period; 11724086ee28SSean Wang u8 pad; 11734086ee28SSean Wang } __packed bcnft; 11744086ee28SSean Wang } __packed bcnft_req = { 11754086ee28SSean Wang .hdr = { 11764086ee28SSean Wang .bss_idx = mvif->mt76.idx, 11774086ee28SSean Wang }, 11784086ee28SSean Wang .bcnft = { 11794086ee28SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), 11804086ee28SSean Wang .len = cpu_to_le16(sizeof(struct bcnft_tlv)), 11814086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 11824086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 11834086ee28SSean Wang }, 11844086ee28SSean Wang }; 11854086ee28SSean Wang 11864086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 11874086ee28SSean Wang return 0; 11884086ee28SSean Wang 118954722402SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), 11904086ee28SSean Wang &bcnft_req, sizeof(bcnft_req), true); 11914086ee28SSean Wang } 11924086ee28SSean Wang 1193890809caSLorenzo Bianconi static int 1194890809caSLorenzo Bianconi mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, 11954086ee28SSean Wang bool enable) 11964086ee28SSean Wang { 11974086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 11984086ee28SSean Wang struct { 11994086ee28SSean Wang u8 bss_idx; 12004086ee28SSean Wang u8 dtim_period; 12014086ee28SSean Wang __le16 aid; 12024086ee28SSean Wang __le16 bcn_interval; 12034086ee28SSean Wang __le16 atim_window; 12044086ee28SSean Wang u8 uapsd; 12054086ee28SSean Wang u8 bmc_delivered_ac; 12064086ee28SSean Wang u8 bmc_triggered_ac; 12074086ee28SSean Wang u8 pad; 12084086ee28SSean Wang } req = { 12094086ee28SSean Wang .bss_idx = mvif->mt76.idx, 12104086ee28SSean Wang .aid = cpu_to_le16(vif->bss_conf.aid), 12114086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 12124086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 12134086ee28SSean Wang }; 12144086ee28SSean Wang struct { 12154086ee28SSean Wang u8 bss_idx; 12164086ee28SSean Wang u8 pad[3]; 12174086ee28SSean Wang } req_hdr = { 12184086ee28SSean Wang .bss_idx = mvif->mt76.idx, 12194086ee28SSean Wang }; 12204086ee28SSean Wang int err; 12214086ee28SSean Wang 12224086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 12234086ee28SSean Wang return 0; 12244086ee28SSean Wang 1225680a2eadSLorenzo Bianconi err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT), 1226680a2eadSLorenzo Bianconi &req_hdr, sizeof(req_hdr), false); 12274086ee28SSean Wang if (err < 0 || !enable) 12284086ee28SSean Wang return err; 12294086ee28SSean Wang 1230680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED), 1231680a2eadSLorenzo Bianconi &req, sizeof(req), false); 12324086ee28SSean Wang } 12331d8efc74SSean Wang 1234f5056657SSean Wang int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, 1235f5056657SSean Wang struct ieee80211_vif *vif, bool enable, 1236f5056657SSean Wang enum mt76_sta_info_state state) 123736fcc8cfSLorenzo Bianconi { 123836fcc8cfSLorenzo Bianconi struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 123936fcc8cfSLorenzo Bianconi int rssi = -ewma_rssi_read(&mvif->rssi); 124036fcc8cfSLorenzo Bianconi struct mt76_sta_cmd_info info = { 124136fcc8cfSLorenzo Bianconi .sta = sta, 124236fcc8cfSLorenzo Bianconi .vif = vif, 124336fcc8cfSLorenzo Bianconi .enable = enable, 124454722402SLorenzo Bianconi .cmd = MCU_UNI_CMD(STA_REC_UPDATE), 1245f5056657SSean Wang .state = state, 124682453b1cSLorenzo Bianconi .offload_fw = true, 124736fcc8cfSLorenzo Bianconi .rcpi = to_rcpi(rssi), 124836fcc8cfSLorenzo Bianconi }; 124936fcc8cfSLorenzo Bianconi struct mt7921_sta *msta; 125036fcc8cfSLorenzo Bianconi 125136fcc8cfSLorenzo Bianconi msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL; 125236fcc8cfSLorenzo Bianconi info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; 1253f5056657SSean Wang info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; 125436fcc8cfSLorenzo Bianconi 1255f5056657SSean Wang return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); 125636fcc8cfSLorenzo Bianconi } 125736fcc8cfSLorenzo Bianconi 12587bf0a71eSSean Wang int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) 12597bf0a71eSSean Wang { 12607bf0a71eSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 12617bf0a71eSSean Wang struct mt76_connac_pm *pm = &dev->pm; 12627bf0a71eSSean Wang int err = 0; 12637bf0a71eSSean Wang 12647bf0a71eSSean Wang mutex_lock(&pm->mutex); 12657bf0a71eSSean Wang 12667bf0a71eSSean Wang if (!test_bit(MT76_STATE_PM, &mphy->state)) 12677bf0a71eSSean Wang goto out; 12687bf0a71eSSean Wang 12697bf0a71eSSean Wang err = __mt7921_mcu_drv_pmctrl(dev); 12707bf0a71eSSean Wang out: 127136873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 12721d8efc74SSean Wang 1273fad90e43SLorenzo Bianconi if (err) 1274fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 1275fad90e43SLorenzo Bianconi 1276fad90e43SLorenzo Bianconi return err; 12771d8efc74SSean Wang } 12788910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_drv_pmctrl); 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; 1284dfc7743dSSean Wang int 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 1291dfc7743dSSean Wang err = __mt7921_mcu_fw_pmctrl(dev); 1292fad90e43SLorenzo Bianconi out: 129336873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 12941d8efc74SSean Wang 1295fad90e43SLorenzo Bianconi if (err) 1296fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 1297fad90e43SLorenzo Bianconi 1298fad90e43SLorenzo Bianconi return err; 12991d8efc74SSean Wang } 13008910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_fw_pmctrl); 13011d8efc74SSean Wang 1302890809caSLorenzo Bianconi int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, 1303890809caSLorenzo Bianconi struct ieee80211_vif *vif, 1304890809caSLorenzo Bianconi bool enable) 13051d8efc74SSean Wang { 130610de032aSSean Wang struct ieee80211_hw *hw = mt76_hw(dev); 1307890809caSLorenzo Bianconi int err; 13081d8efc74SSean Wang 1309890809caSLorenzo Bianconi if (enable) { 1310890809caSLorenzo Bianconi err = mt7921_mcu_uni_bss_bcnft(dev, vif, true); 1311890809caSLorenzo Bianconi if (err) 1312890809caSLorenzo Bianconi return err; 1313159f6dd6SSean Wang 13141d8efc74SSean Wang vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; 131510de032aSSean Wang ieee80211_hw_set(hw, CONNECTION_MONITOR); 13161d8efc74SSean Wang mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); 1317890809caSLorenzo Bianconi 1318890809caSLorenzo Bianconi return 0; 1319890809caSLorenzo Bianconi } 1320890809caSLorenzo Bianconi 1321890809caSLorenzo Bianconi err = mt7921_mcu_set_bss_pm(dev, vif, false); 1322890809caSLorenzo Bianconi if (err) 1323890809caSLorenzo Bianconi return err; 1324890809caSLorenzo Bianconi 13251d8efc74SSean Wang vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; 132610de032aSSean Wang __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); 13271d8efc74SSean Wang mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); 1328890809caSLorenzo Bianconi 1329890809caSLorenzo Bianconi return 0; 13301d8efc74SSean Wang } 13319c9d8321SSean Wang 1332ea29acc9SSean Wang int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr) 1333ea29acc9SSean Wang { 1334ea29acc9SSean Wang struct mt7921_txpwr_event *event; 1335ea29acc9SSean Wang struct mt7921_txpwr_req req = { 1336ea29acc9SSean Wang .dbdc_idx = 0, 1337ea29acc9SSean Wang }; 1338ea29acc9SSean Wang struct sk_buff *skb; 1339ea29acc9SSean Wang int ret; 1340ea29acc9SSean Wang 1341680a2eadSLorenzo Bianconi ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(GET_TXPWR), 1342ea29acc9SSean Wang &req, sizeof(req), true, &skb); 1343ea29acc9SSean Wang if (ret) 1344ea29acc9SSean Wang return ret; 1345ea29acc9SSean Wang 1346ea29acc9SSean Wang event = (struct mt7921_txpwr_event *)skb->data; 1347ea29acc9SSean Wang WARN_ON(skb->len != le16_to_cpu(event->len)); 1348ea29acc9SSean Wang memcpy(txpwr, &event->txpwr, sizeof(event->txpwr)); 1349ea29acc9SSean Wang 1350ea29acc9SSean Wang dev_kfree_skb(skb); 1351ea29acc9SSean Wang 1352ea29acc9SSean Wang return 0; 1353ea29acc9SSean Wang } 1354