11c099ab4SSean Wang // SPDX-License-Identifier: ISC 21c099ab4SSean Wang /* Copyright (C) 2020 MediaTek Inc. */ 31c099ab4SSean Wang 41c099ab4SSean Wang #include <linux/firmware.h> 51c099ab4SSean Wang #include <linux/fs.h> 61c099ab4SSean Wang #include "mt7921.h" 71c099ab4SSean Wang #include "mcu.h" 81c099ab4SSean Wang #include "mac.h" 91c099ab4SSean Wang 101c099ab4SSean Wang struct mt7921_patch_hdr { 111c099ab4SSean Wang char build_date[16]; 121c099ab4SSean Wang char platform[4]; 131c099ab4SSean Wang __be32 hw_sw_ver; 141c099ab4SSean Wang __be32 patch_ver; 151c099ab4SSean Wang __be16 checksum; 161c099ab4SSean Wang u16 reserved; 171c099ab4SSean Wang struct { 181c099ab4SSean Wang __be32 patch_ver; 191c099ab4SSean Wang __be32 subsys; 201c099ab4SSean Wang __be32 feature; 211c099ab4SSean Wang __be32 n_region; 221c099ab4SSean Wang __be32 crc; 231c099ab4SSean Wang u32 reserved[11]; 241c099ab4SSean Wang } desc; 251c099ab4SSean Wang } __packed; 261c099ab4SSean Wang 271c099ab4SSean Wang struct mt7921_patch_sec { 281c099ab4SSean Wang __be32 type; 291c099ab4SSean Wang __be32 offs; 301c099ab4SSean Wang __be32 size; 311c099ab4SSean Wang union { 321c099ab4SSean Wang __be32 spec[13]; 331c099ab4SSean Wang struct { 341c099ab4SSean Wang __be32 addr; 351c099ab4SSean Wang __be32 len; 361c099ab4SSean Wang __be32 sec_key_idx; 371c099ab4SSean Wang __be32 align_len; 381c099ab4SSean Wang u32 reserved[9]; 391c099ab4SSean Wang } info; 401c099ab4SSean Wang }; 411c099ab4SSean Wang } __packed; 421c099ab4SSean Wang 431c099ab4SSean Wang struct mt7921_fw_trailer { 441c099ab4SSean Wang u8 chip_id; 451c099ab4SSean Wang u8 eco_code; 461c099ab4SSean Wang u8 n_region; 471c099ab4SSean Wang u8 format_ver; 481c099ab4SSean Wang u8 format_flag; 491c099ab4SSean Wang u8 reserved[2]; 501c099ab4SSean Wang char fw_ver[10]; 511c099ab4SSean Wang char build_date[15]; 521c099ab4SSean Wang u32 crc; 531c099ab4SSean Wang } __packed; 541c099ab4SSean Wang 551c099ab4SSean Wang struct mt7921_fw_region { 561c099ab4SSean Wang __le32 decomp_crc; 571c099ab4SSean Wang __le32 decomp_len; 581c099ab4SSean Wang __le32 decomp_blk_sz; 591c099ab4SSean Wang u8 reserved[4]; 601c099ab4SSean Wang __le32 addr; 611c099ab4SSean Wang __le32 len; 621c099ab4SSean Wang u8 feature_set; 631c099ab4SSean Wang u8 reserved1[15]; 641c099ab4SSean Wang } __packed; 651c099ab4SSean Wang 661c099ab4SSean Wang #define MT_STA_BFER BIT(0) 671c099ab4SSean Wang #define MT_STA_BFEE BIT(1) 681c099ab4SSean Wang 691c099ab4SSean Wang #define FW_FEATURE_SET_ENCRYPT BIT(0) 701c099ab4SSean Wang #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) 711c099ab4SSean Wang #define FW_FEATURE_ENCRY_MODE BIT(4) 721c099ab4SSean Wang #define FW_FEATURE_OVERRIDE_ADDR BIT(5) 731c099ab4SSean Wang 741c099ab4SSean Wang #define DL_MODE_ENCRYPT BIT(0) 751c099ab4SSean Wang #define DL_MODE_KEY_IDX GENMASK(2, 1) 761c099ab4SSean Wang #define DL_MODE_RESET_SEC_IV BIT(3) 771c099ab4SSean Wang #define DL_MODE_WORKING_PDA_CR4 BIT(4) 781c099ab4SSean Wang #define DL_CONFIG_ENCRY_MODE_SEL BIT(6) 791c099ab4SSean Wang #define DL_MODE_NEED_RSP BIT(31) 801c099ab4SSean Wang 811c099ab4SSean Wang #define FW_START_OVERRIDE BIT(0) 821c099ab4SSean Wang #define FW_START_WORKING_PDA_CR4 BIT(2) 831c099ab4SSean Wang 841c099ab4SSean Wang #define PATCH_SEC_TYPE_MASK GENMASK(15, 0) 851c099ab4SSean Wang #define PATCH_SEC_TYPE_INFO 0x2 861c099ab4SSean Wang 871c099ab4SSean Wang #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) 881c099ab4SSean Wang #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) 891c099ab4SSean Wang 901c099ab4SSean Wang static enum mt7921_cipher_type 911c099ab4SSean Wang mt7921_mcu_get_cipher(int cipher) 921c099ab4SSean Wang { 931c099ab4SSean Wang switch (cipher) { 941c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP40: 951c099ab4SSean Wang return MT_CIPHER_WEP40; 961c099ab4SSean Wang case WLAN_CIPHER_SUITE_WEP104: 971c099ab4SSean Wang return MT_CIPHER_WEP104; 981c099ab4SSean Wang case WLAN_CIPHER_SUITE_TKIP: 991c099ab4SSean Wang return MT_CIPHER_TKIP; 1001c099ab4SSean Wang case WLAN_CIPHER_SUITE_AES_CMAC: 1011c099ab4SSean Wang return MT_CIPHER_BIP_CMAC_128; 1021c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP: 1031c099ab4SSean Wang return MT_CIPHER_AES_CCMP; 1041c099ab4SSean Wang case WLAN_CIPHER_SUITE_CCMP_256: 1051c099ab4SSean Wang return MT_CIPHER_CCMP_256; 1061c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP: 1071c099ab4SSean Wang return MT_CIPHER_GCMP; 1081c099ab4SSean Wang case WLAN_CIPHER_SUITE_GCMP_256: 1091c099ab4SSean Wang return MT_CIPHER_GCMP_256; 1101c099ab4SSean Wang case WLAN_CIPHER_SUITE_SMS4: 1111c099ab4SSean Wang return MT_CIPHER_WAPI; 1121c099ab4SSean Wang default: 1131c099ab4SSean Wang return MT_CIPHER_NONE; 1141c099ab4SSean Wang } 1151c099ab4SSean Wang } 1161c099ab4SSean Wang 1171c099ab4SSean Wang static u8 mt7921_mcu_chan_bw(struct cfg80211_chan_def *chandef) 1181c099ab4SSean Wang { 1191c099ab4SSean Wang static const u8 width_to_bw[] = { 1201c099ab4SSean Wang [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, 1211c099ab4SSean Wang [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, 1221c099ab4SSean Wang [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, 1231c099ab4SSean Wang [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, 1241c099ab4SSean Wang [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, 1251c099ab4SSean Wang [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, 1261c099ab4SSean Wang [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, 1271c099ab4SSean Wang [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, 1281c099ab4SSean Wang }; 1291c099ab4SSean Wang 1301c099ab4SSean Wang if (chandef->width >= ARRAY_SIZE(width_to_bw)) 1311c099ab4SSean Wang return 0; 1321c099ab4SSean Wang 1331c099ab4SSean Wang return width_to_bw[chandef->width]; 1341c099ab4SSean Wang } 1351c099ab4SSean Wang 1361c099ab4SSean Wang static int 1371c099ab4SSean Wang mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) 1381c099ab4SSean Wang { 1391c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 1401c099ab4SSean Wang u8 *buf; 1411c099ab4SSean Wang 1421c099ab4SSean Wang if (!skb) 1431c099ab4SSean Wang return -EINVAL; 1441c099ab4SSean Wang 1451c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 1461c099ab4SSean Wang 1471c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 1481c099ab4SSean Wang buf = dev->eeprom.data + le32_to_cpu(res->addr); 1491c099ab4SSean Wang memcpy(buf, res->data, 16); 1501c099ab4SSean Wang 1511c099ab4SSean Wang return 0; 1521c099ab4SSean Wang } 1531c099ab4SSean Wang 1541c099ab4SSean Wang static int 1551c099ab4SSean Wang mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, 1561c099ab4SSean Wang struct sk_buff *skb, int seq) 1571c099ab4SSean Wang { 1581c099ab4SSean Wang struct mt7921_mcu_rxd *rxd; 1591c099ab4SSean Wang int ret = 0; 1601c099ab4SSean Wang 1611c099ab4SSean Wang if (!skb) { 1621c099ab4SSean Wang dev_err(mdev->dev, "Message %d (seq %d) timeout\n", 1631c099ab4SSean Wang cmd, seq); 1641c099ab4SSean Wang return -ETIMEDOUT; 1651c099ab4SSean Wang } 1661c099ab4SSean Wang 1671c099ab4SSean Wang rxd = (struct mt7921_mcu_rxd *)skb->data; 1681c099ab4SSean Wang if (seq != rxd->seq) 1691c099ab4SSean Wang return -EAGAIN; 1701c099ab4SSean Wang 1711c099ab4SSean Wang switch (cmd) { 1721c099ab4SSean Wang case MCU_CMD_PATCH_SEM_CONTROL: 1731c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) - 4); 1741c099ab4SSean Wang ret = *skb->data; 1751c099ab4SSean Wang break; 17667aa2743SLorenzo Bianconi case MCU_EXT_CMD_GET_TEMP: 1771c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) + 4); 1781c099ab4SSean Wang ret = le32_to_cpu(*(__le32 *)skb->data); 1791c099ab4SSean Wang break; 1801c099ab4SSean Wang case MCU_EXT_CMD_EFUSE_ACCESS: 1811c099ab4SSean Wang ret = mt7921_mcu_parse_eeprom(mdev, skb); 1821c099ab4SSean Wang break; 1831c099ab4SSean Wang case MCU_UNI_CMD_DEV_INFO_UPDATE: 1841c099ab4SSean Wang case MCU_UNI_CMD_BSS_INFO_UPDATE: 1851c099ab4SSean Wang case MCU_UNI_CMD_STA_REC_UPDATE: 1861c099ab4SSean Wang case MCU_UNI_CMD_HIF_CTRL: 1871c099ab4SSean Wang case MCU_UNI_CMD_OFFLOAD: 1881c099ab4SSean Wang case MCU_UNI_CMD_SUSPEND: { 1891c099ab4SSean Wang struct mt7921_mcu_uni_event *event; 1901c099ab4SSean Wang 1911c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 1921c099ab4SSean Wang event = (struct mt7921_mcu_uni_event *)skb->data; 1931c099ab4SSean Wang ret = le32_to_cpu(event->status); 1941c099ab4SSean Wang break; 1951c099ab4SSean Wang } 1961c099ab4SSean Wang case MCU_CMD_REG_READ: { 1971c099ab4SSean Wang struct mt7921_mcu_reg_event *event; 1981c099ab4SSean Wang 1991c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 2001c099ab4SSean Wang event = (struct mt7921_mcu_reg_event *)skb->data; 2011c099ab4SSean Wang ret = (int)le32_to_cpu(event->val); 2021c099ab4SSean Wang break; 2031c099ab4SSean Wang } 2041c099ab4SSean Wang default: 2051c099ab4SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 2061c099ab4SSean Wang break; 2071c099ab4SSean Wang } 2081c099ab4SSean Wang 2091c099ab4SSean Wang return ret; 2101c099ab4SSean Wang } 2111c099ab4SSean Wang 2121c099ab4SSean Wang static int 2131c099ab4SSean Wang mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 2141c099ab4SSean Wang int cmd, int *wait_seq) 2151c099ab4SSean Wang { 2161c099ab4SSean Wang struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 2171c099ab4SSean Wang int txd_len, mcu_cmd = cmd & MCU_CMD_MASK; 2181c099ab4SSean Wang enum mt76_mcuq_id txq = MT_MCUQ_WM; 2191c099ab4SSean Wang struct mt7921_uni_txd *uni_txd; 2201c099ab4SSean Wang struct mt7921_mcu_txd *mcu_txd; 2211c099ab4SSean Wang __le32 *txd; 2221c099ab4SSean Wang u32 val; 2231c099ab4SSean Wang u8 seq; 2241c099ab4SSean Wang 2251c099ab4SSean Wang /* TODO: make dynamic based on msg type */ 2261c099ab4SSean Wang mdev->mcu.timeout = 20 * HZ; 2271c099ab4SSean Wang 2281c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2291c099ab4SSean Wang if (!seq) 2301c099ab4SSean Wang seq = ++dev->mt76.mcu.msg_seq & 0xf; 2311c099ab4SSean Wang 2321c099ab4SSean Wang if (cmd == MCU_CMD_FW_SCATTER) { 2331c099ab4SSean Wang txq = MT_MCUQ_FWDL; 2341c099ab4SSean Wang goto exit; 2351c099ab4SSean Wang } 2361c099ab4SSean Wang 2371c099ab4SSean Wang txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd); 2381c099ab4SSean Wang txd = (__le32 *)skb_push(skb, txd_len); 2391c099ab4SSean Wang 2401c099ab4SSean Wang val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | 2411c099ab4SSean Wang FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | 2421c099ab4SSean Wang FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); 2431c099ab4SSean Wang txd[0] = cpu_to_le32(val); 2441c099ab4SSean Wang 2451c099ab4SSean Wang val = MT_TXD1_LONG_FORMAT | 2461c099ab4SSean Wang FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); 2471c099ab4SSean Wang txd[1] = cpu_to_le32(val); 2481c099ab4SSean Wang 2491c099ab4SSean Wang if (cmd & MCU_UNI_PREFIX) { 2501c099ab4SSean Wang uni_txd = (struct mt7921_uni_txd *)txd; 2511c099ab4SSean Wang uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); 2521c099ab4SSean Wang uni_txd->option = MCU_CMD_UNI_EXT_ACK; 2531c099ab4SSean Wang uni_txd->cid = cpu_to_le16(mcu_cmd); 2541c099ab4SSean Wang uni_txd->s2d_index = MCU_S2D_H2N; 2551c099ab4SSean Wang uni_txd->pkt_type = MCU_PKT_ID; 2561c099ab4SSean Wang uni_txd->seq = seq; 2571c099ab4SSean Wang 2581c099ab4SSean Wang goto exit; 2591c099ab4SSean Wang } 2601c099ab4SSean Wang 2611c099ab4SSean Wang mcu_txd = (struct mt7921_mcu_txd *)txd; 2621c099ab4SSean Wang mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); 2631c099ab4SSean Wang mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, 2641c099ab4SSean Wang MT_TX_MCU_PORT_RX_Q0)); 2651c099ab4SSean Wang mcu_txd->pkt_type = MCU_PKT_ID; 2661c099ab4SSean Wang mcu_txd->seq = seq; 2671c099ab4SSean Wang 2681c099ab4SSean Wang switch (cmd & ~MCU_CMD_MASK) { 2691c099ab4SSean Wang case MCU_FW_PREFIX: 2701c099ab4SSean Wang mcu_txd->set_query = MCU_Q_NA; 2711c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 2721c099ab4SSean Wang break; 2731c099ab4SSean Wang case MCU_CE_PREFIX: 2741c099ab4SSean Wang if (cmd & MCU_QUERY_MASK) 2751c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 2761c099ab4SSean Wang else 2771c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 2781c099ab4SSean Wang mcu_txd->cid = mcu_cmd; 2791c099ab4SSean Wang break; 2801c099ab4SSean Wang default: 2811c099ab4SSean Wang mcu_txd->cid = MCU_CMD_EXT_CID; 2821c099ab4SSean Wang if (cmd & MCU_QUERY_PREFIX || cmd == MCU_EXT_CMD_EFUSE_ACCESS) 2831c099ab4SSean Wang mcu_txd->set_query = MCU_Q_QUERY; 2841c099ab4SSean Wang else 2851c099ab4SSean Wang mcu_txd->set_query = MCU_Q_SET; 2861c099ab4SSean Wang mcu_txd->ext_cid = mcu_cmd; 2871c099ab4SSean Wang mcu_txd->ext_cid_ack = 1; 2881c099ab4SSean Wang break; 2891c099ab4SSean Wang } 2901c099ab4SSean Wang 2911c099ab4SSean Wang mcu_txd->s2d_index = MCU_S2D_H2N; 2921c099ab4SSean Wang WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && 2931c099ab4SSean Wang mcu_txd->set_query != MCU_Q_QUERY); 2941c099ab4SSean Wang 2951c099ab4SSean Wang exit: 2961c099ab4SSean Wang if (wait_seq) 2971c099ab4SSean Wang *wait_seq = seq; 2981c099ab4SSean Wang 2991c099ab4SSean Wang return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); 3001c099ab4SSean Wang } 3011c099ab4SSean Wang 3021c099ab4SSean Wang static void 3031c099ab4SSean Wang mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, 3041c099ab4SSean Wang struct mt7921_mcu_peer_cap *peer, 3051c099ab4SSean Wang struct rate_info *rate, u16 r) 3061c099ab4SSean Wang { 3071c099ab4SSean Wang struct ieee80211_supported_band *sband; 3081c099ab4SSean Wang u16 flags = 0; 3091c099ab4SSean Wang u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r); 3101c099ab4SSean Wang u8 gi = 0; 3111c099ab4SSean Wang u8 bw = 0; 3121c099ab4SSean Wang 3131c099ab4SSean Wang rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r); 3141c099ab4SSean Wang rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1; 3151c099ab4SSean Wang 3161c099ab4SSean Wang switch (peer->bw) { 3171c099ab4SSean Wang case IEEE80211_STA_RX_BW_160: 3181c099ab4SSean Wang gi = peer->g16; 3191c099ab4SSean Wang break; 3201c099ab4SSean Wang case IEEE80211_STA_RX_BW_80: 3211c099ab4SSean Wang gi = peer->g8; 3221c099ab4SSean Wang break; 3231c099ab4SSean Wang case IEEE80211_STA_RX_BW_40: 3241c099ab4SSean Wang gi = peer->g4; 3251c099ab4SSean Wang break; 3261c099ab4SSean Wang default: 3271c099ab4SSean Wang gi = peer->g2; 3281c099ab4SSean Wang break; 3291c099ab4SSean Wang } 3301c099ab4SSean Wang 3311c099ab4SSean Wang gi = txmode >= MT_PHY_TYPE_HE_SU ? 3321c099ab4SSean Wang FIELD_GET(MT_WTBL_RATE_HE_GI, gi) : 3331c099ab4SSean Wang FIELD_GET(MT_WTBL_RATE_GI, gi); 3341c099ab4SSean Wang 3351c099ab4SSean Wang switch (txmode) { 3361c099ab4SSean Wang case MT_PHY_TYPE_CCK: 3371c099ab4SSean Wang case MT_PHY_TYPE_OFDM: 3381c099ab4SSean Wang if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 3391c099ab4SSean Wang sband = &mphy->sband_5g.sband; 3401c099ab4SSean Wang else 3411c099ab4SSean Wang sband = &mphy->sband_2g.sband; 3421c099ab4SSean Wang 3431c099ab4SSean Wang rate->legacy = sband->bitrates[rate->mcs].bitrate; 3441c099ab4SSean Wang break; 3451c099ab4SSean Wang case MT_PHY_TYPE_HT: 3461c099ab4SSean Wang case MT_PHY_TYPE_HT_GF: 3471c099ab4SSean Wang flags |= RATE_INFO_FLAGS_MCS; 3481c099ab4SSean Wang 3491c099ab4SSean Wang if (gi) 3501c099ab4SSean Wang flags |= RATE_INFO_FLAGS_SHORT_GI; 3511c099ab4SSean Wang break; 3521c099ab4SSean Wang case MT_PHY_TYPE_VHT: 3531c099ab4SSean Wang flags |= RATE_INFO_FLAGS_VHT_MCS; 3541c099ab4SSean Wang 3551c099ab4SSean Wang if (gi) 3561c099ab4SSean Wang flags |= RATE_INFO_FLAGS_SHORT_GI; 3571c099ab4SSean Wang break; 3581c099ab4SSean Wang case MT_PHY_TYPE_HE_SU: 3591c099ab4SSean Wang case MT_PHY_TYPE_HE_EXT_SU: 3601c099ab4SSean Wang case MT_PHY_TYPE_HE_TB: 3611c099ab4SSean Wang case MT_PHY_TYPE_HE_MU: 3621c099ab4SSean Wang rate->he_gi = gi; 3631c099ab4SSean Wang rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); 3641c099ab4SSean Wang 3651c099ab4SSean Wang flags |= RATE_INFO_FLAGS_HE_MCS; 3661c099ab4SSean Wang break; 3671c099ab4SSean Wang default: 3681c099ab4SSean Wang break; 3691c099ab4SSean Wang } 3701c099ab4SSean Wang rate->flags = flags; 3711c099ab4SSean Wang 3721c099ab4SSean Wang bw = mt7921_mcu_chan_bw(&mphy->chandef) - FIELD_GET(MT_RA_RATE_BW, r); 3731c099ab4SSean Wang 3741c099ab4SSean Wang switch (bw) { 3751c099ab4SSean Wang case IEEE80211_STA_RX_BW_160: 3761c099ab4SSean Wang rate->bw = RATE_INFO_BW_160; 3771c099ab4SSean Wang break; 3781c099ab4SSean Wang case IEEE80211_STA_RX_BW_80: 3791c099ab4SSean Wang rate->bw = RATE_INFO_BW_80; 3801c099ab4SSean Wang break; 3811c099ab4SSean Wang case IEEE80211_STA_RX_BW_40: 3821c099ab4SSean Wang rate->bw = RATE_INFO_BW_40; 3831c099ab4SSean Wang break; 3841c099ab4SSean Wang default: 3851c099ab4SSean Wang rate->bw = RATE_INFO_BW_20; 3861c099ab4SSean Wang break; 3871c099ab4SSean Wang } 3881c099ab4SSean Wang } 3891c099ab4SSean Wang 3901c099ab4SSean Wang static void 3911c099ab4SSean Wang mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb, 3921c099ab4SSean Wang u16 wlan_idx) 3931c099ab4SSean Wang { 3941c099ab4SSean Wang struct mt7921_mcu_wlan_info_event *wtbl_info = 3951c099ab4SSean Wang (struct mt7921_mcu_wlan_info_event *)(skb->data); 3961c099ab4SSean Wang struct rate_info rate = {}; 3971c099ab4SSean Wang u8 curr_idx = wtbl_info->rate_info.rate_idx; 3981c099ab4SSean Wang u16 curr = le16_to_cpu(wtbl_info->rate_info.rate[curr_idx]); 3991c099ab4SSean Wang struct mt7921_mcu_peer_cap peer = wtbl_info->peer_cap; 4001c099ab4SSean Wang struct mt76_phy *mphy = &dev->mphy; 4011c099ab4SSean Wang struct mt7921_sta_stats *stats; 4021c099ab4SSean Wang struct mt7921_sta *msta; 4031c099ab4SSean Wang struct mt76_wcid *wcid; 4041c099ab4SSean Wang 4051c099ab4SSean Wang if (wlan_idx >= MT76_N_WCIDS) 4061c099ab4SSean Wang return; 4071c099ab4SSean Wang wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); 4081c099ab4SSean Wang if (!wcid) { 4091c099ab4SSean Wang stats->tx_rate = rate; 4101c099ab4SSean Wang return; 4111c099ab4SSean Wang } 4121c099ab4SSean Wang 4131c099ab4SSean Wang msta = container_of(wcid, struct mt7921_sta, wcid); 4141c099ab4SSean Wang stats = &msta->stats; 4151c099ab4SSean Wang 4161c099ab4SSean Wang /* current rate */ 4171c099ab4SSean Wang mt7921_mcu_tx_rate_parse(mphy, &peer, &rate, curr); 4181c099ab4SSean Wang stats->tx_rate = rate; 4191c099ab4SSean Wang } 4201c099ab4SSean Wang 4211c099ab4SSean Wang static void 4221c099ab4SSean Wang mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) 4231c099ab4SSean Wang { 4241c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 4251c099ab4SSean Wang struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; 4261c099ab4SSean Wang 4271c099ab4SSean Wang spin_lock_bh(&dev->mt76.lock); 4281c099ab4SSean Wang __skb_queue_tail(&phy->scan_event_list, skb); 4291c099ab4SSean Wang spin_unlock_bh(&dev->mt76.lock); 4301c099ab4SSean Wang 4311c099ab4SSean Wang ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, 4321c099ab4SSean Wang MT7921_HW_SCAN_TIMEOUT); 4331c099ab4SSean Wang } 4341c099ab4SSean Wang 4351c099ab4SSean Wang static void 436b88f5c64SSean Wang mt7921_mcu_beacon_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) 437b88f5c64SSean Wang { 43867aa2743SLorenzo Bianconi struct mt76_connac_beacon_loss_event *event; 439b88f5c64SSean Wang struct mt76_phy *mphy; 440b88f5c64SSean Wang u8 band_idx = 0; /* DBDC support */ 441b88f5c64SSean Wang 442b88f5c64SSean Wang skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 44367aa2743SLorenzo Bianconi event = (struct mt76_connac_beacon_loss_event *)skb->data; 444b88f5c64SSean Wang if (band_idx && dev->mt76.phy2) 445b88f5c64SSean Wang mphy = dev->mt76.phy2; 446b88f5c64SSean Wang else 447b88f5c64SSean Wang mphy = &dev->mt76.phy; 448b88f5c64SSean Wang 449b88f5c64SSean Wang ieee80211_iterate_active_interfaces_atomic(mphy->hw, 450b88f5c64SSean Wang IEEE80211_IFACE_ITER_RESUME_ALL, 45167aa2743SLorenzo Bianconi mt76_connac_mcu_beacon_loss_iter, event); 452b88f5c64SSean Wang } 453b88f5c64SSean Wang 454b88f5c64SSean Wang static void 4551c099ab4SSean Wang mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb) 4561c099ab4SSean Wang { 4571c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 45867aa2743SLorenzo Bianconi struct mt76_connac_mcu_bss_event *event; 4591c099ab4SSean Wang 46067aa2743SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); 46167aa2743SLorenzo Bianconi event = (struct mt76_connac_mcu_bss_event *)skb->data; 4621c099ab4SSean Wang if (event->is_absent) 4631c099ab4SSean Wang ieee80211_stop_queues(mphy->hw); 4641c099ab4SSean Wang else 4651c099ab4SSean Wang ieee80211_wake_queues(mphy->hw); 4661c099ab4SSean Wang } 4671c099ab4SSean Wang 4681c099ab4SSean Wang static void 4691c099ab4SSean Wang mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) 4701c099ab4SSean Wang { 4711c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 4721c099ab4SSean Wang struct debug_msg { 4731c099ab4SSean Wang __le16 id; 4741c099ab4SSean Wang u8 type; 4751c099ab4SSean Wang u8 flag; 4761c099ab4SSean Wang __le32 value; 4771c099ab4SSean Wang __le16 len; 4781c099ab4SSean Wang u8 content[512]; 4791c099ab4SSean Wang } __packed * debug_msg; 4801c099ab4SSean Wang u16 cur_len; 4811c099ab4SSean Wang int i; 4821c099ab4SSean Wang 4831c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 4841c099ab4SSean Wang debug_msg = (struct debug_msg *)skb->data; 4851c099ab4SSean Wang 4861c099ab4SSean Wang cur_len = min_t(u16, le16_to_cpu(debug_msg->len), 512); 4871c099ab4SSean Wang 4881c099ab4SSean Wang if (debug_msg->type == 0x3) { 4891c099ab4SSean Wang for (i = 0 ; i < cur_len; i++) 4901c099ab4SSean Wang if (!debug_msg->content[i]) 4911c099ab4SSean Wang debug_msg->content[i] = ' '; 4921c099ab4SSean Wang 4931c099ab4SSean Wang dev_dbg(dev->mt76.dev, "%s", debug_msg->content); 4941c099ab4SSean Wang } 4951c099ab4SSean Wang } 4961c099ab4SSean Wang 4971c099ab4SSean Wang static void 4981c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) 4991c099ab4SSean Wang { 5001c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 5011c099ab4SSean Wang 5021c099ab4SSean Wang switch (rxd->eid) { 5031c099ab4SSean Wang case MCU_EVENT_BSS_BEACON_LOSS: 504b88f5c64SSean Wang mt7921_mcu_beacon_loss_event(dev, skb); 5051c099ab4SSean Wang break; 5061c099ab4SSean Wang case MCU_EVENT_SCHED_SCAN_DONE: 5071c099ab4SSean Wang case MCU_EVENT_SCAN_DONE: 5081c099ab4SSean Wang mt7921_mcu_scan_event(dev, skb); 5091c099ab4SSean Wang return; 5101c099ab4SSean Wang case MCU_EVENT_BSS_ABSENCE: 5111c099ab4SSean Wang mt7921_mcu_bss_event(dev, skb); 5121c099ab4SSean Wang break; 5131c099ab4SSean Wang case MCU_EVENT_DBG_MSG: 5141c099ab4SSean Wang mt7921_mcu_debug_msg_event(dev, skb); 5151c099ab4SSean Wang break; 5161c099ab4SSean Wang default: 5171c099ab4SSean Wang break; 5181c099ab4SSean Wang } 5191c099ab4SSean Wang dev_kfree_skb(skb); 5201c099ab4SSean Wang } 5211c099ab4SSean Wang 5221c099ab4SSean Wang void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) 5231c099ab4SSean Wang { 5241c099ab4SSean Wang struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; 5251c099ab4SSean Wang 5261c099ab4SSean Wang if (rxd->eid == 0x6) { 5271c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 5281c099ab4SSean Wang return; 5291c099ab4SSean Wang } 5301c099ab4SSean Wang 5311c099ab4SSean Wang if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || 5321c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || 5331c099ab4SSean Wang rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || 5341c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_ABSENCE || 5351c099ab4SSean Wang rxd->eid == MCU_EVENT_SCAN_DONE || 5361c099ab4SSean Wang rxd->eid == MCU_EVENT_DBG_MSG || 5371c099ab4SSean Wang !rxd->seq) 5381c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(dev, skb); 5391c099ab4SSean Wang else 5401c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 5411c099ab4SSean Wang } 5421c099ab4SSean Wang 5431c099ab4SSean Wang /** starec & wtbl **/ 5441c099ab4SSean Wang static int 5451c099ab4SSean Wang mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, 5461c099ab4SSean Wang struct ieee80211_key_conf *key, enum set_key_cmd cmd) 5471c099ab4SSean Wang { 5481c099ab4SSean Wang struct mt7921_sta_key_conf *bip = &msta->bip; 5491c099ab4SSean Wang struct sta_rec_sec *sec; 5501c099ab4SSean Wang struct tlv *tlv; 5511c099ab4SSean Wang u32 len = sizeof(*sec); 5521c099ab4SSean Wang 55367aa2743SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); 5541c099ab4SSean Wang 5551c099ab4SSean Wang sec = (struct sta_rec_sec *)tlv; 5561c099ab4SSean Wang sec->add = cmd; 5571c099ab4SSean Wang 5581c099ab4SSean Wang if (cmd == SET_KEY) { 5591c099ab4SSean Wang struct sec_key *sec_key; 5601c099ab4SSean Wang u8 cipher; 5611c099ab4SSean Wang 5621c099ab4SSean Wang cipher = mt7921_mcu_get_cipher(key->cipher); 5631c099ab4SSean Wang if (cipher == MT_CIPHER_NONE) 5641c099ab4SSean Wang return -EOPNOTSUPP; 5651c099ab4SSean Wang 5661c099ab4SSean Wang sec_key = &sec->key[0]; 5671c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 5681c099ab4SSean Wang 5691c099ab4SSean Wang if (cipher == MT_CIPHER_BIP_CMAC_128) { 5701c099ab4SSean Wang sec_key->cipher_id = MT_CIPHER_AES_CCMP; 5711c099ab4SSean Wang sec_key->key_id = bip->keyidx; 5721c099ab4SSean Wang sec_key->key_len = 16; 5731c099ab4SSean Wang memcpy(sec_key->key, bip->key, 16); 5741c099ab4SSean Wang 5751c099ab4SSean Wang sec_key = &sec->key[1]; 5761c099ab4SSean Wang sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; 5771c099ab4SSean Wang sec_key->cipher_len = sizeof(*sec_key); 5781c099ab4SSean Wang sec_key->key_len = 16; 5791c099ab4SSean Wang memcpy(sec_key->key, key->key, 16); 5801c099ab4SSean Wang 5811c099ab4SSean Wang sec->n_cipher = 2; 5821c099ab4SSean Wang } else { 5831c099ab4SSean Wang sec_key->cipher_id = cipher; 5841c099ab4SSean Wang sec_key->key_id = key->keyidx; 5851c099ab4SSean Wang sec_key->key_len = key->keylen; 5861c099ab4SSean Wang memcpy(sec_key->key, key->key, key->keylen); 5871c099ab4SSean Wang 5881c099ab4SSean Wang if (cipher == MT_CIPHER_TKIP) { 5891c099ab4SSean Wang /* Rx/Tx MIC keys are swapped */ 5901c099ab4SSean Wang memcpy(sec_key->key + 16, key->key + 24, 8); 5911c099ab4SSean Wang memcpy(sec_key->key + 24, key->key + 16, 8); 5921c099ab4SSean Wang } 5931c099ab4SSean Wang 5941c099ab4SSean Wang /* store key_conf for BIP batch update */ 5951c099ab4SSean Wang if (cipher == MT_CIPHER_AES_CCMP) { 5961c099ab4SSean Wang memcpy(bip->key, key->key, key->keylen); 5971c099ab4SSean Wang bip->keyidx = key->keyidx; 5981c099ab4SSean Wang } 5991c099ab4SSean Wang 6001c099ab4SSean Wang len -= sizeof(*sec_key); 6011c099ab4SSean Wang sec->n_cipher = 1; 6021c099ab4SSean Wang } 6031c099ab4SSean Wang } else { 6041c099ab4SSean Wang len -= sizeof(sec->key); 6051c099ab4SSean Wang sec->n_cipher = 0; 6061c099ab4SSean Wang } 6071c099ab4SSean Wang sec->len = cpu_to_le16(len); 6081c099ab4SSean Wang 6091c099ab4SSean Wang return 0; 6101c099ab4SSean Wang } 6111c099ab4SSean Wang 6121c099ab4SSean Wang int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, 6131c099ab4SSean Wang struct mt7921_sta *msta, struct ieee80211_key_conf *key, 6141c099ab4SSean Wang enum set_key_cmd cmd) 6151c099ab4SSean Wang { 6161c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 6171c099ab4SSean Wang struct sk_buff *skb; 6181c099ab4SSean Wang int ret; 6191c099ab4SSean Wang 62067aa2743SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 62167aa2743SLorenzo Bianconi &msta->wcid); 6221c099ab4SSean Wang if (IS_ERR(skb)) 6231c099ab4SSean Wang return PTR_ERR(skb); 6241c099ab4SSean Wang 6251c099ab4SSean Wang ret = mt7921_mcu_sta_key_tlv(msta, skb, key, cmd); 6261c099ab4SSean Wang if (ret) 6271c099ab4SSean Wang return ret; 6281c099ab4SSean Wang 6291c099ab4SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, 6301c099ab4SSean Wang MCU_UNI_CMD_STA_REC_UPDATE, true); 6311c099ab4SSean Wang } 6321c099ab4SSean Wang 6331c099ab4SSean Wang int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, 6341c099ab4SSean Wang struct ieee80211_ampdu_params *params, 6351c099ab4SSean Wang bool enable) 6361c099ab4SSean Wang { 63767aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 63867aa2743SLorenzo Bianconi 63967aa2743SLorenzo Bianconi if (enable && !params->amsdu) 64067aa2743SLorenzo Bianconi msta->wcid.amsdu = false; 64167aa2743SLorenzo Bianconi 64267aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 64367aa2743SLorenzo Bianconi enable, true); 6441c099ab4SSean Wang } 6451c099ab4SSean Wang 6461c099ab4SSean Wang int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, 6471c099ab4SSean Wang struct ieee80211_ampdu_params *params, 6481c099ab4SSean Wang bool enable) 6491c099ab4SSean Wang { 65067aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 6511c099ab4SSean Wang 65267aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 65367aa2743SLorenzo Bianconi enable, false); 6541c099ab4SSean Wang } 6551c099ab4SSean Wang 6561c099ab4SSean Wang static int mt7921_mcu_restart(struct mt76_dev *dev) 6571c099ab4SSean Wang { 6581c099ab4SSean Wang struct { 6591c099ab4SSean Wang u8 power_mode; 6601c099ab4SSean Wang u8 rsv[3]; 6611c099ab4SSean Wang } req = { 6621c099ab4SSean Wang .power_mode = 1, 6631c099ab4SSean Wang }; 6641c099ab4SSean Wang 6651c099ab4SSean Wang return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req, 6661c099ab4SSean Wang sizeof(req), false); 6671c099ab4SSean Wang } 6681c099ab4SSean Wang 6691c099ab4SSean Wang static int mt7921_driver_own(struct mt7921_dev *dev) 6701c099ab4SSean Wang { 6711c099ab4SSean Wang u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 6721c099ab4SSean Wang 6731c099ab4SSean Wang mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); 6741c099ab4SSean Wang if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, 6751c099ab4SSean Wang 0, 500)) { 6761c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for driver own\n"); 6771c099ab4SSean Wang return -EIO; 6781c099ab4SSean Wang } 6791c099ab4SSean Wang 6801c099ab4SSean Wang return 0; 6811c099ab4SSean Wang } 6821c099ab4SSean Wang 6831c099ab4SSean Wang static int mt7921_load_patch(struct mt7921_dev *dev) 6841c099ab4SSean Wang { 6851c099ab4SSean Wang const struct mt7921_patch_hdr *hdr; 6861c099ab4SSean Wang const struct firmware *fw = NULL; 6871c099ab4SSean Wang int i, ret, sem; 6881c099ab4SSean Wang 68967aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); 6901c099ab4SSean Wang switch (sem) { 6911c099ab4SSean Wang case PATCH_IS_DL: 6921c099ab4SSean Wang return 0; 6931c099ab4SSean Wang case PATCH_NOT_DL_SEM_SUCCESS: 6941c099ab4SSean Wang break; 6951c099ab4SSean Wang default: 6961c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); 6971c099ab4SSean Wang return -EAGAIN; 6981c099ab4SSean Wang } 6991c099ab4SSean Wang 7001c099ab4SSean Wang ret = request_firmware(&fw, MT7921_ROM_PATCH, dev->mt76.dev); 7011c099ab4SSean Wang if (ret) 7021c099ab4SSean Wang goto out; 7031c099ab4SSean Wang 7041c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 7051c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 7061c099ab4SSean Wang ret = -EINVAL; 7071c099ab4SSean Wang goto out; 7081c099ab4SSean Wang } 7091c099ab4SSean Wang 7101c099ab4SSean Wang hdr = (const struct mt7921_patch_hdr *)(fw->data); 7111c099ab4SSean Wang 7121c099ab4SSean Wang dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", 7131c099ab4SSean Wang be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); 7141c099ab4SSean Wang 7151c099ab4SSean Wang for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { 7161c099ab4SSean Wang struct mt7921_patch_sec *sec; 7171c099ab4SSean Wang const u8 *dl; 7181c099ab4SSean Wang u32 len, addr; 7191c099ab4SSean Wang 7201c099ab4SSean Wang sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + 7211c099ab4SSean Wang i * sizeof(*sec)); 7221c099ab4SSean Wang if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != 7231c099ab4SSean Wang PATCH_SEC_TYPE_INFO) { 7241c099ab4SSean Wang ret = -EINVAL; 7251c099ab4SSean Wang goto out; 7261c099ab4SSean Wang } 7271c099ab4SSean Wang 7281c099ab4SSean Wang addr = be32_to_cpu(sec->info.addr); 7291c099ab4SSean Wang len = be32_to_cpu(sec->info.len); 7301c099ab4SSean Wang dl = fw->data + be32_to_cpu(sec->offs); 7311c099ab4SSean Wang 73267aa2743SLorenzo Bianconi ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 7331c099ab4SSean Wang DL_MODE_NEED_RSP); 7341c099ab4SSean Wang if (ret) { 7351c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 7361c099ab4SSean Wang goto out; 7371c099ab4SSean Wang } 7381c099ab4SSean Wang 7391c099ab4SSean Wang ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 7401c099ab4SSean Wang dl, len); 7411c099ab4SSean Wang if (ret) { 7421c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send patch\n"); 7431c099ab4SSean Wang goto out; 7441c099ab4SSean Wang } 7451c099ab4SSean Wang } 7461c099ab4SSean Wang 74767aa2743SLorenzo Bianconi ret = mt76_connac_mcu_start_patch(&dev->mt76); 7481c099ab4SSean Wang if (ret) 7491c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start patch\n"); 7501c099ab4SSean Wang 7511c099ab4SSean Wang out: 75267aa2743SLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); 7531c099ab4SSean Wang switch (sem) { 7541c099ab4SSean Wang case PATCH_REL_SEM_SUCCESS: 7551c099ab4SSean Wang break; 7561c099ab4SSean Wang default: 7571c099ab4SSean Wang ret = -EAGAIN; 7581c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); 7591c099ab4SSean Wang goto out; 7601c099ab4SSean Wang } 7611c099ab4SSean Wang release_firmware(fw); 7621c099ab4SSean Wang 7631c099ab4SSean Wang return ret; 7641c099ab4SSean Wang } 7651c099ab4SSean Wang 7661c099ab4SSean Wang static u32 mt7921_mcu_gen_dl_mode(u8 feature_set, bool is_wa) 7671c099ab4SSean Wang { 7681c099ab4SSean Wang u32 ret = 0; 7691c099ab4SSean Wang 7701c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? 7711c099ab4SSean Wang (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; 7721c099ab4SSean Wang ret |= (feature_set & FW_FEATURE_ENCRY_MODE) ? 7731c099ab4SSean Wang DL_CONFIG_ENCRY_MODE_SEL : 0; 7741c099ab4SSean Wang ret |= FIELD_PREP(DL_MODE_KEY_IDX, 7751c099ab4SSean Wang FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); 7761c099ab4SSean Wang ret |= DL_MODE_NEED_RSP; 7771c099ab4SSean Wang ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; 7781c099ab4SSean Wang 7791c099ab4SSean Wang return ret; 7801c099ab4SSean Wang } 7811c099ab4SSean Wang 7821c099ab4SSean Wang static int 7831c099ab4SSean Wang mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, 7841c099ab4SSean Wang const struct mt7921_fw_trailer *hdr, 7851c099ab4SSean Wang const u8 *data, bool is_wa) 7861c099ab4SSean Wang { 7871c099ab4SSean Wang int i, offset = 0; 7881c099ab4SSean Wang u32 override = 0, option = 0; 7891c099ab4SSean Wang 7901c099ab4SSean Wang for (i = 0; i < hdr->n_region; i++) { 7911c099ab4SSean Wang const struct mt7921_fw_region *region; 7921c099ab4SSean Wang int err; 7931c099ab4SSean Wang u32 len, addr, mode; 7941c099ab4SSean Wang 7951c099ab4SSean Wang region = (const struct mt7921_fw_region *)((const u8 *)hdr - 7961c099ab4SSean Wang (hdr->n_region - i) * sizeof(*region)); 7971c099ab4SSean Wang mode = mt7921_mcu_gen_dl_mode(region->feature_set, is_wa); 7981c099ab4SSean Wang len = le32_to_cpu(region->len); 7991c099ab4SSean Wang addr = le32_to_cpu(region->addr); 8001c099ab4SSean Wang 8011c099ab4SSean Wang if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) 8021c099ab4SSean Wang override = addr; 8031c099ab4SSean Wang 80467aa2743SLorenzo Bianconi err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 80567aa2743SLorenzo Bianconi mode); 8061c099ab4SSean Wang if (err) { 8071c099ab4SSean Wang dev_err(dev->mt76.dev, "Download request failed\n"); 8081c099ab4SSean Wang return err; 8091c099ab4SSean Wang } 8101c099ab4SSean Wang 8111c099ab4SSean Wang err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, 8121c099ab4SSean Wang data + offset, len); 8131c099ab4SSean Wang if (err) { 8141c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to send firmware.\n"); 8151c099ab4SSean Wang return err; 8161c099ab4SSean Wang } 8171c099ab4SSean Wang 8181c099ab4SSean Wang offset += len; 8191c099ab4SSean Wang } 8201c099ab4SSean Wang 8211c099ab4SSean Wang if (override) 8221c099ab4SSean Wang option |= FW_START_OVERRIDE; 8231c099ab4SSean Wang 8241c099ab4SSean Wang if (is_wa) 8251c099ab4SSean Wang option |= FW_START_WORKING_PDA_CR4; 8261c099ab4SSean Wang 82767aa2743SLorenzo Bianconi return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); 8281c099ab4SSean Wang } 8291c099ab4SSean Wang 8301c099ab4SSean Wang static int mt7921_load_ram(struct mt7921_dev *dev) 8311c099ab4SSean Wang { 8321c099ab4SSean Wang const struct mt7921_fw_trailer *hdr; 8331c099ab4SSean Wang const struct firmware *fw; 8341c099ab4SSean Wang int ret; 8351c099ab4SSean Wang 8361c099ab4SSean Wang ret = request_firmware(&fw, MT7921_FIRMWARE_WM, dev->mt76.dev); 8371c099ab4SSean Wang if (ret) 8381c099ab4SSean Wang return ret; 8391c099ab4SSean Wang 8401c099ab4SSean Wang if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 8411c099ab4SSean Wang dev_err(dev->mt76.dev, "Invalid firmware\n"); 8421c099ab4SSean Wang ret = -EINVAL; 8431c099ab4SSean Wang goto out; 8441c099ab4SSean Wang } 8451c099ab4SSean Wang 8461c099ab4SSean Wang hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size - 8471c099ab4SSean Wang sizeof(*hdr)); 8481c099ab4SSean Wang 8491c099ab4SSean Wang dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", 8501c099ab4SSean Wang hdr->fw_ver, hdr->build_date); 8511c099ab4SSean Wang 8521c099ab4SSean Wang ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false); 8531c099ab4SSean Wang if (ret) { 8541c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); 8551c099ab4SSean Wang goto out; 8561c099ab4SSean Wang } 8571c099ab4SSean Wang 8581c099ab4SSean Wang snprintf(dev->mt76.hw->wiphy->fw_version, 8591c099ab4SSean Wang sizeof(dev->mt76.hw->wiphy->fw_version), 8601c099ab4SSean Wang "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 8611c099ab4SSean Wang 8621c099ab4SSean Wang out: 8631c099ab4SSean Wang release_firmware(fw); 8641c099ab4SSean Wang 8651c099ab4SSean Wang return ret; 8661c099ab4SSean Wang } 8671c099ab4SSean Wang 868ffa1bf97SSean Wang static const struct wiphy_wowlan_support mt7921_wowlan_support = { 869ffa1bf97SSean Wang .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | 870ffa1bf97SSean Wang WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT, 871ffa1bf97SSean Wang .n_patterns = 1, 872ffa1bf97SSean Wang .pattern_min_len = 1, 873ffa1bf97SSean Wang .pattern_max_len = MT7921_WOW_PATTEN_MAX_LEN, 874ffa1bf97SSean Wang .max_nd_match_sets = 10, 875ffa1bf97SSean Wang }; 876ffa1bf97SSean Wang 8771c099ab4SSean Wang static int mt7921_load_firmware(struct mt7921_dev *dev) 8781c099ab4SSean Wang { 8791c099ab4SSean Wang int ret; 8801c099ab4SSean Wang 8811c099ab4SSean Wang ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 8821c099ab4SSean Wang if (ret) { 8831c099ab4SSean Wang dev_dbg(dev->mt76.dev, "Firmware is already download\n"); 8841c099ab4SSean Wang return -EIO; 8851c099ab4SSean Wang } 8861c099ab4SSean Wang 8871c099ab4SSean Wang ret = mt7921_load_patch(dev); 8881c099ab4SSean Wang if (ret) 8891c099ab4SSean Wang return ret; 8901c099ab4SSean Wang 8911c099ab4SSean Wang ret = mt7921_load_ram(dev); 8921c099ab4SSean Wang if (ret) 8931c099ab4SSean Wang return ret; 8941c099ab4SSean Wang 8951c099ab4SSean Wang if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, 8961c099ab4SSean Wang MT_TOP_MISC2_FW_N9_RDY, 1500)) { 8971c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 8981c099ab4SSean Wang 8991c099ab4SSean Wang return -EIO; 9001c099ab4SSean Wang } 9011c099ab4SSean Wang 9021c099ab4SSean Wang mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); 9031c099ab4SSean Wang 904ffa1bf97SSean Wang #ifdef CONFIG_PM 905ffa1bf97SSean Wang dev->mt76.hw->wiphy->wowlan = &mt7921_wowlan_support; 906ffa1bf97SSean Wang #endif /* CONFIG_PM */ 907ffa1bf97SSean Wang 9081c099ab4SSean Wang dev_err(dev->mt76.dev, "Firmware init done\n"); 9091c099ab4SSean Wang 9101c099ab4SSean Wang return 0; 9111c099ab4SSean Wang } 9121c099ab4SSean Wang 9131c099ab4SSean Wang int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) 9141c099ab4SSean Wang { 9151c099ab4SSean Wang struct { 9161c099ab4SSean Wang u8 ctrl_val; 9171c099ab4SSean Wang u8 pad[3]; 9181c099ab4SSean Wang } data = { 9191c099ab4SSean Wang .ctrl_val = ctrl 9201c099ab4SSean Wang }; 9211c099ab4SSean Wang 9221c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FWLOG_2_HOST, &data, 9231c099ab4SSean Wang sizeof(data), false); 9241c099ab4SSean Wang } 9251c099ab4SSean Wang 9261c099ab4SSean Wang int mt7921_mcu_init(struct mt7921_dev *dev) 9271c099ab4SSean Wang { 9281c099ab4SSean Wang static const struct mt76_mcu_ops mt7921_mcu_ops = { 9291c099ab4SSean Wang .headroom = sizeof(struct mt7921_mcu_txd), 9301c099ab4SSean Wang .mcu_skb_send_msg = mt7921_mcu_send_message, 9311c099ab4SSean Wang .mcu_parse_response = mt7921_mcu_parse_response, 9321c099ab4SSean Wang .mcu_restart = mt7921_mcu_restart, 9331c099ab4SSean Wang }; 9341c099ab4SSean Wang int ret; 9351c099ab4SSean Wang 9361c099ab4SSean Wang dev->mt76.mcu_ops = &mt7921_mcu_ops; 9371c099ab4SSean Wang 9381c099ab4SSean Wang ret = mt7921_driver_own(dev); 9391c099ab4SSean Wang if (ret) 9401c099ab4SSean Wang return ret; 9411c099ab4SSean Wang 9421c099ab4SSean Wang ret = mt7921_load_firmware(dev); 9431c099ab4SSean Wang if (ret) 9441c099ab4SSean Wang return ret; 9451c099ab4SSean Wang 9461c099ab4SSean Wang set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 9471c099ab4SSean Wang mt7921_mcu_fw_log_2_host(dev, 1); 9481c099ab4SSean Wang 9491c099ab4SSean Wang return 0; 9501c099ab4SSean Wang } 9511c099ab4SSean Wang 9521c099ab4SSean Wang void mt7921_mcu_exit(struct mt7921_dev *dev) 9531c099ab4SSean Wang { 9541c099ab4SSean Wang u32 reg = mt7921_reg_map_l1(dev, MT_TOP_MISC); 9551c099ab4SSean Wang 9561c099ab4SSean Wang __mt76_mcu_restart(&dev->mt76); 9571c099ab4SSean Wang if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, 9581c099ab4SSean Wang FIELD_PREP(MT_TOP_MISC_FW_STATE, 9591c099ab4SSean Wang FW_STATE_FW_DOWNLOAD), 1000)) { 9601c099ab4SSean Wang dev_err(dev->mt76.dev, "Failed to exit mcu\n"); 9611c099ab4SSean Wang return; 9621c099ab4SSean Wang } 9631c099ab4SSean Wang 9641c099ab4SSean Wang reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 9651c099ab4SSean Wang mt76_wr(dev, reg, MT_TOP_LPCR_HOST_FW_OWN); 9661c099ab4SSean Wang skb_queue_purge(&dev->mt76.mcu.res_q); 9671c099ab4SSean Wang } 9681c099ab4SSean Wang 9691c099ab4SSean Wang int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) 9701c099ab4SSean Wang { 9711c099ab4SSean Wang #define WMM_AIFS_SET BIT(0) 9721c099ab4SSean Wang #define WMM_CW_MIN_SET BIT(1) 9731c099ab4SSean Wang #define WMM_CW_MAX_SET BIT(2) 9741c099ab4SSean Wang #define WMM_TXOP_SET BIT(3) 9751c099ab4SSean Wang #define WMM_PARAM_SET GENMASK(3, 0) 9761c099ab4SSean Wang #define TX_CMD_MODE 1 9771c099ab4SSean Wang struct edca { 9781c099ab4SSean Wang u8 queue; 9791c099ab4SSean Wang u8 set; 9801c099ab4SSean Wang u8 aifs; 9811c099ab4SSean Wang u8 cw_min; 9821c099ab4SSean Wang __le16 cw_max; 9831c099ab4SSean Wang __le16 txop; 9841c099ab4SSean Wang }; 9851c099ab4SSean Wang struct mt7921_mcu_tx { 9861c099ab4SSean Wang u8 total; 9871c099ab4SSean Wang u8 action; 9881c099ab4SSean Wang u8 valid; 9891c099ab4SSean Wang u8 mode; 9901c099ab4SSean Wang 9911c099ab4SSean Wang struct edca edca[IEEE80211_NUM_ACS]; 9921c099ab4SSean Wang } __packed req = { 9931c099ab4SSean Wang .valid = true, 9941c099ab4SSean Wang .mode = TX_CMD_MODE, 9951c099ab4SSean Wang .total = IEEE80211_NUM_ACS, 9961c099ab4SSean Wang }; 9971c099ab4SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 9981c099ab4SSean Wang int ac; 9991c099ab4SSean Wang 10001c099ab4SSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 10011c099ab4SSean Wang struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 10021c099ab4SSean Wang struct edca *e = &req.edca[ac]; 10031c099ab4SSean Wang 10041c099ab4SSean Wang e->set = WMM_PARAM_SET; 10051c099ab4SSean Wang e->queue = ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS; 10061c099ab4SSean Wang e->aifs = q->aifs; 10071c099ab4SSean Wang e->txop = cpu_to_le16(q->txop); 10081c099ab4SSean Wang 10091c099ab4SSean Wang if (q->cw_min) 10101c099ab4SSean Wang e->cw_min = fls(q->cw_min); 10111c099ab4SSean Wang else 10121c099ab4SSean Wang e->cw_min = 5; 10131c099ab4SSean Wang 10141c099ab4SSean Wang if (q->cw_max) 10151c099ab4SSean Wang e->cw_max = cpu_to_le16(fls(q->cw_max)); 10161c099ab4SSean Wang else 10171c099ab4SSean Wang e->cw_max = cpu_to_le16(10); 10181c099ab4SSean Wang } 10191c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, 10201c099ab4SSean Wang sizeof(req), true); 10211c099ab4SSean Wang } 10221c099ab4SSean Wang 10231c099ab4SSean Wang int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) 10241c099ab4SSean Wang { 10251c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 10261c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 10271c099ab4SSean Wang int freq1 = chandef->center_freq1; 10281c099ab4SSean Wang struct { 10291c099ab4SSean Wang u8 control_ch; 10301c099ab4SSean Wang u8 center_ch; 10311c099ab4SSean Wang u8 bw; 10321c099ab4SSean Wang u8 tx_streams_num; 10331c099ab4SSean Wang u8 rx_streams; /* mask or num */ 10341c099ab4SSean Wang u8 switch_reason; 10351c099ab4SSean Wang u8 band_idx; 10361c099ab4SSean Wang u8 center_ch2; /* for 80+80 only */ 10371c099ab4SSean Wang __le16 cac_case; 10381c099ab4SSean Wang u8 channel_band; 10391c099ab4SSean Wang u8 rsv0; 10401c099ab4SSean Wang __le32 outband_freq; 10411c099ab4SSean Wang u8 txpower_drop; 10421c099ab4SSean Wang u8 ap_bw; 10431c099ab4SSean Wang u8 ap_center_ch; 10441c099ab4SSean Wang u8 rsv1[57]; 10451c099ab4SSean Wang } __packed req = { 10461c099ab4SSean Wang .control_ch = chandef->chan->hw_value, 10471c099ab4SSean Wang .center_ch = ieee80211_frequency_to_channel(freq1), 10481c099ab4SSean Wang .bw = mt7921_mcu_chan_bw(chandef), 10491c099ab4SSean Wang .tx_streams_num = hweight8(phy->mt76->antenna_mask), 10501c099ab4SSean Wang .rx_streams = phy->mt76->antenna_mask, 10511c099ab4SSean Wang .band_idx = phy != &dev->phy, 10521c099ab4SSean Wang .channel_band = chandef->chan->band, 10531c099ab4SSean Wang }; 10541c099ab4SSean Wang 10551c099ab4SSean Wang if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 10561c099ab4SSean Wang req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 10571c099ab4SSean Wang else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 10581c099ab4SSean Wang chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 10591c099ab4SSean Wang req.switch_reason = CH_SWITCH_DFS; 10601c099ab4SSean Wang else 10611c099ab4SSean Wang req.switch_reason = CH_SWITCH_NORMAL; 10621c099ab4SSean Wang 10631c099ab4SSean Wang if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) 10641c099ab4SSean Wang req.rx_streams = hweight8(req.rx_streams); 10651c099ab4SSean Wang 10661c099ab4SSean Wang if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 10671c099ab4SSean Wang int freq2 = chandef->center_freq2; 10681c099ab4SSean Wang 10691c099ab4SSean Wang req.center_ch2 = ieee80211_frequency_to_channel(freq2); 10701c099ab4SSean Wang } 10711c099ab4SSean Wang 10721c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 10731c099ab4SSean Wang } 10741c099ab4SSean Wang 10751c099ab4SSean Wang int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) 10761c099ab4SSean Wang { 10771c099ab4SSean Wang struct req_hdr { 10781c099ab4SSean Wang u8 buffer_mode; 10791c099ab4SSean Wang u8 format; 10801c099ab4SSean Wang __le16 len; 10811c099ab4SSean Wang } __packed req = { 10821c099ab4SSean Wang .buffer_mode = EE_MODE_EFUSE, 10831c099ab4SSean Wang .format = EE_FORMAT_WHOLE, 10841c099ab4SSean Wang }; 10851c099ab4SSean Wang 10861c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 10871c099ab4SSean Wang &req, sizeof(req), true); 10881c099ab4SSean Wang } 10891c099ab4SSean Wang 10901c099ab4SSean Wang int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) 10911c099ab4SSean Wang { 10921c099ab4SSean Wang struct mt7921_mcu_eeprom_info req = { 10931c099ab4SSean Wang .addr = cpu_to_le32(round_down(offset, 16)), 10941c099ab4SSean Wang }; 10951c099ab4SSean Wang struct mt7921_mcu_eeprom_info *res; 10961c099ab4SSean Wang struct sk_buff *skb; 10971c099ab4SSean Wang int ret; 10981c099ab4SSean Wang u8 *buf; 10991c099ab4SSean Wang 11001c099ab4SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, 11011c099ab4SSean Wang sizeof(req), true, &skb); 11021c099ab4SSean Wang if (ret) 11031c099ab4SSean Wang return ret; 11041c099ab4SSean Wang 11051c099ab4SSean Wang res = (struct mt7921_mcu_eeprom_info *)skb->data; 11061c099ab4SSean Wang buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); 11071c099ab4SSean Wang memcpy(buf, res->data, 16); 11081c099ab4SSean Wang dev_kfree_skb(skb); 11091c099ab4SSean Wang 11101c099ab4SSean Wang return 0; 11111c099ab4SSean Wang } 11121c099ab4SSean Wang 1113*80fc1e37SLorenzo Bianconi u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx) 11141c099ab4SSean Wang { 11151c099ab4SSean Wang struct mt7921_mcu_wlan_info wtbl_info = { 11161c099ab4SSean Wang .wlan_idx = cpu_to_le32(wlan_idx), 11171c099ab4SSean Wang }; 11181c099ab4SSean Wang struct sk_buff *skb; 11191c099ab4SSean Wang int ret; 11201c099ab4SSean Wang 11211c099ab4SSean Wang ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_WTBL, 11221c099ab4SSean Wang &wtbl_info, sizeof(wtbl_info), true, 11231c099ab4SSean Wang &skb); 11241c099ab4SSean Wang if (ret) 11251c099ab4SSean Wang return ret; 11261c099ab4SSean Wang 11271c099ab4SSean Wang mt7921_mcu_tx_rate_report(dev, skb, wlan_idx); 11281c099ab4SSean Wang dev_kfree_skb(skb); 11291c099ab4SSean Wang 11301c099ab4SSean Wang return 0; 11311c099ab4SSean Wang } 113256d965daSSean Wang 113356d965daSSean Wang int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) 113456d965daSSean Wang { 113556d965daSSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 113656d965daSSean Wang struct { 113756d965daSSean Wang struct { 113856d965daSSean Wang u8 bss_idx; 113956d965daSSean Wang u8 pad[3]; 114056d965daSSean Wang } __packed hdr; 114156d965daSSean Wang struct ps_tlv { 114256d965daSSean Wang __le16 tag; 114356d965daSSean Wang __le16 len; 114456d965daSSean Wang u8 ps_state; /* 0: device awake 114556d965daSSean Wang * 1: static power save 114656d965daSSean Wang * 2: dynamic power saving 114756d965daSSean Wang * 3: enter TWT power saving 114856d965daSSean Wang * 4: leave TWT power saving 114956d965daSSean Wang */ 115056d965daSSean Wang u8 pad[3]; 115156d965daSSean Wang } __packed ps; 115256d965daSSean Wang } __packed ps_req = { 115356d965daSSean Wang .hdr = { 115456d965daSSean Wang .bss_idx = mvif->mt76.idx, 115556d965daSSean Wang }, 115656d965daSSean Wang .ps = { 115756d965daSSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_PS), 115856d965daSSean Wang .len = cpu_to_le16(sizeof(struct ps_tlv)), 115956d965daSSean Wang .ps_state = vif->bss_conf.ps ? 2 : 0, 116056d965daSSean Wang }, 116156d965daSSean Wang }; 116256d965daSSean Wang 116356d965daSSean Wang if (vif->type != NL80211_IFTYPE_STATION) 116456d965daSSean Wang return -EOPNOTSUPP; 116556d965daSSean Wang 116656d965daSSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 116756d965daSSean Wang &ps_req, sizeof(ps_req), true); 116856d965daSSean Wang } 11694086ee28SSean Wang 11704086ee28SSean Wang int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, 11714086ee28SSean Wang bool enable) 11724086ee28SSean Wang { 11734086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 11744086ee28SSean Wang struct { 11754086ee28SSean Wang struct { 11764086ee28SSean Wang u8 bss_idx; 11774086ee28SSean Wang u8 pad[3]; 11784086ee28SSean Wang } __packed hdr; 11794086ee28SSean Wang struct bcnft_tlv { 11804086ee28SSean Wang __le16 tag; 11814086ee28SSean Wang __le16 len; 11824086ee28SSean Wang __le16 bcn_interval; 11834086ee28SSean Wang u8 dtim_period; 11844086ee28SSean Wang u8 pad; 11854086ee28SSean Wang } __packed bcnft; 11864086ee28SSean Wang } __packed bcnft_req = { 11874086ee28SSean Wang .hdr = { 11884086ee28SSean Wang .bss_idx = mvif->mt76.idx, 11894086ee28SSean Wang }, 11904086ee28SSean Wang .bcnft = { 11914086ee28SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), 11924086ee28SSean Wang .len = cpu_to_le16(sizeof(struct bcnft_tlv)), 11934086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 11944086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 11954086ee28SSean Wang }, 11964086ee28SSean Wang }; 11974086ee28SSean Wang 11984086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 11994086ee28SSean Wang return 0; 12004086ee28SSean Wang 12014086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 12024086ee28SSean Wang &bcnft_req, sizeof(bcnft_req), true); 12034086ee28SSean Wang } 12044086ee28SSean Wang 12054086ee28SSean Wang int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, 12064086ee28SSean Wang bool enable) 12074086ee28SSean Wang { 12084086ee28SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 12094086ee28SSean Wang struct { 12104086ee28SSean Wang u8 bss_idx; 12114086ee28SSean Wang u8 dtim_period; 12124086ee28SSean Wang __le16 aid; 12134086ee28SSean Wang __le16 bcn_interval; 12144086ee28SSean Wang __le16 atim_window; 12154086ee28SSean Wang u8 uapsd; 12164086ee28SSean Wang u8 bmc_delivered_ac; 12174086ee28SSean Wang u8 bmc_triggered_ac; 12184086ee28SSean Wang u8 pad; 12194086ee28SSean Wang } req = { 12204086ee28SSean Wang .bss_idx = mvif->mt76.idx, 12214086ee28SSean Wang .aid = cpu_to_le16(vif->bss_conf.aid), 12224086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 12234086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 12244086ee28SSean Wang }; 12254086ee28SSean Wang struct { 12264086ee28SSean Wang u8 bss_idx; 12274086ee28SSean Wang u8 pad[3]; 12284086ee28SSean Wang } req_hdr = { 12294086ee28SSean Wang .bss_idx = mvif->mt76.idx, 12304086ee28SSean Wang }; 12314086ee28SSean Wang int err; 12324086ee28SSean Wang 12334086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 12344086ee28SSean Wang return 0; 12354086ee28SSean Wang 12364086ee28SSean Wang err = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, &req_hdr, 12374086ee28SSean Wang sizeof(req_hdr), false); 12384086ee28SSean Wang if (err < 0 || !enable) 12394086ee28SSean Wang return err; 12404086ee28SSean Wang 12414086ee28SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, &req, 12424086ee28SSean Wang sizeof(req), false); 12434086ee28SSean Wang } 1244ffa1bf97SSean Wang 1245ffa1bf97SSean Wang #ifdef CONFIG_PM 1246ffa1bf97SSean Wang int mt7921_mcu_set_hif_suspend(struct mt7921_dev *dev, bool suspend) 1247ffa1bf97SSean Wang { 1248ffa1bf97SSean Wang struct { 1249ffa1bf97SSean Wang struct { 1250ffa1bf97SSean Wang u8 hif_type; /* 0x0: HIF_SDIO 1251ffa1bf97SSean Wang * 0x1: HIF_USB 1252ffa1bf97SSean Wang * 0x2: HIF_PCIE 1253ffa1bf97SSean Wang */ 1254ffa1bf97SSean Wang u8 pad[3]; 1255ffa1bf97SSean Wang } __packed hdr; 1256ffa1bf97SSean Wang struct hif_suspend_tlv { 1257ffa1bf97SSean Wang __le16 tag; 1258ffa1bf97SSean Wang __le16 len; 1259ffa1bf97SSean Wang u8 suspend; 1260ffa1bf97SSean Wang } __packed hif_suspend; 1261ffa1bf97SSean Wang } req = { 1262ffa1bf97SSean Wang .hif_suspend = { 1263ffa1bf97SSean Wang .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ 1264ffa1bf97SSean Wang .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), 1265ffa1bf97SSean Wang .suspend = suspend, 1266ffa1bf97SSean Wang }, 1267ffa1bf97SSean Wang }; 1268ffa1bf97SSean Wang 1269ffa1bf97SSean Wang if (mt76_is_mmio(&dev->mt76)) 1270ffa1bf97SSean Wang req.hdr.hif_type = 2; 1271ffa1bf97SSean Wang else if (mt76_is_usb(&dev->mt76)) 1272ffa1bf97SSean Wang req.hdr.hif_type = 1; 1273ffa1bf97SSean Wang else if (mt76_is_sdio(&dev->mt76)) 1274ffa1bf97SSean Wang req.hdr.hif_type = 0; 1275ffa1bf97SSean Wang 1276ffa1bf97SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, &req, 1277ffa1bf97SSean Wang sizeof(req), true); 1278ffa1bf97SSean Wang } 1279ffa1bf97SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_set_hif_suspend); 1280ffa1bf97SSean Wang 1281ffa1bf97SSean Wang static int 1282ffa1bf97SSean Wang mt7921_mcu_set_wow_ctrl(struct mt7921_phy *phy, struct ieee80211_vif *vif, 1283ffa1bf97SSean Wang bool suspend, struct cfg80211_wowlan *wowlan) 1284ffa1bf97SSean Wang { 1285ffa1bf97SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 1286ffa1bf97SSean Wang struct mt7921_dev *dev = phy->dev; 1287ffa1bf97SSean Wang struct { 1288ffa1bf97SSean Wang struct { 1289ffa1bf97SSean Wang u8 bss_idx; 1290ffa1bf97SSean Wang u8 pad[3]; 1291ffa1bf97SSean Wang } __packed hdr; 1292ffa1bf97SSean Wang struct mt7921_wow_ctrl_tlv wow_ctrl_tlv; 1293ffa1bf97SSean Wang struct mt7921_wow_gpio_param_tlv gpio_tlv; 1294ffa1bf97SSean Wang } req = { 1295ffa1bf97SSean Wang .hdr = { 1296ffa1bf97SSean Wang .bss_idx = mvif->mt76.idx, 1297ffa1bf97SSean Wang }, 1298ffa1bf97SSean Wang .wow_ctrl_tlv = { 1299ffa1bf97SSean Wang .tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL), 1300ffa1bf97SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_wow_ctrl_tlv)), 1301ffa1bf97SSean Wang .cmd = suspend ? 1 : 2, 1302ffa1bf97SSean Wang }, 1303ffa1bf97SSean Wang .gpio_tlv = { 1304ffa1bf97SSean Wang .tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM), 1305ffa1bf97SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_wow_gpio_param_tlv)), 1306ffa1bf97SSean Wang .gpio_pin = 0xff, /* follow fw about GPIO pin */ 1307ffa1bf97SSean Wang }, 1308ffa1bf97SSean Wang }; 1309ffa1bf97SSean Wang 1310ffa1bf97SSean Wang if (wowlan->magic_pkt) 1311ffa1bf97SSean Wang req.wow_ctrl_tlv.trigger |= BIT(0); 1312ffa1bf97SSean Wang if (wowlan->disconnect) 1313ffa1bf97SSean Wang req.wow_ctrl_tlv.trigger |= BIT(2); 1314ffa1bf97SSean Wang if (wowlan->nd_config) { 1315*80fc1e37SLorenzo Bianconi mt76_connac_mcu_sched_scan_req(&dev->mphy, vif, 1316*80fc1e37SLorenzo Bianconi wowlan->nd_config); 1317ffa1bf97SSean Wang req.wow_ctrl_tlv.trigger |= BIT(5); 1318*80fc1e37SLorenzo Bianconi mt76_connac_mcu_sched_scan_enable(&dev->mphy, vif, suspend); 1319ffa1bf97SSean Wang } 1320ffa1bf97SSean Wang 1321ffa1bf97SSean Wang if (mt76_is_mmio(&dev->mt76)) 1322ffa1bf97SSean Wang req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE; 1323ffa1bf97SSean Wang else if (mt76_is_usb(&dev->mt76)) 1324ffa1bf97SSean Wang req.wow_ctrl_tlv.wakeup_hif = WOW_USB; 1325ffa1bf97SSean Wang else if (mt76_is_sdio(&dev->mt76)) 1326ffa1bf97SSean Wang req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO; 1327ffa1bf97SSean Wang 1328ffa1bf97SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, &req, 1329ffa1bf97SSean Wang sizeof(req), true); 1330ffa1bf97SSean Wang } 1331ffa1bf97SSean Wang 1332ffa1bf97SSean Wang static int 1333ffa1bf97SSean Wang mt7921_mcu_set_wow_pattern(struct mt7921_dev *dev, 1334ffa1bf97SSean Wang struct ieee80211_vif *vif, 1335ffa1bf97SSean Wang u8 index, bool enable, 1336ffa1bf97SSean Wang struct cfg80211_pkt_pattern *pattern) 1337ffa1bf97SSean Wang { 1338ffa1bf97SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 1339ffa1bf97SSean Wang struct mt7921_wow_pattern_tlv *ptlv; 1340ffa1bf97SSean Wang struct sk_buff *skb; 1341ffa1bf97SSean Wang struct req_hdr { 1342ffa1bf97SSean Wang u8 bss_idx; 1343ffa1bf97SSean Wang u8 pad[3]; 1344ffa1bf97SSean Wang } __packed hdr = { 1345ffa1bf97SSean Wang .bss_idx = mvif->mt76.idx, 1346ffa1bf97SSean Wang }; 1347ffa1bf97SSean Wang 1348ffa1bf97SSean Wang skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 1349ffa1bf97SSean Wang sizeof(hdr) + sizeof(*ptlv)); 1350ffa1bf97SSean Wang if (!skb) 1351ffa1bf97SSean Wang return -ENOMEM; 1352ffa1bf97SSean Wang 1353ffa1bf97SSean Wang skb_put_data(skb, &hdr, sizeof(hdr)); 1354ffa1bf97SSean Wang ptlv = (struct mt7921_wow_pattern_tlv *)skb_put(skb, sizeof(*ptlv)); 1355ffa1bf97SSean Wang ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); 1356ffa1bf97SSean Wang ptlv->len = cpu_to_le16(sizeof(*ptlv)); 1357ffa1bf97SSean Wang ptlv->data_len = pattern->pattern_len; 1358ffa1bf97SSean Wang ptlv->enable = enable; 1359ffa1bf97SSean Wang ptlv->index = index; 1360ffa1bf97SSean Wang 1361ffa1bf97SSean Wang memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); 1362ffa1bf97SSean Wang memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8); 1363ffa1bf97SSean Wang 1364ffa1bf97SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_SUSPEND, 1365ffa1bf97SSean Wang true); 1366ffa1bf97SSean Wang } 1367ffa1bf97SSean Wang 1368ffa1bf97SSean Wang static int 1369ffa1bf97SSean Wang mt7921_mcu_set_suspend_mode(struct mt7921_dev *dev, 1370ffa1bf97SSean Wang struct ieee80211_vif *vif, 1371ffa1bf97SSean Wang bool enable, u8 mdtim, bool wow_suspend) 1372ffa1bf97SSean Wang { 1373ffa1bf97SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 1374ffa1bf97SSean Wang struct { 1375ffa1bf97SSean Wang struct { 1376ffa1bf97SSean Wang u8 bss_idx; 1377ffa1bf97SSean Wang u8 pad[3]; 1378ffa1bf97SSean Wang } __packed hdr; 1379ffa1bf97SSean Wang struct mt7921_suspend_tlv suspend_tlv; 1380ffa1bf97SSean Wang } req = { 1381ffa1bf97SSean Wang .hdr = { 1382ffa1bf97SSean Wang .bss_idx = mvif->mt76.idx, 1383ffa1bf97SSean Wang }, 1384ffa1bf97SSean Wang .suspend_tlv = { 1385ffa1bf97SSean Wang .tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING), 1386ffa1bf97SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_suspend_tlv)), 1387ffa1bf97SSean Wang .enable = enable, 1388ffa1bf97SSean Wang .mdtim = mdtim, 1389ffa1bf97SSean Wang .wow_suspend = wow_suspend, 1390ffa1bf97SSean Wang }, 1391ffa1bf97SSean Wang }; 1392ffa1bf97SSean Wang 1393ffa1bf97SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, &req, 1394ffa1bf97SSean Wang sizeof(req), true); 1395ffa1bf97SSean Wang } 1396ffa1bf97SSean Wang 1397ffa1bf97SSean Wang static int 1398ffa1bf97SSean Wang mt7921_mcu_set_gtk_rekey(struct mt7921_dev *dev, 1399ffa1bf97SSean Wang struct ieee80211_vif *vif, 1400ffa1bf97SSean Wang bool suspend) 1401ffa1bf97SSean Wang { 1402ffa1bf97SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 1403ffa1bf97SSean Wang struct { 1404ffa1bf97SSean Wang struct { 1405ffa1bf97SSean Wang u8 bss_idx; 1406ffa1bf97SSean Wang u8 pad[3]; 1407ffa1bf97SSean Wang } __packed hdr; 1408ffa1bf97SSean Wang struct mt7921_gtk_rekey_tlv gtk_tlv; 1409ffa1bf97SSean Wang } __packed req = { 1410ffa1bf97SSean Wang .hdr = { 1411ffa1bf97SSean Wang .bss_idx = mvif->mt76.idx, 1412ffa1bf97SSean Wang }, 1413ffa1bf97SSean Wang .gtk_tlv = { 1414ffa1bf97SSean Wang .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY), 1415ffa1bf97SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_gtk_rekey_tlv)), 1416ffa1bf97SSean Wang .rekey_mode = !suspend, 1417ffa1bf97SSean Wang }, 1418ffa1bf97SSean Wang }; 1419ffa1bf97SSean Wang 1420ffa1bf97SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, &req, 1421ffa1bf97SSean Wang sizeof(req), true); 1422ffa1bf97SSean Wang } 1423ffa1bf97SSean Wang 1424ffa1bf97SSean Wang static int 1425ffa1bf97SSean Wang mt7921_mcu_set_arp_filter(struct mt7921_dev *dev, struct ieee80211_vif *vif, 1426ffa1bf97SSean Wang bool suspend) 1427ffa1bf97SSean Wang { 1428ffa1bf97SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 1429ffa1bf97SSean Wang struct { 1430ffa1bf97SSean Wang struct { 1431ffa1bf97SSean Wang u8 bss_idx; 1432ffa1bf97SSean Wang u8 pad[3]; 1433ffa1bf97SSean Wang } __packed hdr; 1434ffa1bf97SSean Wang struct mt7921_arpns_tlv arpns; 1435ffa1bf97SSean Wang } req = { 1436ffa1bf97SSean Wang .hdr = { 1437ffa1bf97SSean Wang .bss_idx = mvif->mt76.idx, 1438ffa1bf97SSean Wang }, 1439ffa1bf97SSean Wang .arpns = { 1440ffa1bf97SSean Wang .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), 1441ffa1bf97SSean Wang .len = cpu_to_le16(sizeof(struct mt7921_arpns_tlv)), 1442ffa1bf97SSean Wang .mode = suspend, 1443ffa1bf97SSean Wang }, 1444ffa1bf97SSean Wang }; 1445ffa1bf97SSean Wang 1446ffa1bf97SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, &req, 1447ffa1bf97SSean Wang sizeof(req), true); 1448ffa1bf97SSean Wang } 1449ffa1bf97SSean Wang 1450ffa1bf97SSean Wang void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, 1451ffa1bf97SSean Wang struct ieee80211_vif *vif) 1452ffa1bf97SSean Wang { 1453ffa1bf97SSean Wang struct mt7921_phy *phy = priv; 1454ffa1bf97SSean Wang bool suspend = test_bit(MT76_STATE_SUSPEND, &phy->mt76->state); 1455ffa1bf97SSean Wang struct ieee80211_hw *hw = phy->mt76->hw; 1456ffa1bf97SSean Wang struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; 1457ffa1bf97SSean Wang int i; 1458ffa1bf97SSean Wang 1459ffa1bf97SSean Wang mt7921_mcu_set_gtk_rekey(phy->dev, vif, suspend); 1460ffa1bf97SSean Wang mt7921_mcu_set_arp_filter(phy->dev, vif, suspend); 1461ffa1bf97SSean Wang 1462ffa1bf97SSean Wang mt7921_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); 1463ffa1bf97SSean Wang 1464ffa1bf97SSean Wang for (i = 0; i < wowlan->n_patterns; i++) 1465ffa1bf97SSean Wang mt7921_mcu_set_wow_pattern(phy->dev, vif, i, suspend, 1466ffa1bf97SSean Wang &wowlan->patterns[i]); 1467ffa1bf97SSean Wang mt7921_mcu_set_wow_ctrl(phy, vif, suspend, wowlan); 1468ffa1bf97SSean Wang } 1469ffa1bf97SSean Wang 1470ffa1bf97SSean Wang static void 1471ffa1bf97SSean Wang mt7921_mcu_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1472ffa1bf97SSean Wang struct ieee80211_sta *sta, struct ieee80211_key_conf *key, 1473ffa1bf97SSean Wang void *data) 1474ffa1bf97SSean Wang { 1475ffa1bf97SSean Wang struct mt7921_gtk_rekey_tlv *gtk_tlv = data; 1476ffa1bf97SSean Wang u32 cipher; 1477ffa1bf97SSean Wang 1478ffa1bf97SSean Wang if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC && 1479ffa1bf97SSean Wang key->cipher != WLAN_CIPHER_SUITE_CCMP && 1480ffa1bf97SSean Wang key->cipher != WLAN_CIPHER_SUITE_TKIP) 1481ffa1bf97SSean Wang return; 1482ffa1bf97SSean Wang 1483ffa1bf97SSean Wang if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { 1484ffa1bf97SSean Wang gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1); 1485ffa1bf97SSean Wang cipher = BIT(3); 1486ffa1bf97SSean Wang } else { 1487ffa1bf97SSean Wang gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2); 1488ffa1bf97SSean Wang cipher = BIT(4); 1489ffa1bf97SSean Wang } 1490ffa1bf97SSean Wang 1491ffa1bf97SSean Wang /* we are assuming here to have a single pairwise key */ 1492ffa1bf97SSean Wang if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 1493ffa1bf97SSean Wang gtk_tlv->pairwise_cipher = cpu_to_le32(cipher); 1494ffa1bf97SSean Wang gtk_tlv->group_cipher = cpu_to_le32(cipher); 1495ffa1bf97SSean Wang gtk_tlv->keyid = key->keyidx; 1496ffa1bf97SSean Wang } 1497ffa1bf97SSean Wang } 1498ffa1bf97SSean Wang 1499ffa1bf97SSean Wang int mt7921_mcu_update_gtk_rekey(struct ieee80211_hw *hw, 1500ffa1bf97SSean Wang struct ieee80211_vif *vif, 1501ffa1bf97SSean Wang struct cfg80211_gtk_rekey_data *key) 1502ffa1bf97SSean Wang { 1503ffa1bf97SSean Wang struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; 1504ffa1bf97SSean Wang struct mt7921_dev *dev = mt7921_hw_dev(hw); 1505ffa1bf97SSean Wang struct mt7921_gtk_rekey_tlv *gtk_tlv; 1506ffa1bf97SSean Wang struct sk_buff *skb; 1507ffa1bf97SSean Wang struct { 1508ffa1bf97SSean Wang u8 bss_idx; 1509ffa1bf97SSean Wang u8 pad[3]; 1510ffa1bf97SSean Wang } __packed hdr = { 1511ffa1bf97SSean Wang .bss_idx = mvif->mt76.idx, 1512ffa1bf97SSean Wang }; 1513ffa1bf97SSean Wang 1514ffa1bf97SSean Wang skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 1515ffa1bf97SSean Wang sizeof(hdr) + sizeof(*gtk_tlv)); 1516ffa1bf97SSean Wang if (!skb) 1517ffa1bf97SSean Wang return -ENOMEM; 1518ffa1bf97SSean Wang 1519ffa1bf97SSean Wang skb_put_data(skb, &hdr, sizeof(hdr)); 1520ffa1bf97SSean Wang gtk_tlv = (struct mt7921_gtk_rekey_tlv *)skb_put(skb, 1521ffa1bf97SSean Wang sizeof(*gtk_tlv)); 1522ffa1bf97SSean Wang gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY); 1523ffa1bf97SSean Wang gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv)); 1524ffa1bf97SSean Wang gtk_tlv->rekey_mode = 2; 1525ffa1bf97SSean Wang gtk_tlv->option = 1; 1526ffa1bf97SSean Wang 1527ffa1bf97SSean Wang rcu_read_lock(); 1528ffa1bf97SSean Wang ieee80211_iter_keys_rcu(hw, vif, mt7921_mcu_key_iter, gtk_tlv); 1529ffa1bf97SSean Wang rcu_read_unlock(); 1530ffa1bf97SSean Wang 1531ffa1bf97SSean Wang memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN); 1532ffa1bf97SSean Wang memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN); 1533ffa1bf97SSean Wang memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN); 1534ffa1bf97SSean Wang 1535ffa1bf97SSean Wang return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_OFFLOAD, 1536ffa1bf97SSean Wang true); 1537ffa1bf97SSean Wang } 1538ffa1bf97SSean Wang #endif /* CONFIG_PM */ 1539