18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* Copyright (C) 2019 MediaTek Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author: Roy Luo <royluo@google.com> 58c2ecf20Sopenharmony_ci * Ryder Lee <ryder.lee@mediatek.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/firmware.h> 98c2ecf20Sopenharmony_ci#include "mt7615.h" 108c2ecf20Sopenharmony_ci#include "mcu.h" 118c2ecf20Sopenharmony_ci#include "mac.h" 128c2ecf20Sopenharmony_ci#include "eeprom.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic bool prefer_offload_fw = true; 158c2ecf20Sopenharmony_cimodule_param(prefer_offload_fw, bool, 0644); 168c2ecf20Sopenharmony_ciMODULE_PARM_DESC(prefer_offload_fw, 178c2ecf20Sopenharmony_ci "Prefer client mode offload firmware (MT7663)"); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistruct mt7615_patch_hdr { 208c2ecf20Sopenharmony_ci char build_date[16]; 218c2ecf20Sopenharmony_ci char platform[4]; 228c2ecf20Sopenharmony_ci __be32 hw_sw_ver; 238c2ecf20Sopenharmony_ci __be32 patch_ver; 248c2ecf20Sopenharmony_ci __be16 checksum; 258c2ecf20Sopenharmony_ci} __packed; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct mt7615_fw_trailer { 288c2ecf20Sopenharmony_ci __le32 addr; 298c2ecf20Sopenharmony_ci u8 chip_id; 308c2ecf20Sopenharmony_ci u8 feature_set; 318c2ecf20Sopenharmony_ci u8 eco_code; 328c2ecf20Sopenharmony_ci char fw_ver[10]; 338c2ecf20Sopenharmony_ci char build_date[15]; 348c2ecf20Sopenharmony_ci __le32 len; 358c2ecf20Sopenharmony_ci} __packed; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define FW_V3_COMMON_TAILER_SIZE 36 388c2ecf20Sopenharmony_ci#define FW_V3_REGION_TAILER_SIZE 40 398c2ecf20Sopenharmony_ci#define FW_START_OVERRIDE BIT(0) 408c2ecf20Sopenharmony_ci#define FW_START_DLYCAL BIT(1) 418c2ecf20Sopenharmony_ci#define FW_START_WORKING_PDA_CR4 BIT(2) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct mt7663_fw_trailer { 448c2ecf20Sopenharmony_ci u8 chip_id; 458c2ecf20Sopenharmony_ci u8 eco_code; 468c2ecf20Sopenharmony_ci u8 n_region; 478c2ecf20Sopenharmony_ci u8 format_ver; 488c2ecf20Sopenharmony_ci u8 format_flag; 498c2ecf20Sopenharmony_ci u8 reserv[2]; 508c2ecf20Sopenharmony_ci char fw_ver[10]; 518c2ecf20Sopenharmony_ci char build_date[15]; 528c2ecf20Sopenharmony_ci __le32 crc; 538c2ecf20Sopenharmony_ci} __packed; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct mt7663_fw_buf { 568c2ecf20Sopenharmony_ci __le32 crc; 578c2ecf20Sopenharmony_ci __le32 d_img_size; 588c2ecf20Sopenharmony_ci __le32 block_size; 598c2ecf20Sopenharmony_ci u8 rsv[4]; 608c2ecf20Sopenharmony_ci __le32 img_dest_addr; 618c2ecf20Sopenharmony_ci __le32 img_size; 628c2ecf20Sopenharmony_ci u8 feature_set; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define MT7615_PATCH_ADDRESS 0x80000 668c2ecf20Sopenharmony_ci#define MT7622_PATCH_ADDRESS 0x9c000 678c2ecf20Sopenharmony_ci#define MT7663_PATCH_ADDRESS 0xdc000 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define N9_REGION_NUM 2 708c2ecf20Sopenharmony_ci#define CR4_REGION_NUM 1 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define IMG_CRC_LEN 4 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define FW_FEATURE_SET_ENCRYPT BIT(0) 758c2ecf20Sopenharmony_ci#define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define DL_MODE_ENCRYPT BIT(0) 788c2ecf20Sopenharmony_ci#define DL_MODE_KEY_IDX GENMASK(2, 1) 798c2ecf20Sopenharmony_ci#define DL_MODE_RESET_SEC_IV BIT(3) 808c2ecf20Sopenharmony_ci#define DL_MODE_WORKING_PDA_CR4 BIT(4) 818c2ecf20Sopenharmony_ci#define DL_MODE_VALID_RAM_ENTRY BIT(5) 828c2ecf20Sopenharmony_ci#define DL_MODE_NEED_RSP BIT(31) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define FW_START_OVERRIDE BIT(0) 858c2ecf20Sopenharmony_ci#define FW_START_WORKING_PDA_CR4 BIT(2) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_civoid mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, 888c2ecf20Sopenharmony_ci int cmd, int *wait_seq) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci int txd_len, mcu_cmd = cmd & MCU_CMD_MASK; 918c2ecf20Sopenharmony_ci struct mt7615_uni_txd *uni_txd; 928c2ecf20Sopenharmony_ci struct mt7615_mcu_txd *mcu_txd; 938c2ecf20Sopenharmony_ci u8 seq, q_idx, pkt_fmt; 948c2ecf20Sopenharmony_ci __le32 *txd; 958c2ecf20Sopenharmony_ci u32 val; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci seq = ++dev->mt76.mcu.msg_seq & 0xf; 988c2ecf20Sopenharmony_ci if (!seq) 998c2ecf20Sopenharmony_ci seq = ++dev->mt76.mcu.msg_seq & 0xf; 1008c2ecf20Sopenharmony_ci if (wait_seq) 1018c2ecf20Sopenharmony_ci *wait_seq = seq; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd); 1048c2ecf20Sopenharmony_ci txd = (__le32 *)skb_push(skb, txd_len); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (cmd != MCU_CMD_FW_SCATTER) { 1078c2ecf20Sopenharmony_ci q_idx = MT_TX_MCU_PORT_RX_Q0; 1088c2ecf20Sopenharmony_ci pkt_fmt = MT_TX_TYPE_CMD; 1098c2ecf20Sopenharmony_ci } else { 1108c2ecf20Sopenharmony_ci q_idx = MT_TX_MCU_PORT_RX_FWDL; 1118c2ecf20Sopenharmony_ci pkt_fmt = MT_TX_TYPE_FW; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | 1158c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) | 1168c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD0_Q_IDX, q_idx); 1178c2ecf20Sopenharmony_ci txd[0] = cpu_to_le32(val); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci val = MT_TXD1_LONG_FORMAT | 1208c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) | 1218c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt); 1228c2ecf20Sopenharmony_ci txd[1] = cpu_to_le32(val); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (cmd & MCU_UNI_PREFIX) { 1258c2ecf20Sopenharmony_ci uni_txd = (struct mt7615_uni_txd *)txd; 1268c2ecf20Sopenharmony_ci uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); 1278c2ecf20Sopenharmony_ci uni_txd->option = MCU_CMD_UNI_EXT_ACK; 1288c2ecf20Sopenharmony_ci uni_txd->cid = cpu_to_le16(mcu_cmd); 1298c2ecf20Sopenharmony_ci uni_txd->s2d_index = MCU_S2D_H2N; 1308c2ecf20Sopenharmony_ci uni_txd->pkt_type = MCU_PKT_ID; 1318c2ecf20Sopenharmony_ci uni_txd->seq = seq; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci mcu_txd = (struct mt7615_mcu_txd *)txd; 1378c2ecf20Sopenharmony_ci mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); 1388c2ecf20Sopenharmony_ci mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx)); 1398c2ecf20Sopenharmony_ci mcu_txd->s2d_index = MCU_S2D_H2N; 1408c2ecf20Sopenharmony_ci mcu_txd->pkt_type = MCU_PKT_ID; 1418c2ecf20Sopenharmony_ci mcu_txd->seq = seq; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci switch (cmd & ~MCU_CMD_MASK) { 1448c2ecf20Sopenharmony_ci case MCU_FW_PREFIX: 1458c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_NA; 1468c2ecf20Sopenharmony_ci mcu_txd->cid = mcu_cmd; 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case MCU_CE_PREFIX: 1498c2ecf20Sopenharmony_ci if (cmd & MCU_QUERY_MASK) 1508c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_QUERY; 1518c2ecf20Sopenharmony_ci else 1528c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_SET; 1538c2ecf20Sopenharmony_ci mcu_txd->cid = mcu_cmd; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci default: 1568c2ecf20Sopenharmony_ci mcu_txd->cid = MCU_CMD_EXT_CID; 1578c2ecf20Sopenharmony_ci if (cmd & MCU_QUERY_PREFIX) 1588c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_QUERY; 1598c2ecf20Sopenharmony_ci else 1608c2ecf20Sopenharmony_ci mcu_txd->set_query = MCU_Q_SET; 1618c2ecf20Sopenharmony_ci mcu_txd->ext_cid = mcu_cmd; 1628c2ecf20Sopenharmony_ci mcu_txd->ext_cid_ack = 1; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb, 1698c2ecf20Sopenharmony_ci int cmd, int *wait_seq) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci enum mt76_txq_id qid; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci mt7615_mcu_fill_msg(dev, skb, cmd, wait_seq); 1748c2ecf20Sopenharmony_ci if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) 1758c2ecf20Sopenharmony_ci qid = MT_TXQ_MCU; 1768c2ecf20Sopenharmony_ci else 1778c2ecf20Sopenharmony_ci qid = MT_TXQ_FWDL; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return mt76_tx_queue_skb_raw(dev, qid, skb, 0); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int 1838c2ecf20Sopenharmony_cimt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, 1848c2ecf20Sopenharmony_ci struct sk_buff *skb, int seq) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; 1878c2ecf20Sopenharmony_ci int ret = 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (seq != rxd->seq) { 1908c2ecf20Sopenharmony_ci ret = -EAGAIN; 1918c2ecf20Sopenharmony_ci goto out; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci switch (cmd) { 1958c2ecf20Sopenharmony_ci case MCU_CMD_PATCH_SEM_CONTROL: 1968c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*rxd) - 4); 1978c2ecf20Sopenharmony_ci ret = *skb->data; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case MCU_EXT_CMD_GET_TEMP: 2008c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*rxd)); 2018c2ecf20Sopenharmony_ci ret = le32_to_cpu(*(__le32 *)skb->data); 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci case MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX: 2048c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*rxd)); 2058c2ecf20Sopenharmony_ci ret = le32_to_cpu(*(__le32 *)&skb->data[8]); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case MCU_UNI_CMD_DEV_INFO_UPDATE: 2088c2ecf20Sopenharmony_ci case MCU_UNI_CMD_BSS_INFO_UPDATE: 2098c2ecf20Sopenharmony_ci case MCU_UNI_CMD_STA_REC_UPDATE: 2108c2ecf20Sopenharmony_ci case MCU_UNI_CMD_HIF_CTRL: 2118c2ecf20Sopenharmony_ci case MCU_UNI_CMD_OFFLOAD: 2128c2ecf20Sopenharmony_ci case MCU_UNI_CMD_SUSPEND: { 2138c2ecf20Sopenharmony_ci struct mt7615_mcu_uni_event *event; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*rxd)); 2168c2ecf20Sopenharmony_ci event = (struct mt7615_mcu_uni_event *)skb->data; 2178c2ecf20Sopenharmony_ci ret = le32_to_cpu(event->status); 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci case MCU_CMD_REG_READ: { 2218c2ecf20Sopenharmony_ci struct mt7615_mcu_reg_event *event; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*rxd)); 2248c2ecf20Sopenharmony_ci event = (struct mt7615_mcu_reg_event *)skb->data; 2258c2ecf20Sopenharmony_ci ret = (int)le32_to_cpu(event->val); 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci default: 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ciout: 2328c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return ret; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci unsigned long expires = jiffies + 20 * HZ; 2408c2ecf20Sopenharmony_ci struct sk_buff *skb; 2418c2ecf20Sopenharmony_ci int ret = 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci while (true) { 2448c2ecf20Sopenharmony_ci skb = mt76_mcu_get_response(&dev->mt76, expires); 2458c2ecf20Sopenharmony_ci if (!skb) { 2468c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Message %ld (seq %d) timeout\n", 2478c2ecf20Sopenharmony_ci cmd & MCU_CMD_MASK, seq); 2488c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ret = mt7615_mcu_parse_response(dev, cmd, skb, seq); 2528c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_wait_response); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int 2618c2ecf20Sopenharmony_cimt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 2628c2ecf20Sopenharmony_ci int cmd, bool wait_resp) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 2658c2ecf20Sopenharmony_ci int ret, seq; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci mutex_lock(&mdev->mcu.mutex); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ret = __mt7615_mcu_msg_send(dev, skb, cmd, &seq); 2708c2ecf20Sopenharmony_ci if (ret) 2718c2ecf20Sopenharmony_ci goto out; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (wait_resp) 2748c2ecf20Sopenharmony_ci ret = mt7615_mcu_wait_response(dev, cmd, seq); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciout: 2778c2ecf20Sopenharmony_ci mutex_unlock(&mdev->mcu.mutex); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ciint mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, 2838c2ecf20Sopenharmony_ci int len, bool wait_resp) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct sk_buff *skb; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(mdev, data, len); 2888c2ecf20Sopenharmony_ci if (!skb) 2898c2ecf20Sopenharmony_ci return -ENOMEM; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_msg_send); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ciu32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct { 2988c2ecf20Sopenharmony_ci __le32 wifi_stream; 2998c2ecf20Sopenharmony_ci __le32 address; 3008c2ecf20Sopenharmony_ci __le32 data; 3018c2ecf20Sopenharmony_ci } req = { 3028c2ecf20Sopenharmony_ci .wifi_stream = cpu_to_le32(wf), 3038c2ecf20Sopenharmony_ci .address = cpu_to_le32(reg), 3048c2ecf20Sopenharmony_ci }; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, 3078c2ecf20Sopenharmony_ci MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX, 3088c2ecf20Sopenharmony_ci &req, sizeof(req), true); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciint mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct { 3148c2ecf20Sopenharmony_ci __le32 wifi_stream; 3158c2ecf20Sopenharmony_ci __le32 address; 3168c2ecf20Sopenharmony_ci __le32 data; 3178c2ecf20Sopenharmony_ci } req = { 3188c2ecf20Sopenharmony_ci .wifi_stream = cpu_to_le32(wf), 3198c2ecf20Sopenharmony_ci .address = cpu_to_le32(reg), 3208c2ecf20Sopenharmony_ci .data = cpu_to_le32(val), 3218c2ecf20Sopenharmony_ci }; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RF_REG_ACCESS, &req, 3248c2ecf20Sopenharmony_ci sizeof(req), false); 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci if (!is_mt7622(&dev->mt76)) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC, 3338c2ecf20Sopenharmony_ci MT_INFRACFG_MISC_AP2CONN_WAKE, 3348c2ecf20Sopenharmony_ci !en * MT_INFRACFG_MISC_AP2CONN_WAKE); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 3408c2ecf20Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 3418c2ecf20Sopenharmony_ci u32 addr; 3428c2ecf20Sopenharmony_ci int err; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (is_mt7663(mdev)) { 3458c2ecf20Sopenharmony_ci /* Clear firmware own via N9 eint */ 3468c2ecf20Sopenharmony_ci mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN); 3478c2ecf20Sopenharmony_ci mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci addr = MT_CONN_HIF_ON_LPCTL; 3508c2ecf20Sopenharmony_ci } else { 3518c2ecf20Sopenharmony_ci addr = MT_CFG_LPCR_HOST; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci mt7622_trigger_hif_int(dev, true); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci mt7622_trigger_hif_int(dev, false); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (err) { 3638c2ecf20Sopenharmony_ci dev_err(mdev->dev, "driver own failed\n"); 3648c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci clear_bit(MT76_STATE_PM, &mphy->state); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 3758c2ecf20Sopenharmony_ci int i; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) 3788c2ecf20Sopenharmony_ci goto out; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) { 3818c2ecf20Sopenharmony_ci mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN); 3828c2ecf20Sopenharmony_ci if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL, 3838c2ecf20Sopenharmony_ci MT_CFG_LPCR_HOST_FW_OWN, 0, 50)) 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (i == MT7615_DRV_OWN_RETRY_COUNT) { 3888c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "driver own failed\n"); 3898c2ecf20Sopenharmony_ci set_bit(MT76_STATE_PM, &mphy->state); 3908c2ecf20Sopenharmony_ci return -EIO; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciout: 3948c2ecf20Sopenharmony_ci dev->pm.last_activity = jiffies; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 4028c2ecf20Sopenharmony_ci int err = 0; 4038c2ecf20Sopenharmony_ci u32 addr; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci mt7622_trigger_hif_int(dev, true); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; 4118c2ecf20Sopenharmony_ci mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (is_mt7622(&dev->mt76) && 4148c2ecf20Sopenharmony_ci !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 4158c2ecf20Sopenharmony_ci MT_CFG_LPCR_HOST_FW_OWN, 3000)) { 4168c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout for firmware own\n"); 4178c2ecf20Sopenharmony_ci clear_bit(MT76_STATE_PM, &mphy->state); 4188c2ecf20Sopenharmony_ci err = -EIO; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci mt7622_trigger_hif_int(dev, false); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return err; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic void 4278c2ecf20Sopenharmony_cimt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci if (vif->csa_active) 4308c2ecf20Sopenharmony_ci ieee80211_csa_finish(vif); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void 4348c2ecf20Sopenharmony_cimt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct mt76_phy *mphy = &dev->mt76.phy; 4378c2ecf20Sopenharmony_ci struct mt7615_mcu_rdd_report *r; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci r = (struct mt7615_mcu_rdd_report *)skb->data; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (r->idx && dev->mt76.phy2) 4428c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ieee80211_radar_detected(mphy->hw); 4458c2ecf20Sopenharmony_ci dev->hw_pattern++; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void 4498c2ecf20Sopenharmony_cimt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; 4528c2ecf20Sopenharmony_ci const char *data = (char *)&rxd[1]; 4538c2ecf20Sopenharmony_ci const char *type; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci switch (rxd->s2d_index) { 4568c2ecf20Sopenharmony_ci case 0: 4578c2ecf20Sopenharmony_ci type = "N9"; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci case 2: 4608c2ecf20Sopenharmony_ci type = "CR4"; 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci default: 4638c2ecf20Sopenharmony_ci type = "unknown"; 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci wiphy_info(mt76_hw(dev)->wiphy, "%s: %s", type, data); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic void 4718c2ecf20Sopenharmony_cimt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci switch (rxd->ext_eid) { 4768c2ecf20Sopenharmony_ci case MCU_EXT_EVENT_RDD_REPORT: 4778c2ecf20Sopenharmony_ci mt7615_mcu_rx_radar_detected(dev, skb); 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci case MCU_EXT_EVENT_CSA_NOTIFY: 4808c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, 4818c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 4828c2ecf20Sopenharmony_ci mt7615_mcu_csa_finish, dev); 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci case MCU_EXT_EVENT_FW_LOG_2_HOST: 4858c2ecf20Sopenharmony_ci mt7615_mcu_rx_log_message(dev, skb); 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci default: 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic void 4938c2ecf20Sopenharmony_cimt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd); 4968c2ecf20Sopenharmony_ci struct mt7615_phy *phy; 4978c2ecf20Sopenharmony_ci struct mt76_phy *mphy; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (*seq_num & BIT(7) && dev->mt76.phy2) 5008c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 5018c2ecf20Sopenharmony_ci else 5028c2ecf20Sopenharmony_ci mphy = &dev->mt76.phy; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci phy = (struct mt7615_phy *)mphy->priv; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci spin_lock_bh(&dev->mt76.lock); 5078c2ecf20Sopenharmony_ci __skb_queue_tail(&phy->scan_event_list, skb); 5088c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->mt76.lock); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, 5118c2ecf20Sopenharmony_ci MT7615_HW_SCAN_TIMEOUT); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void 5158c2ecf20Sopenharmony_cimt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct mt7615_roc_tlv *event; 5188c2ecf20Sopenharmony_ci struct mt7615_phy *phy; 5198c2ecf20Sopenharmony_ci struct mt76_phy *mphy; 5208c2ecf20Sopenharmony_ci int duration; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); 5238c2ecf20Sopenharmony_ci event = (struct mt7615_roc_tlv *)skb->data; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (event->dbdc_band && dev->mt76.phy2) 5268c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 5278c2ecf20Sopenharmony_ci else 5288c2ecf20Sopenharmony_ci mphy = &dev->mt76.phy; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci ieee80211_ready_on_channel(mphy->hw); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci phy = (struct mt7615_phy *)mphy->priv; 5338c2ecf20Sopenharmony_ci phy->roc_grant = true; 5348c2ecf20Sopenharmony_ci wake_up(&phy->roc_wait); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci duration = le32_to_cpu(event->max_interval); 5378c2ecf20Sopenharmony_ci mod_timer(&phy->roc_timer, 5388c2ecf20Sopenharmony_ci round_jiffies_up(jiffies + msecs_to_jiffies(duration))); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic void 5428c2ecf20Sopenharmony_cimt7615_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 5458c2ecf20Sopenharmony_ci struct mt7615_beacon_loss_event *event = priv; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (mvif->idx != event->bss_idx) 5488c2ecf20Sopenharmony_ci return; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) 5518c2ecf20Sopenharmony_ci return; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci ieee80211_beacon_loss(vif); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void 5578c2ecf20Sopenharmony_cimt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct mt7615_beacon_loss_event *event; 5608c2ecf20Sopenharmony_ci struct mt76_phy *mphy; 5618c2ecf20Sopenharmony_ci u8 band_idx = 0; /* DBDC support */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); 5648c2ecf20Sopenharmony_ci event = (struct mt7615_beacon_loss_event *)skb->data; 5658c2ecf20Sopenharmony_ci if (band_idx && dev->mt76.phy2) 5668c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 5678c2ecf20Sopenharmony_ci else 5688c2ecf20Sopenharmony_ci mphy = &dev->mt76.phy; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(mphy->hw, 5718c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 5728c2ecf20Sopenharmony_ci mt7615_mcu_beacon_loss_iter, event); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic void 5768c2ecf20Sopenharmony_cimt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct mt7615_mcu_bss_event *event; 5798c2ecf20Sopenharmony_ci struct mt76_phy *mphy; 5808c2ecf20Sopenharmony_ci u8 band_idx = 0; /* DBDC support */ 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci event = (struct mt7615_mcu_bss_event *)(skb->data + 5838c2ecf20Sopenharmony_ci sizeof(struct mt7615_mcu_rxd)); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (band_idx && dev->mt76.phy2) 5868c2ecf20Sopenharmony_ci mphy = dev->mt76.phy2; 5878c2ecf20Sopenharmony_ci else 5888c2ecf20Sopenharmony_ci mphy = &dev->mt76.phy; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (event->is_absent) 5918c2ecf20Sopenharmony_ci ieee80211_stop_queues(mphy->hw); 5928c2ecf20Sopenharmony_ci else 5938c2ecf20Sopenharmony_ci ieee80211_wake_queues(mphy->hw); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void 5978c2ecf20Sopenharmony_cimt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci switch (rxd->eid) { 6028c2ecf20Sopenharmony_ci case MCU_EVENT_EXT: 6038c2ecf20Sopenharmony_ci mt7615_mcu_rx_ext_event(dev, skb); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci case MCU_EVENT_BSS_BEACON_LOSS: 6068c2ecf20Sopenharmony_ci mt7615_mcu_beacon_loss_event(dev, skb); 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci case MCU_EVENT_ROC: 6098c2ecf20Sopenharmony_ci mt7615_mcu_roc_event(dev, skb); 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci case MCU_EVENT_SCHED_SCAN_DONE: 6128c2ecf20Sopenharmony_ci case MCU_EVENT_SCAN_DONE: 6138c2ecf20Sopenharmony_ci mt7615_mcu_scan_event(dev, skb); 6148c2ecf20Sopenharmony_ci return; 6158c2ecf20Sopenharmony_ci case MCU_EVENT_BSS_ABSENCE: 6168c2ecf20Sopenharmony_ci mt7615_mcu_bss_event(dev, skb); 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci default: 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_civoid mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || 6298c2ecf20Sopenharmony_ci rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || 6308c2ecf20Sopenharmony_ci rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || 6318c2ecf20Sopenharmony_ci rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || 6328c2ecf20Sopenharmony_ci rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || 6338c2ecf20Sopenharmony_ci rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || 6348c2ecf20Sopenharmony_ci rxd->eid == MCU_EVENT_BSS_ABSENCE || 6358c2ecf20Sopenharmony_ci rxd->eid == MCU_EVENT_SCAN_DONE || 6368c2ecf20Sopenharmony_ci rxd->eid == MCU_EVENT_ROC || 6378c2ecf20Sopenharmony_ci !rxd->seq) 6388c2ecf20Sopenharmony_ci mt7615_mcu_rx_unsolicited_event(dev, skb); 6398c2ecf20Sopenharmony_ci else 6408c2ecf20Sopenharmony_ci mt76_mcu_rx_event(&dev->mt76, skb); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr, 6448c2ecf20Sopenharmony_ci u32 len, u32 mode) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct { 6478c2ecf20Sopenharmony_ci __le32 addr; 6488c2ecf20Sopenharmony_ci __le32 len; 6498c2ecf20Sopenharmony_ci __le32 mode; 6508c2ecf20Sopenharmony_ci } req = { 6518c2ecf20Sopenharmony_ci .addr = cpu_to_le32(addr), 6528c2ecf20Sopenharmony_ci .len = cpu_to_le32(len), 6538c2ecf20Sopenharmony_ci .mode = cpu_to_le32(mode), 6548c2ecf20Sopenharmony_ci }; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_TARGET_ADDRESS_LEN_REQ, 6578c2ecf20Sopenharmony_ci &req, sizeof(req), true); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int 6618c2ecf20Sopenharmony_cimt7615_mcu_add_dev(struct mt7615_dev *dev, struct ieee80211_vif *vif, 6628c2ecf20Sopenharmony_ci bool enable) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 6658c2ecf20Sopenharmony_ci struct { 6668c2ecf20Sopenharmony_ci struct req_hdr { 6678c2ecf20Sopenharmony_ci u8 omac_idx; 6688c2ecf20Sopenharmony_ci u8 band_idx; 6698c2ecf20Sopenharmony_ci __le16 tlv_num; 6708c2ecf20Sopenharmony_ci u8 is_tlv_append; 6718c2ecf20Sopenharmony_ci u8 rsv[3]; 6728c2ecf20Sopenharmony_ci } __packed hdr; 6738c2ecf20Sopenharmony_ci struct req_tlv { 6748c2ecf20Sopenharmony_ci __le16 tag; 6758c2ecf20Sopenharmony_ci __le16 len; 6768c2ecf20Sopenharmony_ci u8 active; 6778c2ecf20Sopenharmony_ci u8 band_idx; 6788c2ecf20Sopenharmony_ci u8 omac_addr[ETH_ALEN]; 6798c2ecf20Sopenharmony_ci } __packed tlv; 6808c2ecf20Sopenharmony_ci } data = { 6818c2ecf20Sopenharmony_ci .hdr = { 6828c2ecf20Sopenharmony_ci .omac_idx = mvif->omac_idx, 6838c2ecf20Sopenharmony_ci .band_idx = mvif->band_idx, 6848c2ecf20Sopenharmony_ci .tlv_num = cpu_to_le16(1), 6858c2ecf20Sopenharmony_ci .is_tlv_append = 1, 6868c2ecf20Sopenharmony_ci }, 6878c2ecf20Sopenharmony_ci .tlv = { 6888c2ecf20Sopenharmony_ci .tag = cpu_to_le16(DEV_INFO_ACTIVE), 6898c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct req_tlv)), 6908c2ecf20Sopenharmony_ci .active = enable, 6918c2ecf20Sopenharmony_ci .band_idx = mvif->band_idx, 6928c2ecf20Sopenharmony_ci }, 6938c2ecf20Sopenharmony_ci }; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); 6968c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE, 6978c2ecf20Sopenharmony_ci &data, sizeof(data), true); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic int 7018c2ecf20Sopenharmony_cimt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, 7028c2ecf20Sopenharmony_ci struct ieee80211_hw *hw, 7038c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, bool enable) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 7068c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = &dev->mt76.global_wcid; 7078c2ecf20Sopenharmony_ci struct ieee80211_mutable_offsets offs; 7088c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 7098c2ecf20Sopenharmony_ci struct req { 7108c2ecf20Sopenharmony_ci u8 omac_idx; 7118c2ecf20Sopenharmony_ci u8 enable; 7128c2ecf20Sopenharmony_ci u8 wlan_idx; 7138c2ecf20Sopenharmony_ci u8 band_idx; 7148c2ecf20Sopenharmony_ci u8 pkt_type; 7158c2ecf20Sopenharmony_ci u8 need_pre_tbtt_int; 7168c2ecf20Sopenharmony_ci __le16 csa_ie_pos; 7178c2ecf20Sopenharmony_ci __le16 pkt_len; 7188c2ecf20Sopenharmony_ci __le16 tim_ie_pos; 7198c2ecf20Sopenharmony_ci u8 pkt[512]; 7208c2ecf20Sopenharmony_ci u8 csa_cnt; 7218c2ecf20Sopenharmony_ci /* bss color change */ 7228c2ecf20Sopenharmony_ci u8 bcc_cnt; 7238c2ecf20Sopenharmony_ci __le16 bcc_ie_pos; 7248c2ecf20Sopenharmony_ci } __packed req = { 7258c2ecf20Sopenharmony_ci .omac_idx = mvif->omac_idx, 7268c2ecf20Sopenharmony_ci .enable = enable, 7278c2ecf20Sopenharmony_ci .wlan_idx = wcid->idx, 7288c2ecf20Sopenharmony_ci .band_idx = mvif->band_idx, 7298c2ecf20Sopenharmony_ci }; 7308c2ecf20Sopenharmony_ci struct sk_buff *skb; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci skb = ieee80211_beacon_get_template(hw, vif, &offs); 7338c2ecf20Sopenharmony_ci if (!skb) 7348c2ecf20Sopenharmony_ci return -EINVAL; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (skb->len > 512 - MT_TXD_SIZE) { 7378c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); 7388c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 7398c2ecf20Sopenharmony_ci return -EINVAL; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (mvif->band_idx) { 7438c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 7448c2ecf20Sopenharmony_ci info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL, 7488c2ecf20Sopenharmony_ci 0, NULL, true); 7498c2ecf20Sopenharmony_ci memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len); 7508c2ecf20Sopenharmony_ci req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); 7518c2ecf20Sopenharmony_ci req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); 7528c2ecf20Sopenharmony_ci if (offs.cntdwn_counter_offs[0]) { 7538c2ecf20Sopenharmony_ci u16 csa_offs; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4; 7568c2ecf20Sopenharmony_ci req.csa_ie_pos = cpu_to_le16(csa_offs); 7578c2ecf20Sopenharmony_ci req.csa_cnt = skb->data[offs.cntdwn_counter_offs[0]]; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD, 7628c2ecf20Sopenharmony_ci &req, sizeof(req), true); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int 7668c2ecf20Sopenharmony_cimt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci#define ENTER_PM_STATE 1 7698c2ecf20Sopenharmony_ci#define EXIT_PM_STATE 2 7708c2ecf20Sopenharmony_ci struct { 7718c2ecf20Sopenharmony_ci u8 pm_number; 7728c2ecf20Sopenharmony_ci u8 pm_state; 7738c2ecf20Sopenharmony_ci u8 bssid[ETH_ALEN]; 7748c2ecf20Sopenharmony_ci u8 dtim_period; 7758c2ecf20Sopenharmony_ci u8 wlan_idx; 7768c2ecf20Sopenharmony_ci __le16 bcn_interval; 7778c2ecf20Sopenharmony_ci __le32 aid; 7788c2ecf20Sopenharmony_ci __le32 rx_filter; 7798c2ecf20Sopenharmony_ci u8 band_idx; 7808c2ecf20Sopenharmony_ci u8 rsv[3]; 7818c2ecf20Sopenharmony_ci __le32 feature; 7828c2ecf20Sopenharmony_ci u8 omac_idx; 7838c2ecf20Sopenharmony_ci u8 wmm_idx; 7848c2ecf20Sopenharmony_ci u8 bcn_loss_cnt; 7858c2ecf20Sopenharmony_ci u8 bcn_sp_duration; 7868c2ecf20Sopenharmony_ci } __packed req = { 7878c2ecf20Sopenharmony_ci .pm_number = 5, 7888c2ecf20Sopenharmony_ci .pm_state = state ? ENTER_PM_STATE : EXIT_PM_STATE, 7898c2ecf20Sopenharmony_ci .band_idx = band, 7908c2ecf20Sopenharmony_ci }; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, 7938c2ecf20Sopenharmony_ci &req, sizeof(req), true); 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic struct sk_buff * 7978c2ecf20Sopenharmony_cimt7615_mcu_alloc_sta_req(struct mt7615_dev *dev, struct mt7615_vif *mvif, 7988c2ecf20Sopenharmony_ci struct mt7615_sta *msta) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct sta_req_hdr hdr = { 8018c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 8028c2ecf20Sopenharmony_ci .wlan_idx = msta ? msta->wcid.idx : 0, 8038c2ecf20Sopenharmony_ci .muar_idx = msta ? mvif->omac_idx : 0, 8048c2ecf20Sopenharmony_ci .is_tlv_append = 1, 8058c2ecf20Sopenharmony_ci }; 8068c2ecf20Sopenharmony_ci struct sk_buff *skb; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, MT7615_STA_UPDATE_MAX_SIZE); 8098c2ecf20Sopenharmony_ci if (!skb) 8108c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci skb_put_data(skb, &hdr, sizeof(hdr)); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return skb; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic struct wtbl_req_hdr * 8188c2ecf20Sopenharmony_cimt7615_mcu_alloc_wtbl_req(struct mt7615_dev *dev, struct mt7615_sta *msta, 8198c2ecf20Sopenharmony_ci int cmd, void *sta_wtbl, struct sk_buff **skb) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct tlv *sta_hdr = sta_wtbl; 8228c2ecf20Sopenharmony_ci struct wtbl_req_hdr hdr = { 8238c2ecf20Sopenharmony_ci .wlan_idx = msta->wcid.idx, 8248c2ecf20Sopenharmony_ci .operation = cmd, 8258c2ecf20Sopenharmony_ci }; 8268c2ecf20Sopenharmony_ci struct sk_buff *nskb = *skb; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (!nskb) { 8298c2ecf20Sopenharmony_ci nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 8308c2ecf20Sopenharmony_ci MT7615_WTBL_UPDATE_BA_SIZE); 8318c2ecf20Sopenharmony_ci if (!nskb) 8328c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci *skb = nskb; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (sta_hdr) 8388c2ecf20Sopenharmony_ci sta_hdr->len = cpu_to_le16(sizeof(hdr)); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci return skb_put_data(nskb, &hdr, sizeof(hdr)); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic struct tlv * 8448c2ecf20Sopenharmony_cimt7615_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, 8458c2ecf20Sopenharmony_ci void *sta_ntlv, void *sta_wtbl) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; 8488c2ecf20Sopenharmony_ci struct tlv *sta_hdr = sta_wtbl; 8498c2ecf20Sopenharmony_ci struct tlv *ptlv, tlv = { 8508c2ecf20Sopenharmony_ci .tag = cpu_to_le16(tag), 8518c2ecf20Sopenharmony_ci .len = cpu_to_le16(len), 8528c2ecf20Sopenharmony_ci }; 8538c2ecf20Sopenharmony_ci u16 ntlv; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci ptlv = skb_put(skb, len); 8568c2ecf20Sopenharmony_ci memcpy(ptlv, &tlv, sizeof(tlv)); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci ntlv = le16_to_cpu(ntlv_hdr->tlv_num); 8598c2ecf20Sopenharmony_ci ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (sta_hdr) { 8628c2ecf20Sopenharmony_ci u16 size = le16_to_cpu(sta_hdr->len); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci sta_hdr->len = cpu_to_le16(size + len); 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci return ptlv; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic struct tlv * 8718c2ecf20Sopenharmony_cimt7615_mcu_add_tlv(struct sk_buff *skb, int tag, int len) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci return mt7615_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic int 8778c2ecf20Sopenharmony_cimt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 8788c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 8818c2ecf20Sopenharmony_ci u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA; 8828c2ecf20Sopenharmony_ci struct bss_info_basic *bss; 8838c2ecf20Sopenharmony_ci u8 wlan_idx = mvif->sta.wcid.idx; 8848c2ecf20Sopenharmony_ci struct tlv *tlv; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci switch (vif->type) { 8898c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 8908c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 8938c2ecf20Sopenharmony_ci /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ 8948c2ecf20Sopenharmony_ci if (enable && sta) { 8958c2ecf20Sopenharmony_ci struct mt7615_sta *msta; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci msta = (struct mt7615_sta *)sta->drv_priv; 8988c2ecf20Sopenharmony_ci wlan_idx = msta->wcid.idx; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci break; 9018c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 9028c2ecf20Sopenharmony_ci type = NETWORK_IBSS; 9038c2ecf20Sopenharmony_ci break; 9048c2ecf20Sopenharmony_ci default: 9058c2ecf20Sopenharmony_ci WARN_ON(1); 9068c2ecf20Sopenharmony_ci break; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci bss = (struct bss_info_basic *)tlv; 9108c2ecf20Sopenharmony_ci memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); 9118c2ecf20Sopenharmony_ci bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); 9128c2ecf20Sopenharmony_ci bss->network_type = cpu_to_le32(type); 9138c2ecf20Sopenharmony_ci bss->dtim_period = vif->bss_conf.dtim_period; 9148c2ecf20Sopenharmony_ci bss->bmc_tx_wlan_idx = wlan_idx; 9158c2ecf20Sopenharmony_ci bss->wmm_idx = mvif->wmm_idx; 9168c2ecf20Sopenharmony_ci bss->active = enable; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic void 9228c2ecf20Sopenharmony_cimt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 9258c2ecf20Sopenharmony_ci struct bss_info_omac *omac; 9268c2ecf20Sopenharmony_ci struct tlv *tlv; 9278c2ecf20Sopenharmony_ci u32 type = 0; 9288c2ecf20Sopenharmony_ci u8 idx; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci switch (vif->type) { 9338c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 9348c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 9358c2ecf20Sopenharmony_ci if (vif->p2p) 9368c2ecf20Sopenharmony_ci type = CONNECTION_P2P_GO; 9378c2ecf20Sopenharmony_ci else 9388c2ecf20Sopenharmony_ci type = CONNECTION_INFRA_AP; 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 9418c2ecf20Sopenharmony_ci if (vif->p2p) 9428c2ecf20Sopenharmony_ci type = CONNECTION_P2P_GC; 9438c2ecf20Sopenharmony_ci else 9448c2ecf20Sopenharmony_ci type = CONNECTION_INFRA_STA; 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 9478c2ecf20Sopenharmony_ci type = CONNECTION_IBSS_ADHOC; 9488c2ecf20Sopenharmony_ci break; 9498c2ecf20Sopenharmony_ci default: 9508c2ecf20Sopenharmony_ci WARN_ON(1); 9518c2ecf20Sopenharmony_ci break; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci omac = (struct bss_info_omac *)tlv; 9558c2ecf20Sopenharmony_ci idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; 9568c2ecf20Sopenharmony_ci omac->conn_type = cpu_to_le32(type); 9578c2ecf20Sopenharmony_ci omac->omac_idx = mvif->omac_idx; 9588c2ecf20Sopenharmony_ci omac->band_idx = mvif->band_idx; 9598c2ecf20Sopenharmony_ci omac->hw_bss_idx = idx; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */ 9638c2ecf20Sopenharmony_ci#define BCN_TX_ESTIMATE_TIME (4096 + 20) 9648c2ecf20Sopenharmony_cistatic void 9658c2ecf20Sopenharmony_cimt7615_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7615_vif *mvif) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci struct bss_info_ext_bss *ext; 9688c2ecf20Sopenharmony_ci int ext_bss_idx, tsf_offset; 9698c2ecf20Sopenharmony_ci struct tlv *tlv; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci ext_bss_idx = mvif->omac_idx - EXT_BSSID_START; 9728c2ecf20Sopenharmony_ci if (ext_bss_idx < 0) 9738c2ecf20Sopenharmony_ci return; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext)); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci ext = (struct bss_info_ext_bss *)tlv; 9788c2ecf20Sopenharmony_ci tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME; 9798c2ecf20Sopenharmony_ci ext->mbss_tsf_offset = cpu_to_le32(tsf_offset); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic void 9838c2ecf20Sopenharmony_cimt7615_mcu_sta_ba_tlv(struct sk_buff *skb, 9848c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 9858c2ecf20Sopenharmony_ci bool enable, bool tx) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct sta_rec_ba *ba; 9888c2ecf20Sopenharmony_ci struct tlv *tlv; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci ba = (struct sta_rec_ba *)tlv; 9938c2ecf20Sopenharmony_ci ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT, 9948c2ecf20Sopenharmony_ci ba->winsize = cpu_to_le16(params->buf_size); 9958c2ecf20Sopenharmony_ci ba->ssn = cpu_to_le16(params->ssn); 9968c2ecf20Sopenharmony_ci ba->ba_en = enable << params->tid; 9978c2ecf20Sopenharmony_ci ba->amsdu = params->amsdu; 9988c2ecf20Sopenharmony_ci ba->tid = params->tid; 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cistatic void 10028c2ecf20Sopenharmony_cimt7615_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 10038c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct sta_rec_basic *basic; 10068c2ecf20Sopenharmony_ci struct tlv *tlv; 10078c2ecf20Sopenharmony_ci int conn_type; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci basic = (struct sta_rec_basic *)tlv; 10128c2ecf20Sopenharmony_ci basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (enable) { 10158c2ecf20Sopenharmony_ci basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); 10168c2ecf20Sopenharmony_ci basic->conn_state = CONN_STATE_PORT_SECURE; 10178c2ecf20Sopenharmony_ci } else { 10188c2ecf20Sopenharmony_ci basic->conn_state = CONN_STATE_DISCONNECT; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (!sta) { 10228c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); 10238c2ecf20Sopenharmony_ci eth_broadcast_addr(basic->peer_addr); 10248c2ecf20Sopenharmony_ci return; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci switch (vif->type) { 10288c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 10298c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 10308c2ecf20Sopenharmony_ci if (vif->p2p) 10318c2ecf20Sopenharmony_ci conn_type = CONNECTION_P2P_GC; 10328c2ecf20Sopenharmony_ci else 10338c2ecf20Sopenharmony_ci conn_type = CONNECTION_INFRA_STA; 10348c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(conn_type); 10358c2ecf20Sopenharmony_ci basic->aid = cpu_to_le16(sta->aid); 10368c2ecf20Sopenharmony_ci break; 10378c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 10388c2ecf20Sopenharmony_ci if (vif->p2p) 10398c2ecf20Sopenharmony_ci conn_type = CONNECTION_P2P_GO; 10408c2ecf20Sopenharmony_ci else 10418c2ecf20Sopenharmony_ci conn_type = CONNECTION_INFRA_AP; 10428c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(conn_type); 10438c2ecf20Sopenharmony_ci basic->aid = cpu_to_le16(vif->bss_conf.aid); 10448c2ecf20Sopenharmony_ci break; 10458c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 10468c2ecf20Sopenharmony_ci basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); 10478c2ecf20Sopenharmony_ci basic->aid = cpu_to_le16(sta->aid); 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci default: 10508c2ecf20Sopenharmony_ci WARN_ON(1); 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci memcpy(basic->peer_addr, sta->addr, ETH_ALEN); 10558c2ecf20Sopenharmony_ci basic->qos = sta->wme; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic void 10598c2ecf20Sopenharmony_cimt7615_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct tlv *tlv; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 10648c2ecf20Sopenharmony_ci struct sta_rec_ht *ht; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); 10678c2ecf20Sopenharmony_ci ht = (struct sta_rec_ht *)tlv; 10688c2ecf20Sopenharmony_ci ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci if (sta->vht_cap.vht_supported) { 10718c2ecf20Sopenharmony_ci struct sta_rec_vht *vht; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); 10748c2ecf20Sopenharmony_ci vht = (struct sta_rec_vht *)tlv; 10758c2ecf20Sopenharmony_ci vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; 10768c2ecf20Sopenharmony_ci vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; 10778c2ecf20Sopenharmony_ci vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic void 10828c2ecf20Sopenharmony_cimt7615_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, 10838c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci struct sta_rec_uapsd *uapsd; 10868c2ecf20Sopenharmony_ci struct tlv *tlv; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP || !sta->wme) 10898c2ecf20Sopenharmony_ci return; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); 10928c2ecf20Sopenharmony_ci uapsd = (struct sta_rec_uapsd *)tlv; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { 10958c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(3); 10968c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(3); 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { 10998c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(2); 11008c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(2); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { 11038c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(1); 11048c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(1); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { 11078c2ecf20Sopenharmony_ci uapsd->dac_map |= BIT(0); 11088c2ecf20Sopenharmony_ci uapsd->tac_map |= BIT(0); 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci uapsd->max_sp = sta->max_sp; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic void 11148c2ecf20Sopenharmony_cimt7615_mcu_wtbl_ba_tlv(struct sk_buff *skb, 11158c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 11168c2ecf20Sopenharmony_ci bool enable, bool tx, void *sta_wtbl, 11178c2ecf20Sopenharmony_ci void *wtbl_tlv) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci struct wtbl_ba *ba; 11208c2ecf20Sopenharmony_ci struct tlv *tlv; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), 11238c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci ba = (struct wtbl_ba *)tlv; 11268c2ecf20Sopenharmony_ci ba->tid = params->tid; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (tx) { 11298c2ecf20Sopenharmony_ci ba->ba_type = MT_BA_TYPE_ORIGINATOR; 11308c2ecf20Sopenharmony_ci ba->sn = enable ? cpu_to_le16(params->ssn) : 0; 11318c2ecf20Sopenharmony_ci ba->ba_winsize = cpu_to_le16(params->buf_size); 11328c2ecf20Sopenharmony_ci ba->ba_en = enable; 11338c2ecf20Sopenharmony_ci } else { 11348c2ecf20Sopenharmony_ci memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); 11358c2ecf20Sopenharmony_ci ba->ba_type = MT_BA_TYPE_RECIPIENT; 11368c2ecf20Sopenharmony_ci ba->rst_ba_tid = params->tid; 11378c2ecf20Sopenharmony_ci ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; 11388c2ecf20Sopenharmony_ci ba->rst_ba_sb = 1; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (enable && tx) { 11428c2ecf20Sopenharmony_ci u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 }; 11438c2ecf20Sopenharmony_ci int i; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci for (i = 7; i > 0; i--) { 11468c2ecf20Sopenharmony_ci if (params->buf_size >= ba_range[i]) 11478c2ecf20Sopenharmony_ci break; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci ba->ba_winsize_idx = i; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic void 11548c2ecf20Sopenharmony_cimt7615_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 11558c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, void *sta_wtbl, 11568c2ecf20Sopenharmony_ci void *wtbl_tlv) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 11598c2ecf20Sopenharmony_ci struct wtbl_generic *generic; 11608c2ecf20Sopenharmony_ci struct wtbl_rx *rx; 11618c2ecf20Sopenharmony_ci struct wtbl_spe *spe; 11628c2ecf20Sopenharmony_ci struct tlv *tlv; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), 11658c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci generic = (struct wtbl_generic *)tlv; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (sta) { 11708c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 11718c2ecf20Sopenharmony_ci generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); 11728c2ecf20Sopenharmony_ci else 11738c2ecf20Sopenharmony_ci generic->partial_aid = cpu_to_le16(sta->aid); 11748c2ecf20Sopenharmony_ci memcpy(generic->peer_addr, sta->addr, ETH_ALEN); 11758c2ecf20Sopenharmony_ci generic->muar_idx = mvif->omac_idx; 11768c2ecf20Sopenharmony_ci generic->qos = sta->wme; 11778c2ecf20Sopenharmony_ci } else { 11788c2ecf20Sopenharmony_ci eth_broadcast_addr(generic->peer_addr); 11798c2ecf20Sopenharmony_ci generic->muar_idx = 0xe; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), 11838c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci rx = (struct wtbl_rx *)tlv; 11868c2ecf20Sopenharmony_ci rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; 11878c2ecf20Sopenharmony_ci rx->rca2 = 1; 11888c2ecf20Sopenharmony_ci rx->rv = 1; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_SPE, sizeof(*spe), 11918c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 11928c2ecf20Sopenharmony_ci spe = (struct wtbl_spe *)tlv; 11938c2ecf20Sopenharmony_ci spe->spe_idx = 24; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic void 11978c2ecf20Sopenharmony_cimt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 11988c2ecf20Sopenharmony_ci void *sta_wtbl, void *wtbl_tlv) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct tlv *tlv; 12018c2ecf20Sopenharmony_ci struct wtbl_ht *ht = NULL; 12028c2ecf20Sopenharmony_ci u32 flags = 0; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 12058c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), 12068c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 12078c2ecf20Sopenharmony_ci ht = (struct wtbl_ht *)tlv; 12088c2ecf20Sopenharmony_ci ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING); 12098c2ecf20Sopenharmony_ci ht->af = sta->ht_cap.ampdu_factor; 12108c2ecf20Sopenharmony_ci ht->mm = sta->ht_cap.ampdu_density; 12118c2ecf20Sopenharmony_ci ht->ht = 1; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) 12148c2ecf20Sopenharmony_ci flags |= MT_WTBL_W5_SHORT_GI_20; 12158c2ecf20Sopenharmony_ci if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) 12168c2ecf20Sopenharmony_ci flags |= MT_WTBL_W5_SHORT_GI_40; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (sta->vht_cap.vht_supported) { 12208c2ecf20Sopenharmony_ci struct wtbl_vht *vht; 12218c2ecf20Sopenharmony_ci u8 af; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), 12248c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 12258c2ecf20Sopenharmony_ci vht = (struct wtbl_vht *)tlv; 12268c2ecf20Sopenharmony_ci vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); 12278c2ecf20Sopenharmony_ci vht->vht = 1; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci af = (sta->vht_cap.cap & 12308c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> 12318c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (ht) 12348c2ecf20Sopenharmony_ci ht->af = max(ht->af, af); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) 12378c2ecf20Sopenharmony_ci flags |= MT_WTBL_W5_SHORT_GI_80; 12388c2ecf20Sopenharmony_ci if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) 12398c2ecf20Sopenharmony_ci flags |= MT_WTBL_W5_SHORT_GI_160; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci /* wtbl smps */ 12438c2ecf20Sopenharmony_ci if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) { 12448c2ecf20Sopenharmony_ci struct wtbl_smps *smps; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), 12478c2ecf20Sopenharmony_ci wtbl_tlv, sta_wtbl); 12488c2ecf20Sopenharmony_ci smps = (struct wtbl_smps *)tlv; 12498c2ecf20Sopenharmony_ci smps->smps = 1; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 12538c2ecf20Sopenharmony_ci /* sgi */ 12548c2ecf20Sopenharmony_ci u32 msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 | 12558c2ecf20Sopenharmony_ci MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160; 12568c2ecf20Sopenharmony_ci struct wtbl_raw *raw; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_RAW_DATA, 12598c2ecf20Sopenharmony_ci sizeof(*raw), wtbl_tlv, 12608c2ecf20Sopenharmony_ci sta_wtbl); 12618c2ecf20Sopenharmony_ci raw = (struct wtbl_raw *)tlv; 12628c2ecf20Sopenharmony_ci raw->val = cpu_to_le32(flags); 12638c2ecf20Sopenharmony_ci raw->msk = cpu_to_le32(~msk); 12648c2ecf20Sopenharmony_ci raw->wtbl_idx = 1; 12658c2ecf20Sopenharmony_ci raw->dw = 5; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic int 12708c2ecf20Sopenharmony_cimt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, 12718c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 12748c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 12758c2ecf20Sopenharmony_ci struct sk_buff *skb; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, NULL); 12788c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 12798c2ecf20Sopenharmony_ci return PTR_ERR(skb); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (enable) 12828c2ecf20Sopenharmony_ci mt7615_mcu_bss_omac_tlv(skb, vif); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci mt7615_mcu_bss_basic_tlv(skb, vif, sta, enable); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if (enable && mvif->omac_idx > EXT_BSSID_START) 12878c2ecf20Sopenharmony_ci mt7615_mcu_bss_ext_tlv(skb, mvif); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 12908c2ecf20Sopenharmony_ci MCU_EXT_CMD_BSS_INFO_UPDATE, true); 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic int 12948c2ecf20Sopenharmony_cimt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev, 12958c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 12968c2ecf20Sopenharmony_ci bool enable) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; 12998c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = msta->vif; 13008c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 13018c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 13028c2ecf20Sopenharmony_ci int err; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb); 13058c2ecf20Sopenharmony_ci if (IS_ERR(wtbl_hdr)) 13068c2ecf20Sopenharmony_ci return PTR_ERR(wtbl_hdr); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, NULL, wtbl_hdr); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, 13118c2ecf20Sopenharmony_ci MCU_EXT_CMD_WTBL_UPDATE, true); 13128c2ecf20Sopenharmony_ci if (err < 0) 13138c2ecf20Sopenharmony_ci return err; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 13168c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 13178c2ecf20Sopenharmony_ci return PTR_ERR(skb); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci mt7615_mcu_sta_ba_tlv(skb, params, enable, true); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 13228c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic int 13268c2ecf20Sopenharmony_cimt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev, 13278c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 13288c2ecf20Sopenharmony_ci bool enable) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; 13318c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = msta->vif; 13328c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 13338c2ecf20Sopenharmony_ci struct sk_buff *skb; 13348c2ecf20Sopenharmony_ci int err; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 13378c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 13388c2ecf20Sopenharmony_ci return PTR_ERR(skb); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci mt7615_mcu_sta_ba_tlv(skb, params, enable, false); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, 13438c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 13448c2ecf20Sopenharmony_ci if (err < 0 || !enable) 13458c2ecf20Sopenharmony_ci return err; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci skb = NULL; 13488c2ecf20Sopenharmony_ci wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb); 13498c2ecf20Sopenharmony_ci if (IS_ERR(wtbl_hdr)) 13508c2ecf20Sopenharmony_ci return PTR_ERR(wtbl_hdr); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, NULL, wtbl_hdr); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 13558c2ecf20Sopenharmony_ci MCU_EXT_CMD_WTBL_UPDATE, true); 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic int 13598c2ecf20Sopenharmony_cimt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, 13608c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 13638c2ecf20Sopenharmony_ci struct sk_buff *skb, *sskb, *wskb = NULL; 13648c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 13658c2ecf20Sopenharmony_ci struct mt7615_sta *msta; 13668c2ecf20Sopenharmony_ci int cmd, err; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci sskb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 13718c2ecf20Sopenharmony_ci if (IS_ERR(sskb)) 13728c2ecf20Sopenharmony_ci return PTR_ERR(sskb); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci mt7615_mcu_sta_basic_tlv(sskb, vif, sta, enable); 13758c2ecf20Sopenharmony_ci if (enable && sta) { 13768c2ecf20Sopenharmony_ci mt7615_mcu_sta_ht_tlv(sskb, sta); 13778c2ecf20Sopenharmony_ci mt7615_mcu_sta_uapsd(sskb, vif, sta); 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, 13818c2ecf20Sopenharmony_ci NULL, &wskb); 13828c2ecf20Sopenharmony_ci if (IS_ERR(wtbl_hdr)) 13838c2ecf20Sopenharmony_ci return PTR_ERR(wtbl_hdr); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (enable) { 13868c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_generic_tlv(wskb, vif, sta, NULL, wtbl_hdr); 13878c2ecf20Sopenharmony_ci if (sta) 13888c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_ht_tlv(wskb, sta, NULL, wtbl_hdr); 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE; 13928c2ecf20Sopenharmony_ci skb = enable ? wskb : sskb; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); 13958c2ecf20Sopenharmony_ci if (err < 0) { 13968c2ecf20Sopenharmony_ci skb = enable ? sskb : wskb; 13978c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci return err; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci cmd = enable ? MCU_EXT_CMD_STA_REC_UPDATE : MCU_EXT_CMD_WTBL_UPDATE; 14038c2ecf20Sopenharmony_ci skb = enable ? sskb : wskb; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic const struct mt7615_mcu_ops wtbl_update_ops = { 14098c2ecf20Sopenharmony_ci .add_beacon_offload = mt7615_mcu_add_beacon_offload, 14108c2ecf20Sopenharmony_ci .set_pm_state = mt7615_mcu_ctrl_pm_state, 14118c2ecf20Sopenharmony_ci .add_dev_info = mt7615_mcu_add_dev, 14128c2ecf20Sopenharmony_ci .add_bss_info = mt7615_mcu_add_bss, 14138c2ecf20Sopenharmony_ci .add_tx_ba = mt7615_mcu_wtbl_tx_ba, 14148c2ecf20Sopenharmony_ci .add_rx_ba = mt7615_mcu_wtbl_rx_ba, 14158c2ecf20Sopenharmony_ci .sta_add = mt7615_mcu_wtbl_sta_add, 14168c2ecf20Sopenharmony_ci .set_drv_ctrl = mt7615_mcu_drv_pmctrl, 14178c2ecf20Sopenharmony_ci .set_fw_ctrl = mt7615_mcu_fw_pmctrl, 14188c2ecf20Sopenharmony_ci}; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic int 14218c2ecf20Sopenharmony_cimt7615_mcu_sta_ba(struct mt7615_dev *dev, 14228c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 14238c2ecf20Sopenharmony_ci bool enable, bool tx) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; 14268c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = msta->vif; 14278c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 14288c2ecf20Sopenharmony_ci struct tlv *sta_wtbl; 14298c2ecf20Sopenharmony_ci struct sk_buff *skb; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 14328c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 14338c2ecf20Sopenharmony_ci return PTR_ERR(skb); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci mt7615_mcu_sta_ba_tlv(skb, params, enable, tx); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, 14408c2ecf20Sopenharmony_ci &skb); 14418c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 14448c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE, true); 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic int 14488c2ecf20Sopenharmony_cimt7615_mcu_sta_tx_ba(struct mt7615_dev *dev, 14498c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 14508c2ecf20Sopenharmony_ci bool enable) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci return mt7615_mcu_sta_ba(dev, params, enable, true); 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic int 14568c2ecf20Sopenharmony_cimt7615_mcu_sta_rx_ba(struct mt7615_dev *dev, 14578c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 14588c2ecf20Sopenharmony_ci bool enable) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci return mt7615_mcu_sta_ba(dev, params, enable, false); 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic int 14648c2ecf20Sopenharmony_cimt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif, 14658c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable, int cmd) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 14688c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 14698c2ecf20Sopenharmony_ci struct mt7615_sta *msta; 14708c2ecf20Sopenharmony_ci struct tlv *sta_wtbl; 14718c2ecf20Sopenharmony_ci struct sk_buff *skb; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 14768c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 14778c2ecf20Sopenharmony_ci return PTR_ERR(skb); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci mt7615_mcu_sta_basic_tlv(skb, vif, sta, enable); 14808c2ecf20Sopenharmony_ci if (enable && sta) { 14818c2ecf20Sopenharmony_ci mt7615_mcu_sta_ht_tlv(skb, sta); 14828c2ecf20Sopenharmony_ci mt7615_mcu_sta_uapsd(skb, vif, sta); 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, 14888c2ecf20Sopenharmony_ci sta_wtbl, &skb); 14898c2ecf20Sopenharmony_ci if (enable) { 14908c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); 14918c2ecf20Sopenharmony_ci if (sta) 14928c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic int 14998c2ecf20Sopenharmony_cimt7615_mcu_add_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif, 15008c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci return mt7615_mcu_add_sta_cmd(dev, vif, sta, enable, 15038c2ecf20Sopenharmony_ci MCU_EXT_CMD_STA_REC_UPDATE); 15048c2ecf20Sopenharmony_ci} 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_cistatic const struct mt7615_mcu_ops sta_update_ops = { 15078c2ecf20Sopenharmony_ci .add_beacon_offload = mt7615_mcu_add_beacon_offload, 15088c2ecf20Sopenharmony_ci .set_pm_state = mt7615_mcu_ctrl_pm_state, 15098c2ecf20Sopenharmony_ci .add_dev_info = mt7615_mcu_add_dev, 15108c2ecf20Sopenharmony_ci .add_bss_info = mt7615_mcu_add_bss, 15118c2ecf20Sopenharmony_ci .add_tx_ba = mt7615_mcu_sta_tx_ba, 15128c2ecf20Sopenharmony_ci .add_rx_ba = mt7615_mcu_sta_rx_ba, 15138c2ecf20Sopenharmony_ci .sta_add = mt7615_mcu_add_sta, 15148c2ecf20Sopenharmony_ci .set_drv_ctrl = mt7615_mcu_drv_pmctrl, 15158c2ecf20Sopenharmony_ci .set_fw_ctrl = mt7615_mcu_fw_pmctrl, 15168c2ecf20Sopenharmony_ci}; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_cistatic int 15198c2ecf20Sopenharmony_cimt7615_mcu_uni_add_dev(struct mt7615_dev *dev, 15208c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, bool enable) 15218c2ecf20Sopenharmony_ci{ 15228c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 15238c2ecf20Sopenharmony_ci struct { 15248c2ecf20Sopenharmony_ci struct { 15258c2ecf20Sopenharmony_ci u8 omac_idx; 15268c2ecf20Sopenharmony_ci u8 band_idx; 15278c2ecf20Sopenharmony_ci __le16 pad; 15288c2ecf20Sopenharmony_ci } __packed hdr; 15298c2ecf20Sopenharmony_ci struct req_tlv { 15308c2ecf20Sopenharmony_ci __le16 tag; 15318c2ecf20Sopenharmony_ci __le16 len; 15328c2ecf20Sopenharmony_ci u8 active; 15338c2ecf20Sopenharmony_ci u8 pad; 15348c2ecf20Sopenharmony_ci u8 omac_addr[ETH_ALEN]; 15358c2ecf20Sopenharmony_ci } __packed tlv; 15368c2ecf20Sopenharmony_ci } dev_req = { 15378c2ecf20Sopenharmony_ci .hdr = { 15388c2ecf20Sopenharmony_ci .omac_idx = mvif->omac_idx, 15398c2ecf20Sopenharmony_ci .band_idx = mvif->band_idx, 15408c2ecf20Sopenharmony_ci }, 15418c2ecf20Sopenharmony_ci .tlv = { 15428c2ecf20Sopenharmony_ci .tag = cpu_to_le16(DEV_INFO_ACTIVE), 15438c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct req_tlv)), 15448c2ecf20Sopenharmony_ci .active = enable, 15458c2ecf20Sopenharmony_ci }, 15468c2ecf20Sopenharmony_ci }; 15478c2ecf20Sopenharmony_ci struct { 15488c2ecf20Sopenharmony_ci struct { 15498c2ecf20Sopenharmony_ci u8 bss_idx; 15508c2ecf20Sopenharmony_ci u8 pad[3]; 15518c2ecf20Sopenharmony_ci } __packed hdr; 15528c2ecf20Sopenharmony_ci struct mt7615_bss_basic_tlv basic; 15538c2ecf20Sopenharmony_ci } basic_req = { 15548c2ecf20Sopenharmony_ci .hdr = { 15558c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 15568c2ecf20Sopenharmony_ci }, 15578c2ecf20Sopenharmony_ci .basic = { 15588c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), 15598c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_bss_basic_tlv)), 15608c2ecf20Sopenharmony_ci .omac_idx = mvif->omac_idx, 15618c2ecf20Sopenharmony_ci .band_idx = mvif->band_idx, 15628c2ecf20Sopenharmony_ci .wmm_idx = mvif->wmm_idx, 15638c2ecf20Sopenharmony_ci .active = enable, 15648c2ecf20Sopenharmony_ci .bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx), 15658c2ecf20Sopenharmony_ci .sta_idx = cpu_to_le16(mvif->sta.wcid.idx), 15668c2ecf20Sopenharmony_ci .conn_state = 1, 15678c2ecf20Sopenharmony_ci }, 15688c2ecf20Sopenharmony_ci }; 15698c2ecf20Sopenharmony_ci int err, idx, cmd, len; 15708c2ecf20Sopenharmony_ci void *data; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci switch (vif->type) { 15738c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 15748c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 15758c2ecf20Sopenharmony_ci basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 15788c2ecf20Sopenharmony_ci basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); 15798c2ecf20Sopenharmony_ci break; 15808c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 15818c2ecf20Sopenharmony_ci basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); 15828c2ecf20Sopenharmony_ci break; 15838c2ecf20Sopenharmony_ci default: 15848c2ecf20Sopenharmony_ci WARN_ON(1); 15858c2ecf20Sopenharmony_ci break; 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; 15898c2ecf20Sopenharmony_ci basic_req.basic.hw_bss_idx = idx; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci cmd = enable ? MCU_UNI_CMD_DEV_INFO_UPDATE : MCU_UNI_CMD_BSS_INFO_UPDATE; 15948c2ecf20Sopenharmony_ci data = enable ? (void *)&dev_req : (void *)&basic_req; 15958c2ecf20Sopenharmony_ci len = enable ? sizeof(dev_req) : sizeof(basic_req); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci err = __mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); 15988c2ecf20Sopenharmony_ci if (err < 0) 15998c2ecf20Sopenharmony_ci return err; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci cmd = enable ? MCU_UNI_CMD_BSS_INFO_UPDATE : MCU_UNI_CMD_DEV_INFO_UPDATE; 16028c2ecf20Sopenharmony_ci data = enable ? (void *)&basic_req : (void *)&dev_req; 16038c2ecf20Sopenharmony_ci len = enable ? sizeof(basic_req) : sizeof(dev_req); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cistatic int 16098c2ecf20Sopenharmony_cimt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci return 0; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic int 16158c2ecf20Sopenharmony_cimt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, 16168c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 16198c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 16208c2ecf20Sopenharmony_ci int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; 16218c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 16228c2ecf20Sopenharmony_ci struct { 16238c2ecf20Sopenharmony_ci struct { 16248c2ecf20Sopenharmony_ci u8 bss_idx; 16258c2ecf20Sopenharmony_ci u8 pad[3]; 16268c2ecf20Sopenharmony_ci } __packed hdr; 16278c2ecf20Sopenharmony_ci struct mt7615_bss_basic_tlv basic; 16288c2ecf20Sopenharmony_ci struct mt7615_bss_qos_tlv qos; 16298c2ecf20Sopenharmony_ci } basic_req = { 16308c2ecf20Sopenharmony_ci .hdr = { 16318c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 16328c2ecf20Sopenharmony_ci }, 16338c2ecf20Sopenharmony_ci .basic = { 16348c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), 16358c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_bss_basic_tlv)), 16368c2ecf20Sopenharmony_ci .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 16378c2ecf20Sopenharmony_ci .dtim_period = vif->bss_conf.dtim_period, 16388c2ecf20Sopenharmony_ci .omac_idx = mvif->omac_idx, 16398c2ecf20Sopenharmony_ci .band_idx = mvif->band_idx, 16408c2ecf20Sopenharmony_ci .wmm_idx = mvif->wmm_idx, 16418c2ecf20Sopenharmony_ci .active = true, /* keep bss deactivated */ 16428c2ecf20Sopenharmony_ci .phymode = 0x38, 16438c2ecf20Sopenharmony_ci }, 16448c2ecf20Sopenharmony_ci .qos = { 16458c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_BSS_INFO_QBSS), 16468c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_bss_qos_tlv)), 16478c2ecf20Sopenharmony_ci .qos = vif->bss_conf.qos, 16488c2ecf20Sopenharmony_ci }, 16498c2ecf20Sopenharmony_ci }; 16508c2ecf20Sopenharmony_ci struct { 16518c2ecf20Sopenharmony_ci struct { 16528c2ecf20Sopenharmony_ci u8 bss_idx; 16538c2ecf20Sopenharmony_ci u8 pad[3]; 16548c2ecf20Sopenharmony_ci } __packed hdr; 16558c2ecf20Sopenharmony_ci struct rlm_tlv { 16568c2ecf20Sopenharmony_ci __le16 tag; 16578c2ecf20Sopenharmony_ci __le16 len; 16588c2ecf20Sopenharmony_ci u8 control_channel; 16598c2ecf20Sopenharmony_ci u8 center_chan; 16608c2ecf20Sopenharmony_ci u8 center_chan2; 16618c2ecf20Sopenharmony_ci u8 bw; 16628c2ecf20Sopenharmony_ci u8 tx_streams; 16638c2ecf20Sopenharmony_ci u8 rx_streams; 16648c2ecf20Sopenharmony_ci u8 short_st; 16658c2ecf20Sopenharmony_ci u8 ht_op_info; 16668c2ecf20Sopenharmony_ci u8 sco; 16678c2ecf20Sopenharmony_ci u8 pad[3]; 16688c2ecf20Sopenharmony_ci } __packed rlm; 16698c2ecf20Sopenharmony_ci } __packed rlm_req = { 16708c2ecf20Sopenharmony_ci .hdr = { 16718c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 16728c2ecf20Sopenharmony_ci }, 16738c2ecf20Sopenharmony_ci .rlm = { 16748c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_BSS_INFO_RLM), 16758c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct rlm_tlv)), 16768c2ecf20Sopenharmony_ci .control_channel = chandef->chan->hw_value, 16778c2ecf20Sopenharmony_ci .center_chan = ieee80211_frequency_to_channel(freq1), 16788c2ecf20Sopenharmony_ci .center_chan2 = ieee80211_frequency_to_channel(freq2), 16798c2ecf20Sopenharmony_ci .tx_streams = hweight8(phy->mt76->antenna_mask), 16808c2ecf20Sopenharmony_ci .rx_streams = phy->chainmask, 16818c2ecf20Sopenharmony_ci .short_st = true, 16828c2ecf20Sopenharmony_ci }, 16838c2ecf20Sopenharmony_ci }; 16848c2ecf20Sopenharmony_ci int err, conn_type; 16858c2ecf20Sopenharmony_ci u8 idx; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; 16888c2ecf20Sopenharmony_ci basic_req.basic.hw_bss_idx = idx; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci switch (vif->type) { 16918c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 16928c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 16938c2ecf20Sopenharmony_ci if (vif->p2p) 16948c2ecf20Sopenharmony_ci conn_type = CONNECTION_P2P_GO; 16958c2ecf20Sopenharmony_ci else 16968c2ecf20Sopenharmony_ci conn_type = CONNECTION_INFRA_AP; 16978c2ecf20Sopenharmony_ci basic_req.basic.conn_type = cpu_to_le32(conn_type); 16988c2ecf20Sopenharmony_ci break; 16998c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 17008c2ecf20Sopenharmony_ci if (vif->p2p) 17018c2ecf20Sopenharmony_ci conn_type = CONNECTION_P2P_GC; 17028c2ecf20Sopenharmony_ci else 17038c2ecf20Sopenharmony_ci conn_type = CONNECTION_INFRA_STA; 17048c2ecf20Sopenharmony_ci basic_req.basic.conn_type = cpu_to_le32(conn_type); 17058c2ecf20Sopenharmony_ci break; 17068c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 17078c2ecf20Sopenharmony_ci basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); 17088c2ecf20Sopenharmony_ci break; 17098c2ecf20Sopenharmony_ci default: 17108c2ecf20Sopenharmony_ci WARN_ON(1); 17118c2ecf20Sopenharmony_ci break; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); 17158c2ecf20Sopenharmony_ci basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx); 17168c2ecf20Sopenharmony_ci basic_req.basic.sta_idx = cpu_to_le16(mvif->sta.wcid.idx); 17178c2ecf20Sopenharmony_ci basic_req.basic.conn_state = !enable; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci err = __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 17208c2ecf20Sopenharmony_ci &basic_req, sizeof(basic_req), true); 17218c2ecf20Sopenharmony_ci if (err < 0) 17228c2ecf20Sopenharmony_ci return err; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci switch (chandef->width) { 17258c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 17268c2ecf20Sopenharmony_ci rlm_req.rlm.bw = CMD_CBW_40MHZ; 17278c2ecf20Sopenharmony_ci break; 17288c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 17298c2ecf20Sopenharmony_ci rlm_req.rlm.bw = CMD_CBW_80MHZ; 17308c2ecf20Sopenharmony_ci break; 17318c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 17328c2ecf20Sopenharmony_ci rlm_req.rlm.bw = CMD_CBW_8080MHZ; 17338c2ecf20Sopenharmony_ci break; 17348c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 17358c2ecf20Sopenharmony_ci rlm_req.rlm.bw = CMD_CBW_160MHZ; 17368c2ecf20Sopenharmony_ci break; 17378c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_5: 17388c2ecf20Sopenharmony_ci rlm_req.rlm.bw = CMD_CBW_5MHZ; 17398c2ecf20Sopenharmony_ci break; 17408c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_10: 17418c2ecf20Sopenharmony_ci rlm_req.rlm.bw = CMD_CBW_10MHZ; 17428c2ecf20Sopenharmony_ci break; 17438c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 17448c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 17458c2ecf20Sopenharmony_ci default: 17468c2ecf20Sopenharmony_ci rlm_req.rlm.bw = CMD_CBW_20MHZ; 17478c2ecf20Sopenharmony_ci break; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan) 17518c2ecf20Sopenharmony_ci rlm_req.rlm.sco = 1; /* SCA */ 17528c2ecf20Sopenharmony_ci else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan) 17538c2ecf20Sopenharmony_ci rlm_req.rlm.sco = 3; /* SCB */ 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 17568c2ecf20Sopenharmony_ci &rlm_req, sizeof(rlm_req), true); 17578c2ecf20Sopenharmony_ci} 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_cistatic int 17608c2ecf20Sopenharmony_cimt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, 17618c2ecf20Sopenharmony_ci struct ieee80211_hw *hw, 17628c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 17638c2ecf20Sopenharmony_ci bool enable) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 17668c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = &dev->mt76.global_wcid; 17678c2ecf20Sopenharmony_ci struct ieee80211_mutable_offsets offs; 17688c2ecf20Sopenharmony_ci struct { 17698c2ecf20Sopenharmony_ci struct req_hdr { 17708c2ecf20Sopenharmony_ci u8 bss_idx; 17718c2ecf20Sopenharmony_ci u8 pad[3]; 17728c2ecf20Sopenharmony_ci } __packed hdr; 17738c2ecf20Sopenharmony_ci struct bcn_content_tlv { 17748c2ecf20Sopenharmony_ci __le16 tag; 17758c2ecf20Sopenharmony_ci __le16 len; 17768c2ecf20Sopenharmony_ci __le16 tim_ie_pos; 17778c2ecf20Sopenharmony_ci __le16 csa_ie_pos; 17788c2ecf20Sopenharmony_ci __le16 bcc_ie_pos; 17798c2ecf20Sopenharmony_ci /* 0: enable beacon offload 17808c2ecf20Sopenharmony_ci * 1: disable beacon offload 17818c2ecf20Sopenharmony_ci * 2: update probe respond offload 17828c2ecf20Sopenharmony_ci */ 17838c2ecf20Sopenharmony_ci u8 enable; 17848c2ecf20Sopenharmony_ci /* 0: legacy format (TXD + payload) 17858c2ecf20Sopenharmony_ci * 1: only cap field IE 17868c2ecf20Sopenharmony_ci */ 17878c2ecf20Sopenharmony_ci u8 type; 17888c2ecf20Sopenharmony_ci __le16 pkt_len; 17898c2ecf20Sopenharmony_ci u8 pkt[512]; 17908c2ecf20Sopenharmony_ci } __packed beacon_tlv; 17918c2ecf20Sopenharmony_ci } req = { 17928c2ecf20Sopenharmony_ci .hdr = { 17938c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 17948c2ecf20Sopenharmony_ci }, 17958c2ecf20Sopenharmony_ci .beacon_tlv = { 17968c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), 17978c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct bcn_content_tlv)), 17988c2ecf20Sopenharmony_ci .enable = enable, 17998c2ecf20Sopenharmony_ci }, 18008c2ecf20Sopenharmony_ci }; 18018c2ecf20Sopenharmony_ci struct sk_buff *skb; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs); 18048c2ecf20Sopenharmony_ci if (!skb) 18058c2ecf20Sopenharmony_ci return -EINVAL; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci if (skb->len > 512 - MT_TXD_SIZE) { 18088c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "beacon size limit exceed\n"); 18098c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 18108c2ecf20Sopenharmony_ci return -EINVAL; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb, 18148c2ecf20Sopenharmony_ci wcid, NULL, 0, NULL, true); 18158c2ecf20Sopenharmony_ci memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); 18168c2ecf20Sopenharmony_ci req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); 18178c2ecf20Sopenharmony_ci req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci if (offs.cntdwn_counter_offs[0]) { 18208c2ecf20Sopenharmony_ci u16 csa_offs; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4; 18238c2ecf20Sopenharmony_ci req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs); 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, 18288c2ecf20Sopenharmony_ci &req, sizeof(req), true); 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic int 18328c2ecf20Sopenharmony_cimt7615_mcu_uni_tx_ba(struct mt7615_dev *dev, 18338c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 18348c2ecf20Sopenharmony_ci bool enable) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; 18378c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = msta->vif; 18388c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 18398c2ecf20Sopenharmony_ci struct tlv *sta_wtbl; 18408c2ecf20Sopenharmony_ci struct sk_buff *skb; 18418c2ecf20Sopenharmony_ci int err; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 18448c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 18458c2ecf20Sopenharmony_ci return PTR_ERR(skb); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, 18508c2ecf20Sopenharmony_ci &skb); 18518c2ecf20Sopenharmony_ci if (IS_ERR(wtbl_hdr)) 18528c2ecf20Sopenharmony_ci return PTR_ERR(wtbl_hdr); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, sta_wtbl, 18558c2ecf20Sopenharmony_ci wtbl_hdr); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, 18588c2ecf20Sopenharmony_ci MCU_UNI_CMD_STA_REC_UPDATE, true); 18598c2ecf20Sopenharmony_ci if (err < 0) 18608c2ecf20Sopenharmony_ci return err; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 18638c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 18648c2ecf20Sopenharmony_ci return PTR_ERR(skb); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci mt7615_mcu_sta_ba_tlv(skb, params, enable, true); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 18698c2ecf20Sopenharmony_ci MCU_UNI_CMD_STA_REC_UPDATE, true); 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_cistatic int 18738c2ecf20Sopenharmony_cimt7615_mcu_uni_rx_ba(struct mt7615_dev *dev, 18748c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params, 18758c2ecf20Sopenharmony_ci bool enable) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; 18788c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = msta->vif; 18798c2ecf20Sopenharmony_ci struct wtbl_req_hdr *wtbl_hdr; 18808c2ecf20Sopenharmony_ci struct tlv *sta_wtbl; 18818c2ecf20Sopenharmony_ci struct sk_buff *skb; 18828c2ecf20Sopenharmony_ci int err; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 18858c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 18868c2ecf20Sopenharmony_ci return PTR_ERR(skb); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci mt7615_mcu_sta_ba_tlv(skb, params, enable, false); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, 18918c2ecf20Sopenharmony_ci MCU_UNI_CMD_STA_REC_UPDATE, true); 18928c2ecf20Sopenharmony_ci if (err < 0 || !enable) 18938c2ecf20Sopenharmony_ci return err; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); 18968c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 18978c2ecf20Sopenharmony_ci return PTR_ERR(skb); 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, 19028c2ecf20Sopenharmony_ci &skb); 19038c2ecf20Sopenharmony_ci if (IS_ERR(wtbl_hdr)) 19048c2ecf20Sopenharmony_ci return PTR_ERR(wtbl_hdr); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, sta_wtbl, 19078c2ecf20Sopenharmony_ci wtbl_hdr); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 19108c2ecf20Sopenharmony_ci MCU_UNI_CMD_STA_REC_UPDATE, true); 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_cistatic int 19148c2ecf20Sopenharmony_cimt7615_mcu_uni_add_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif, 19158c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool enable) 19168c2ecf20Sopenharmony_ci{ 19178c2ecf20Sopenharmony_ci return mt7615_mcu_add_sta_cmd(dev, vif, sta, enable, 19188c2ecf20Sopenharmony_ci MCU_UNI_CMD_STA_REC_UPDATE); 19198c2ecf20Sopenharmony_ci} 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_cistatic const struct mt7615_mcu_ops uni_update_ops = { 19228c2ecf20Sopenharmony_ci .add_beacon_offload = mt7615_mcu_uni_add_beacon_offload, 19238c2ecf20Sopenharmony_ci .set_pm_state = mt7615_mcu_uni_ctrl_pm_state, 19248c2ecf20Sopenharmony_ci .add_dev_info = mt7615_mcu_uni_add_dev, 19258c2ecf20Sopenharmony_ci .add_bss_info = mt7615_mcu_uni_add_bss, 19268c2ecf20Sopenharmony_ci .add_tx_ba = mt7615_mcu_uni_tx_ba, 19278c2ecf20Sopenharmony_ci .add_rx_ba = mt7615_mcu_uni_rx_ba, 19288c2ecf20Sopenharmony_ci .sta_add = mt7615_mcu_uni_add_sta, 19298c2ecf20Sopenharmony_ci .set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl, 19308c2ecf20Sopenharmony_ci .set_fw_ctrl = mt7615_mcu_fw_pmctrl, 19318c2ecf20Sopenharmony_ci}; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_cistatic int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data, 19348c2ecf20Sopenharmony_ci int len) 19358c2ecf20Sopenharmony_ci{ 19368c2ecf20Sopenharmony_ci int ret = 0, cur_len; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci while (len > 0) { 19398c2ecf20Sopenharmony_ci cur_len = min_t(int, 4096 - dev->mt76.mcu_ops->headroom, len); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_SCATTER, 19428c2ecf20Sopenharmony_ci data, cur_len, false); 19438c2ecf20Sopenharmony_ci if (ret) 19448c2ecf20Sopenharmony_ci break; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci data += cur_len; 19478c2ecf20Sopenharmony_ci len -= cur_len; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (mt76_is_mmio(&dev->mt76)) 19508c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci return ret; 19548c2ecf20Sopenharmony_ci} 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_cistatic int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr, 19578c2ecf20Sopenharmony_ci u32 option) 19588c2ecf20Sopenharmony_ci{ 19598c2ecf20Sopenharmony_ci struct { 19608c2ecf20Sopenharmony_ci __le32 option; 19618c2ecf20Sopenharmony_ci __le32 addr; 19628c2ecf20Sopenharmony_ci } req = { 19638c2ecf20Sopenharmony_ci .option = cpu_to_le32(option), 19648c2ecf20Sopenharmony_ci .addr = cpu_to_le32(addr), 19658c2ecf20Sopenharmony_ci }; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_START_REQ, 19688c2ecf20Sopenharmony_ci &req, sizeof(req), true); 19698c2ecf20Sopenharmony_ci} 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ciint mt7615_mcu_restart(struct mt76_dev *dev) 19728c2ecf20Sopenharmony_ci{ 19738c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(dev, MCU_CMD_RESTART_DL_REQ, NULL, 19748c2ecf20Sopenharmony_ci 0, true); 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_restart); 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_cistatic int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get) 19798c2ecf20Sopenharmony_ci{ 19808c2ecf20Sopenharmony_ci struct { 19818c2ecf20Sopenharmony_ci __le32 op; 19828c2ecf20Sopenharmony_ci } req = { 19838c2ecf20Sopenharmony_ci .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), 19848c2ecf20Sopenharmony_ci }; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_SEM_CONTROL, 19878c2ecf20Sopenharmony_ci &req, sizeof(req), true); 19888c2ecf20Sopenharmony_ci} 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_cistatic int mt7615_mcu_start_patch(struct mt7615_dev *dev) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci struct { 19938c2ecf20Sopenharmony_ci u8 check_crc; 19948c2ecf20Sopenharmony_ci u8 reserved[3]; 19958c2ecf20Sopenharmony_ci } req = { 19968c2ecf20Sopenharmony_ci .check_crc = 0, 19978c2ecf20Sopenharmony_ci }; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_FINISH_REQ, 20008c2ecf20Sopenharmony_ci &req, sizeof(req), true); 20018c2ecf20Sopenharmony_ci} 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_cistatic int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name) 20048c2ecf20Sopenharmony_ci{ 20058c2ecf20Sopenharmony_ci const struct mt7615_patch_hdr *hdr; 20068c2ecf20Sopenharmony_ci const struct firmware *fw = NULL; 20078c2ecf20Sopenharmony_ci int len, ret, sem; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci sem = mt7615_mcu_patch_sem_ctrl(dev, 1); 20108c2ecf20Sopenharmony_ci switch (sem) { 20118c2ecf20Sopenharmony_ci case PATCH_IS_DL: 20128c2ecf20Sopenharmony_ci return 0; 20138c2ecf20Sopenharmony_ci case PATCH_NOT_DL_SEM_SUCCESS: 20148c2ecf20Sopenharmony_ci break; 20158c2ecf20Sopenharmony_ci default: 20168c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); 20178c2ecf20Sopenharmony_ci return -EAGAIN; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci ret = firmware_request_nowarn(&fw, name, dev->mt76.dev); 20218c2ecf20Sopenharmony_ci if (ret) 20228c2ecf20Sopenharmony_ci goto out; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 20258c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 20268c2ecf20Sopenharmony_ci ret = -EINVAL; 20278c2ecf20Sopenharmony_ci goto out; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci hdr = (const struct mt7615_patch_hdr *)(fw->data); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", 20338c2ecf20Sopenharmony_ci be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci len = fw->size - sizeof(*hdr); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci ret = mt7615_mcu_init_download(dev, addr, len, DL_MODE_NEED_RSP); 20388c2ecf20Sopenharmony_ci if (ret) { 20398c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Download request failed\n"); 20408c2ecf20Sopenharmony_ci goto out; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci ret = mt7615_mcu_send_firmware(dev, fw->data + sizeof(*hdr), len); 20448c2ecf20Sopenharmony_ci if (ret) { 20458c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); 20468c2ecf20Sopenharmony_ci goto out; 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci ret = mt7615_mcu_start_patch(dev); 20508c2ecf20Sopenharmony_ci if (ret) 20518c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start patch\n"); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ciout: 20548c2ecf20Sopenharmony_ci release_firmware(fw); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci sem = mt7615_mcu_patch_sem_ctrl(dev, 0); 20578c2ecf20Sopenharmony_ci switch (sem) { 20588c2ecf20Sopenharmony_ci case PATCH_REL_SEM_SUCCESS: 20598c2ecf20Sopenharmony_ci break; 20608c2ecf20Sopenharmony_ci default: 20618c2ecf20Sopenharmony_ci ret = -EAGAIN; 20628c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); 20638c2ecf20Sopenharmony_ci break; 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci return ret; 20678c2ecf20Sopenharmony_ci} 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_cistatic u32 mt7615_mcu_gen_dl_mode(u8 feature_set, bool is_cr4) 20708c2ecf20Sopenharmony_ci{ 20718c2ecf20Sopenharmony_ci u32 ret = 0; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? 20748c2ecf20Sopenharmony_ci (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; 20758c2ecf20Sopenharmony_ci ret |= FIELD_PREP(DL_MODE_KEY_IDX, 20768c2ecf20Sopenharmony_ci FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); 20778c2ecf20Sopenharmony_ci ret |= DL_MODE_NEED_RSP; 20788c2ecf20Sopenharmony_ci ret |= is_cr4 ? DL_MODE_WORKING_PDA_CR4 : 0; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci return ret; 20818c2ecf20Sopenharmony_ci} 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic int 20848c2ecf20Sopenharmony_cimt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, 20858c2ecf20Sopenharmony_ci const struct mt7615_fw_trailer *hdr, 20868c2ecf20Sopenharmony_ci const u8 *data, bool is_cr4) 20878c2ecf20Sopenharmony_ci{ 20888c2ecf20Sopenharmony_ci int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM; 20898c2ecf20Sopenharmony_ci int err, i, offset = 0; 20908c2ecf20Sopenharmony_ci u32 len, addr, mode; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci for (i = 0; i < n_region; i++) { 20938c2ecf20Sopenharmony_ci mode = mt7615_mcu_gen_dl_mode(hdr[i].feature_set, is_cr4); 20948c2ecf20Sopenharmony_ci len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN; 20958c2ecf20Sopenharmony_ci addr = le32_to_cpu(hdr[i].addr); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci err = mt7615_mcu_init_download(dev, addr, len, mode); 20988c2ecf20Sopenharmony_ci if (err) { 20998c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Download request failed\n"); 21008c2ecf20Sopenharmony_ci return err; 21018c2ecf20Sopenharmony_ci } 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci err = mt7615_mcu_send_firmware(dev, data + offset, len); 21048c2ecf20Sopenharmony_ci if (err) { 21058c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); 21068c2ecf20Sopenharmony_ci return err; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci offset += len; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci return 0; 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_cistatic const struct wiphy_wowlan_support mt7615_wowlan_support = { 21168c2ecf20Sopenharmony_ci .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | 21178c2ecf20Sopenharmony_ci WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT, 21188c2ecf20Sopenharmony_ci .n_patterns = 1, 21198c2ecf20Sopenharmony_ci .pattern_min_len = 1, 21208c2ecf20Sopenharmony_ci .pattern_max_len = MT7615_WOW_PATTEN_MAX_LEN, 21218c2ecf20Sopenharmony_ci .max_nd_match_sets = 10, 21228c2ecf20Sopenharmony_ci}; 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic int mt7615_load_n9(struct mt7615_dev *dev, const char *name) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci const struct mt7615_fw_trailer *hdr; 21278c2ecf20Sopenharmony_ci const struct firmware *fw; 21288c2ecf20Sopenharmony_ci int ret; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci ret = request_firmware(&fw, name, dev->mt76.dev); 21318c2ecf20Sopenharmony_ci if (ret) 21328c2ecf20Sopenharmony_ci return ret; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) { 21358c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 21368c2ecf20Sopenharmony_ci ret = -EINVAL; 21378c2ecf20Sopenharmony_ci goto out; 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size - 21418c2ecf20Sopenharmony_ci N9_REGION_NUM * sizeof(*hdr)); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n", 21448c2ecf20Sopenharmony_ci hdr->fw_ver, hdr->build_date); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false); 21478c2ecf20Sopenharmony_ci if (ret) 21488c2ecf20Sopenharmony_ci goto out; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci ret = mt7615_mcu_start_firmware(dev, le32_to_cpu(hdr->addr), 21518c2ecf20Sopenharmony_ci FW_START_OVERRIDE); 21528c2ecf20Sopenharmony_ci if (ret) { 21538c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); 21548c2ecf20Sopenharmony_ci goto out; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci snprintf(dev->mt76.hw->wiphy->fw_version, 21588c2ecf20Sopenharmony_ci sizeof(dev->mt76.hw->wiphy->fw_version), 21598c2ecf20Sopenharmony_ci "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci if (!is_mt7615(&dev->mt76) && 21628c2ecf20Sopenharmony_ci !strncmp(hdr->fw_ver, "2.0", sizeof(hdr->fw_ver))) { 21638c2ecf20Sopenharmony_ci dev->fw_ver = MT7615_FIRMWARE_V2; 21648c2ecf20Sopenharmony_ci dev->mcu_ops = &sta_update_ops; 21658c2ecf20Sopenharmony_ci } else { 21668c2ecf20Sopenharmony_ci dev->fw_ver = MT7615_FIRMWARE_V1; 21678c2ecf20Sopenharmony_ci dev->mcu_ops = &wtbl_update_ops; 21688c2ecf20Sopenharmony_ci } 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ciout: 21718c2ecf20Sopenharmony_ci release_firmware(fw); 21728c2ecf20Sopenharmony_ci return ret; 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_cistatic int mt7615_load_cr4(struct mt7615_dev *dev, const char *name) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci const struct mt7615_fw_trailer *hdr; 21788c2ecf20Sopenharmony_ci const struct firmware *fw; 21798c2ecf20Sopenharmony_ci int ret; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci ret = request_firmware(&fw, name, dev->mt76.dev); 21828c2ecf20Sopenharmony_ci if (ret) 21838c2ecf20Sopenharmony_ci return ret; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) { 21868c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 21878c2ecf20Sopenharmony_ci ret = -EINVAL; 21888c2ecf20Sopenharmony_ci goto out; 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size - 21928c2ecf20Sopenharmony_ci CR4_REGION_NUM * sizeof(*hdr)); 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n", 21958c2ecf20Sopenharmony_ci hdr->fw_ver, hdr->build_date); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true); 21988c2ecf20Sopenharmony_ci if (ret) 21998c2ecf20Sopenharmony_ci goto out; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci ret = mt7615_mcu_start_firmware(dev, 0, FW_START_WORKING_PDA_CR4); 22028c2ecf20Sopenharmony_ci if (ret) { 22038c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n"); 22048c2ecf20Sopenharmony_ci goto out; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ciout: 22088c2ecf20Sopenharmony_ci release_firmware(fw); 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci return ret; 22118c2ecf20Sopenharmony_ci} 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_cistatic int mt7615_load_ram(struct mt7615_dev *dev) 22148c2ecf20Sopenharmony_ci{ 22158c2ecf20Sopenharmony_ci int ret; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci ret = mt7615_load_n9(dev, MT7615_FIRMWARE_N9); 22188c2ecf20Sopenharmony_ci if (ret) 22198c2ecf20Sopenharmony_ci return ret; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci return mt7615_load_cr4(dev, MT7615_FIRMWARE_CR4); 22228c2ecf20Sopenharmony_ci} 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_cistatic int mt7615_load_firmware(struct mt7615_dev *dev) 22258c2ecf20Sopenharmony_ci{ 22268c2ecf20Sopenharmony_ci int ret; 22278c2ecf20Sopenharmony_ci u32 val; 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci if (val != FW_STATE_FW_DOWNLOAD) { 22328c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); 22338c2ecf20Sopenharmony_ci return -EIO; 22348c2ecf20Sopenharmony_ci } 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci ret = mt7615_load_patch(dev, MT7615_PATCH_ADDRESS, MT7615_ROM_PATCH); 22378c2ecf20Sopenharmony_ci if (ret) 22388c2ecf20Sopenharmony_ci return ret; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci ret = mt7615_load_ram(dev); 22418c2ecf20Sopenharmony_ci if (ret) 22428c2ecf20Sopenharmony_ci return ret; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE, 22458c2ecf20Sopenharmony_ci FIELD_PREP(MT_TOP_MISC2_FW_STATE, 22468c2ecf20Sopenharmony_ci FW_STATE_CR4_RDY), 500)) { 22478c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 22488c2ecf20Sopenharmony_ci return -EIO; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci return 0; 22528c2ecf20Sopenharmony_ci} 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_cistatic int mt7622_load_firmware(struct mt7615_dev *dev) 22558c2ecf20Sopenharmony_ci{ 22568c2ecf20Sopenharmony_ci int ret; 22578c2ecf20Sopenharmony_ci u32 val; 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci val = mt76_get_field(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE); 22628c2ecf20Sopenharmony_ci if (val != FW_STATE_FW_DOWNLOAD) { 22638c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); 22648c2ecf20Sopenharmony_ci return -EIO; 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci ret = mt7615_load_patch(dev, MT7622_PATCH_ADDRESS, MT7622_ROM_PATCH); 22688c2ecf20Sopenharmony_ci if (ret) 22698c2ecf20Sopenharmony_ci return ret; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci ret = mt7615_load_n9(dev, MT7622_FIRMWARE_N9); 22728c2ecf20Sopenharmony_ci if (ret) 22738c2ecf20Sopenharmony_ci return ret; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE, 22768c2ecf20Sopenharmony_ci FIELD_PREP(MT_TOP_OFF_RSV_FW_STATE, 22778c2ecf20Sopenharmony_ci FW_STATE_NORMAL_TRX), 1500)) { 22788c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 22798c2ecf20Sopenharmony_ci return -EIO; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci return 0; 22858c2ecf20Sopenharmony_ci} 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ciint mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl) 22888c2ecf20Sopenharmony_ci{ 22898c2ecf20Sopenharmony_ci struct { 22908c2ecf20Sopenharmony_ci u8 ctrl_val; 22918c2ecf20Sopenharmony_ci u8 pad[3]; 22928c2ecf20Sopenharmony_ci } data = { 22938c2ecf20Sopenharmony_ci .ctrl_val = ctrl 22948c2ecf20Sopenharmony_ci }; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST, 22978c2ecf20Sopenharmony_ci &data, sizeof(data), true); 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistatic int mt7663_load_n9(struct mt7615_dev *dev, const char *name) 23018c2ecf20Sopenharmony_ci{ 23028c2ecf20Sopenharmony_ci u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL; 23038c2ecf20Sopenharmony_ci const struct mt7663_fw_trailer *hdr; 23048c2ecf20Sopenharmony_ci const struct mt7663_fw_buf *buf; 23058c2ecf20Sopenharmony_ci const struct firmware *fw; 23068c2ecf20Sopenharmony_ci const u8 *base_addr; 23078c2ecf20Sopenharmony_ci int i, ret; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci ret = request_firmware(&fw, name, dev->mt76.dev); 23108c2ecf20Sopenharmony_ci if (ret) 23118c2ecf20Sopenharmony_ci return ret; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < FW_V3_COMMON_TAILER_SIZE) { 23148c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 23158c2ecf20Sopenharmony_ci ret = -EINVAL; 23168c2ecf20Sopenharmony_ci goto out; 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci hdr = (const struct mt7663_fw_trailer *)(fw->data + fw->size - 23208c2ecf20Sopenharmony_ci FW_V3_COMMON_TAILER_SIZE); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n", 23238c2ecf20Sopenharmony_ci hdr->fw_ver, hdr->build_date); 23248c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region); 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci base_addr = fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE; 23278c2ecf20Sopenharmony_ci for (i = 0; i < hdr->n_region; i++) { 23288c2ecf20Sopenharmony_ci u32 shift = (hdr->n_region - i) * FW_V3_REGION_TAILER_SIZE; 23298c2ecf20Sopenharmony_ci u32 len, addr, mode; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "Parsing tailer Region: %d\n", i); 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci buf = (const struct mt7663_fw_buf *)(base_addr - shift); 23348c2ecf20Sopenharmony_ci mode = mt7615_mcu_gen_dl_mode(buf->feature_set, false); 23358c2ecf20Sopenharmony_ci addr = le32_to_cpu(buf->img_dest_addr); 23368c2ecf20Sopenharmony_ci len = le32_to_cpu(buf->img_size); 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci ret = mt7615_mcu_init_download(dev, addr, len, mode); 23398c2ecf20Sopenharmony_ci if (ret) { 23408c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Download request failed\n"); 23418c2ecf20Sopenharmony_ci goto out; 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci ret = mt7615_mcu_send_firmware(dev, fw->data + offset, len); 23458c2ecf20Sopenharmony_ci if (ret) { 23468c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to send firmware\n"); 23478c2ecf20Sopenharmony_ci goto out; 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci offset += le32_to_cpu(buf->img_size); 23518c2ecf20Sopenharmony_ci if (buf->feature_set & DL_MODE_VALID_RAM_ENTRY) { 23528c2ecf20Sopenharmony_ci override_addr = le32_to_cpu(buf->img_dest_addr); 23538c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "Region %d, override_addr = 0x%08x\n", 23548c2ecf20Sopenharmony_ci i, override_addr); 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci if (override_addr) 23598c2ecf20Sopenharmony_ci flag |= FW_START_OVERRIDE; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n", 23628c2ecf20Sopenharmony_ci override_addr, flag); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci ret = mt7615_mcu_start_firmware(dev, override_addr, flag); 23658c2ecf20Sopenharmony_ci if (ret) { 23668c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); 23678c2ecf20Sopenharmony_ci goto out; 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci snprintf(dev->mt76.hw->wiphy->fw_version, 23718c2ecf20Sopenharmony_ci sizeof(dev->mt76.hw->wiphy->fw_version), 23728c2ecf20Sopenharmony_ci "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ciout: 23758c2ecf20Sopenharmony_ci release_firmware(fw); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci return ret; 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_cistatic int 23818c2ecf20Sopenharmony_cimt7663_load_rom_patch(struct mt7615_dev *dev, const char **n9_firmware) 23828c2ecf20Sopenharmony_ci{ 23838c2ecf20Sopenharmony_ci const char *selected_rom, *secondary_rom = MT7663_ROM_PATCH; 23848c2ecf20Sopenharmony_ci const char *primary_rom = MT7663_OFFLOAD_ROM_PATCH; 23858c2ecf20Sopenharmony_ci int ret; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci if (!prefer_offload_fw) { 23888c2ecf20Sopenharmony_ci secondary_rom = MT7663_OFFLOAD_ROM_PATCH; 23898c2ecf20Sopenharmony_ci primary_rom = MT7663_ROM_PATCH; 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci selected_rom = primary_rom; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, primary_rom); 23948c2ecf20Sopenharmony_ci if (ret) { 23958c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "%s not found, switching to %s", 23968c2ecf20Sopenharmony_ci primary_rom, secondary_rom); 23978c2ecf20Sopenharmony_ci ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, 23988c2ecf20Sopenharmony_ci secondary_rom); 23998c2ecf20Sopenharmony_ci if (ret) { 24008c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "failed to load %s", 24018c2ecf20Sopenharmony_ci secondary_rom); 24028c2ecf20Sopenharmony_ci return ret; 24038c2ecf20Sopenharmony_ci } 24048c2ecf20Sopenharmony_ci selected_rom = secondary_rom; 24058c2ecf20Sopenharmony_ci } 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci if (!strcmp(selected_rom, MT7663_OFFLOAD_ROM_PATCH)) { 24088c2ecf20Sopenharmony_ci *n9_firmware = MT7663_OFFLOAD_FIRMWARE_N9; 24098c2ecf20Sopenharmony_ci dev->fw_ver = MT7615_FIRMWARE_V3; 24108c2ecf20Sopenharmony_ci dev->mcu_ops = &uni_update_ops; 24118c2ecf20Sopenharmony_ci } else { 24128c2ecf20Sopenharmony_ci *n9_firmware = MT7663_FIRMWARE_N9; 24138c2ecf20Sopenharmony_ci dev->fw_ver = MT7615_FIRMWARE_V2; 24148c2ecf20Sopenharmony_ci dev->mcu_ops = &sta_update_ops; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci return 0; 24188c2ecf20Sopenharmony_ci} 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ciint __mt7663_load_firmware(struct mt7615_dev *dev) 24218c2ecf20Sopenharmony_ci{ 24228c2ecf20Sopenharmony_ci const char *n9_firmware; 24238c2ecf20Sopenharmony_ci int ret; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 24268c2ecf20Sopenharmony_ci if (ret) { 24278c2ecf20Sopenharmony_ci dev_dbg(dev->mt76.dev, "Firmware is already download\n"); 24288c2ecf20Sopenharmony_ci return -EIO; 24298c2ecf20Sopenharmony_ci } 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci ret = mt7663_load_rom_patch(dev, &n9_firmware); 24328c2ecf20Sopenharmony_ci if (ret) 24338c2ecf20Sopenharmony_ci return ret; 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci ret = mt7663_load_n9(dev, n9_firmware); 24368c2ecf20Sopenharmony_ci if (ret) 24378c2ecf20Sopenharmony_ci return ret; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, 24408c2ecf20Sopenharmony_ci MT_TOP_MISC2_FW_N9_RDY, 1500)) { 24418c2ecf20Sopenharmony_ci ret = mt76_get_field(dev, MT_CONN_ON_MISC, 24428c2ecf20Sopenharmony_ci MT7663_TOP_MISC2_FW_STATE); 24438c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 24448c2ecf20Sopenharmony_ci return -EIO; 24458c2ecf20Sopenharmony_ci } 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 24488c2ecf20Sopenharmony_ci if (mt7615_firmware_offload(dev)) 24498c2ecf20Sopenharmony_ci dev->mt76.hw->wiphy->wowlan = &mt7615_wowlan_support; 24508c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci dev_dbg(dev->mt76.dev, "Firmware init done\n"); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci return 0; 24558c2ecf20Sopenharmony_ci} 24568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__mt7663_load_firmware); 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_cistatic int mt7663_load_firmware(struct mt7615_dev *dev) 24598c2ecf20Sopenharmony_ci{ 24608c2ecf20Sopenharmony_ci int ret; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci ret = __mt7663_load_firmware(dev); 24658c2ecf20Sopenharmony_ci if (ret) 24668c2ecf20Sopenharmony_ci return ret; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci return 0; 24718c2ecf20Sopenharmony_ci} 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ciint mt7615_mcu_init(struct mt7615_dev *dev) 24748c2ecf20Sopenharmony_ci{ 24758c2ecf20Sopenharmony_ci static const struct mt76_mcu_ops mt7615_mcu_ops = { 24768c2ecf20Sopenharmony_ci .headroom = sizeof(struct mt7615_mcu_txd), 24778c2ecf20Sopenharmony_ci .mcu_skb_send_msg = mt7615_mcu_send_message, 24788c2ecf20Sopenharmony_ci .mcu_send_msg = mt7615_mcu_msg_send, 24798c2ecf20Sopenharmony_ci .mcu_restart = mt7615_mcu_restart, 24808c2ecf20Sopenharmony_ci }; 24818c2ecf20Sopenharmony_ci int ret; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci dev->mt76.mcu_ops = &mt7615_mcu_ops, 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci ret = mt7615_mcu_drv_pmctrl(dev); 24868c2ecf20Sopenharmony_ci if (ret) 24878c2ecf20Sopenharmony_ci return ret; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci switch (mt76_chip(&dev->mt76)) { 24908c2ecf20Sopenharmony_ci case 0x7622: 24918c2ecf20Sopenharmony_ci ret = mt7622_load_firmware(dev); 24928c2ecf20Sopenharmony_ci break; 24938c2ecf20Sopenharmony_ci case 0x7663: 24948c2ecf20Sopenharmony_ci ret = mt7663_load_firmware(dev); 24958c2ecf20Sopenharmony_ci break; 24968c2ecf20Sopenharmony_ci default: 24978c2ecf20Sopenharmony_ci ret = mt7615_load_firmware(dev); 24988c2ecf20Sopenharmony_ci break; 24998c2ecf20Sopenharmony_ci } 25008c2ecf20Sopenharmony_ci if (ret) 25018c2ecf20Sopenharmony_ci return ret; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); 25048c2ecf20Sopenharmony_ci dev_dbg(dev->mt76.dev, "Firmware init done\n"); 25058c2ecf20Sopenharmony_ci set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 25068c2ecf20Sopenharmony_ci mt7615_mcu_fw_log_2_host(dev, 0); 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci return 0; 25098c2ecf20Sopenharmony_ci} 25108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_init); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_civoid mt7615_mcu_exit(struct mt7615_dev *dev) 25138c2ecf20Sopenharmony_ci{ 25148c2ecf20Sopenharmony_ci __mt76_mcu_restart(&dev->mt76); 25158c2ecf20Sopenharmony_ci mt7615_mcu_set_fw_ctrl(dev); 25168c2ecf20Sopenharmony_ci skb_queue_purge(&dev->mt76.mcu.res_q); 25178c2ecf20Sopenharmony_ci} 25188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_exit); 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ciint mt7615_mcu_set_eeprom(struct mt7615_dev *dev) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci struct { 25238c2ecf20Sopenharmony_ci u8 buffer_mode; 25248c2ecf20Sopenharmony_ci u8 content_format; 25258c2ecf20Sopenharmony_ci __le16 len; 25268c2ecf20Sopenharmony_ci } __packed req_hdr = { 25278c2ecf20Sopenharmony_ci .buffer_mode = 1, 25288c2ecf20Sopenharmony_ci }; 25298c2ecf20Sopenharmony_ci u8 *eep = (u8 *)dev->mt76.eeprom.data; 25308c2ecf20Sopenharmony_ci struct sk_buff *skb; 25318c2ecf20Sopenharmony_ci int eep_len, offset; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci switch (mt76_chip(&dev->mt76)) { 25348c2ecf20Sopenharmony_ci case 0x7622: 25358c2ecf20Sopenharmony_ci eep_len = MT7622_EE_MAX - MT_EE_NIC_CONF_0; 25368c2ecf20Sopenharmony_ci offset = MT_EE_NIC_CONF_0; 25378c2ecf20Sopenharmony_ci break; 25388c2ecf20Sopenharmony_ci case 0x7663: 25398c2ecf20Sopenharmony_ci eep_len = MT7663_EE_MAX - MT_EE_CHIP_ID; 25408c2ecf20Sopenharmony_ci req_hdr.content_format = 1; 25418c2ecf20Sopenharmony_ci offset = MT_EE_CHIP_ID; 25428c2ecf20Sopenharmony_ci break; 25438c2ecf20Sopenharmony_ci default: 25448c2ecf20Sopenharmony_ci eep_len = MT7615_EE_MAX - MT_EE_NIC_CONF_0; 25458c2ecf20Sopenharmony_ci offset = MT_EE_NIC_CONF_0; 25468c2ecf20Sopenharmony_ci break; 25478c2ecf20Sopenharmony_ci } 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci req_hdr.len = cpu_to_le16(eep_len); 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + eep_len); 25528c2ecf20Sopenharmony_ci if (!skb) 25538c2ecf20Sopenharmony_ci return -ENOMEM; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci skb_put_data(skb, &req_hdr, sizeof(req_hdr)); 25568c2ecf20Sopenharmony_ci skb_put_data(skb, eep + offset, eep_len); 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 25598c2ecf20Sopenharmony_ci MCU_EXT_CMD_EFUSE_BUFFER_MODE, true); 25608c2ecf20Sopenharmony_ci} 25618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_set_eeprom); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ciint mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable) 25648c2ecf20Sopenharmony_ci{ 25658c2ecf20Sopenharmony_ci struct { 25668c2ecf20Sopenharmony_ci u8 enable; 25678c2ecf20Sopenharmony_ci u8 band; 25688c2ecf20Sopenharmony_ci u8 rsv[2]; 25698c2ecf20Sopenharmony_ci } __packed req = { 25708c2ecf20Sopenharmony_ci .enable = enable, 25718c2ecf20Sopenharmony_ci .band = band, 25728c2ecf20Sopenharmony_ci }; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, 25758c2ecf20Sopenharmony_ci &req, sizeof(req), true); 25768c2ecf20Sopenharmony_ci} 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ciint mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val) 25798c2ecf20Sopenharmony_ci{ 25808c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 25818c2ecf20Sopenharmony_ci struct { 25828c2ecf20Sopenharmony_ci u8 prot_idx; 25838c2ecf20Sopenharmony_ci u8 band; 25848c2ecf20Sopenharmony_ci u8 rsv[2]; 25858c2ecf20Sopenharmony_ci __le32 len_thresh; 25868c2ecf20Sopenharmony_ci __le32 pkt_thresh; 25878c2ecf20Sopenharmony_ci } __packed req = { 25888c2ecf20Sopenharmony_ci .prot_idx = 1, 25898c2ecf20Sopenharmony_ci .band = phy != &dev->phy, 25908c2ecf20Sopenharmony_ci .len_thresh = cpu_to_le32(val), 25918c2ecf20Sopenharmony_ci .pkt_thresh = cpu_to_le32(0x2), 25928c2ecf20Sopenharmony_ci }; 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, 25958c2ecf20Sopenharmony_ci &req, sizeof(req), true); 25968c2ecf20Sopenharmony_ci} 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ciint mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, 25998c2ecf20Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 26008c2ecf20Sopenharmony_ci{ 26018c2ecf20Sopenharmony_ci#define WMM_AIFS_SET BIT(0) 26028c2ecf20Sopenharmony_ci#define WMM_CW_MIN_SET BIT(1) 26038c2ecf20Sopenharmony_ci#define WMM_CW_MAX_SET BIT(2) 26048c2ecf20Sopenharmony_ci#define WMM_TXOP_SET BIT(3) 26058c2ecf20Sopenharmony_ci#define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ 26068c2ecf20Sopenharmony_ci WMM_CW_MAX_SET | WMM_TXOP_SET) 26078c2ecf20Sopenharmony_ci struct req_data { 26088c2ecf20Sopenharmony_ci u8 number; 26098c2ecf20Sopenharmony_ci u8 rsv[3]; 26108c2ecf20Sopenharmony_ci u8 queue; 26118c2ecf20Sopenharmony_ci u8 valid; 26128c2ecf20Sopenharmony_ci u8 aifs; 26138c2ecf20Sopenharmony_ci u8 cw_min; 26148c2ecf20Sopenharmony_ci __le16 cw_max; 26158c2ecf20Sopenharmony_ci __le16 txop; 26168c2ecf20Sopenharmony_ci } __packed req = { 26178c2ecf20Sopenharmony_ci .number = 1, 26188c2ecf20Sopenharmony_ci .queue = queue, 26198c2ecf20Sopenharmony_ci .valid = WMM_PARAM_SET, 26208c2ecf20Sopenharmony_ci .aifs = params->aifs, 26218c2ecf20Sopenharmony_ci .cw_min = 5, 26228c2ecf20Sopenharmony_ci .cw_max = cpu_to_le16(10), 26238c2ecf20Sopenharmony_ci .txop = cpu_to_le16(params->txop), 26248c2ecf20Sopenharmony_ci }; 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci if (params->cw_min) 26278c2ecf20Sopenharmony_ci req.cw_min = fls(params->cw_min); 26288c2ecf20Sopenharmony_ci if (params->cw_max) 26298c2ecf20Sopenharmony_ci req.cw_max = cpu_to_le16(fls(params->cw_max)); 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, 26328c2ecf20Sopenharmony_ci &req, sizeof(req), true); 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ciint mt7615_mcu_set_dbdc(struct mt7615_dev *dev) 26368c2ecf20Sopenharmony_ci{ 26378c2ecf20Sopenharmony_ci struct mt7615_phy *ext_phy = mt7615_ext_phy(dev); 26388c2ecf20Sopenharmony_ci struct dbdc_entry { 26398c2ecf20Sopenharmony_ci u8 type; 26408c2ecf20Sopenharmony_ci u8 index; 26418c2ecf20Sopenharmony_ci u8 band; 26428c2ecf20Sopenharmony_ci u8 _rsv; 26438c2ecf20Sopenharmony_ci }; 26448c2ecf20Sopenharmony_ci struct { 26458c2ecf20Sopenharmony_ci u8 enable; 26468c2ecf20Sopenharmony_ci u8 num; 26478c2ecf20Sopenharmony_ci u8 _rsv[2]; 26488c2ecf20Sopenharmony_ci struct dbdc_entry entry[64]; 26498c2ecf20Sopenharmony_ci } req = { 26508c2ecf20Sopenharmony_ci .enable = !!ext_phy, 26518c2ecf20Sopenharmony_ci }; 26528c2ecf20Sopenharmony_ci int i; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci if (!ext_phy) 26558c2ecf20Sopenharmony_ci goto out; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci#define ADD_DBDC_ENTRY(_type, _idx, _band) \ 26588c2ecf20Sopenharmony_ci do { \ 26598c2ecf20Sopenharmony_ci req.entry[req.num].type = _type; \ 26608c2ecf20Sopenharmony_ci req.entry[req.num].index = _idx; \ 26618c2ecf20Sopenharmony_ci req.entry[req.num++].band = _band; \ 26628c2ecf20Sopenharmony_ci } while (0) 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 26658c2ecf20Sopenharmony_ci bool band = !!(ext_phy->omac_mask & BIT(i)); 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_BSS, i, band); 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci for (i = 0; i < 14; i++) { 26718c2ecf20Sopenharmony_ci bool band = !!(ext_phy->omac_mask & BIT(0x11 + i)); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_MBSS, i, band); 26748c2ecf20Sopenharmony_ci } 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_MU, 0, 1); 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 26798c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_BF, i, 1); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 0, 0); 26828c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 1, 0); 26838c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 2, 1); 26848c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 3, 1); 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 0, 0); 26878c2ecf20Sopenharmony_ci ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 1, 1); 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ciout: 26908c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DBDC_CTRL, 26918c2ecf20Sopenharmony_ci &req, sizeof(req), true); 26928c2ecf20Sopenharmony_ci} 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ciint mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev) 26958c2ecf20Sopenharmony_ci{ 26968c2ecf20Sopenharmony_ci struct wtbl_req_hdr req = { 26978c2ecf20Sopenharmony_ci .operation = WTBL_RESET_ALL, 26988c2ecf20Sopenharmony_ci }; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, 27018c2ecf20Sopenharmony_ci &req, sizeof(req), true); 27028c2ecf20Sopenharmony_ci} 27038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_del_wtbl_all); 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ciint mt7615_mcu_rdd_cmd(struct mt7615_dev *dev, 27068c2ecf20Sopenharmony_ci enum mt7615_rdd_cmd cmd, u8 index, 27078c2ecf20Sopenharmony_ci u8 rx_sel, u8 val) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci struct { 27108c2ecf20Sopenharmony_ci u8 ctrl; 27118c2ecf20Sopenharmony_ci u8 rdd_idx; 27128c2ecf20Sopenharmony_ci u8 rdd_rx_sel; 27138c2ecf20Sopenharmony_ci u8 val; 27148c2ecf20Sopenharmony_ci u8 rsv[4]; 27158c2ecf20Sopenharmony_ci } req = { 27168c2ecf20Sopenharmony_ci .ctrl = cmd, 27178c2ecf20Sopenharmony_ci .rdd_idx = index, 27188c2ecf20Sopenharmony_ci .rdd_rx_sel = rx_sel, 27198c2ecf20Sopenharmony_ci .val = val, 27208c2ecf20Sopenharmony_ci }; 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, 27238c2ecf20Sopenharmony_ci &req, sizeof(req), true); 27248c2ecf20Sopenharmony_ci} 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ciint mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci struct { 27298c2ecf20Sopenharmony_ci __le16 tag; 27308c2ecf20Sopenharmony_ci __le16 min_lpn; 27318c2ecf20Sopenharmony_ci } req = { 27328c2ecf20Sopenharmony_ci .tag = cpu_to_le16(0x1), 27338c2ecf20Sopenharmony_ci .min_lpn = cpu_to_le16(val), 27348c2ecf20Sopenharmony_ci }; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, 27378c2ecf20Sopenharmony_ci &req, sizeof(req), true); 27388c2ecf20Sopenharmony_ci} 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ciint mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, 27418c2ecf20Sopenharmony_ci const struct mt7615_dfs_pulse *pulse) 27428c2ecf20Sopenharmony_ci{ 27438c2ecf20Sopenharmony_ci struct { 27448c2ecf20Sopenharmony_ci __le16 tag; 27458c2ecf20Sopenharmony_ci __le32 max_width; /* us */ 27468c2ecf20Sopenharmony_ci __le32 max_pwr; /* dbm */ 27478c2ecf20Sopenharmony_ci __le32 min_pwr; /* dbm */ 27488c2ecf20Sopenharmony_ci __le32 min_stgr_pri; /* us */ 27498c2ecf20Sopenharmony_ci __le32 max_stgr_pri; /* us */ 27508c2ecf20Sopenharmony_ci __le32 min_cr_pri; /* us */ 27518c2ecf20Sopenharmony_ci __le32 max_cr_pri; /* us */ 27528c2ecf20Sopenharmony_ci } req = { 27538c2ecf20Sopenharmony_ci .tag = cpu_to_le16(0x3), 27548c2ecf20Sopenharmony_ci#define __req_field(field) .field = cpu_to_le32(pulse->field) 27558c2ecf20Sopenharmony_ci __req_field(max_width), 27568c2ecf20Sopenharmony_ci __req_field(max_pwr), 27578c2ecf20Sopenharmony_ci __req_field(min_pwr), 27588c2ecf20Sopenharmony_ci __req_field(min_stgr_pri), 27598c2ecf20Sopenharmony_ci __req_field(max_stgr_pri), 27608c2ecf20Sopenharmony_ci __req_field(min_cr_pri), 27618c2ecf20Sopenharmony_ci __req_field(max_cr_pri), 27628c2ecf20Sopenharmony_ci#undef __req_field 27638c2ecf20Sopenharmony_ci }; 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, 27668c2ecf20Sopenharmony_ci &req, sizeof(req), true); 27678c2ecf20Sopenharmony_ci} 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ciint mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, 27708c2ecf20Sopenharmony_ci const struct mt7615_dfs_pattern *pattern) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci struct { 27738c2ecf20Sopenharmony_ci __le16 tag; 27748c2ecf20Sopenharmony_ci __le16 radar_type; 27758c2ecf20Sopenharmony_ci u8 enb; 27768c2ecf20Sopenharmony_ci u8 stgr; 27778c2ecf20Sopenharmony_ci u8 min_crpn; 27788c2ecf20Sopenharmony_ci u8 max_crpn; 27798c2ecf20Sopenharmony_ci u8 min_crpr; 27808c2ecf20Sopenharmony_ci u8 min_pw; 27818c2ecf20Sopenharmony_ci u8 max_pw; 27828c2ecf20Sopenharmony_ci __le32 min_pri; 27838c2ecf20Sopenharmony_ci __le32 max_pri; 27848c2ecf20Sopenharmony_ci u8 min_crbn; 27858c2ecf20Sopenharmony_ci u8 max_crbn; 27868c2ecf20Sopenharmony_ci u8 min_stgpn; 27878c2ecf20Sopenharmony_ci u8 max_stgpn; 27888c2ecf20Sopenharmony_ci u8 min_stgpr; 27898c2ecf20Sopenharmony_ci } req = { 27908c2ecf20Sopenharmony_ci .tag = cpu_to_le16(0x2), 27918c2ecf20Sopenharmony_ci .radar_type = cpu_to_le16(index), 27928c2ecf20Sopenharmony_ci#define __req_field_u8(field) .field = pattern->field 27938c2ecf20Sopenharmony_ci#define __req_field_u32(field) .field = cpu_to_le32(pattern->field) 27948c2ecf20Sopenharmony_ci __req_field_u8(enb), 27958c2ecf20Sopenharmony_ci __req_field_u8(stgr), 27968c2ecf20Sopenharmony_ci __req_field_u8(min_crpn), 27978c2ecf20Sopenharmony_ci __req_field_u8(max_crpn), 27988c2ecf20Sopenharmony_ci __req_field_u8(min_crpr), 27998c2ecf20Sopenharmony_ci __req_field_u8(min_pw), 28008c2ecf20Sopenharmony_ci __req_field_u8(max_pw), 28018c2ecf20Sopenharmony_ci __req_field_u32(min_pri), 28028c2ecf20Sopenharmony_ci __req_field_u32(max_pri), 28038c2ecf20Sopenharmony_ci __req_field_u8(min_crbn), 28048c2ecf20Sopenharmony_ci __req_field_u8(max_crbn), 28058c2ecf20Sopenharmony_ci __req_field_u8(min_stgpn), 28068c2ecf20Sopenharmony_ci __req_field_u8(max_stgpn), 28078c2ecf20Sopenharmony_ci __req_field_u8(min_stgpr), 28088c2ecf20Sopenharmony_ci#undef __req_field_u8 28098c2ecf20Sopenharmony_ci#undef __req_field_u32 28108c2ecf20Sopenharmony_ci }; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, 28138c2ecf20Sopenharmony_ci &req, sizeof(req), true); 28148c2ecf20Sopenharmony_ci} 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ciint mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev) 28178c2ecf20Sopenharmony_ci{ 28188c2ecf20Sopenharmony_ci struct { 28198c2ecf20Sopenharmony_ci u8 pulse_num; 28208c2ecf20Sopenharmony_ci u8 rsv[3]; 28218c2ecf20Sopenharmony_ci struct { 28228c2ecf20Sopenharmony_ci __le32 start_time; 28238c2ecf20Sopenharmony_ci __le16 width; 28248c2ecf20Sopenharmony_ci __le16 power; 28258c2ecf20Sopenharmony_ci } pattern[32]; 28268c2ecf20Sopenharmony_ci } req = { 28278c2ecf20Sopenharmony_ci .pulse_num = dev->radar_pattern.n_pulses, 28288c2ecf20Sopenharmony_ci }; 28298c2ecf20Sopenharmony_ci u32 start_time = ktime_to_ms(ktime_get_boottime()); 28308c2ecf20Sopenharmony_ci int i; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern)) 28338c2ecf20Sopenharmony_ci return -EINVAL; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci /* TODO: add some noise here */ 28368c2ecf20Sopenharmony_ci for (i = 0; i < dev->radar_pattern.n_pulses; i++) { 28378c2ecf20Sopenharmony_ci u32 ts = start_time + i * dev->radar_pattern.period; 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci req.pattern[i].width = cpu_to_le16(dev->radar_pattern.width); 28408c2ecf20Sopenharmony_ci req.pattern[i].power = cpu_to_le16(dev->radar_pattern.power); 28418c2ecf20Sopenharmony_ci req.pattern[i].start_time = cpu_to_le32(ts); 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_PATTERN, 28458c2ecf20Sopenharmony_ci &req, sizeof(req), false); 28468c2ecf20Sopenharmony_ci} 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_cistatic void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku) 28498c2ecf20Sopenharmony_ci{ 28508c2ecf20Sopenharmony_ci struct mt76_phy *mphy = phy->mt76; 28518c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = mphy->hw; 28528c2ecf20Sopenharmony_ci int n_chains = hweight8(mphy->antenna_mask); 28538c2ecf20Sopenharmony_ci int tx_power; 28548c2ecf20Sopenharmony_ci int i; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci tx_power = hw->conf.power_level * 2 - 28578c2ecf20Sopenharmony_ci mt76_tx_power_nss_delta(n_chains); 28588c2ecf20Sopenharmony_ci mphy->txpower_cur = tx_power; 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci for (i = 0; i < MT_SKU_1SS_DELTA; i++) 28618c2ecf20Sopenharmony_ci sku[i] = tx_power; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 28648c2ecf20Sopenharmony_ci int delta = 0; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci if (i < n_chains - 1) 28678c2ecf20Sopenharmony_ci delta = mt76_tx_power_nss_delta(n_chains) - 28688c2ecf20Sopenharmony_ci mt76_tx_power_nss_delta(i + 1); 28698c2ecf20Sopenharmony_ci sku[MT_SKU_1SS_DELTA + i] = delta; 28708c2ecf20Sopenharmony_ci } 28718c2ecf20Sopenharmony_ci} 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_cistatic u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef) 28748c2ecf20Sopenharmony_ci{ 28758c2ecf20Sopenharmony_ci static const u8 width_to_bw[] = { 28768c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, 28778c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, 28788c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, 28798c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, 28808c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, 28818c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, 28828c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, 28838c2ecf20Sopenharmony_ci [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, 28848c2ecf20Sopenharmony_ci }; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci if (chandef->width >= ARRAY_SIZE(width_to_bw)) 28878c2ecf20Sopenharmony_ci return 0; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci return width_to_bw[chandef->width]; 28908c2ecf20Sopenharmony_ci} 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ciint mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) 28938c2ecf20Sopenharmony_ci{ 28948c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 28958c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 28968c2ecf20Sopenharmony_ci int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; 28978c2ecf20Sopenharmony_ci struct { 28988c2ecf20Sopenharmony_ci u8 control_chan; 28998c2ecf20Sopenharmony_ci u8 center_chan; 29008c2ecf20Sopenharmony_ci u8 bw; 29018c2ecf20Sopenharmony_ci u8 tx_streams; 29028c2ecf20Sopenharmony_ci u8 rx_streams_mask; 29038c2ecf20Sopenharmony_ci u8 switch_reason; 29048c2ecf20Sopenharmony_ci u8 band_idx; 29058c2ecf20Sopenharmony_ci /* for 80+80 only */ 29068c2ecf20Sopenharmony_ci u8 center_chan2; 29078c2ecf20Sopenharmony_ci __le16 cac_case; 29088c2ecf20Sopenharmony_ci u8 channel_band; 29098c2ecf20Sopenharmony_ci u8 rsv0; 29108c2ecf20Sopenharmony_ci __le32 outband_freq; 29118c2ecf20Sopenharmony_ci u8 txpower_drop; 29128c2ecf20Sopenharmony_ci u8 rsv1[3]; 29138c2ecf20Sopenharmony_ci u8 txpower_sku[53]; 29148c2ecf20Sopenharmony_ci u8 rsv2[3]; 29158c2ecf20Sopenharmony_ci } req = { 29168c2ecf20Sopenharmony_ci .control_chan = chandef->chan->hw_value, 29178c2ecf20Sopenharmony_ci .center_chan = ieee80211_frequency_to_channel(freq1), 29188c2ecf20Sopenharmony_ci .tx_streams = hweight8(phy->mt76->antenna_mask), 29198c2ecf20Sopenharmony_ci .rx_streams_mask = phy->chainmask, 29208c2ecf20Sopenharmony_ci .center_chan2 = ieee80211_frequency_to_channel(freq2), 29218c2ecf20Sopenharmony_ci }; 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 29248c2ecf20Sopenharmony_ci req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 29258c2ecf20Sopenharmony_ci else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 29268c2ecf20Sopenharmony_ci chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) 29278c2ecf20Sopenharmony_ci req.switch_reason = CH_SWITCH_DFS; 29288c2ecf20Sopenharmony_ci else 29298c2ecf20Sopenharmony_ci req.switch_reason = CH_SWITCH_NORMAL; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci req.band_idx = phy != &dev->phy; 29328c2ecf20Sopenharmony_ci req.bw = mt7615_mcu_chan_bw(chandef); 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci if (mt76_testmode_enabled(&dev->mt76)) 29358c2ecf20Sopenharmony_ci memset(req.txpower_sku, 0x3f, 49); 29368c2ecf20Sopenharmony_ci else 29378c2ecf20Sopenharmony_ci mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 29408c2ecf20Sopenharmony_ci} 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ciint mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index) 29438c2ecf20Sopenharmony_ci{ 29448c2ecf20Sopenharmony_ci struct { 29458c2ecf20Sopenharmony_ci u8 action; 29468c2ecf20Sopenharmony_ci u8 rsv[3]; 29478c2ecf20Sopenharmony_ci } req = { 29488c2ecf20Sopenharmony_ci .action = index, 29498c2ecf20Sopenharmony_ci }; 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req, 29528c2ecf20Sopenharmony_ci sizeof(req), true); 29538c2ecf20Sopenharmony_ci} 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ciint mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, 29568c2ecf20Sopenharmony_ci u32 val) 29578c2ecf20Sopenharmony_ci{ 29588c2ecf20Sopenharmony_ci struct { 29598c2ecf20Sopenharmony_ci u8 test_mode_en; 29608c2ecf20Sopenharmony_ci u8 param_idx; 29618c2ecf20Sopenharmony_ci u8 _rsv[2]; 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci __le32 value; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci u8 pad[8]; 29668c2ecf20Sopenharmony_ci } req = { 29678c2ecf20Sopenharmony_ci .test_mode_en = test_mode, 29688c2ecf20Sopenharmony_ci .param_idx = param, 29698c2ecf20Sopenharmony_ci .value = cpu_to_le32(val), 29708c2ecf20Sopenharmony_ci }; 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req, 29738c2ecf20Sopenharmony_ci sizeof(req), false); 29748c2ecf20Sopenharmony_ci} 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ciint mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable) 29778c2ecf20Sopenharmony_ci{ 29788c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 29798c2ecf20Sopenharmony_ci struct { 29808c2ecf20Sopenharmony_ci u8 format_id; 29818c2ecf20Sopenharmony_ci u8 sku_enable; 29828c2ecf20Sopenharmony_ci u8 band_idx; 29838c2ecf20Sopenharmony_ci u8 rsv; 29848c2ecf20Sopenharmony_ci } req = { 29858c2ecf20Sopenharmony_ci .format_id = 0, 29868c2ecf20Sopenharmony_ci .band_idx = phy != &dev->phy, 29878c2ecf20Sopenharmony_ci .sku_enable = enable, 29888c2ecf20Sopenharmony_ci }; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req, 29918c2ecf20Sopenharmony_ci sizeof(req), true); 29928c2ecf20Sopenharmony_ci} 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ciint mt7615_mcu_set_vif_ps(struct mt7615_dev *dev, struct ieee80211_vif *vif) 29958c2ecf20Sopenharmony_ci{ 29968c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 29978c2ecf20Sopenharmony_ci struct { 29988c2ecf20Sopenharmony_ci u8 bss_idx; 29998c2ecf20Sopenharmony_ci u8 ps_state; /* 0: device awake 30008c2ecf20Sopenharmony_ci * 1: static power save 30018c2ecf20Sopenharmony_ci * 2: dynamic power saving 30028c2ecf20Sopenharmony_ci */ 30038c2ecf20Sopenharmony_ci } req = { 30048c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 30058c2ecf20Sopenharmony_ci .ps_state = vif->bss_conf.ps ? 2 : 0, 30068c2ecf20Sopenharmony_ci }; 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION) 30098c2ecf20Sopenharmony_ci return -ENOTSUPP; 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_PS_PROFILE, 30128c2ecf20Sopenharmony_ci &req, sizeof(req), false); 30138c2ecf20Sopenharmony_ci} 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ciint mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) 30168c2ecf20Sopenharmony_ci{ 30178c2ecf20Sopenharmony_ci struct mt76_phy *mphy = phy->mt76; 30188c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 30198c2ecf20Sopenharmony_ci struct mt7615_mcu_channel_domain { 30208c2ecf20Sopenharmony_ci __le32 country_code; /* regulatory_request.alpha2 */ 30218c2ecf20Sopenharmony_ci u8 bw_2g; /* BW_20_40M 0 30228c2ecf20Sopenharmony_ci * BW_20M 1 30238c2ecf20Sopenharmony_ci * BW_20_40_80M 2 30248c2ecf20Sopenharmony_ci * BW_20_40_80_160M 3 30258c2ecf20Sopenharmony_ci * BW_20_40_80_8080M 4 30268c2ecf20Sopenharmony_ci */ 30278c2ecf20Sopenharmony_ci u8 bw_5g; 30288c2ecf20Sopenharmony_ci __le16 pad; 30298c2ecf20Sopenharmony_ci u8 n_2ch; 30308c2ecf20Sopenharmony_ci u8 n_5ch; 30318c2ecf20Sopenharmony_ci __le16 pad2; 30328c2ecf20Sopenharmony_ci } __packed hdr = { 30338c2ecf20Sopenharmony_ci .bw_2g = 0, 30348c2ecf20Sopenharmony_ci .bw_5g = 3, 30358c2ecf20Sopenharmony_ci .n_2ch = mphy->sband_2g.sband.n_channels, 30368c2ecf20Sopenharmony_ci .n_5ch = mphy->sband_5g.sband.n_channels, 30378c2ecf20Sopenharmony_ci }; 30388c2ecf20Sopenharmony_ci struct mt7615_mcu_chan { 30398c2ecf20Sopenharmony_ci __le16 hw_value; 30408c2ecf20Sopenharmony_ci __le16 pad; 30418c2ecf20Sopenharmony_ci __le32 flags; 30428c2ecf20Sopenharmony_ci } __packed; 30438c2ecf20Sopenharmony_ci int i, n_channels = hdr.n_2ch + hdr.n_5ch; 30448c2ecf20Sopenharmony_ci int len = sizeof(hdr) + n_channels * sizeof(struct mt7615_mcu_chan); 30458c2ecf20Sopenharmony_ci struct sk_buff *skb; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 30488c2ecf20Sopenharmony_ci return 0; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); 30518c2ecf20Sopenharmony_ci if (!skb) 30528c2ecf20Sopenharmony_ci return -ENOMEM; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci skb_put_data(skb, &hdr, sizeof(hdr)); 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci for (i = 0; i < n_channels; i++) { 30578c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 30588c2ecf20Sopenharmony_ci struct mt7615_mcu_chan channel; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci if (i < hdr.n_2ch) 30618c2ecf20Sopenharmony_ci chan = &mphy->sband_2g.sband.channels[i]; 30628c2ecf20Sopenharmony_ci else 30638c2ecf20Sopenharmony_ci chan = &mphy->sband_5g.sband.channels[i - hdr.n_2ch]; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci channel.hw_value = cpu_to_le16(chan->hw_value); 30668c2ecf20Sopenharmony_ci channel.flags = cpu_to_le32(chan->flags); 30678c2ecf20Sopenharmony_ci channel.pad = 0; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci skb_put_data(skb, &channel, sizeof(channel)); 30708c2ecf20Sopenharmony_ci } 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 30738c2ecf20Sopenharmony_ci MCU_CMD_SET_CHAN_DOMAIN, false); 30748c2ecf20Sopenharmony_ci} 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci#define MT7615_SCAN_CHANNEL_TIME 60 30778c2ecf20Sopenharmony_ciint mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, 30788c2ecf20Sopenharmony_ci struct ieee80211_scan_request *scan_req) 30798c2ecf20Sopenharmony_ci{ 30808c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 30818c2ecf20Sopenharmony_ci struct cfg80211_scan_request *sreq = &scan_req->req; 30828c2ecf20Sopenharmony_ci int n_ssids = 0, err, i, duration = MT7615_SCAN_CHANNEL_TIME; 30838c2ecf20Sopenharmony_ci int ext_channels_num = max_t(int, sreq->n_channels - 32, 0); 30848c2ecf20Sopenharmony_ci struct ieee80211_channel **scan_list = sreq->channels; 30858c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 30868c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 30878c2ecf20Sopenharmony_ci struct mt7615_mcu_scan_channel *chan; 30888c2ecf20Sopenharmony_ci struct mt7615_hw_scan_req *req; 30898c2ecf20Sopenharmony_ci struct sk_buff *skb; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci /* fall-back to sw-scan */ 30928c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 30938c2ecf20Sopenharmony_ci return 1; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(*req)); 30968c2ecf20Sopenharmony_ci if (!skb) 30978c2ecf20Sopenharmony_ci return -ENOMEM; 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci set_bit(MT76_HW_SCANNING, &phy->mt76->state); 31008c2ecf20Sopenharmony_ci mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci req = (struct mt7615_hw_scan_req *)skb_put(skb, sizeof(*req)); 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci req->seq_num = mvif->scan_seq_num | ext_phy << 7; 31058c2ecf20Sopenharmony_ci req->bss_idx = mvif->idx; 31068c2ecf20Sopenharmony_ci req->scan_type = sreq->n_ssids ? 1 : 0; 31078c2ecf20Sopenharmony_ci req->probe_req_num = sreq->n_ssids ? 2 : 0; 31088c2ecf20Sopenharmony_ci req->version = 1; 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci for (i = 0; i < sreq->n_ssids; i++) { 31118c2ecf20Sopenharmony_ci if (!sreq->ssids[i].ssid_len) 31128c2ecf20Sopenharmony_ci continue; 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); 31158c2ecf20Sopenharmony_ci memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, 31168c2ecf20Sopenharmony_ci sreq->ssids[i].ssid_len); 31178c2ecf20Sopenharmony_ci n_ssids++; 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci req->ssid_type = n_ssids ? BIT(2) : BIT(0); 31208c2ecf20Sopenharmony_ci req->ssid_type_ext = n_ssids ? BIT(0) : 0; 31218c2ecf20Sopenharmony_ci req->ssids_num = n_ssids; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci /* increase channel time for passive scan */ 31248c2ecf20Sopenharmony_ci if (!sreq->n_ssids) 31258c2ecf20Sopenharmony_ci duration *= 2; 31268c2ecf20Sopenharmony_ci req->timeout_value = cpu_to_le16(sreq->n_channels * duration); 31278c2ecf20Sopenharmony_ci req->channel_min_dwell_time = cpu_to_le16(duration); 31288c2ecf20Sopenharmony_ci req->channel_dwell_time = cpu_to_le16(duration); 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci req->channels_num = min_t(u8, sreq->n_channels, 32); 31318c2ecf20Sopenharmony_ci req->ext_channels_num = min_t(u8, ext_channels_num, 32); 31328c2ecf20Sopenharmony_ci for (i = 0; i < req->channels_num + req->ext_channels_num; i++) { 31338c2ecf20Sopenharmony_ci if (i >= 32) 31348c2ecf20Sopenharmony_ci chan = &req->ext_channels[i - 32]; 31358c2ecf20Sopenharmony_ci else 31368c2ecf20Sopenharmony_ci chan = &req->channels[i]; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; 31398c2ecf20Sopenharmony_ci chan->channel_num = scan_list[i]->hw_value; 31408c2ecf20Sopenharmony_ci } 31418c2ecf20Sopenharmony_ci req->channel_type = sreq->n_channels ? 4 : 0; 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci if (sreq->ie_len > 0) { 31448c2ecf20Sopenharmony_ci memcpy(req->ies, sreq->ie, sreq->ie_len); 31458c2ecf20Sopenharmony_ci req->ies_len = cpu_to_le16(sreq->ie_len); 31468c2ecf20Sopenharmony_ci } 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci memcpy(req->bssid, sreq->bssid, ETH_ALEN); 31498c2ecf20Sopenharmony_ci if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { 31508c2ecf20Sopenharmony_ci get_random_mask_addr(req->random_mac, sreq->mac_addr, 31518c2ecf20Sopenharmony_ci sreq->mac_addr_mask); 31528c2ecf20Sopenharmony_ci req->scan_func = 1; 31538c2ecf20Sopenharmony_ci } 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_START_HW_SCAN, 31568c2ecf20Sopenharmony_ci false); 31578c2ecf20Sopenharmony_ci if (err < 0) 31588c2ecf20Sopenharmony_ci clear_bit(MT76_HW_SCANNING, &phy->mt76->state); 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci return err; 31618c2ecf20Sopenharmony_ci} 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ciint mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, 31648c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 31658c2ecf20Sopenharmony_ci{ 31668c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 31678c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 31688c2ecf20Sopenharmony_ci struct { 31698c2ecf20Sopenharmony_ci u8 seq_num; 31708c2ecf20Sopenharmony_ci u8 is_ext_channel; 31718c2ecf20Sopenharmony_ci u8 rsv[2]; 31728c2ecf20Sopenharmony_ci } __packed req = { 31738c2ecf20Sopenharmony_ci .seq_num = mvif->scan_seq_num, 31748c2ecf20Sopenharmony_ci }; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) { 31778c2ecf20Sopenharmony_ci struct cfg80211_scan_info info = { 31788c2ecf20Sopenharmony_ci .aborted = true, 31798c2ecf20Sopenharmony_ci }; 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci ieee80211_scan_completed(phy->mt76->hw, &info); 31828c2ecf20Sopenharmony_ci } 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req, 31858c2ecf20Sopenharmony_ci sizeof(req), false); 31868c2ecf20Sopenharmony_ci} 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_ciint mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, 31898c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 31908c2ecf20Sopenharmony_ci struct cfg80211_sched_scan_request *sreq) 31918c2ecf20Sopenharmony_ci{ 31928c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 31938c2ecf20Sopenharmony_ci struct ieee80211_channel **scan_list = sreq->channels; 31948c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 31958c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 31968c2ecf20Sopenharmony_ci struct mt7615_mcu_scan_channel *chan; 31978c2ecf20Sopenharmony_ci struct mt7615_sched_scan_req *req; 31988c2ecf20Sopenharmony_ci struct cfg80211_match_set *match; 31998c2ecf20Sopenharmony_ci struct cfg80211_ssid *ssid; 32008c2ecf20Sopenharmony_ci struct sk_buff *skb; 32018c2ecf20Sopenharmony_ci int i; 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 32048c2ecf20Sopenharmony_ci return -ENOTSUPP; 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 32078c2ecf20Sopenharmony_ci sizeof(*req) + sreq->ie_len); 32088c2ecf20Sopenharmony_ci if (!skb) 32098c2ecf20Sopenharmony_ci return -ENOMEM; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci req = (struct mt7615_sched_scan_req *)skb_put(skb, sizeof(*req)); 32148c2ecf20Sopenharmony_ci req->version = 1; 32158c2ecf20Sopenharmony_ci req->seq_num = mvif->scan_seq_num | ext_phy << 7; 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { 32188c2ecf20Sopenharmony_ci get_random_mask_addr(req->random_mac, sreq->mac_addr, 32198c2ecf20Sopenharmony_ci sreq->mac_addr_mask); 32208c2ecf20Sopenharmony_ci req->scan_func = 1; 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci req->ssids_num = sreq->n_ssids; 32248c2ecf20Sopenharmony_ci for (i = 0; i < req->ssids_num; i++) { 32258c2ecf20Sopenharmony_ci ssid = &sreq->ssids[i]; 32268c2ecf20Sopenharmony_ci memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len); 32278c2ecf20Sopenharmony_ci req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len); 32288c2ecf20Sopenharmony_ci } 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci req->match_num = sreq->n_match_sets; 32318c2ecf20Sopenharmony_ci for (i = 0; i < req->match_num; i++) { 32328c2ecf20Sopenharmony_ci match = &sreq->match_sets[i]; 32338c2ecf20Sopenharmony_ci memcpy(req->match[i].ssid, match->ssid.ssid, 32348c2ecf20Sopenharmony_ci match->ssid.ssid_len); 32358c2ecf20Sopenharmony_ci req->match[i].rssi_th = cpu_to_le32(match->rssi_thold); 32368c2ecf20Sopenharmony_ci req->match[i].ssid_len = match->ssid.ssid_len; 32378c2ecf20Sopenharmony_ci } 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci req->channel_type = sreq->n_channels ? 4 : 0; 32408c2ecf20Sopenharmony_ci req->channels_num = min_t(u8, sreq->n_channels, 64); 32418c2ecf20Sopenharmony_ci for (i = 0; i < req->channels_num; i++) { 32428c2ecf20Sopenharmony_ci chan = &req->channels[i]; 32438c2ecf20Sopenharmony_ci chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; 32448c2ecf20Sopenharmony_ci chan->channel_num = scan_list[i]->hw_value; 32458c2ecf20Sopenharmony_ci } 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci req->intervals_num = sreq->n_scan_plans; 32488c2ecf20Sopenharmony_ci for (i = 0; i < req->intervals_num; i++) 32498c2ecf20Sopenharmony_ci req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval); 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci if (sreq->ie_len > 0) { 32528c2ecf20Sopenharmony_ci req->ie_len = cpu_to_le16(sreq->ie_len); 32538c2ecf20Sopenharmony_ci memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len); 32548c2ecf20Sopenharmony_ci } 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 32578c2ecf20Sopenharmony_ci MCU_CMD_SCHED_SCAN_REQ, false); 32588c2ecf20Sopenharmony_ci} 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ciint mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy, 32618c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 32628c2ecf20Sopenharmony_ci bool enable) 32638c2ecf20Sopenharmony_ci{ 32648c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 32658c2ecf20Sopenharmony_ci struct { 32668c2ecf20Sopenharmony_ci u8 active; /* 0: enabled 1: disabled */ 32678c2ecf20Sopenharmony_ci u8 rsv[3]; 32688c2ecf20Sopenharmony_ci } __packed req = { 32698c2ecf20Sopenharmony_ci .active = !enable, 32708c2ecf20Sopenharmony_ci }; 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 32738c2ecf20Sopenharmony_ci return -ENOTSUPP; 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci if (enable) 32768c2ecf20Sopenharmony_ci set_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); 32778c2ecf20Sopenharmony_ci else 32788c2ecf20Sopenharmony_ci clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, 32818c2ecf20Sopenharmony_ci &req, sizeof(req), false); 32828c2ecf20Sopenharmony_ci} 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_cistatic int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur) 32858c2ecf20Sopenharmony_ci{ 32868c2ecf20Sopenharmony_ci int i; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci for (i = 0; i < n_freqs; i++) 32898c2ecf20Sopenharmony_ci if (cur == freqs[i]) 32908c2ecf20Sopenharmony_ci return i; 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci return -1; 32938c2ecf20Sopenharmony_ci} 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_cistatic int mt7615_dcoc_freq_idx(u16 freq, u8 bw) 32968c2ecf20Sopenharmony_ci{ 32978c2ecf20Sopenharmony_ci static const u16 freq_list[] = { 32988c2ecf20Sopenharmony_ci 4980, 5805, 5905, 5190, 32998c2ecf20Sopenharmony_ci 5230, 5270, 5310, 5350, 33008c2ecf20Sopenharmony_ci 5390, 5430, 5470, 5510, 33018c2ecf20Sopenharmony_ci 5550, 5590, 5630, 5670, 33028c2ecf20Sopenharmony_ci 5710, 5755, 5795, 5835, 33038c2ecf20Sopenharmony_ci 5875, 5210, 5290, 5370, 33048c2ecf20Sopenharmony_ci 5450, 5530, 5610, 5690, 33058c2ecf20Sopenharmony_ci 5775, 5855 33068c2ecf20Sopenharmony_ci }; 33078c2ecf20Sopenharmony_ci static const u16 freq_bw40[] = { 33088c2ecf20Sopenharmony_ci 5190, 5230, 5270, 5310, 33098c2ecf20Sopenharmony_ci 5350, 5390, 5430, 5470, 33108c2ecf20Sopenharmony_ci 5510, 5550, 5590, 5630, 33118c2ecf20Sopenharmony_ci 5670, 5710, 5755, 5795, 33128c2ecf20Sopenharmony_ci 5835, 5875 33138c2ecf20Sopenharmony_ci }; 33148c2ecf20Sopenharmony_ci int offset_2g = ARRAY_SIZE(freq_list); 33158c2ecf20Sopenharmony_ci int idx; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci if (freq < 4000) { 33188c2ecf20Sopenharmony_ci if (freq < 2427) 33198c2ecf20Sopenharmony_ci return offset_2g; 33208c2ecf20Sopenharmony_ci if (freq < 2442) 33218c2ecf20Sopenharmony_ci return offset_2g + 1; 33228c2ecf20Sopenharmony_ci if (freq < 2457) 33238c2ecf20Sopenharmony_ci return offset_2g + 2; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci return offset_2g + 3; 33268c2ecf20Sopenharmony_ci } 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci switch (bw) { 33298c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 33308c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 33318c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 33328c2ecf20Sopenharmony_ci break; 33338c2ecf20Sopenharmony_ci default: 33348c2ecf20Sopenharmony_ci idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), 33358c2ecf20Sopenharmony_ci freq + 10); 33368c2ecf20Sopenharmony_ci if (idx >= 0) { 33378c2ecf20Sopenharmony_ci freq = freq_bw40[idx]; 33388c2ecf20Sopenharmony_ci break; 33398c2ecf20Sopenharmony_ci } 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ci idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), 33428c2ecf20Sopenharmony_ci freq - 10); 33438c2ecf20Sopenharmony_ci if (idx >= 0) { 33448c2ecf20Sopenharmony_ci freq = freq_bw40[idx]; 33458c2ecf20Sopenharmony_ci break; 33468c2ecf20Sopenharmony_ci } 33478c2ecf20Sopenharmony_ci fallthrough; 33488c2ecf20Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 33498c2ecf20Sopenharmony_ci idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), 33508c2ecf20Sopenharmony_ci freq); 33518c2ecf20Sopenharmony_ci if (idx >= 0) 33528c2ecf20Sopenharmony_ci break; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci return -1; 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci } 33578c2ecf20Sopenharmony_ci 33588c2ecf20Sopenharmony_ci return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); 33598c2ecf20Sopenharmony_ci} 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ciint mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy) 33628c2ecf20Sopenharmony_ci{ 33638c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 33648c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 33658c2ecf20Sopenharmony_ci int freq2 = chandef->center_freq2; 33668c2ecf20Sopenharmony_ci int ret; 33678c2ecf20Sopenharmony_ci struct { 33688c2ecf20Sopenharmony_ci u8 direction; 33698c2ecf20Sopenharmony_ci u8 runtime_calibration; 33708c2ecf20Sopenharmony_ci u8 _rsv[2]; 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_ci __le16 center_freq; 33738c2ecf20Sopenharmony_ci u8 bw; 33748c2ecf20Sopenharmony_ci u8 band; 33758c2ecf20Sopenharmony_ci u8 is_freq2; 33768c2ecf20Sopenharmony_ci u8 success; 33778c2ecf20Sopenharmony_ci u8 dbdc_en; 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_ci u8 _rsv2; 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci struct { 33828c2ecf20Sopenharmony_ci __le32 sx0_i_lna[4]; 33838c2ecf20Sopenharmony_ci __le32 sx0_q_lna[4]; 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci __le32 sx2_i_lna[4]; 33868c2ecf20Sopenharmony_ci __le32 sx2_q_lna[4]; 33878c2ecf20Sopenharmony_ci } dcoc_data[4]; 33888c2ecf20Sopenharmony_ci } req = { 33898c2ecf20Sopenharmony_ci .direction = 1, 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci .bw = mt7615_mcu_chan_bw(chandef), 33928c2ecf20Sopenharmony_ci .band = chandef->center_freq1 > 4000, 33938c2ecf20Sopenharmony_ci .dbdc_en = !!dev->mt76.phy2, 33948c2ecf20Sopenharmony_ci }; 33958c2ecf20Sopenharmony_ci u16 center_freq = chandef->center_freq1; 33968c2ecf20Sopenharmony_ci int freq_idx; 33978c2ecf20Sopenharmony_ci u8 *eep = dev->mt76.eeprom.data; 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL)) 34008c2ecf20Sopenharmony_ci return 0; 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_160) { 34038c2ecf20Sopenharmony_ci freq2 = center_freq + 40; 34048c2ecf20Sopenharmony_ci center_freq -= 40; 34058c2ecf20Sopenharmony_ci } 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ciagain: 34088c2ecf20Sopenharmony_ci req.runtime_calibration = 1; 34098c2ecf20Sopenharmony_ci freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width); 34108c2ecf20Sopenharmony_ci if (freq_idx < 0) 34118c2ecf20Sopenharmony_ci goto out; 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_ci memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET + 34148c2ecf20Sopenharmony_ci freq_idx * MT7615_EEPROM_DCOC_SIZE, 34158c2ecf20Sopenharmony_ci sizeof(req.dcoc_data)); 34168c2ecf20Sopenharmony_ci req.runtime_calibration = 0; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ciout: 34198c2ecf20Sopenharmony_ci req.center_freq = cpu_to_le16(center_freq); 34208c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RXDCOC_CAL, &req, 34218c2ecf20Sopenharmony_ci sizeof(req), true); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci if ((chandef->width == NL80211_CHAN_WIDTH_80P80 || 34248c2ecf20Sopenharmony_ci chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) { 34258c2ecf20Sopenharmony_ci req.is_freq2 = true; 34268c2ecf20Sopenharmony_ci center_freq = freq2; 34278c2ecf20Sopenharmony_ci goto again; 34288c2ecf20Sopenharmony_ci } 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci return ret; 34318c2ecf20Sopenharmony_ci} 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_cistatic int mt7615_dpd_freq_idx(u16 freq, u8 bw) 34348c2ecf20Sopenharmony_ci{ 34358c2ecf20Sopenharmony_ci static const u16 freq_list[] = { 34368c2ecf20Sopenharmony_ci 4920, 4940, 4960, 4980, 34378c2ecf20Sopenharmony_ci 5040, 5060, 5080, 5180, 34388c2ecf20Sopenharmony_ci 5200, 5220, 5240, 5260, 34398c2ecf20Sopenharmony_ci 5280, 5300, 5320, 5340, 34408c2ecf20Sopenharmony_ci 5360, 5380, 5400, 5420, 34418c2ecf20Sopenharmony_ci 5440, 5460, 5480, 5500, 34428c2ecf20Sopenharmony_ci 5520, 5540, 5560, 5580, 34438c2ecf20Sopenharmony_ci 5600, 5620, 5640, 5660, 34448c2ecf20Sopenharmony_ci 5680, 5700, 5720, 5745, 34458c2ecf20Sopenharmony_ci 5765, 5785, 5805, 5825, 34468c2ecf20Sopenharmony_ci 5845, 5865, 5885, 5905 34478c2ecf20Sopenharmony_ci }; 34488c2ecf20Sopenharmony_ci int offset_2g = ARRAY_SIZE(freq_list); 34498c2ecf20Sopenharmony_ci int idx; 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci if (freq < 4000) { 34528c2ecf20Sopenharmony_ci if (freq < 2432) 34538c2ecf20Sopenharmony_ci return offset_2g; 34548c2ecf20Sopenharmony_ci if (freq < 2457) 34558c2ecf20Sopenharmony_ci return offset_2g + 1; 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci return offset_2g + 2; 34588c2ecf20Sopenharmony_ci } 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci if (bw != NL80211_CHAN_WIDTH_20) { 34618c2ecf20Sopenharmony_ci idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), 34628c2ecf20Sopenharmony_ci freq + 10); 34638c2ecf20Sopenharmony_ci if (idx >= 0) 34648c2ecf20Sopenharmony_ci return idx; 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), 34678c2ecf20Sopenharmony_ci freq - 10); 34688c2ecf20Sopenharmony_ci if (idx >= 0) 34698c2ecf20Sopenharmony_ci return idx; 34708c2ecf20Sopenharmony_ci } 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); 34738c2ecf20Sopenharmony_ci} 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ciint mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy) 34778c2ecf20Sopenharmony_ci{ 34788c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 34798c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 34808c2ecf20Sopenharmony_ci int freq2 = chandef->center_freq2; 34818c2ecf20Sopenharmony_ci int ret; 34828c2ecf20Sopenharmony_ci struct { 34838c2ecf20Sopenharmony_ci u8 direction; 34848c2ecf20Sopenharmony_ci u8 runtime_calibration; 34858c2ecf20Sopenharmony_ci u8 _rsv[2]; 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci __le16 center_freq; 34888c2ecf20Sopenharmony_ci u8 bw; 34898c2ecf20Sopenharmony_ci u8 band; 34908c2ecf20Sopenharmony_ci u8 is_freq2; 34918c2ecf20Sopenharmony_ci u8 success; 34928c2ecf20Sopenharmony_ci u8 dbdc_en; 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci u8 _rsv2; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci struct { 34978c2ecf20Sopenharmony_ci struct { 34988c2ecf20Sopenharmony_ci u32 dpd_g0; 34998c2ecf20Sopenharmony_ci u8 data[32]; 35008c2ecf20Sopenharmony_ci } wf0, wf1; 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci struct { 35038c2ecf20Sopenharmony_ci u32 dpd_g0_prim; 35048c2ecf20Sopenharmony_ci u32 dpd_g0_sec; 35058c2ecf20Sopenharmony_ci u8 data_prim[32]; 35068c2ecf20Sopenharmony_ci u8 data_sec[32]; 35078c2ecf20Sopenharmony_ci } wf2, wf3; 35088c2ecf20Sopenharmony_ci } dpd_data; 35098c2ecf20Sopenharmony_ci } req = { 35108c2ecf20Sopenharmony_ci .direction = 1, 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci .bw = mt7615_mcu_chan_bw(chandef), 35138c2ecf20Sopenharmony_ci .band = chandef->center_freq1 > 4000, 35148c2ecf20Sopenharmony_ci .dbdc_en = !!dev->mt76.phy2, 35158c2ecf20Sopenharmony_ci }; 35168c2ecf20Sopenharmony_ci u16 center_freq = chandef->center_freq1; 35178c2ecf20Sopenharmony_ci int freq_idx; 35188c2ecf20Sopenharmony_ci u8 *eep = dev->mt76.eeprom.data; 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_TX_DPD)) 35218c2ecf20Sopenharmony_ci return 0; 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci if (chandef->width == NL80211_CHAN_WIDTH_160) { 35248c2ecf20Sopenharmony_ci freq2 = center_freq + 40; 35258c2ecf20Sopenharmony_ci center_freq -= 40; 35268c2ecf20Sopenharmony_ci } 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ciagain: 35298c2ecf20Sopenharmony_ci req.runtime_calibration = 1; 35308c2ecf20Sopenharmony_ci freq_idx = mt7615_dpd_freq_idx(center_freq, chandef->width); 35318c2ecf20Sopenharmony_ci if (freq_idx < 0) 35328c2ecf20Sopenharmony_ci goto out; 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci memcpy(&req.dpd_data, eep + MT7615_EEPROM_TXDPD_OFFSET + 35358c2ecf20Sopenharmony_ci freq_idx * MT7615_EEPROM_TXDPD_SIZE, 35368c2ecf20Sopenharmony_ci sizeof(req.dpd_data)); 35378c2ecf20Sopenharmony_ci req.runtime_calibration = 0; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ciout: 35408c2ecf20Sopenharmony_ci req.center_freq = cpu_to_le16(center_freq); 35418c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXDPD_CAL, &req, 35428c2ecf20Sopenharmony_ci sizeof(req), true); 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci if ((chandef->width == NL80211_CHAN_WIDTH_80P80 || 35458c2ecf20Sopenharmony_ci chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) { 35468c2ecf20Sopenharmony_ci req.is_freq2 = true; 35478c2ecf20Sopenharmony_ci center_freq = freq2; 35488c2ecf20Sopenharmony_ci goto again; 35498c2ecf20Sopenharmony_ci } 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci return ret; 35528c2ecf20Sopenharmony_ci} 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ciint mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, 35558c2ecf20Sopenharmony_ci bool enable) 35568c2ecf20Sopenharmony_ci{ 35578c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 35588c2ecf20Sopenharmony_ci struct { 35598c2ecf20Sopenharmony_ci u8 bss_idx; 35608c2ecf20Sopenharmony_ci u8 dtim_period; 35618c2ecf20Sopenharmony_ci __le16 aid; 35628c2ecf20Sopenharmony_ci __le16 bcn_interval; 35638c2ecf20Sopenharmony_ci __le16 atim_window; 35648c2ecf20Sopenharmony_ci u8 uapsd; 35658c2ecf20Sopenharmony_ci u8 bmc_delivered_ac; 35668c2ecf20Sopenharmony_ci u8 bmc_triggered_ac; 35678c2ecf20Sopenharmony_ci u8 pad; 35688c2ecf20Sopenharmony_ci } req = { 35698c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 35708c2ecf20Sopenharmony_ci .aid = cpu_to_le16(vif->bss_conf.aid), 35718c2ecf20Sopenharmony_ci .dtim_period = vif->bss_conf.dtim_period, 35728c2ecf20Sopenharmony_ci .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 35738c2ecf20Sopenharmony_ci }; 35748c2ecf20Sopenharmony_ci struct { 35758c2ecf20Sopenharmony_ci u8 bss_idx; 35768c2ecf20Sopenharmony_ci u8 pad[3]; 35778c2ecf20Sopenharmony_ci } req_hdr = { 35788c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 35798c2ecf20Sopenharmony_ci }; 35808c2ecf20Sopenharmony_ci int err; 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION || 35838c2ecf20Sopenharmony_ci !mt7615_firmware_offload(dev)) 35848c2ecf20Sopenharmony_ci return -ENOTSUPP; 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci err = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, 35878c2ecf20Sopenharmony_ci &req_hdr, sizeof(req_hdr), false); 35888c2ecf20Sopenharmony_ci if (err < 0 || !enable) 35898c2ecf20Sopenharmony_ci return err; 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, 35928c2ecf20Sopenharmony_ci &req, sizeof(req), false); 35938c2ecf20Sopenharmony_ci} 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 35968c2ecf20Sopenharmony_ciint mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) 35978c2ecf20Sopenharmony_ci{ 35988c2ecf20Sopenharmony_ci struct { 35998c2ecf20Sopenharmony_ci struct { 36008c2ecf20Sopenharmony_ci u8 hif_type; /* 0x0: HIF_SDIO 36018c2ecf20Sopenharmony_ci * 0x1: HIF_USB 36028c2ecf20Sopenharmony_ci * 0x2: HIF_PCIE 36038c2ecf20Sopenharmony_ci */ 36048c2ecf20Sopenharmony_ci u8 pad[3]; 36058c2ecf20Sopenharmony_ci } __packed hdr; 36068c2ecf20Sopenharmony_ci struct hif_suspend_tlv { 36078c2ecf20Sopenharmony_ci __le16 tag; 36088c2ecf20Sopenharmony_ci __le16 len; 36098c2ecf20Sopenharmony_ci u8 suspend; 36108c2ecf20Sopenharmony_ci } __packed hif_suspend; 36118c2ecf20Sopenharmony_ci } req = { 36128c2ecf20Sopenharmony_ci .hif_suspend = { 36138c2ecf20Sopenharmony_ci .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ 36148c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), 36158c2ecf20Sopenharmony_ci .suspend = suspend, 36168c2ecf20Sopenharmony_ci }, 36178c2ecf20Sopenharmony_ci }; 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci if (mt76_is_mmio(&dev->mt76)) 36208c2ecf20Sopenharmony_ci req.hdr.hif_type = 2; 36218c2ecf20Sopenharmony_ci else if (mt76_is_usb(&dev->mt76)) 36228c2ecf20Sopenharmony_ci req.hdr.hif_type = 1; 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, 36258c2ecf20Sopenharmony_ci &req, sizeof(req), true); 36268c2ecf20Sopenharmony_ci} 36278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_cistatic int 36308c2ecf20Sopenharmony_cimt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif, 36318c2ecf20Sopenharmony_ci bool suspend, struct cfg80211_wowlan *wowlan) 36328c2ecf20Sopenharmony_ci{ 36338c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 36348c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 36358c2ecf20Sopenharmony_ci struct { 36368c2ecf20Sopenharmony_ci struct { 36378c2ecf20Sopenharmony_ci u8 bss_idx; 36388c2ecf20Sopenharmony_ci u8 pad[3]; 36398c2ecf20Sopenharmony_ci } __packed hdr; 36408c2ecf20Sopenharmony_ci struct mt7615_wow_ctrl_tlv wow_ctrl_tlv; 36418c2ecf20Sopenharmony_ci } req = { 36428c2ecf20Sopenharmony_ci .hdr = { 36438c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 36448c2ecf20Sopenharmony_ci }, 36458c2ecf20Sopenharmony_ci .wow_ctrl_tlv = { 36468c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL), 36478c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_wow_ctrl_tlv)), 36488c2ecf20Sopenharmony_ci .cmd = suspend ? 1 : 2, 36498c2ecf20Sopenharmony_ci }, 36508c2ecf20Sopenharmony_ci }; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci if (wowlan->magic_pkt) 36538c2ecf20Sopenharmony_ci req.wow_ctrl_tlv.trigger |= BIT(0); 36548c2ecf20Sopenharmony_ci if (wowlan->disconnect) 36558c2ecf20Sopenharmony_ci req.wow_ctrl_tlv.trigger |= BIT(2); 36568c2ecf20Sopenharmony_ci if (wowlan->nd_config) { 36578c2ecf20Sopenharmony_ci mt7615_mcu_sched_scan_req(phy, vif, wowlan->nd_config); 36588c2ecf20Sopenharmony_ci req.wow_ctrl_tlv.trigger |= BIT(5); 36598c2ecf20Sopenharmony_ci mt7615_mcu_sched_scan_enable(phy, vif, suspend); 36608c2ecf20Sopenharmony_ci } 36618c2ecf20Sopenharmony_ci 36628c2ecf20Sopenharmony_ci if (mt76_is_mmio(&dev->mt76)) 36638c2ecf20Sopenharmony_ci req.wow_ctrl_tlv.wakeup_hif = 2; 36648c2ecf20Sopenharmony_ci else if (mt76_is_usb(&dev->mt76)) 36658c2ecf20Sopenharmony_ci req.wow_ctrl_tlv.wakeup_hif = 1; 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, 36688c2ecf20Sopenharmony_ci &req, sizeof(req), true); 36698c2ecf20Sopenharmony_ci} 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_cistatic int 36728c2ecf20Sopenharmony_cimt7615_mcu_set_wow_pattern(struct mt7615_dev *dev, 36738c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 36748c2ecf20Sopenharmony_ci u8 index, bool enable, 36758c2ecf20Sopenharmony_ci struct cfg80211_pkt_pattern *pattern) 36768c2ecf20Sopenharmony_ci{ 36778c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 36788c2ecf20Sopenharmony_ci struct mt7615_wow_pattern_tlv *ptlv; 36798c2ecf20Sopenharmony_ci struct sk_buff *skb; 36808c2ecf20Sopenharmony_ci struct req_hdr { 36818c2ecf20Sopenharmony_ci u8 bss_idx; 36828c2ecf20Sopenharmony_ci u8 pad[3]; 36838c2ecf20Sopenharmony_ci } __packed hdr = { 36848c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 36858c2ecf20Sopenharmony_ci }; 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 36888c2ecf20Sopenharmony_ci sizeof(hdr) + sizeof(*ptlv)); 36898c2ecf20Sopenharmony_ci if (!skb) 36908c2ecf20Sopenharmony_ci return -ENOMEM; 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci skb_put_data(skb, &hdr, sizeof(hdr)); 36938c2ecf20Sopenharmony_ci ptlv = (struct mt7615_wow_pattern_tlv *)skb_put(skb, sizeof(*ptlv)); 36948c2ecf20Sopenharmony_ci ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); 36958c2ecf20Sopenharmony_ci ptlv->len = cpu_to_le16(sizeof(*ptlv)); 36968c2ecf20Sopenharmony_ci ptlv->data_len = pattern->pattern_len; 36978c2ecf20Sopenharmony_ci ptlv->enable = enable; 36988c2ecf20Sopenharmony_ci ptlv->index = index; 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); 37018c2ecf20Sopenharmony_ci memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8); 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 37048c2ecf20Sopenharmony_ci MCU_UNI_CMD_SUSPEND, true); 37058c2ecf20Sopenharmony_ci} 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_cistatic int 37088c2ecf20Sopenharmony_cimt7615_mcu_set_suspend_mode(struct mt7615_dev *dev, 37098c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 37108c2ecf20Sopenharmony_ci bool enable, u8 mdtim, bool wow_suspend) 37118c2ecf20Sopenharmony_ci{ 37128c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 37138c2ecf20Sopenharmony_ci struct { 37148c2ecf20Sopenharmony_ci struct { 37158c2ecf20Sopenharmony_ci u8 bss_idx; 37168c2ecf20Sopenharmony_ci u8 pad[3]; 37178c2ecf20Sopenharmony_ci } __packed hdr; 37188c2ecf20Sopenharmony_ci struct mt7615_suspend_tlv suspend_tlv; 37198c2ecf20Sopenharmony_ci } req = { 37208c2ecf20Sopenharmony_ci .hdr = { 37218c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 37228c2ecf20Sopenharmony_ci }, 37238c2ecf20Sopenharmony_ci .suspend_tlv = { 37248c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING), 37258c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_suspend_tlv)), 37268c2ecf20Sopenharmony_ci .enable = enable, 37278c2ecf20Sopenharmony_ci .mdtim = mdtim, 37288c2ecf20Sopenharmony_ci .wow_suspend = wow_suspend, 37298c2ecf20Sopenharmony_ci }, 37308c2ecf20Sopenharmony_ci }; 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, 37338c2ecf20Sopenharmony_ci &req, sizeof(req), true); 37348c2ecf20Sopenharmony_ci} 37358c2ecf20Sopenharmony_ci 37368c2ecf20Sopenharmony_cistatic int 37378c2ecf20Sopenharmony_cimt7615_mcu_set_gtk_rekey(struct mt7615_dev *dev, 37388c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 37398c2ecf20Sopenharmony_ci bool suspend) 37408c2ecf20Sopenharmony_ci{ 37418c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 37428c2ecf20Sopenharmony_ci struct { 37438c2ecf20Sopenharmony_ci struct { 37448c2ecf20Sopenharmony_ci u8 bss_idx; 37458c2ecf20Sopenharmony_ci u8 pad[3]; 37468c2ecf20Sopenharmony_ci } __packed hdr; 37478c2ecf20Sopenharmony_ci struct mt7615_gtk_rekey_tlv gtk_tlv; 37488c2ecf20Sopenharmony_ci } __packed req = { 37498c2ecf20Sopenharmony_ci .hdr = { 37508c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 37518c2ecf20Sopenharmony_ci }, 37528c2ecf20Sopenharmony_ci .gtk_tlv = { 37538c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY), 37548c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_gtk_rekey_tlv)), 37558c2ecf20Sopenharmony_ci .rekey_mode = !suspend, 37568c2ecf20Sopenharmony_ci }, 37578c2ecf20Sopenharmony_ci }; 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, 37608c2ecf20Sopenharmony_ci &req, sizeof(req), true); 37618c2ecf20Sopenharmony_ci} 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_cistatic int 37648c2ecf20Sopenharmony_cimt7615_mcu_set_arp_filter(struct mt7615_dev *dev, struct ieee80211_vif *vif, 37658c2ecf20Sopenharmony_ci bool suspend) 37668c2ecf20Sopenharmony_ci{ 37678c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 37688c2ecf20Sopenharmony_ci struct { 37698c2ecf20Sopenharmony_ci struct { 37708c2ecf20Sopenharmony_ci u8 bss_idx; 37718c2ecf20Sopenharmony_ci u8 pad[3]; 37728c2ecf20Sopenharmony_ci } __packed hdr; 37738c2ecf20Sopenharmony_ci struct mt7615_arpns_tlv arpns; 37748c2ecf20Sopenharmony_ci } req = { 37758c2ecf20Sopenharmony_ci .hdr = { 37768c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 37778c2ecf20Sopenharmony_ci }, 37788c2ecf20Sopenharmony_ci .arpns = { 37798c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), 37808c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), 37818c2ecf20Sopenharmony_ci .mode = suspend, 37828c2ecf20Sopenharmony_ci }, 37838c2ecf20Sopenharmony_ci }; 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, 37868c2ecf20Sopenharmony_ci &req, sizeof(req), true); 37878c2ecf20Sopenharmony_ci} 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_civoid mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, 37908c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 37918c2ecf20Sopenharmony_ci{ 37928c2ecf20Sopenharmony_ci struct mt7615_phy *phy = priv; 37938c2ecf20Sopenharmony_ci bool suspend = test_bit(MT76_STATE_SUSPEND, &phy->mt76->state); 37948c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = phy->mt76->hw; 37958c2ecf20Sopenharmony_ci struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; 37968c2ecf20Sopenharmony_ci int i; 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci mt7615_mcu_set_bss_pm(phy->dev, vif, suspend); 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci mt7615_mcu_set_gtk_rekey(phy->dev, vif, suspend); 38018c2ecf20Sopenharmony_ci mt7615_mcu_set_arp_filter(phy->dev, vif, suspend); 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci mt7615_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci for (i = 0; i < wowlan->n_patterns; i++) 38068c2ecf20Sopenharmony_ci mt7615_mcu_set_wow_pattern(phy->dev, vif, i, suspend, 38078c2ecf20Sopenharmony_ci &wowlan->patterns[i]); 38088c2ecf20Sopenharmony_ci mt7615_mcu_set_wow_ctrl(phy, vif, suspend, wowlan); 38098c2ecf20Sopenharmony_ci} 38108c2ecf20Sopenharmony_ci 38118c2ecf20Sopenharmony_cistatic void 38128c2ecf20Sopenharmony_cimt7615_mcu_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 38138c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, struct ieee80211_key_conf *key, 38148c2ecf20Sopenharmony_ci void *data) 38158c2ecf20Sopenharmony_ci{ 38168c2ecf20Sopenharmony_ci struct mt7615_gtk_rekey_tlv *gtk_tlv = data; 38178c2ecf20Sopenharmony_ci u32 cipher; 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC && 38208c2ecf20Sopenharmony_ci key->cipher != WLAN_CIPHER_SUITE_CCMP && 38218c2ecf20Sopenharmony_ci key->cipher != WLAN_CIPHER_SUITE_TKIP) 38228c2ecf20Sopenharmony_ci return; 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { 38258c2ecf20Sopenharmony_ci gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1); 38268c2ecf20Sopenharmony_ci cipher = BIT(3); 38278c2ecf20Sopenharmony_ci } else { 38288c2ecf20Sopenharmony_ci gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2); 38298c2ecf20Sopenharmony_ci cipher = BIT(4); 38308c2ecf20Sopenharmony_ci } 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_ci /* we are assuming here to have a single pairwise key */ 38338c2ecf20Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 38348c2ecf20Sopenharmony_ci gtk_tlv->pairwise_cipher = cpu_to_le32(cipher); 38358c2ecf20Sopenharmony_ci gtk_tlv->group_cipher = cpu_to_le32(cipher); 38368c2ecf20Sopenharmony_ci gtk_tlv->keyid = key->keyidx; 38378c2ecf20Sopenharmony_ci } 38388c2ecf20Sopenharmony_ci} 38398c2ecf20Sopenharmony_ci 38408c2ecf20Sopenharmony_ciint mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, 38418c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 38428c2ecf20Sopenharmony_ci struct cfg80211_gtk_rekey_data *key) 38438c2ecf20Sopenharmony_ci{ 38448c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 38458c2ecf20Sopenharmony_ci struct mt7615_dev *dev = mt7615_hw_dev(hw); 38468c2ecf20Sopenharmony_ci struct mt7615_gtk_rekey_tlv *gtk_tlv; 38478c2ecf20Sopenharmony_ci struct sk_buff *skb; 38488c2ecf20Sopenharmony_ci struct { 38498c2ecf20Sopenharmony_ci u8 bss_idx; 38508c2ecf20Sopenharmony_ci u8 pad[3]; 38518c2ecf20Sopenharmony_ci } __packed hdr = { 38528c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 38538c2ecf20Sopenharmony_ci }; 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 38568c2ecf20Sopenharmony_ci sizeof(hdr) + sizeof(*gtk_tlv)); 38578c2ecf20Sopenharmony_ci if (!skb) 38588c2ecf20Sopenharmony_ci return -ENOMEM; 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci skb_put_data(skb, &hdr, sizeof(hdr)); 38618c2ecf20Sopenharmony_ci gtk_tlv = (struct mt7615_gtk_rekey_tlv *)skb_put(skb, 38628c2ecf20Sopenharmony_ci sizeof(*gtk_tlv)); 38638c2ecf20Sopenharmony_ci gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY); 38648c2ecf20Sopenharmony_ci gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv)); 38658c2ecf20Sopenharmony_ci gtk_tlv->rekey_mode = 2; 38668c2ecf20Sopenharmony_ci gtk_tlv->option = 1; 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_ci rcu_read_lock(); 38698c2ecf20Sopenharmony_ci ieee80211_iter_keys_rcu(hw, vif, mt7615_mcu_key_iter, gtk_tlv); 38708c2ecf20Sopenharmony_ci rcu_read_unlock(); 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN); 38738c2ecf20Sopenharmony_ci memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN); 38748c2ecf20Sopenharmony_ci memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN); 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 38778c2ecf20Sopenharmony_ci MCU_UNI_CMD_OFFLOAD, true); 38788c2ecf20Sopenharmony_ci} 38798c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ciint mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, 38828c2ecf20Sopenharmony_ci struct ieee80211_channel *chan, int duration) 38838c2ecf20Sopenharmony_ci{ 38848c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 38858c2ecf20Sopenharmony_ci struct mt7615_dev *dev = phy->dev; 38868c2ecf20Sopenharmony_ci struct mt7615_roc_tlv req = { 38878c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 38888c2ecf20Sopenharmony_ci .active = !chan, 38898c2ecf20Sopenharmony_ci .max_interval = cpu_to_le32(duration), 38908c2ecf20Sopenharmony_ci .primary_chan = chan ? chan->hw_value : 0, 38918c2ecf20Sopenharmony_ci .band = chan ? chan->band : 0, 38928c2ecf20Sopenharmony_ci .req_type = 2, 38938c2ecf20Sopenharmony_ci }; 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci phy->roc_grant = false; 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_ROC, &req, 38988c2ecf20Sopenharmony_ci sizeof(req), false); 38998c2ecf20Sopenharmony_ci} 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ciint mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, 39028c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 39038c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *info) 39048c2ecf20Sopenharmony_ci{ 39058c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 39068c2ecf20Sopenharmony_ci struct mt7615_dev *dev = mt7615_hw_dev(hw); 39078c2ecf20Sopenharmony_ci struct sk_buff *skb; 39088c2ecf20Sopenharmony_ci int i, len = min_t(int, info->arp_addr_cnt, 39098c2ecf20Sopenharmony_ci IEEE80211_BSS_ARP_ADDR_LIST_LEN); 39108c2ecf20Sopenharmony_ci struct { 39118c2ecf20Sopenharmony_ci struct { 39128c2ecf20Sopenharmony_ci u8 bss_idx; 39138c2ecf20Sopenharmony_ci u8 pad[3]; 39148c2ecf20Sopenharmony_ci } __packed hdr; 39158c2ecf20Sopenharmony_ci struct mt7615_arpns_tlv arp; 39168c2ecf20Sopenharmony_ci } req_hdr = { 39178c2ecf20Sopenharmony_ci .hdr = { 39188c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 39198c2ecf20Sopenharmony_ci }, 39208c2ecf20Sopenharmony_ci .arp = { 39218c2ecf20Sopenharmony_ci .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), 39228c2ecf20Sopenharmony_ci .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), 39238c2ecf20Sopenharmony_ci .ips_num = len, 39248c2ecf20Sopenharmony_ci .mode = 2, /* update */ 39258c2ecf20Sopenharmony_ci .option = 1, 39268c2ecf20Sopenharmony_ci }, 39278c2ecf20Sopenharmony_ci }; 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 39308c2ecf20Sopenharmony_ci return 0; 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 39338c2ecf20Sopenharmony_ci sizeof(req_hdr) + len * sizeof(__be32)); 39348c2ecf20Sopenharmony_ci if (!skb) 39358c2ecf20Sopenharmony_ci return -ENOMEM; 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci skb_put_data(skb, &req_hdr, sizeof(req_hdr)); 39388c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 39398c2ecf20Sopenharmony_ci u8 *addr = (u8 *)skb_put(skb, sizeof(__be32)); 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci memcpy(addr, &info->arp_addr_list[i], sizeof(__be32)); 39428c2ecf20Sopenharmony_ci } 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci return __mt76_mcu_skb_send_msg(&dev->mt76, skb, 39458c2ecf20Sopenharmony_ci MCU_UNI_CMD_OFFLOAD, true); 39468c2ecf20Sopenharmony_ci} 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ciint mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, 39498c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 39508c2ecf20Sopenharmony_ci{ 39518c2ecf20Sopenharmony_ci struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; 39528c2ecf20Sopenharmony_ci int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow; 39538c2ecf20Sopenharmony_ci struct mt7615_dev *dev = mt7615_hw_dev(hw); 39548c2ecf20Sopenharmony_ci struct { 39558c2ecf20Sopenharmony_ci __le32 ct_win; 39568c2ecf20Sopenharmony_ci u8 bss_idx; 39578c2ecf20Sopenharmony_ci u8 rsv[3]; 39588c2ecf20Sopenharmony_ci } __packed req = { 39598c2ecf20Sopenharmony_ci .ct_win = cpu_to_le32(ct_window), 39608c2ecf20Sopenharmony_ci .bss_idx = mvif->idx, 39618c2ecf20Sopenharmony_ci }; 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci if (!mt7615_firmware_offload(dev)) 39648c2ecf20Sopenharmony_ci return -ENOTSUPP; 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS, 39678c2ecf20Sopenharmony_ci &req, sizeof(req), false); 39688c2ecf20Sopenharmony_ci} 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ciu32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset) 39718c2ecf20Sopenharmony_ci{ 39728c2ecf20Sopenharmony_ci struct { 39738c2ecf20Sopenharmony_ci __le32 addr; 39748c2ecf20Sopenharmony_ci __le32 val; 39758c2ecf20Sopenharmony_ci } __packed req = { 39768c2ecf20Sopenharmony_ci .addr = cpu_to_le32(offset), 39778c2ecf20Sopenharmony_ci }; 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, 39808c2ecf20Sopenharmony_ci &req, sizeof(req), true); 39818c2ecf20Sopenharmony_ci} 39828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_reg_rr); 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_civoid mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val) 39858c2ecf20Sopenharmony_ci{ 39868c2ecf20Sopenharmony_ci struct { 39878c2ecf20Sopenharmony_ci __le32 addr; 39888c2ecf20Sopenharmony_ci __le32 val; 39898c2ecf20Sopenharmony_ci } __packed req = { 39908c2ecf20Sopenharmony_ci .addr = cpu_to_le32(offset), 39918c2ecf20Sopenharmony_ci .val = cpu_to_le32(val), 39928c2ecf20Sopenharmony_ci }; 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci __mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, 39958c2ecf20Sopenharmony_ci &req, sizeof(req), false); 39968c2ecf20Sopenharmony_ci} 39978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_reg_wr); 3998