162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2019-2020 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "cam.h" 662306a36Sopenharmony_ci#include "chan.h" 762306a36Sopenharmony_ci#include "coex.h" 862306a36Sopenharmony_ci#include "debug.h" 962306a36Sopenharmony_ci#include "fw.h" 1062306a36Sopenharmony_ci#include "mac.h" 1162306a36Sopenharmony_ci#include "phy.h" 1262306a36Sopenharmony_ci#include "ps.h" 1362306a36Sopenharmony_ci#include "reg.h" 1462306a36Sopenharmony_ci#include "util.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, 1762306a36Sopenharmony_ci struct sk_buff *skb); 1862306a36Sopenharmony_cistatic int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, 1962306a36Sopenharmony_ci struct rtw89_wait_info *wait, unsigned int cond); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len, 2262306a36Sopenharmony_ci bool header) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct sk_buff *skb; 2562306a36Sopenharmony_ci u32 header_len = 0; 2662306a36Sopenharmony_ci u32 h2c_desc_size = rtwdev->chip->h2c_desc_size; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (header) 2962306a36Sopenharmony_ci header_len = H2C_HEADER_LEN; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci skb = dev_alloc_skb(len + header_len + h2c_desc_size); 3262306a36Sopenharmony_ci if (!skb) 3362306a36Sopenharmony_ci return NULL; 3462306a36Sopenharmony_ci skb_reserve(skb, header_len + h2c_desc_size); 3562306a36Sopenharmony_ci memset(skb->data, 0, len); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return skb; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(struct rtw89_dev *rtwdev, u32 len) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci return rtw89_fw_h2c_alloc_skb(rtwdev, len, true); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci return rtw89_fw_h2c_alloc_skb(rtwdev, len, false); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic u8 _fw_get_rdy(struct rtw89_dev *rtwdev) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci u8 val = rtw89_read8(rtwdev, R_AX_WCPU_FW_CTRL); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return FIELD_GET(B_AX_WCPU_FWDL_STS_MASK, val); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define FWDL_WAIT_CNT 400000 5862306a36Sopenharmony_ciint rtw89_fw_check_rdy(struct rtw89_dev *rtwdev) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci u8 val; 6162306a36Sopenharmony_ci int ret; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci ret = read_poll_timeout_atomic(_fw_get_rdy, val, 6462306a36Sopenharmony_ci val == RTW89_FWDL_WCPU_FW_INIT_RDY, 6562306a36Sopenharmony_ci 1, FWDL_WAIT_CNT, false, rtwdev); 6662306a36Sopenharmony_ci if (ret) { 6762306a36Sopenharmony_ci switch (val) { 6862306a36Sopenharmony_ci case RTW89_FWDL_CHECKSUM_FAIL: 6962306a36Sopenharmony_ci rtw89_err(rtwdev, "fw checksum fail\n"); 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci case RTW89_FWDL_SECURITY_FAIL: 7362306a36Sopenharmony_ci rtw89_err(rtwdev, "fw security fail\n"); 7462306a36Sopenharmony_ci return -EINVAL; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci case RTW89_FWDL_CV_NOT_MATCH: 7762306a36Sopenharmony_ci rtw89_err(rtwdev, "fw cv not match\n"); 7862306a36Sopenharmony_ci return -EINVAL; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci default: 8162306a36Sopenharmony_ci return -EBUSY; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci set_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, 9162306a36Sopenharmony_ci struct rtw89_fw_bin_info *info) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw; 9462306a36Sopenharmony_ci struct rtw89_fw_hdr_section_info *section_info; 9562306a36Sopenharmony_ci const struct rtw89_fw_dynhdr_hdr *fwdynhdr; 9662306a36Sopenharmony_ci const struct rtw89_fw_hdr_section *section; 9762306a36Sopenharmony_ci const u8 *fw_end = fw + len; 9862306a36Sopenharmony_ci const u8 *bin; 9962306a36Sopenharmony_ci u32 base_hdr_len; 10062306a36Sopenharmony_ci u32 mssc_len = 0; 10162306a36Sopenharmony_ci u32 i; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (!info) 10462306a36Sopenharmony_ci return -EINVAL; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM); 10762306a36Sopenharmony_ci base_hdr_len = struct_size(fw_hdr, sections, info->section_num); 10862306a36Sopenharmony_ci info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (info->dynamic_hdr_en) { 11162306a36Sopenharmony_ci info->hdr_len = le32_get_bits(fw_hdr->w3, FW_HDR_W3_LEN); 11262306a36Sopenharmony_ci info->dynamic_hdr_len = info->hdr_len - base_hdr_len; 11362306a36Sopenharmony_ci fwdynhdr = (const struct rtw89_fw_dynhdr_hdr *)(fw + base_hdr_len); 11462306a36Sopenharmony_ci if (le32_to_cpu(fwdynhdr->hdr_len) != info->dynamic_hdr_len) { 11562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n"); 11662306a36Sopenharmony_ci return -EINVAL; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci } else { 11962306a36Sopenharmony_ci info->hdr_len = base_hdr_len; 12062306a36Sopenharmony_ci info->dynamic_hdr_len = 0; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci bin = fw + info->hdr_len; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* jump to section header */ 12662306a36Sopenharmony_ci section_info = info->section_info; 12762306a36Sopenharmony_ci for (i = 0; i < info->section_num; i++) { 12862306a36Sopenharmony_ci section = &fw_hdr->sections[i]; 12962306a36Sopenharmony_ci section_info->type = 13062306a36Sopenharmony_ci le32_get_bits(section->w1, FWSECTION_HDR_W1_SECTIONTYPE); 13162306a36Sopenharmony_ci if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { 13262306a36Sopenharmony_ci section_info->mssc = 13362306a36Sopenharmony_ci le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC); 13462306a36Sopenharmony_ci mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; 13562306a36Sopenharmony_ci } else { 13662306a36Sopenharmony_ci section_info->mssc = 0; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_W1_SEC_SIZE); 14062306a36Sopenharmony_ci if (le32_get_bits(section->w1, FWSECTION_HDR_W1_CHECKSUM)) 14162306a36Sopenharmony_ci section_info->len += FWDL_SECTION_CHKSUM_LEN; 14262306a36Sopenharmony_ci section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_W1_REDL); 14362306a36Sopenharmony_ci section_info->dladdr = 14462306a36Sopenharmony_ci le32_get_bits(section->w0, FWSECTION_HDR_W0_DL_ADDR) & 0x1fffffff; 14562306a36Sopenharmony_ci section_info->addr = bin; 14662306a36Sopenharmony_ci bin += section_info->len; 14762306a36Sopenharmony_ci section_info++; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (fw_end != bin + mssc_len) { 15162306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]fw bin size\n"); 15262306a36Sopenharmony_ci return -EINVAL; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, 15962306a36Sopenharmony_ci struct rtw89_fw_bin_info *info) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci const struct rtw89_fw_hdr_v1 *fw_hdr = (const struct rtw89_fw_hdr_v1 *)fw; 16262306a36Sopenharmony_ci struct rtw89_fw_hdr_section_info *section_info; 16362306a36Sopenharmony_ci const struct rtw89_fw_dynhdr_hdr *fwdynhdr; 16462306a36Sopenharmony_ci const struct rtw89_fw_hdr_section_v1 *section; 16562306a36Sopenharmony_ci const u8 *fw_end = fw + len; 16662306a36Sopenharmony_ci const u8 *bin; 16762306a36Sopenharmony_ci u32 base_hdr_len; 16862306a36Sopenharmony_ci u32 mssc_len = 0; 16962306a36Sopenharmony_ci u32 i; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_SEC_NUM); 17262306a36Sopenharmony_ci base_hdr_len = struct_size(fw_hdr, sections, info->section_num); 17362306a36Sopenharmony_ci info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (info->dynamic_hdr_en) { 17662306a36Sopenharmony_ci info->hdr_len = le32_get_bits(fw_hdr->w5, FW_HDR_V1_W5_HDR_SIZE); 17762306a36Sopenharmony_ci info->dynamic_hdr_len = info->hdr_len - base_hdr_len; 17862306a36Sopenharmony_ci fwdynhdr = (const struct rtw89_fw_dynhdr_hdr *)(fw + base_hdr_len); 17962306a36Sopenharmony_ci if (le32_to_cpu(fwdynhdr->hdr_len) != info->dynamic_hdr_len) { 18062306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n"); 18162306a36Sopenharmony_ci return -EINVAL; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci } else { 18462306a36Sopenharmony_ci info->hdr_len = base_hdr_len; 18562306a36Sopenharmony_ci info->dynamic_hdr_len = 0; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci bin = fw + info->hdr_len; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* jump to section header */ 19162306a36Sopenharmony_ci section_info = info->section_info; 19262306a36Sopenharmony_ci for (i = 0; i < info->section_num; i++) { 19362306a36Sopenharmony_ci section = &fw_hdr->sections[i]; 19462306a36Sopenharmony_ci section_info->type = 19562306a36Sopenharmony_ci le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_SECTIONTYPE); 19662306a36Sopenharmony_ci if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { 19762306a36Sopenharmony_ci section_info->mssc = 19862306a36Sopenharmony_ci le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); 19962306a36Sopenharmony_ci mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; 20062306a36Sopenharmony_ci } else { 20162306a36Sopenharmony_ci section_info->mssc = 0; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci section_info->len = 20562306a36Sopenharmony_ci le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_SEC_SIZE); 20662306a36Sopenharmony_ci if (le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_CHECKSUM)) 20762306a36Sopenharmony_ci section_info->len += FWDL_SECTION_CHKSUM_LEN; 20862306a36Sopenharmony_ci section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_REDL); 20962306a36Sopenharmony_ci section_info->dladdr = 21062306a36Sopenharmony_ci le32_get_bits(section->w0, FWSECTION_HDR_V1_W0_DL_ADDR); 21162306a36Sopenharmony_ci section_info->addr = bin; 21262306a36Sopenharmony_ci bin += section_info->len; 21362306a36Sopenharmony_ci section_info++; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (fw_end != bin + mssc_len) { 21762306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]fw bin size\n"); 21862306a36Sopenharmony_ci return -EINVAL; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, 22562306a36Sopenharmony_ci const struct rtw89_fw_suit *fw_suit, 22662306a36Sopenharmony_ci struct rtw89_fw_bin_info *info) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci const u8 *fw = fw_suit->data; 22962306a36Sopenharmony_ci u32 len = fw_suit->size; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (!fw || !len) { 23262306a36Sopenharmony_ci rtw89_err(rtwdev, "fw type %d isn't recognized\n", fw_suit->type); 23362306a36Sopenharmony_ci return -ENOENT; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci switch (fw_suit->hdr_ver) { 23762306a36Sopenharmony_ci case 0: 23862306a36Sopenharmony_ci return rtw89_fw_hdr_parser_v0(rtwdev, fw, len, info); 23962306a36Sopenharmony_ci case 1: 24062306a36Sopenharmony_ci return rtw89_fw_hdr_parser_v1(rtwdev, fw, len, info); 24162306a36Sopenharmony_ci default: 24262306a36Sopenharmony_ci return -ENOENT; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic 24762306a36Sopenharmony_ciint rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, 24862306a36Sopenharmony_ci struct rtw89_fw_suit *fw_suit, bool nowarn) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct rtw89_fw_info *fw_info = &rtwdev->fw; 25162306a36Sopenharmony_ci const struct firmware *firmware = fw_info->req.firmware; 25262306a36Sopenharmony_ci const u8 *mfw = firmware->data; 25362306a36Sopenharmony_ci u32 mfw_len = firmware->size; 25462306a36Sopenharmony_ci const struct rtw89_mfw_hdr *mfw_hdr = (const struct rtw89_mfw_hdr *)mfw; 25562306a36Sopenharmony_ci const struct rtw89_mfw_info *mfw_info; 25662306a36Sopenharmony_ci int i; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (mfw_hdr->sig != RTW89_MFW_SIG) { 25962306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, "use legacy firmware\n"); 26062306a36Sopenharmony_ci /* legacy firmware support normal type only */ 26162306a36Sopenharmony_ci if (type != RTW89_FW_NORMAL) 26262306a36Sopenharmony_ci return -EINVAL; 26362306a36Sopenharmony_ci fw_suit->data = mfw; 26462306a36Sopenharmony_ci fw_suit->size = mfw_len; 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci for (i = 0; i < mfw_hdr->fw_nr; i++) { 26962306a36Sopenharmony_ci mfw_info = &mfw_hdr->info[i]; 27062306a36Sopenharmony_ci if (mfw_info->type == type) { 27162306a36Sopenharmony_ci if (mfw_info->cv == rtwdev->hal.cv && !mfw_info->mp) 27262306a36Sopenharmony_ci goto found; 27362306a36Sopenharmony_ci if (type == RTW89_FW_LOGFMT) 27462306a36Sopenharmony_ci goto found; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!nowarn) 27962306a36Sopenharmony_ci rtw89_err(rtwdev, "no suitable firmware found\n"); 28062306a36Sopenharmony_ci return -ENOENT; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cifound: 28362306a36Sopenharmony_ci fw_suit->data = mfw + le32_to_cpu(mfw_info->shift); 28462306a36Sopenharmony_ci fw_suit->size = le32_to_cpu(mfw_info->size); 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic u32 rtw89_mfw_get_size(struct rtw89_dev *rtwdev) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct rtw89_fw_info *fw_info = &rtwdev->fw; 29162306a36Sopenharmony_ci const struct firmware *firmware = fw_info->req.firmware; 29262306a36Sopenharmony_ci const struct rtw89_mfw_hdr *mfw_hdr = 29362306a36Sopenharmony_ci (const struct rtw89_mfw_hdr *)firmware->data; 29462306a36Sopenharmony_ci const struct rtw89_mfw_info *mfw_info; 29562306a36Sopenharmony_ci u32 size; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (mfw_hdr->sig != RTW89_MFW_SIG) { 29862306a36Sopenharmony_ci rtw89_warn(rtwdev, "not mfw format\n"); 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci mfw_info = &mfw_hdr->info[mfw_hdr->fw_nr - 1]; 30362306a36Sopenharmony_ci size = le32_to_cpu(mfw_info->shift) + le32_to_cpu(mfw_info->size); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return size; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void rtw89_fw_update_ver_v0(struct rtw89_dev *rtwdev, 30962306a36Sopenharmony_ci struct rtw89_fw_suit *fw_suit, 31062306a36Sopenharmony_ci const struct rtw89_fw_hdr *hdr) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci fw_suit->major_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MAJOR_VERSION); 31362306a36Sopenharmony_ci fw_suit->minor_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MINOR_VERSION); 31462306a36Sopenharmony_ci fw_suit->sub_ver = le32_get_bits(hdr->w1, FW_HDR_W1_SUBVERSION); 31562306a36Sopenharmony_ci fw_suit->sub_idex = le32_get_bits(hdr->w1, FW_HDR_W1_SUBINDEX); 31662306a36Sopenharmony_ci fw_suit->commitid = le32_get_bits(hdr->w2, FW_HDR_W2_COMMITID); 31762306a36Sopenharmony_ci fw_suit->build_year = le32_get_bits(hdr->w5, FW_HDR_W5_YEAR); 31862306a36Sopenharmony_ci fw_suit->build_mon = le32_get_bits(hdr->w4, FW_HDR_W4_MONTH); 31962306a36Sopenharmony_ci fw_suit->build_date = le32_get_bits(hdr->w4, FW_HDR_W4_DATE); 32062306a36Sopenharmony_ci fw_suit->build_hour = le32_get_bits(hdr->w4, FW_HDR_W4_HOUR); 32162306a36Sopenharmony_ci fw_suit->build_min = le32_get_bits(hdr->w4, FW_HDR_W4_MIN); 32262306a36Sopenharmony_ci fw_suit->cmd_ver = le32_get_bits(hdr->w7, FW_HDR_W7_CMD_VERSERION); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void rtw89_fw_update_ver_v1(struct rtw89_dev *rtwdev, 32662306a36Sopenharmony_ci struct rtw89_fw_suit *fw_suit, 32762306a36Sopenharmony_ci const struct rtw89_fw_hdr_v1 *hdr) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci fw_suit->major_ver = le32_get_bits(hdr->w1, FW_HDR_V1_W1_MAJOR_VERSION); 33062306a36Sopenharmony_ci fw_suit->minor_ver = le32_get_bits(hdr->w1, FW_HDR_V1_W1_MINOR_VERSION); 33162306a36Sopenharmony_ci fw_suit->sub_ver = le32_get_bits(hdr->w1, FW_HDR_V1_W1_SUBVERSION); 33262306a36Sopenharmony_ci fw_suit->sub_idex = le32_get_bits(hdr->w1, FW_HDR_V1_W1_SUBINDEX); 33362306a36Sopenharmony_ci fw_suit->commitid = le32_get_bits(hdr->w2, FW_HDR_V1_W2_COMMITID); 33462306a36Sopenharmony_ci fw_suit->build_year = le32_get_bits(hdr->w5, FW_HDR_V1_W5_YEAR); 33562306a36Sopenharmony_ci fw_suit->build_mon = le32_get_bits(hdr->w4, FW_HDR_V1_W4_MONTH); 33662306a36Sopenharmony_ci fw_suit->build_date = le32_get_bits(hdr->w4, FW_HDR_V1_W4_DATE); 33762306a36Sopenharmony_ci fw_suit->build_hour = le32_get_bits(hdr->w4, FW_HDR_V1_W4_HOUR); 33862306a36Sopenharmony_ci fw_suit->build_min = le32_get_bits(hdr->w4, FW_HDR_V1_W4_MIN); 33962306a36Sopenharmony_ci fw_suit->cmd_ver = le32_get_bits(hdr->w7, FW_HDR_V1_W3_CMD_VERSERION); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int rtw89_fw_update_ver(struct rtw89_dev *rtwdev, 34362306a36Sopenharmony_ci enum rtw89_fw_type type, 34462306a36Sopenharmony_ci struct rtw89_fw_suit *fw_suit) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci const struct rtw89_fw_hdr *v0 = (const struct rtw89_fw_hdr *)fw_suit->data; 34762306a36Sopenharmony_ci const struct rtw89_fw_hdr_v1 *v1 = (const struct rtw89_fw_hdr_v1 *)fw_suit->data; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (type == RTW89_FW_LOGFMT) 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci fw_suit->type = type; 35362306a36Sopenharmony_ci fw_suit->hdr_ver = le32_get_bits(v0->w3, FW_HDR_W3_HDR_VER); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci switch (fw_suit->hdr_ver) { 35662306a36Sopenharmony_ci case 0: 35762306a36Sopenharmony_ci rtw89_fw_update_ver_v0(rtwdev, fw_suit, v0); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case 1: 36062306a36Sopenharmony_ci rtw89_fw_update_ver_v1(rtwdev, fw_suit, v1); 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci default: 36362306a36Sopenharmony_ci rtw89_err(rtwdev, "Unknown firmware header version %u\n", 36462306a36Sopenharmony_ci fw_suit->hdr_ver); 36562306a36Sopenharmony_ci return -ENOENT; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci rtw89_info(rtwdev, 36962306a36Sopenharmony_ci "Firmware version %u.%u.%u.%u (%08x), cmd version %u, type %u\n", 37062306a36Sopenharmony_ci fw_suit->major_ver, fw_suit->minor_ver, fw_suit->sub_ver, 37162306a36Sopenharmony_ci fw_suit->sub_idex, fw_suit->commitid, fw_suit->cmd_ver, type); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic 37762306a36Sopenharmony_ciint __rtw89_fw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, 37862306a36Sopenharmony_ci bool nowarn) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type); 38162306a36Sopenharmony_ci int ret; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = rtw89_mfw_recognize(rtwdev, type, fw_suit, nowarn); 38462306a36Sopenharmony_ci if (ret) 38562306a36Sopenharmony_ci return ret; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return rtw89_fw_update_ver(rtwdev, type, fw_suit); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic 39162306a36Sopenharmony_ciint __rtw89_fw_recognize_from_elm(struct rtw89_dev *rtwdev, 39262306a36Sopenharmony_ci const struct rtw89_fw_element_hdr *elm, 39362306a36Sopenharmony_ci const void *data) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci enum rtw89_fw_type type = (enum rtw89_fw_type)data; 39662306a36Sopenharmony_ci struct rtw89_fw_suit *fw_suit; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci fw_suit = rtw89_fw_suit_get(rtwdev, type); 39962306a36Sopenharmony_ci fw_suit->data = elm->u.common.contents; 40062306a36Sopenharmony_ci fw_suit->size = le32_to_cpu(elm->size); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return rtw89_fw_update_ver(rtwdev, type, fw_suit); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci#define __DEF_FW_FEAT_COND(__cond, __op) \ 40662306a36Sopenharmony_cistatic bool __fw_feat_cond_ ## __cond(u32 suit_ver_code, u32 comp_ver_code) \ 40762306a36Sopenharmony_ci{ \ 40862306a36Sopenharmony_ci return suit_ver_code __op comp_ver_code; \ 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci__DEF_FW_FEAT_COND(ge, >=); /* greater or equal */ 41262306a36Sopenharmony_ci__DEF_FW_FEAT_COND(le, <=); /* less or equal */ 41362306a36Sopenharmony_ci__DEF_FW_FEAT_COND(lt, <); /* less than */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistruct __fw_feat_cfg { 41662306a36Sopenharmony_ci enum rtw89_core_chip_id chip_id; 41762306a36Sopenharmony_ci enum rtw89_fw_feature feature; 41862306a36Sopenharmony_ci u32 ver_code; 41962306a36Sopenharmony_ci bool (*cond)(u32 suit_ver_code, u32 comp_ver_code); 42062306a36Sopenharmony_ci}; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci#define __CFG_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) \ 42362306a36Sopenharmony_ci { \ 42462306a36Sopenharmony_ci .chip_id = _chip, \ 42562306a36Sopenharmony_ci .feature = RTW89_FW_FEATURE_ ## _feat, \ 42662306a36Sopenharmony_ci .ver_code = RTW89_FW_VER_CODE(_maj, _min, _sub, _idx), \ 42762306a36Sopenharmony_ci .cond = __fw_feat_cond_ ## _cond, \ 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic const struct __fw_feat_cfg fw_feat_tbl[] = { 43162306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), 43262306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), 43362306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER), 43462306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), 43562306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), 43662306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), 43762306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER), 43862306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP), 43962306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG), 44062306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE), 44162306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER), 44262306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), 44362306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), 44462306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), 44562306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), 44662306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), 44762306a36Sopenharmony_ci __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, 45162306a36Sopenharmony_ci const struct rtw89_chip_info *chip, 45262306a36Sopenharmony_ci u32 ver_code) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci int i; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fw_feat_tbl); i++) { 45762306a36Sopenharmony_ci const struct __fw_feat_cfg *ent = &fw_feat_tbl[i]; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (chip->chip_id != ent->chip_id) 46062306a36Sopenharmony_ci continue; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (ent->cond(ver_code, ent->ver_code)) 46362306a36Sopenharmony_ci RTW89_SET_FW_FEATURE(ent->feature, fw); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 47062306a36Sopenharmony_ci const struct rtw89_fw_suit *fw_suit; 47162306a36Sopenharmony_ci u32 suit_ver_code; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL); 47462306a36Sopenharmony_ci suit_ver_code = RTW89_FW_SUIT_VER_CODE(fw_suit); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci rtw89_fw_iterate_feature_cfg(&rtwdev->fw, chip, suit_ver_code); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciconst struct firmware * 48062306a36Sopenharmony_cirtw89_early_fw_feature_recognize(struct device *device, 48162306a36Sopenharmony_ci const struct rtw89_chip_info *chip, 48262306a36Sopenharmony_ci struct rtw89_fw_info *early_fw, 48362306a36Sopenharmony_ci int *used_fw_format) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci const struct firmware *firmware; 48662306a36Sopenharmony_ci char fw_name[64]; 48762306a36Sopenharmony_ci int fw_format; 48862306a36Sopenharmony_ci u32 ver_code; 48962306a36Sopenharmony_ci int ret; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci for (fw_format = chip->fw_format_max; fw_format >= 0; fw_format--) { 49262306a36Sopenharmony_ci rtw89_fw_get_filename(fw_name, sizeof(fw_name), 49362306a36Sopenharmony_ci chip->fw_basename, fw_format); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci ret = request_firmware(&firmware, fw_name, device); 49662306a36Sopenharmony_ci if (!ret) { 49762306a36Sopenharmony_ci dev_info(device, "loaded firmware %s\n", fw_name); 49862306a36Sopenharmony_ci *used_fw_format = fw_format; 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (ret) { 50462306a36Sopenharmony_ci dev_err(device, "failed to early request firmware: %d\n", ret); 50562306a36Sopenharmony_ci return NULL; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (!ver_code) 51162306a36Sopenharmony_ci goto out; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci rtw89_fw_iterate_feature_cfg(early_fw, chip, ver_code); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ciout: 51662306a36Sopenharmony_ci return firmware; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ciint rtw89_fw_recognize(struct rtw89_dev *rtwdev) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 52262306a36Sopenharmony_ci int ret; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (chip->try_ce_fw) { 52562306a36Sopenharmony_ci ret = __rtw89_fw_recognize(rtwdev, RTW89_FW_NORMAL_CE, true); 52662306a36Sopenharmony_ci if (!ret) 52762306a36Sopenharmony_ci goto normal_done; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci ret = __rtw89_fw_recognize(rtwdev, RTW89_FW_NORMAL, false); 53162306a36Sopenharmony_ci if (ret) 53262306a36Sopenharmony_ci return ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cinormal_done: 53562306a36Sopenharmony_ci /* It still works if wowlan firmware isn't existing. */ 53662306a36Sopenharmony_ci __rtw89_fw_recognize(rtwdev, RTW89_FW_WOWLAN, false); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* It still works if log format file isn't existing. */ 53962306a36Sopenharmony_ci __rtw89_fw_recognize(rtwdev, RTW89_FW_LOGFMT, true); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci rtw89_fw_recognize_features(rtwdev); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci rtw89_coex_recognize_ver(rtwdev); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic 54962306a36Sopenharmony_ciint rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev, 55062306a36Sopenharmony_ci const struct rtw89_fw_element_hdr *elm, 55162306a36Sopenharmony_ci const void *data) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; 55462306a36Sopenharmony_ci struct rtw89_phy_table *tbl; 55562306a36Sopenharmony_ci struct rtw89_reg2_def *regs; 55662306a36Sopenharmony_ci enum rtw89_rf_path rf_path; 55762306a36Sopenharmony_ci u32 n_regs, i; 55862306a36Sopenharmony_ci u8 idx; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); 56162306a36Sopenharmony_ci if (!tbl) 56262306a36Sopenharmony_ci return -ENOMEM; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci switch (le32_to_cpu(elm->id)) { 56562306a36Sopenharmony_ci case RTW89_FW_ELEMENT_ID_BB_REG: 56662306a36Sopenharmony_ci elm_info->bb_tbl = tbl; 56762306a36Sopenharmony_ci break; 56862306a36Sopenharmony_ci case RTW89_FW_ELEMENT_ID_BB_GAIN: 56962306a36Sopenharmony_ci elm_info->bb_gain = tbl; 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci case RTW89_FW_ELEMENT_ID_RADIO_A: 57262306a36Sopenharmony_ci case RTW89_FW_ELEMENT_ID_RADIO_B: 57362306a36Sopenharmony_ci case RTW89_FW_ELEMENT_ID_RADIO_C: 57462306a36Sopenharmony_ci case RTW89_FW_ELEMENT_ID_RADIO_D: 57562306a36Sopenharmony_ci rf_path = (enum rtw89_rf_path)data; 57662306a36Sopenharmony_ci idx = elm->u.reg2.idx; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci elm_info->rf_radio[idx] = tbl; 57962306a36Sopenharmony_ci tbl->rf_path = rf_path; 58062306a36Sopenharmony_ci tbl->config = rtw89_phy_config_rf_reg_v1; 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case RTW89_FW_ELEMENT_ID_RF_NCTL: 58362306a36Sopenharmony_ci elm_info->rf_nctl = tbl; 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci default: 58662306a36Sopenharmony_ci kfree(tbl); 58762306a36Sopenharmony_ci return -ENOENT; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci n_regs = le32_to_cpu(elm->size) / sizeof(tbl->regs[0]); 59162306a36Sopenharmony_ci regs = kcalloc(n_regs, sizeof(tbl->regs[0]), GFP_KERNEL); 59262306a36Sopenharmony_ci if (!regs) 59362306a36Sopenharmony_ci goto out; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci for (i = 0; i < n_regs; i++) { 59662306a36Sopenharmony_ci regs[i].addr = le32_to_cpu(elm->u.reg2.regs[i].addr); 59762306a36Sopenharmony_ci regs[i].data = le32_to_cpu(elm->u.reg2.regs[i].data); 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci tbl->n_regs = n_regs; 60162306a36Sopenharmony_ci tbl->regs = regs; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ciout: 60662306a36Sopenharmony_ci kfree(tbl); 60762306a36Sopenharmony_ci return -ENOMEM; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistruct rtw89_fw_element_handler { 61162306a36Sopenharmony_ci int (*fn)(struct rtw89_dev *rtwdev, 61262306a36Sopenharmony_ci const struct rtw89_fw_element_hdr *elm, const void *data); 61362306a36Sopenharmony_ci const void *data; 61462306a36Sopenharmony_ci const char *name; 61562306a36Sopenharmony_ci}; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic const struct rtw89_fw_element_handler __fw_element_handlers[] = { 61862306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm, 61962306a36Sopenharmony_ci (const void *)RTW89_FW_BBMCU0, NULL}, 62062306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_BBMCU1] = {__rtw89_fw_recognize_from_elm, 62162306a36Sopenharmony_ci (const void *)RTW89_FW_BBMCU1, NULL}, 62262306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_BB_REG] = {rtw89_build_phy_tbl_from_elm, NULL, "BB"}, 62362306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_BB_GAIN] = {rtw89_build_phy_tbl_from_elm, NULL, NULL}, 62462306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_RADIO_A] = {rtw89_build_phy_tbl_from_elm, 62562306a36Sopenharmony_ci (const void *)RF_PATH_A, "radio A"}, 62662306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_RADIO_B] = {rtw89_build_phy_tbl_from_elm, 62762306a36Sopenharmony_ci (const void *)RF_PATH_B, NULL}, 62862306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_RADIO_C] = {rtw89_build_phy_tbl_from_elm, 62962306a36Sopenharmony_ci (const void *)RF_PATH_C, NULL}, 63062306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_RADIO_D] = {rtw89_build_phy_tbl_from_elm, 63162306a36Sopenharmony_ci (const void *)RF_PATH_D, NULL}, 63262306a36Sopenharmony_ci [RTW89_FW_ELEMENT_ID_RF_NCTL] = {rtw89_build_phy_tbl_from_elm, NULL, "NCTL"}, 63362306a36Sopenharmony_ci}; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ciint rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct rtw89_fw_info *fw_info = &rtwdev->fw; 63862306a36Sopenharmony_ci const struct firmware *firmware = fw_info->req.firmware; 63962306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 64062306a36Sopenharmony_ci u32 unrecognized_elements = chip->needed_fw_elms; 64162306a36Sopenharmony_ci const struct rtw89_fw_element_handler *handler; 64262306a36Sopenharmony_ci const struct rtw89_fw_element_hdr *hdr; 64362306a36Sopenharmony_ci u32 elm_size; 64462306a36Sopenharmony_ci u32 elem_id; 64562306a36Sopenharmony_ci u32 offset; 64662306a36Sopenharmony_ci int ret; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(chip->needed_fw_elms) * 8 < RTW89_FW_ELEMENT_ID_NUM); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci offset = rtw89_mfw_get_size(rtwdev); 65162306a36Sopenharmony_ci offset = ALIGN(offset, RTW89_FW_ELEMENT_ALIGN); 65262306a36Sopenharmony_ci if (offset == 0) 65362306a36Sopenharmony_ci return -EINVAL; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci while (offset + sizeof(*hdr) < firmware->size) { 65662306a36Sopenharmony_ci hdr = (const struct rtw89_fw_element_hdr *)(firmware->data + offset); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci elm_size = le32_to_cpu(hdr->size); 65962306a36Sopenharmony_ci if (offset + elm_size >= firmware->size) { 66062306a36Sopenharmony_ci rtw89_warn(rtwdev, "firmware element size exceeds\n"); 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci elem_id = le32_to_cpu(hdr->id); 66562306a36Sopenharmony_ci if (elem_id >= ARRAY_SIZE(__fw_element_handlers)) 66662306a36Sopenharmony_ci goto next; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci handler = &__fw_element_handlers[elem_id]; 66962306a36Sopenharmony_ci if (!handler->fn) 67062306a36Sopenharmony_ci goto next; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci ret = handler->fn(rtwdev, hdr, handler->data); 67362306a36Sopenharmony_ci if (ret) 67462306a36Sopenharmony_ci return ret; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (handler->name) 67762306a36Sopenharmony_ci rtw89_info(rtwdev, "Firmware element %s version: %4ph\n", 67862306a36Sopenharmony_ci handler->name, hdr->ver); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci unrecognized_elements &= ~BIT(elem_id); 68162306a36Sopenharmony_cinext: 68262306a36Sopenharmony_ci offset += sizeof(*hdr) + elm_size; 68362306a36Sopenharmony_ci offset = ALIGN(offset, RTW89_FW_ELEMENT_ALIGN); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (unrecognized_elements) { 68762306a36Sopenharmony_ci rtw89_err(rtwdev, "Firmware elements 0x%08x are unrecognized\n", 68862306a36Sopenharmony_ci unrecognized_elements); 68962306a36Sopenharmony_ci return -ENOENT; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_civoid rtw89_h2c_pkt_set_hdr(struct rtw89_dev *rtwdev, struct sk_buff *skb, 69662306a36Sopenharmony_ci u8 type, u8 cat, u8 class, u8 func, 69762306a36Sopenharmony_ci bool rack, bool dack, u32 len) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct fwcmd_hdr *hdr; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci hdr = (struct fwcmd_hdr *)skb_push(skb, 8); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (!(rtwdev->fw.h2c_seq % 4)) 70462306a36Sopenharmony_ci rack = true; 70562306a36Sopenharmony_ci hdr->hdr0 = cpu_to_le32(FIELD_PREP(H2C_HDR_DEL_TYPE, type) | 70662306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_CAT, cat) | 70762306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_CLASS, class) | 70862306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_FUNC, func) | 70962306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_H2C_SEQ, rtwdev->fw.h2c_seq)); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci hdr->hdr1 = cpu_to_le32(FIELD_PREP(H2C_HDR_TOTAL_LEN, 71262306a36Sopenharmony_ci len + H2C_HEADER_LEN) | 71362306a36Sopenharmony_ci (rack ? H2C_HDR_REC_ACK : 0) | 71462306a36Sopenharmony_ci (dack ? H2C_HDR_DONE_ACK : 0)); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci rtwdev->fw.h2c_seq++; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic void rtw89_h2c_pkt_set_hdr_fwdl(struct rtw89_dev *rtwdev, 72062306a36Sopenharmony_ci struct sk_buff *skb, 72162306a36Sopenharmony_ci u8 type, u8 cat, u8 class, u8 func, 72262306a36Sopenharmony_ci u32 len) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci struct fwcmd_hdr *hdr; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci hdr = (struct fwcmd_hdr *)skb_push(skb, 8); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci hdr->hdr0 = cpu_to_le32(FIELD_PREP(H2C_HDR_DEL_TYPE, type) | 72962306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_CAT, cat) | 73062306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_CLASS, class) | 73162306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_FUNC, func) | 73262306a36Sopenharmony_ci FIELD_PREP(H2C_HDR_H2C_SEQ, rtwdev->fw.h2c_seq)); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci hdr->hdr1 = cpu_to_le32(FIELD_PREP(H2C_HDR_TOTAL_LEN, 73562306a36Sopenharmony_ci len + H2C_HEADER_LEN)); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct sk_buff *skb; 74162306a36Sopenharmony_ci u32 ret = 0; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 74462306a36Sopenharmony_ci if (!skb) { 74562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw hdr dl\n"); 74662306a36Sopenharmony_ci return -ENOMEM; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci skb_put_data(skb, fw, len); 75062306a36Sopenharmony_ci SET_FW_HDR_PART_SIZE(skb->data, FWDL_SECTION_PER_PKT_LEN); 75162306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr_fwdl(rtwdev, skb, FWCMD_TYPE_H2C, 75262306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FWDL, 75362306a36Sopenharmony_ci H2C_FUNC_MAC_FWHDR_DL, len); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 75662306a36Sopenharmony_ci if (ret) { 75762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 75862306a36Sopenharmony_ci ret = -1; 75962306a36Sopenharmony_ci goto fail; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_cifail: 76462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci return ret; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci u8 val; 77262306a36Sopenharmony_ci int ret; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci ret = __rtw89_fw_download_hdr(rtwdev, fw, len); 77562306a36Sopenharmony_ci if (ret) { 77662306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]FW header download\n"); 77762306a36Sopenharmony_ci return ret; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci ret = read_poll_timeout_atomic(rtw89_read8, val, val & B_AX_FWDL_PATH_RDY, 78162306a36Sopenharmony_ci 1, FWDL_WAIT_CNT, false, 78262306a36Sopenharmony_ci rtwdev, R_AX_WCPU_FW_CTRL); 78362306a36Sopenharmony_ci if (ret) { 78462306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]FWDL path ready\n"); 78562306a36Sopenharmony_ci return ret; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HALT_H2C_CTRL, 0); 78962306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_HALT_C2H_CTRL, 0); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic int __rtw89_fw_download_main(struct rtw89_dev *rtwdev, 79562306a36Sopenharmony_ci struct rtw89_fw_hdr_section_info *info) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci struct sk_buff *skb; 79862306a36Sopenharmony_ci const u8 *section = info->addr; 79962306a36Sopenharmony_ci u32 residue_len = info->len; 80062306a36Sopenharmony_ci u32 pkt_len; 80162306a36Sopenharmony_ci int ret; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci while (residue_len) { 80462306a36Sopenharmony_ci if (residue_len >= FWDL_SECTION_PER_PKT_LEN) 80562306a36Sopenharmony_ci pkt_len = FWDL_SECTION_PER_PKT_LEN; 80662306a36Sopenharmony_ci else 80762306a36Sopenharmony_ci pkt_len = residue_len; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_no_hdr(rtwdev, pkt_len); 81062306a36Sopenharmony_ci if (!skb) { 81162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 81262306a36Sopenharmony_ci return -ENOMEM; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci skb_put_data(skb, section, pkt_len); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, true); 81762306a36Sopenharmony_ci if (ret) { 81862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 81962306a36Sopenharmony_ci ret = -1; 82062306a36Sopenharmony_ci goto fail; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci section += pkt_len; 82462306a36Sopenharmony_ci residue_len -= pkt_len; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_cifail: 82962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return ret; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic int rtw89_fw_download_main(struct rtw89_dev *rtwdev, const u8 *fw, 83562306a36Sopenharmony_ci struct rtw89_fw_bin_info *info) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct rtw89_fw_hdr_section_info *section_info = info->section_info; 83862306a36Sopenharmony_ci u8 section_num = info->section_num; 83962306a36Sopenharmony_ci int ret; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci while (section_num--) { 84262306a36Sopenharmony_ci ret = __rtw89_fw_download_main(rtwdev, section_info); 84362306a36Sopenharmony_ci if (ret) 84462306a36Sopenharmony_ci return ret; 84562306a36Sopenharmony_ci section_info++; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci mdelay(5); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci ret = rtw89_fw_check_rdy(rtwdev); 85162306a36Sopenharmony_ci if (ret) { 85262306a36Sopenharmony_ci rtw89_warn(rtwdev, "download firmware fail\n"); 85362306a36Sopenharmony_ci return ret; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return 0; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic void rtw89_fw_prog_cnt_dump(struct rtw89_dev *rtwdev) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci u32 val32; 86262306a36Sopenharmony_ci u16 index; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci rtw89_write32(rtwdev, R_AX_DBG_CTRL, 86562306a36Sopenharmony_ci FIELD_PREP(B_AX_DBG_SEL0, FW_PROG_CNTR_DBG_SEL) | 86662306a36Sopenharmony_ci FIELD_PREP(B_AX_DBG_SEL1, FW_PROG_CNTR_DBG_SEL)); 86762306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_SEL_0XC0_MASK, MAC_DBG_SEL); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci for (index = 0; index < 15; index++) { 87062306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_DBG_PORT_SEL); 87162306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]fw PC = 0x%x\n", val32); 87262306a36Sopenharmony_ci fsleep(10); 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic void rtw89_fw_dl_fail_dump(struct rtw89_dev *rtwdev) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci u32 val32; 87962306a36Sopenharmony_ci u16 val16; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci val32 = rtw89_read32(rtwdev, R_AX_WCPU_FW_CTRL); 88262306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]fwdl 0x1E0 = 0x%x\n", val32); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci val16 = rtw89_read16(rtwdev, R_AX_BOOT_DBG + 2); 88562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]fwdl 0x83F2 = 0x%x\n", val16); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci rtw89_fw_prog_cnt_dump(rtwdev); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ciint rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct rtw89_fw_info *fw_info = &rtwdev->fw; 89362306a36Sopenharmony_ci struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type); 89462306a36Sopenharmony_ci struct rtw89_fw_bin_info info; 89562306a36Sopenharmony_ci u8 val; 89662306a36Sopenharmony_ci int ret; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci rtw89_mac_disable_cpu(rtwdev); 89962306a36Sopenharmony_ci ret = rtw89_mac_enable_cpu(rtwdev, 0, true); 90062306a36Sopenharmony_ci if (ret) 90162306a36Sopenharmony_ci return ret; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci ret = rtw89_fw_hdr_parser(rtwdev, fw_suit, &info); 90462306a36Sopenharmony_ci if (ret) { 90562306a36Sopenharmony_ci rtw89_err(rtwdev, "parse fw header fail\n"); 90662306a36Sopenharmony_ci goto fwdl_err; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ret = read_poll_timeout_atomic(rtw89_read8, val, val & B_AX_H2C_PATH_RDY, 91062306a36Sopenharmony_ci 1, FWDL_WAIT_CNT, false, 91162306a36Sopenharmony_ci rtwdev, R_AX_WCPU_FW_CTRL); 91262306a36Sopenharmony_ci if (ret) { 91362306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]H2C path ready\n"); 91462306a36Sopenharmony_ci goto fwdl_err; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci ret = rtw89_fw_download_hdr(rtwdev, fw_suit->data, info.hdr_len - 91862306a36Sopenharmony_ci info.dynamic_hdr_len); 91962306a36Sopenharmony_ci if (ret) { 92062306a36Sopenharmony_ci ret = -EBUSY; 92162306a36Sopenharmony_ci goto fwdl_err; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ret = rtw89_fw_download_main(rtwdev, fw_suit->data, &info); 92562306a36Sopenharmony_ci if (ret) { 92662306a36Sopenharmony_ci ret = -EBUSY; 92762306a36Sopenharmony_ci goto fwdl_err; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci fw_info->h2c_seq = 0; 93162306a36Sopenharmony_ci fw_info->rec_seq = 0; 93262306a36Sopenharmony_ci fw_info->h2c_counter = 0; 93362306a36Sopenharmony_ci fw_info->c2h_counter = 0; 93462306a36Sopenharmony_ci rtwdev->mac.rpwm_seq_num = RPWM_SEQ_NUM_MAX; 93562306a36Sopenharmony_ci rtwdev->mac.cpwm_seq_num = CPWM_SEQ_NUM_MAX; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return ret; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cifwdl_err: 94062306a36Sopenharmony_ci rtw89_fw_dl_fail_dump(rtwdev); 94162306a36Sopenharmony_ci return ret; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ciint rtw89_wait_firmware_completion(struct rtw89_dev *rtwdev) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci struct rtw89_fw_info *fw = &rtwdev->fw; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci wait_for_completion(&fw->req.completion); 94962306a36Sopenharmony_ci if (!fw->req.firmware) 95062306a36Sopenharmony_ci return -EINVAL; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return 0; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic int rtw89_load_firmware_req(struct rtw89_dev *rtwdev, 95662306a36Sopenharmony_ci struct rtw89_fw_req_info *req, 95762306a36Sopenharmony_ci const char *fw_name, bool nowarn) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci int ret; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (req->firmware) { 96262306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, 96362306a36Sopenharmony_ci "full firmware has been early requested\n"); 96462306a36Sopenharmony_ci complete_all(&req->completion); 96562306a36Sopenharmony_ci return 0; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (nowarn) 96962306a36Sopenharmony_ci ret = firmware_request_nowarn(&req->firmware, fw_name, rtwdev->dev); 97062306a36Sopenharmony_ci else 97162306a36Sopenharmony_ci ret = request_firmware(&req->firmware, fw_name, rtwdev->dev); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci complete_all(&req->completion); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci return ret; 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_civoid rtw89_load_firmware_work(struct work_struct *work) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci struct rtw89_dev *rtwdev = 98162306a36Sopenharmony_ci container_of(work, struct rtw89_dev, load_firmware_work); 98262306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 98362306a36Sopenharmony_ci char fw_name[64]; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci rtw89_fw_get_filename(fw_name, sizeof(fw_name), 98662306a36Sopenharmony_ci chip->fw_basename, rtwdev->fw.fw_format); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci rtw89_load_firmware_req(rtwdev, &rtwdev->fw.req, fw_name, false); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void rtw89_free_phy_tbl_from_elm(struct rtw89_phy_table *tbl) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci if (!tbl) 99462306a36Sopenharmony_ci return; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci kfree(tbl->regs); 99762306a36Sopenharmony_ci kfree(tbl); 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_cistatic void rtw89_unload_firmware_elements(struct rtw89_dev *rtwdev) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; 100362306a36Sopenharmony_ci int i; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci rtw89_free_phy_tbl_from_elm(elm_info->bb_tbl); 100662306a36Sopenharmony_ci rtw89_free_phy_tbl_from_elm(elm_info->bb_gain); 100762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(elm_info->rf_radio); i++) 100862306a36Sopenharmony_ci rtw89_free_phy_tbl_from_elm(elm_info->rf_radio[i]); 100962306a36Sopenharmony_ci rtw89_free_phy_tbl_from_elm(elm_info->rf_nctl); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_civoid rtw89_unload_firmware(struct rtw89_dev *rtwdev) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct rtw89_fw_info *fw = &rtwdev->fw; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci cancel_work_sync(&rtwdev->load_firmware_work); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (fw->req.firmware) { 101962306a36Sopenharmony_ci release_firmware(fw->req.firmware); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* assign NULL back in case rtw89_free_ieee80211_hw() 102262306a36Sopenharmony_ci * try to release the same one again. 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ci fw->req.firmware = NULL; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci kfree(fw->log.fmts); 102862306a36Sopenharmony_ci rtw89_unload_firmware_elements(rtwdev); 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic u32 rtw89_fw_log_get_fmt_idx(struct rtw89_dev *rtwdev, u32 fmt_id) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct rtw89_fw_log *fw_log = &rtwdev->fw.log; 103462306a36Sopenharmony_ci u32 i; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (fmt_id > fw_log->last_fmt_id) 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci for (i = 0; i < fw_log->fmt_count; i++) { 104062306a36Sopenharmony_ci if (le32_to_cpu(fw_log->fmt_ids[i]) == fmt_id) 104162306a36Sopenharmony_ci return i; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic int rtw89_fw_log_create_fmts_dict(struct rtw89_dev *rtwdev) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci struct rtw89_fw_log *log = &rtwdev->fw.log; 104962306a36Sopenharmony_ci const struct rtw89_fw_logsuit_hdr *suit_hdr; 105062306a36Sopenharmony_ci struct rtw89_fw_suit *suit = &log->suit; 105162306a36Sopenharmony_ci const void *fmts_ptr, *fmts_end_ptr; 105262306a36Sopenharmony_ci u32 fmt_count; 105362306a36Sopenharmony_ci int i; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci suit_hdr = (const struct rtw89_fw_logsuit_hdr *)suit->data; 105662306a36Sopenharmony_ci fmt_count = le32_to_cpu(suit_hdr->count); 105762306a36Sopenharmony_ci log->fmt_ids = suit_hdr->ids; 105862306a36Sopenharmony_ci fmts_ptr = &suit_hdr->ids[fmt_count]; 105962306a36Sopenharmony_ci fmts_end_ptr = suit->data + suit->size; 106062306a36Sopenharmony_ci log->fmts = kcalloc(fmt_count, sizeof(char *), GFP_KERNEL); 106162306a36Sopenharmony_ci if (!log->fmts) 106262306a36Sopenharmony_ci return -ENOMEM; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci for (i = 0; i < fmt_count; i++) { 106562306a36Sopenharmony_ci fmts_ptr = memchr_inv(fmts_ptr, 0, fmts_end_ptr - fmts_ptr); 106662306a36Sopenharmony_ci if (!fmts_ptr) 106762306a36Sopenharmony_ci break; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci (*log->fmts)[i] = fmts_ptr; 107062306a36Sopenharmony_ci log->last_fmt_id = le32_to_cpu(log->fmt_ids[i]); 107162306a36Sopenharmony_ci log->fmt_count++; 107262306a36Sopenharmony_ci fmts_ptr += strlen(fmts_ptr); 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return 0; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ciint rtw89_fw_log_prepare(struct rtw89_dev *rtwdev) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci struct rtw89_fw_log *log = &rtwdev->fw.log; 108162306a36Sopenharmony_ci struct rtw89_fw_suit *suit = &log->suit; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (!suit || !suit->data) { 108462306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, "no log format file\n"); 108562306a36Sopenharmony_ci return -EINVAL; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci if (log->fmts) 108862306a36Sopenharmony_ci return 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci return rtw89_fw_log_create_fmts_dict(rtwdev); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic void rtw89_fw_log_dump_data(struct rtw89_dev *rtwdev, 109462306a36Sopenharmony_ci const struct rtw89_fw_c2h_log_fmt *log_fmt, 109562306a36Sopenharmony_ci u32 fmt_idx, u8 para_int, bool raw_data) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci const char *(*fmts)[] = rtwdev->fw.log.fmts; 109862306a36Sopenharmony_ci char str_buf[RTW89_C2H_FW_LOG_STR_BUF_SIZE]; 109962306a36Sopenharmony_ci u32 args[RTW89_C2H_FW_LOG_MAX_PARA_NUM] = {0}; 110062306a36Sopenharmony_ci int i; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (log_fmt->argc > RTW89_C2H_FW_LOG_MAX_PARA_NUM) { 110362306a36Sopenharmony_ci rtw89_warn(rtwdev, "C2H log: Arg count is unexpected %d\n", 110462306a36Sopenharmony_ci log_fmt->argc); 110562306a36Sopenharmony_ci return; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (para_int) 110962306a36Sopenharmony_ci for (i = 0 ; i < log_fmt->argc; i++) 111062306a36Sopenharmony_ci args[i] = le32_to_cpu(log_fmt->u.argv[i]); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci if (raw_data) { 111362306a36Sopenharmony_ci if (para_int) 111462306a36Sopenharmony_ci snprintf(str_buf, RTW89_C2H_FW_LOG_STR_BUF_SIZE, 111562306a36Sopenharmony_ci "fw_enc(%d, %d, %d) %*ph", le32_to_cpu(log_fmt->fmt_id), 111662306a36Sopenharmony_ci para_int, log_fmt->argc, (int)sizeof(args), args); 111762306a36Sopenharmony_ci else 111862306a36Sopenharmony_ci snprintf(str_buf, RTW89_C2H_FW_LOG_STR_BUF_SIZE, 111962306a36Sopenharmony_ci "fw_enc(%d, %d, %d, %s)", le32_to_cpu(log_fmt->fmt_id), 112062306a36Sopenharmony_ci para_int, log_fmt->argc, log_fmt->u.raw); 112162306a36Sopenharmony_ci } else { 112262306a36Sopenharmony_ci snprintf(str_buf, RTW89_C2H_FW_LOG_STR_BUF_SIZE, (*fmts)[fmt_idx], 112362306a36Sopenharmony_ci args[0x0], args[0x1], args[0x2], args[0x3], args[0x4], 112462306a36Sopenharmony_ci args[0x5], args[0x6], args[0x7], args[0x8], args[0x9], 112562306a36Sopenharmony_ci args[0xa], args[0xb], args[0xc], args[0xd], args[0xe], 112662306a36Sopenharmony_ci args[0xf]); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci rtw89_info(rtwdev, "C2H log: %s", str_buf); 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_civoid rtw89_fw_log_dump(struct rtw89_dev *rtwdev, u8 *buf, u32 len) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci const struct rtw89_fw_c2h_log_fmt *log_fmt; 113562306a36Sopenharmony_ci u8 para_int; 113662306a36Sopenharmony_ci u32 fmt_idx; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (len < RTW89_C2H_HEADER_LEN) { 113962306a36Sopenharmony_ci rtw89_err(rtwdev, "c2h log length is wrong!\n"); 114062306a36Sopenharmony_ci return; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci buf += RTW89_C2H_HEADER_LEN; 114462306a36Sopenharmony_ci len -= RTW89_C2H_HEADER_LEN; 114562306a36Sopenharmony_ci log_fmt = (const struct rtw89_fw_c2h_log_fmt *)buf; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (len < RTW89_C2H_FW_FORMATTED_LOG_MIN_LEN) 114862306a36Sopenharmony_ci goto plain_log; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci if (log_fmt->signature != cpu_to_le16(RTW89_C2H_FW_LOG_SIGNATURE)) 115162306a36Sopenharmony_ci goto plain_log; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (!rtwdev->fw.log.fmts) 115462306a36Sopenharmony_ci return; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci para_int = u8_get_bits(log_fmt->feature, RTW89_C2H_FW_LOG_FEATURE_PARA_INT); 115762306a36Sopenharmony_ci fmt_idx = rtw89_fw_log_get_fmt_idx(rtwdev, le32_to_cpu(log_fmt->fmt_id)); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (!para_int && log_fmt->argc != 0 && fmt_idx != 0) 116062306a36Sopenharmony_ci rtw89_info(rtwdev, "C2H log: %s%s", 116162306a36Sopenharmony_ci (*rtwdev->fw.log.fmts)[fmt_idx], log_fmt->u.raw); 116262306a36Sopenharmony_ci else if (fmt_idx != 0 && para_int) 116362306a36Sopenharmony_ci rtw89_fw_log_dump_data(rtwdev, log_fmt, fmt_idx, para_int, false); 116462306a36Sopenharmony_ci else 116562306a36Sopenharmony_ci rtw89_fw_log_dump_data(rtwdev, log_fmt, fmt_idx, para_int, true); 116662306a36Sopenharmony_ci return; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ciplain_log: 116962306a36Sopenharmony_ci rtw89_info(rtwdev, "C2H log: %.*s", len, buf); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci#define H2C_CAM_LEN 60 117462306a36Sopenharmony_ciint rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 117562306a36Sopenharmony_ci struct rtw89_sta *rtwsta, const u8 *scan_mac_addr) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci struct sk_buff *skb; 117862306a36Sopenharmony_ci int ret; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CAM_LEN); 118162306a36Sopenharmony_ci if (!skb) { 118262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 118362306a36Sopenharmony_ci return -ENOMEM; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci skb_put(skb, H2C_CAM_LEN); 118662306a36Sopenharmony_ci rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif, rtwsta, scan_mac_addr, skb->data); 118762306a36Sopenharmony_ci rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif, rtwsta, skb->data); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 119062306a36Sopenharmony_ci H2C_CAT_MAC, 119162306a36Sopenharmony_ci H2C_CL_MAC_ADDR_CAM_UPDATE, 119262306a36Sopenharmony_ci H2C_FUNC_MAC_ADDR_CAM_UPD, 0, 1, 119362306a36Sopenharmony_ci H2C_CAM_LEN); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 119662306a36Sopenharmony_ci if (ret) { 119762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 119862306a36Sopenharmony_ci goto fail; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci return 0; 120262306a36Sopenharmony_cifail: 120362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci return ret; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci#define H2C_DCTL_SEC_CAM_LEN 68 120962306a36Sopenharmony_ciint rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, 121062306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 121162306a36Sopenharmony_ci struct rtw89_sta *rtwsta) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci struct sk_buff *skb; 121462306a36Sopenharmony_ci int ret; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DCTL_SEC_CAM_LEN); 121762306a36Sopenharmony_ci if (!skb) { 121862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for dctl sec cam\n"); 121962306a36Sopenharmony_ci return -ENOMEM; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci skb_put(skb, H2C_DCTL_SEC_CAM_LEN); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif, rtwsta, skb->data); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 122662306a36Sopenharmony_ci H2C_CAT_MAC, 122762306a36Sopenharmony_ci H2C_CL_MAC_FR_EXCHG, 122862306a36Sopenharmony_ci H2C_FUNC_MAC_DCTLINFO_UD_V1, 0, 0, 122962306a36Sopenharmony_ci H2C_DCTL_SEC_CAM_LEN); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 123262306a36Sopenharmony_ci if (ret) { 123362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 123462306a36Sopenharmony_ci goto fail; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci return 0; 123862306a36Sopenharmony_cifail: 123962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci return ret; 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci#define H2C_BA_CAM_LEN 8 124662306a36Sopenharmony_ciint rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, 124762306a36Sopenharmony_ci bool valid, struct ieee80211_ampdu_params *params) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 125062306a36Sopenharmony_ci struct rtw89_vif *rtwvif = rtwsta->rtwvif; 125162306a36Sopenharmony_ci u8 macid = rtwsta->mac_id; 125262306a36Sopenharmony_ci struct sk_buff *skb; 125362306a36Sopenharmony_ci u8 entry_idx; 125462306a36Sopenharmony_ci int ret; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci ret = valid ? 125762306a36Sopenharmony_ci rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) : 125862306a36Sopenharmony_ci rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx); 125962306a36Sopenharmony_ci if (ret) { 126062306a36Sopenharmony_ci /* it still works even if we don't have static BA CAM, because 126162306a36Sopenharmony_ci * hardware can create dynamic BA CAM automatically. 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_TXRX, 126462306a36Sopenharmony_ci "failed to %s entry tid=%d for h2c ba cam\n", 126562306a36Sopenharmony_ci valid ? "alloc" : "free", params->tid); 126662306a36Sopenharmony_ci return 0; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN); 127062306a36Sopenharmony_ci if (!skb) { 127162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n"); 127262306a36Sopenharmony_ci return -ENOMEM; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci skb_put(skb, H2C_BA_CAM_LEN); 127562306a36Sopenharmony_ci SET_BA_CAM_MACID(skb->data, macid); 127662306a36Sopenharmony_ci if (chip->bacam_ver == RTW89_BACAM_V0_EXT) 127762306a36Sopenharmony_ci SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx); 127862306a36Sopenharmony_ci else 127962306a36Sopenharmony_ci SET_BA_CAM_ENTRY_IDX(skb->data, entry_idx); 128062306a36Sopenharmony_ci if (!valid) 128162306a36Sopenharmony_ci goto end; 128262306a36Sopenharmony_ci SET_BA_CAM_VALID(skb->data, valid); 128362306a36Sopenharmony_ci SET_BA_CAM_TID(skb->data, params->tid); 128462306a36Sopenharmony_ci if (params->buf_size > 64) 128562306a36Sopenharmony_ci SET_BA_CAM_BMAP_SIZE(skb->data, 4); 128662306a36Sopenharmony_ci else 128762306a36Sopenharmony_ci SET_BA_CAM_BMAP_SIZE(skb->data, 0); 128862306a36Sopenharmony_ci /* If init req is set, hw will set the ssn */ 128962306a36Sopenharmony_ci SET_BA_CAM_INIT_REQ(skb->data, 1); 129062306a36Sopenharmony_ci SET_BA_CAM_SSN(skb->data, params->ssn); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (chip->bacam_ver == RTW89_BACAM_V0_EXT) { 129362306a36Sopenharmony_ci SET_BA_CAM_STD_EN(skb->data, 1); 129462306a36Sopenharmony_ci SET_BA_CAM_BAND(skb->data, rtwvif->mac_idx); 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ciend: 129862306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 129962306a36Sopenharmony_ci H2C_CAT_MAC, 130062306a36Sopenharmony_ci H2C_CL_BA_CAM, 130162306a36Sopenharmony_ci H2C_FUNC_MAC_BA_CAM, 0, 1, 130262306a36Sopenharmony_ci H2C_BA_CAM_LEN); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 130562306a36Sopenharmony_ci if (ret) { 130662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 130762306a36Sopenharmony_ci goto fail; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci return 0; 131162306a36Sopenharmony_cifail: 131262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return ret; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic int rtw89_fw_h2c_init_ba_cam_v0_ext(struct rtw89_dev *rtwdev, 131862306a36Sopenharmony_ci u8 entry_idx, u8 uid) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci struct sk_buff *skb; 132162306a36Sopenharmony_ci int ret; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN); 132462306a36Sopenharmony_ci if (!skb) { 132562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for dynamic h2c ba cam\n"); 132662306a36Sopenharmony_ci return -ENOMEM; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci skb_put(skb, H2C_BA_CAM_LEN); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci SET_BA_CAM_VALID(skb->data, 1); 133162306a36Sopenharmony_ci SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx); 133262306a36Sopenharmony_ci SET_BA_CAM_UID(skb->data, uid); 133362306a36Sopenharmony_ci SET_BA_CAM_BAND(skb->data, 0); 133462306a36Sopenharmony_ci SET_BA_CAM_STD_EN(skb->data, 0); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 133762306a36Sopenharmony_ci H2C_CAT_MAC, 133862306a36Sopenharmony_ci H2C_CL_BA_CAM, 133962306a36Sopenharmony_ci H2C_FUNC_MAC_BA_CAM, 0, 1, 134062306a36Sopenharmony_ci H2C_BA_CAM_LEN); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 134362306a36Sopenharmony_ci if (ret) { 134462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 134562306a36Sopenharmony_ci goto fail; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci return 0; 134962306a36Sopenharmony_cifail: 135062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci return ret; 135362306a36Sopenharmony_ci} 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_civoid rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 135862306a36Sopenharmony_ci u8 entry_idx = chip->bacam_num; 135962306a36Sopenharmony_ci u8 uid = 0; 136062306a36Sopenharmony_ci int i; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci for (i = 0; i < chip->bacam_dynamic_num; i++) { 136362306a36Sopenharmony_ci rtw89_fw_h2c_init_ba_cam_v0_ext(rtwdev, entry_idx, uid); 136462306a36Sopenharmony_ci entry_idx++; 136562306a36Sopenharmony_ci uid++; 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci#define H2C_LOG_CFG_LEN 12 137062306a36Sopenharmony_ciint rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct sk_buff *skb; 137362306a36Sopenharmony_ci u32 comp = enable ? BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) | 137462306a36Sopenharmony_ci BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) : 0; 137562306a36Sopenharmony_ci int ret; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LOG_CFG_LEN); 137862306a36Sopenharmony_ci if (!skb) { 137962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw log cfg\n"); 138062306a36Sopenharmony_ci return -ENOMEM; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci skb_put(skb, H2C_LOG_CFG_LEN); 138462306a36Sopenharmony_ci SET_LOG_CFG_LEVEL(skb->data, RTW89_FW_LOG_LEVEL_LOUD); 138562306a36Sopenharmony_ci SET_LOG_CFG_PATH(skb->data, BIT(RTW89_FW_LOG_LEVEL_C2H)); 138662306a36Sopenharmony_ci SET_LOG_CFG_COMP(skb->data, comp); 138762306a36Sopenharmony_ci SET_LOG_CFG_COMP_EXT(skb->data, 0); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 139062306a36Sopenharmony_ci H2C_CAT_MAC, 139162306a36Sopenharmony_ci H2C_CL_FW_INFO, 139262306a36Sopenharmony_ci H2C_FUNC_LOG_CFG, 0, 0, 139362306a36Sopenharmony_ci H2C_LOG_CFG_LEN); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 139662306a36Sopenharmony_ci if (ret) { 139762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 139862306a36Sopenharmony_ci goto fail; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci return 0; 140262306a36Sopenharmony_cifail: 140362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci return ret; 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, 140962306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 141062306a36Sopenharmony_ci enum rtw89_fw_pkt_ofld_type type, 141162306a36Sopenharmony_ci u8 *id) 141262306a36Sopenharmony_ci{ 141362306a36Sopenharmony_ci struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 141462306a36Sopenharmony_ci struct rtw89_pktofld_info *info; 141562306a36Sopenharmony_ci struct sk_buff *skb; 141662306a36Sopenharmony_ci int ret; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 141962306a36Sopenharmony_ci if (!info) 142062306a36Sopenharmony_ci return -ENOMEM; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci switch (type) { 142362306a36Sopenharmony_ci case RTW89_PKT_OFLD_TYPE_PS_POLL: 142462306a36Sopenharmony_ci skb = ieee80211_pspoll_get(rtwdev->hw, vif); 142562306a36Sopenharmony_ci break; 142662306a36Sopenharmony_ci case RTW89_PKT_OFLD_TYPE_PROBE_RSP: 142762306a36Sopenharmony_ci skb = ieee80211_proberesp_get(rtwdev->hw, vif); 142862306a36Sopenharmony_ci break; 142962306a36Sopenharmony_ci case RTW89_PKT_OFLD_TYPE_NULL_DATA: 143062306a36Sopenharmony_ci skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, false); 143162306a36Sopenharmony_ci break; 143262306a36Sopenharmony_ci case RTW89_PKT_OFLD_TYPE_QOS_NULL: 143362306a36Sopenharmony_ci skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, true); 143462306a36Sopenharmony_ci break; 143562306a36Sopenharmony_ci default: 143662306a36Sopenharmony_ci goto err; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (!skb) 144062306a36Sopenharmony_ci goto err; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, skb); 144362306a36Sopenharmony_ci kfree_skb(skb); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci if (ret) 144662306a36Sopenharmony_ci goto err; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci list_add_tail(&info->list, &rtwvif->general_pkt_list); 144962306a36Sopenharmony_ci *id = info->id; 145062306a36Sopenharmony_ci return 0; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cierr: 145362306a36Sopenharmony_ci kfree(info); 145462306a36Sopenharmony_ci return -ENOMEM; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_civoid rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, 145862306a36Sopenharmony_ci struct rtw89_vif *rtwvif, bool notify_fw) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci struct list_head *pkt_list = &rtwvif->general_pkt_list; 146162306a36Sopenharmony_ci struct rtw89_pktofld_info *info, *tmp; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci list_for_each_entry_safe(info, tmp, pkt_list, list) { 146462306a36Sopenharmony_ci if (notify_fw) 146562306a36Sopenharmony_ci rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); 146662306a36Sopenharmony_ci else 146762306a36Sopenharmony_ci rtw89_core_release_bit_map(rtwdev->pkt_offload, info->id); 146862306a36Sopenharmony_ci list_del(&info->list); 146962306a36Sopenharmony_ci kfree(info); 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_civoid rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci struct rtw89_vif *rtwvif; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci rtw89_for_each_rtwvif(rtwdev, rtwvif) 147862306a36Sopenharmony_ci rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, notify_fw); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci#define H2C_GENERAL_PKT_LEN 6 148262306a36Sopenharmony_ci#define H2C_GENERAL_PKT_ID_UND 0xff 148362306a36Sopenharmony_ciint rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, 148462306a36Sopenharmony_ci struct rtw89_vif *rtwvif, u8 macid) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci u8 pkt_id_ps_poll = H2C_GENERAL_PKT_ID_UND; 148762306a36Sopenharmony_ci u8 pkt_id_null = H2C_GENERAL_PKT_ID_UND; 148862306a36Sopenharmony_ci u8 pkt_id_qos_null = H2C_GENERAL_PKT_ID_UND; 148962306a36Sopenharmony_ci struct sk_buff *skb; 149062306a36Sopenharmony_ci int ret; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, 149362306a36Sopenharmony_ci RTW89_PKT_OFLD_TYPE_PS_POLL, &pkt_id_ps_poll); 149462306a36Sopenharmony_ci rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, 149562306a36Sopenharmony_ci RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id_null); 149662306a36Sopenharmony_ci rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, 149762306a36Sopenharmony_ci RTW89_PKT_OFLD_TYPE_QOS_NULL, &pkt_id_qos_null); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_GENERAL_PKT_LEN); 150062306a36Sopenharmony_ci if (!skb) { 150162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 150262306a36Sopenharmony_ci return -ENOMEM; 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci skb_put(skb, H2C_GENERAL_PKT_LEN); 150562306a36Sopenharmony_ci SET_GENERAL_PKT_MACID(skb->data, macid); 150662306a36Sopenharmony_ci SET_GENERAL_PKT_PROBRSP_ID(skb->data, H2C_GENERAL_PKT_ID_UND); 150762306a36Sopenharmony_ci SET_GENERAL_PKT_PSPOLL_ID(skb->data, pkt_id_ps_poll); 150862306a36Sopenharmony_ci SET_GENERAL_PKT_NULL_ID(skb->data, pkt_id_null); 150962306a36Sopenharmony_ci SET_GENERAL_PKT_QOS_NULL_ID(skb->data, pkt_id_qos_null); 151062306a36Sopenharmony_ci SET_GENERAL_PKT_CTS2SELF_ID(skb->data, H2C_GENERAL_PKT_ID_UND); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 151362306a36Sopenharmony_ci H2C_CAT_MAC, 151462306a36Sopenharmony_ci H2C_CL_FW_INFO, 151562306a36Sopenharmony_ci H2C_FUNC_MAC_GENERAL_PKT, 0, 1, 151662306a36Sopenharmony_ci H2C_GENERAL_PKT_LEN); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 151962306a36Sopenharmony_ci if (ret) { 152062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 152162306a36Sopenharmony_ci goto fail; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return 0; 152562306a36Sopenharmony_cifail: 152662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci return ret; 152962306a36Sopenharmony_ci} 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci#define H2C_LPS_PARM_LEN 8 153262306a36Sopenharmony_ciint rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, 153362306a36Sopenharmony_ci struct rtw89_lps_parm *lps_param) 153462306a36Sopenharmony_ci{ 153562306a36Sopenharmony_ci struct sk_buff *skb; 153662306a36Sopenharmony_ci int ret; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LPS_PARM_LEN); 153962306a36Sopenharmony_ci if (!skb) { 154062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 154162306a36Sopenharmony_ci return -ENOMEM; 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci skb_put(skb, H2C_LPS_PARM_LEN); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci SET_LPS_PARM_MACID(skb->data, lps_param->macid); 154662306a36Sopenharmony_ci SET_LPS_PARM_PSMODE(skb->data, lps_param->psmode); 154762306a36Sopenharmony_ci SET_LPS_PARM_LASTRPWM(skb->data, lps_param->lastrpwm); 154862306a36Sopenharmony_ci SET_LPS_PARM_RLBM(skb->data, 1); 154962306a36Sopenharmony_ci SET_LPS_PARM_SMARTPS(skb->data, 1); 155062306a36Sopenharmony_ci SET_LPS_PARM_AWAKEINTERVAL(skb->data, 1); 155162306a36Sopenharmony_ci SET_LPS_PARM_VOUAPSD(skb->data, 0); 155262306a36Sopenharmony_ci SET_LPS_PARM_VIUAPSD(skb->data, 0); 155362306a36Sopenharmony_ci SET_LPS_PARM_BEUAPSD(skb->data, 0); 155462306a36Sopenharmony_ci SET_LPS_PARM_BKUAPSD(skb->data, 0); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 155762306a36Sopenharmony_ci H2C_CAT_MAC, 155862306a36Sopenharmony_ci H2C_CL_MAC_PS, 155962306a36Sopenharmony_ci H2C_FUNC_MAC_LPS_PARM, 0, 1, 156062306a36Sopenharmony_ci H2C_LPS_PARM_LEN); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 156362306a36Sopenharmony_ci if (ret) { 156462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 156562306a36Sopenharmony_ci goto fail; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci return 0; 156962306a36Sopenharmony_cifail: 157062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci return ret; 157362306a36Sopenharmony_ci} 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci#define H2C_P2P_ACT_LEN 20 157662306a36Sopenharmony_ciint rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, 157762306a36Sopenharmony_ci struct ieee80211_p2p_noa_desc *desc, 157862306a36Sopenharmony_ci u8 act, u8 noa_id) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 158162306a36Sopenharmony_ci bool p2p_type_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; 158262306a36Sopenharmony_ci u8 ctwindow_oppps = vif->bss_conf.p2p_noa_attr.oppps_ctwindow; 158362306a36Sopenharmony_ci struct sk_buff *skb; 158462306a36Sopenharmony_ci u8 *cmd; 158562306a36Sopenharmony_ci int ret; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_P2P_ACT_LEN); 158862306a36Sopenharmony_ci if (!skb) { 158962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c p2p act\n"); 159062306a36Sopenharmony_ci return -ENOMEM; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci skb_put(skb, H2C_P2P_ACT_LEN); 159362306a36Sopenharmony_ci cmd = skb->data; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif->mac_id); 159662306a36Sopenharmony_ci RTW89_SET_FWCMD_P2P_P2PID(cmd, 0); 159762306a36Sopenharmony_ci RTW89_SET_FWCMD_P2P_NOAID(cmd, noa_id); 159862306a36Sopenharmony_ci RTW89_SET_FWCMD_P2P_ACT(cmd, act); 159962306a36Sopenharmony_ci RTW89_SET_FWCMD_P2P_TYPE(cmd, p2p_type_gc); 160062306a36Sopenharmony_ci RTW89_SET_FWCMD_P2P_ALL_SLEP(cmd, 0); 160162306a36Sopenharmony_ci if (desc) { 160262306a36Sopenharmony_ci RTW89_SET_FWCMD_NOA_START_TIME(cmd, desc->start_time); 160362306a36Sopenharmony_ci RTW89_SET_FWCMD_NOA_INTERVAL(cmd, desc->interval); 160462306a36Sopenharmony_ci RTW89_SET_FWCMD_NOA_DURATION(cmd, desc->duration); 160562306a36Sopenharmony_ci RTW89_SET_FWCMD_NOA_COUNT(cmd, desc->count); 160662306a36Sopenharmony_ci RTW89_SET_FWCMD_NOA_CTWINDOW(cmd, ctwindow_oppps); 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 161062306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_PS, 161162306a36Sopenharmony_ci H2C_FUNC_P2P_ACT, 0, 0, 161262306a36Sopenharmony_ci H2C_P2P_ACT_LEN); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 161562306a36Sopenharmony_ci if (ret) { 161662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 161762306a36Sopenharmony_ci goto fail; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci return 0; 162162306a36Sopenharmony_cifail: 162262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci return ret; 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_cistatic void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev, 162862306a36Sopenharmony_ci struct sk_buff *skb) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 163162306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 163262306a36Sopenharmony_ci u8 ntx_path; 163362306a36Sopenharmony_ci u8 map_b; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci if (chip->rf_path_num == 1) { 163662306a36Sopenharmony_ci ntx_path = RF_A; 163762306a36Sopenharmony_ci map_b = 0; 163862306a36Sopenharmony_ci } else { 163962306a36Sopenharmony_ci ntx_path = hal->antenna_tx ? hal->antenna_tx : RF_B; 164062306a36Sopenharmony_ci map_b = hal->antenna_tx == RF_AB ? 1 : 0; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci SET_CMC_TBL_NTX_PATH_EN(skb->data, ntx_path); 164462306a36Sopenharmony_ci SET_CMC_TBL_PATH_MAP_A(skb->data, 0); 164562306a36Sopenharmony_ci SET_CMC_TBL_PATH_MAP_B(skb->data, map_b); 164662306a36Sopenharmony_ci SET_CMC_TBL_PATH_MAP_C(skb->data, 0); 164762306a36Sopenharmony_ci SET_CMC_TBL_PATH_MAP_D(skb->data, 0); 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci#define H2C_CMC_TBL_LEN 68 165162306a36Sopenharmony_ciint rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, 165262306a36Sopenharmony_ci struct rtw89_vif *rtwvif) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 165562306a36Sopenharmony_ci struct sk_buff *skb; 165662306a36Sopenharmony_ci u8 macid = rtwvif->mac_id; 165762306a36Sopenharmony_ci int ret; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); 166062306a36Sopenharmony_ci if (!skb) { 166162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 166262306a36Sopenharmony_ci return -ENOMEM; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci skb_put(skb, H2C_CMC_TBL_LEN); 166562306a36Sopenharmony_ci SET_CTRL_INFO_MACID(skb->data, macid); 166662306a36Sopenharmony_ci SET_CTRL_INFO_OPERATION(skb->data, 1); 166762306a36Sopenharmony_ci if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD) { 166862306a36Sopenharmony_ci SET_CMC_TBL_TXPWR_MODE(skb->data, 0); 166962306a36Sopenharmony_ci __rtw89_fw_h2c_set_tx_path(rtwdev, skb); 167062306a36Sopenharmony_ci SET_CMC_TBL_ANTSEL_A(skb->data, 0); 167162306a36Sopenharmony_ci SET_CMC_TBL_ANTSEL_B(skb->data, 0); 167262306a36Sopenharmony_ci SET_CMC_TBL_ANTSEL_C(skb->data, 0); 167362306a36Sopenharmony_ci SET_CMC_TBL_ANTSEL_D(skb->data, 0); 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci SET_CMC_TBL_DOPPLER_CTRL(skb->data, 0); 167662306a36Sopenharmony_ci SET_CMC_TBL_TXPWR_TOLERENCE(skb->data, 0); 167762306a36Sopenharmony_ci if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) 167862306a36Sopenharmony_ci SET_CMC_TBL_DATA_DCM(skb->data, 0); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 168162306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, 168262306a36Sopenharmony_ci chip->h2c_cctl_func_id, 0, 1, 168362306a36Sopenharmony_ci H2C_CMC_TBL_LEN); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 168662306a36Sopenharmony_ci if (ret) { 168762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 168862306a36Sopenharmony_ci goto fail; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci return 0; 169262306a36Sopenharmony_cifail: 169362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci return ret; 169662306a36Sopenharmony_ci} 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_cistatic void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, 169962306a36Sopenharmony_ci struct ieee80211_sta *sta, u8 *pads) 170062306a36Sopenharmony_ci{ 170162306a36Sopenharmony_ci bool ppe_th; 170262306a36Sopenharmony_ci u8 ppe16, ppe8; 170362306a36Sopenharmony_ci u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; 170462306a36Sopenharmony_ci u8 ppe_thres_hdr = sta->deflink.he_cap.ppe_thres[0]; 170562306a36Sopenharmony_ci u8 ru_bitmap; 170662306a36Sopenharmony_ci u8 n, idx, sh; 170762306a36Sopenharmony_ci u16 ppe; 170862306a36Sopenharmony_ci int i; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci if (!sta->deflink.he_cap.has_he) 171162306a36Sopenharmony_ci return; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, 171462306a36Sopenharmony_ci sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]); 171562306a36Sopenharmony_ci if (!ppe_th) { 171662306a36Sopenharmony_ci u8 pad; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK, 171962306a36Sopenharmony_ci sta->deflink.he_cap.he_cap_elem.phy_cap_info[9]); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci for (i = 0; i < RTW89_PPE_BW_NUM; i++) 172262306a36Sopenharmony_ci pads[i] = pad; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci return; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci ru_bitmap = FIELD_GET(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK, ppe_thres_hdr); 172862306a36Sopenharmony_ci n = hweight8(ru_bitmap); 172962306a36Sopenharmony_ci n = 7 + (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) * nss; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci for (i = 0; i < RTW89_PPE_BW_NUM; i++) { 173262306a36Sopenharmony_ci if (!(ru_bitmap & BIT(i))) { 173362306a36Sopenharmony_ci pads[i] = 1; 173462306a36Sopenharmony_ci continue; 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci idx = n >> 3; 173862306a36Sopenharmony_ci sh = n & 7; 173962306a36Sopenharmony_ci n += IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci ppe = le16_to_cpu(*((__le16 *)&sta->deflink.he_cap.ppe_thres[idx])); 174262306a36Sopenharmony_ci ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; 174362306a36Sopenharmony_ci sh += IEEE80211_PPE_THRES_INFO_PPET_SIZE; 174462306a36Sopenharmony_ci ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci if (ppe16 != 7 && ppe8 == 7) 174762306a36Sopenharmony_ci pads[i] = 2; 174862306a36Sopenharmony_ci else if (ppe8 != 7) 174962306a36Sopenharmony_ci pads[i] = 1; 175062306a36Sopenharmony_ci else 175162306a36Sopenharmony_ci pads[i] = 0; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci} 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ciint rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, 175662306a36Sopenharmony_ci struct ieee80211_vif *vif, 175762306a36Sopenharmony_ci struct ieee80211_sta *sta) 175862306a36Sopenharmony_ci{ 175962306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 176062306a36Sopenharmony_ci struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); 176162306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 176262306a36Sopenharmony_ci const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, 176362306a36Sopenharmony_ci rtwvif->sub_entity_idx); 176462306a36Sopenharmony_ci struct sk_buff *skb; 176562306a36Sopenharmony_ci u8 pads[RTW89_PPE_BW_NUM]; 176662306a36Sopenharmony_ci u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; 176762306a36Sopenharmony_ci u16 lowest_rate; 176862306a36Sopenharmony_ci int ret; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci memset(pads, 0, sizeof(pads)); 177162306a36Sopenharmony_ci if (sta) 177262306a36Sopenharmony_ci __get_sta_he_pkt_padding(rtwdev, sta, pads); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci if (vif->p2p) 177562306a36Sopenharmony_ci lowest_rate = RTW89_HW_RATE_OFDM6; 177662306a36Sopenharmony_ci else if (chan->band_type == RTW89_BAND_2G) 177762306a36Sopenharmony_ci lowest_rate = RTW89_HW_RATE_CCK1; 177862306a36Sopenharmony_ci else 177962306a36Sopenharmony_ci lowest_rate = RTW89_HW_RATE_OFDM6; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); 178262306a36Sopenharmony_ci if (!skb) { 178362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 178462306a36Sopenharmony_ci return -ENOMEM; 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci skb_put(skb, H2C_CMC_TBL_LEN); 178762306a36Sopenharmony_ci SET_CTRL_INFO_MACID(skb->data, mac_id); 178862306a36Sopenharmony_ci SET_CTRL_INFO_OPERATION(skb->data, 1); 178962306a36Sopenharmony_ci SET_CMC_TBL_DISRTSFB(skb->data, 1); 179062306a36Sopenharmony_ci SET_CMC_TBL_DISDATAFB(skb->data, 1); 179162306a36Sopenharmony_ci SET_CMC_TBL_RTS_RTY_LOWEST_RATE(skb->data, lowest_rate); 179262306a36Sopenharmony_ci SET_CMC_TBL_RTS_TXCNT_LMT_SEL(skb->data, 0); 179362306a36Sopenharmony_ci SET_CMC_TBL_DATA_TXCNT_LMT_SEL(skb->data, 0); 179462306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 179562306a36Sopenharmony_ci SET_CMC_TBL_ULDL(skb->data, 1); 179662306a36Sopenharmony_ci else 179762306a36Sopenharmony_ci SET_CMC_TBL_ULDL(skb->data, 0); 179862306a36Sopenharmony_ci SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif->port); 179962306a36Sopenharmony_ci if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD_V1) { 180062306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_20]); 180162306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING40_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_40]); 180262306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING80_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_80]); 180362306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING160_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_160]); 180462306a36Sopenharmony_ci } else if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD) { 180562306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING(skb->data, pads[RTW89_CHANNEL_WIDTH_20]); 180662306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING40(skb->data, pads[RTW89_CHANNEL_WIDTH_40]); 180762306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]); 180862306a36Sopenharmony_ci SET_CMC_TBL_NOMINAL_PKT_PADDING160(skb->data, pads[RTW89_CHANNEL_WIDTH_160]); 180962306a36Sopenharmony_ci } 181062306a36Sopenharmony_ci if (sta) 181162306a36Sopenharmony_ci SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data, 181262306a36Sopenharmony_ci sta->deflink.he_cap.has_he); 181362306a36Sopenharmony_ci if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) 181462306a36Sopenharmony_ci SET_CMC_TBL_DATA_DCM(skb->data, 0); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 181762306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, 181862306a36Sopenharmony_ci chip->h2c_cctl_func_id, 0, 1, 181962306a36Sopenharmony_ci H2C_CMC_TBL_LEN); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 182262306a36Sopenharmony_ci if (ret) { 182362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 182462306a36Sopenharmony_ci goto fail; 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci return 0; 182862306a36Sopenharmony_cifail: 182962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci return ret; 183262306a36Sopenharmony_ci} 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ciint rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, 183562306a36Sopenharmony_ci struct rtw89_sta *rtwsta) 183662306a36Sopenharmony_ci{ 183762306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 183862306a36Sopenharmony_ci struct sk_buff *skb; 183962306a36Sopenharmony_ci int ret; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); 184262306a36Sopenharmony_ci if (!skb) { 184362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 184462306a36Sopenharmony_ci return -ENOMEM; 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci skb_put(skb, H2C_CMC_TBL_LEN); 184762306a36Sopenharmony_ci SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id); 184862306a36Sopenharmony_ci SET_CTRL_INFO_OPERATION(skb->data, 1); 184962306a36Sopenharmony_ci if (rtwsta->cctl_tx_time) { 185062306a36Sopenharmony_ci SET_CMC_TBL_AMPDU_TIME_SEL(skb->data, 1); 185162306a36Sopenharmony_ci SET_CMC_TBL_AMPDU_MAX_TIME(skb->data, rtwsta->ampdu_max_time); 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci if (rtwsta->cctl_tx_retry_limit) { 185462306a36Sopenharmony_ci SET_CMC_TBL_DATA_TXCNT_LMT_SEL(skb->data, 1); 185562306a36Sopenharmony_ci SET_CMC_TBL_DATA_TX_CNT_LMT(skb->data, rtwsta->data_tx_cnt_lmt); 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 185962306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, 186062306a36Sopenharmony_ci chip->h2c_cctl_func_id, 0, 1, 186162306a36Sopenharmony_ci H2C_CMC_TBL_LEN); 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 186462306a36Sopenharmony_ci if (ret) { 186562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 186662306a36Sopenharmony_ci goto fail; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci return 0; 187062306a36Sopenharmony_cifail: 187162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci return ret; 187462306a36Sopenharmony_ci} 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ciint rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, 187762306a36Sopenharmony_ci struct rtw89_sta *rtwsta) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 188062306a36Sopenharmony_ci struct sk_buff *skb; 188162306a36Sopenharmony_ci int ret; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (chip->h2c_cctl_func_id != H2C_FUNC_MAC_CCTLINFO_UD) 188462306a36Sopenharmony_ci return 0; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); 188762306a36Sopenharmony_ci if (!skb) { 188862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 188962306a36Sopenharmony_ci return -ENOMEM; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci skb_put(skb, H2C_CMC_TBL_LEN); 189262306a36Sopenharmony_ci SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id); 189362306a36Sopenharmony_ci SET_CTRL_INFO_OPERATION(skb->data, 1); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci __rtw89_fw_h2c_set_tx_path(rtwdev, skb); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 189862306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, 189962306a36Sopenharmony_ci H2C_FUNC_MAC_CCTLINFO_UD, 0, 1, 190062306a36Sopenharmony_ci H2C_CMC_TBL_LEN); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 190362306a36Sopenharmony_ci if (ret) { 190462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 190562306a36Sopenharmony_ci goto fail; 190662306a36Sopenharmony_ci } 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci return 0; 190962306a36Sopenharmony_cifail: 191062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci return ret; 191362306a36Sopenharmony_ci} 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci#define H2C_BCN_BASE_LEN 12 191662306a36Sopenharmony_ciint rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, 191762306a36Sopenharmony_ci struct rtw89_vif *rtwvif) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 192062306a36Sopenharmony_ci const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, 192162306a36Sopenharmony_ci rtwvif->sub_entity_idx); 192262306a36Sopenharmony_ci struct sk_buff *skb; 192362306a36Sopenharmony_ci struct sk_buff *skb_beacon; 192462306a36Sopenharmony_ci u16 tim_offset; 192562306a36Sopenharmony_ci int bcn_total_len; 192662306a36Sopenharmony_ci u16 beacon_rate; 192762306a36Sopenharmony_ci void *noa_data; 192862306a36Sopenharmony_ci u8 noa_len; 192962306a36Sopenharmony_ci int ret; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci if (vif->p2p) 193262306a36Sopenharmony_ci beacon_rate = RTW89_HW_RATE_OFDM6; 193362306a36Sopenharmony_ci else if (chan->band_type == RTW89_BAND_2G) 193462306a36Sopenharmony_ci beacon_rate = RTW89_HW_RATE_CCK1; 193562306a36Sopenharmony_ci else 193662306a36Sopenharmony_ci beacon_rate = RTW89_HW_RATE_OFDM6; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, 193962306a36Sopenharmony_ci NULL, 0); 194062306a36Sopenharmony_ci if (!skb_beacon) { 194162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to get beacon skb\n"); 194262306a36Sopenharmony_ci return -ENOMEM; 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data); 194662306a36Sopenharmony_ci if (noa_len && 194762306a36Sopenharmony_ci (noa_len <= skb_tailroom(skb_beacon) || 194862306a36Sopenharmony_ci pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) { 194962306a36Sopenharmony_ci skb_put_data(skb_beacon, noa_data, noa_len); 195062306a36Sopenharmony_ci } 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len; 195362306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len); 195462306a36Sopenharmony_ci if (!skb) { 195562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); 195662306a36Sopenharmony_ci dev_kfree_skb_any(skb_beacon); 195762306a36Sopenharmony_ci return -ENOMEM; 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci skb_put(skb, H2C_BCN_BASE_LEN); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci SET_BCN_UPD_PORT(skb->data, rtwvif->port); 196262306a36Sopenharmony_ci SET_BCN_UPD_MBSSID(skb->data, 0); 196362306a36Sopenharmony_ci SET_BCN_UPD_BAND(skb->data, rtwvif->mac_idx); 196462306a36Sopenharmony_ci SET_BCN_UPD_GRP_IE_OFST(skb->data, tim_offset); 196562306a36Sopenharmony_ci SET_BCN_UPD_MACID(skb->data, rtwvif->mac_id); 196662306a36Sopenharmony_ci SET_BCN_UPD_SSN_SEL(skb->data, RTW89_MGMT_HW_SSN_SEL); 196762306a36Sopenharmony_ci SET_BCN_UPD_SSN_MODE(skb->data, RTW89_MGMT_HW_SEQ_MODE); 196862306a36Sopenharmony_ci SET_BCN_UPD_RATE(skb->data, beacon_rate); 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci skb_put_data(skb, skb_beacon->data, skb_beacon->len); 197162306a36Sopenharmony_ci dev_kfree_skb_any(skb_beacon); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 197462306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, 197562306a36Sopenharmony_ci H2C_FUNC_MAC_BCN_UPD, 0, 1, 197662306a36Sopenharmony_ci bcn_total_len); 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 197962306a36Sopenharmony_ci if (ret) { 198062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 198162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 198262306a36Sopenharmony_ci return ret; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci return 0; 198662306a36Sopenharmony_ci} 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci#define H2C_ROLE_MAINTAIN_LEN 4 198962306a36Sopenharmony_ciint rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, 199062306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 199162306a36Sopenharmony_ci struct rtw89_sta *rtwsta, 199262306a36Sopenharmony_ci enum rtw89_upd_mode upd_mode) 199362306a36Sopenharmony_ci{ 199462306a36Sopenharmony_ci struct sk_buff *skb; 199562306a36Sopenharmony_ci u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; 199662306a36Sopenharmony_ci u8 self_role; 199762306a36Sopenharmony_ci int ret; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) { 200062306a36Sopenharmony_ci if (rtwsta) 200162306a36Sopenharmony_ci self_role = RTW89_SELF_ROLE_AP_CLIENT; 200262306a36Sopenharmony_ci else 200362306a36Sopenharmony_ci self_role = rtwvif->self_role; 200462306a36Sopenharmony_ci } else { 200562306a36Sopenharmony_ci self_role = rtwvif->self_role; 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ROLE_MAINTAIN_LEN); 200962306a36Sopenharmony_ci if (!skb) { 201062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); 201162306a36Sopenharmony_ci return -ENOMEM; 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci skb_put(skb, H2C_ROLE_MAINTAIN_LEN); 201462306a36Sopenharmony_ci SET_FWROLE_MAINTAIN_MACID(skb->data, mac_id); 201562306a36Sopenharmony_ci SET_FWROLE_MAINTAIN_SELF_ROLE(skb->data, self_role); 201662306a36Sopenharmony_ci SET_FWROLE_MAINTAIN_UPD_MODE(skb->data, upd_mode); 201762306a36Sopenharmony_ci SET_FWROLE_MAINTAIN_WIFI_ROLE(skb->data, rtwvif->wifi_role); 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 202062306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, 202162306a36Sopenharmony_ci H2C_FUNC_MAC_FWROLE_MAINTAIN, 0, 1, 202262306a36Sopenharmony_ci H2C_ROLE_MAINTAIN_LEN); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 202562306a36Sopenharmony_ci if (ret) { 202662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 202762306a36Sopenharmony_ci goto fail; 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci return 0; 203162306a36Sopenharmony_cifail: 203262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci return ret; 203562306a36Sopenharmony_ci} 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci#define H2C_JOIN_INFO_LEN 4 203862306a36Sopenharmony_ciint rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 203962306a36Sopenharmony_ci struct rtw89_sta *rtwsta, bool dis_conn) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci struct sk_buff *skb; 204262306a36Sopenharmony_ci u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; 204362306a36Sopenharmony_ci u8 self_role = rtwvif->self_role; 204462306a36Sopenharmony_ci u8 net_type = rtwvif->net_type; 204562306a36Sopenharmony_ci int ret; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) { 204862306a36Sopenharmony_ci self_role = RTW89_SELF_ROLE_AP_CLIENT; 204962306a36Sopenharmony_ci net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type; 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN); 205362306a36Sopenharmony_ci if (!skb) { 205462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); 205562306a36Sopenharmony_ci return -ENOMEM; 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci skb_put(skb, H2C_JOIN_INFO_LEN); 205862306a36Sopenharmony_ci SET_JOININFO_MACID(skb->data, mac_id); 205962306a36Sopenharmony_ci SET_JOININFO_OP(skb->data, dis_conn); 206062306a36Sopenharmony_ci SET_JOININFO_BAND(skb->data, rtwvif->mac_idx); 206162306a36Sopenharmony_ci SET_JOININFO_WMM(skb->data, rtwvif->wmm); 206262306a36Sopenharmony_ci SET_JOININFO_TGR(skb->data, rtwvif->trigger); 206362306a36Sopenharmony_ci SET_JOININFO_ISHESTA(skb->data, 0); 206462306a36Sopenharmony_ci SET_JOININFO_DLBW(skb->data, 0); 206562306a36Sopenharmony_ci SET_JOININFO_TF_MAC_PAD(skb->data, 0); 206662306a36Sopenharmony_ci SET_JOININFO_DL_T_PE(skb->data, 0); 206762306a36Sopenharmony_ci SET_JOININFO_PORT_ID(skb->data, rtwvif->port); 206862306a36Sopenharmony_ci SET_JOININFO_NET_TYPE(skb->data, net_type); 206962306a36Sopenharmony_ci SET_JOININFO_WIFI_ROLE(skb->data, rtwvif->wifi_role); 207062306a36Sopenharmony_ci SET_JOININFO_SELF_ROLE(skb->data, self_role); 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 207362306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, 207462306a36Sopenharmony_ci H2C_FUNC_MAC_JOININFO, 0, 1, 207562306a36Sopenharmony_ci H2C_JOIN_INFO_LEN); 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 207862306a36Sopenharmony_ci if (ret) { 207962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 208062306a36Sopenharmony_ci goto fail; 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci return 0; 208462306a36Sopenharmony_cifail: 208562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci return ret; 208862306a36Sopenharmony_ci} 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ciint rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, 209162306a36Sopenharmony_ci bool pause) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci struct rtw89_fw_macid_pause_grp h2c = {{0}}; 209462306a36Sopenharmony_ci u8 len = sizeof(struct rtw89_fw_macid_pause_grp); 209562306a36Sopenharmony_ci struct sk_buff *skb; 209662306a36Sopenharmony_ci int ret; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN); 209962306a36Sopenharmony_ci if (!skb) { 210062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); 210162306a36Sopenharmony_ci return -ENOMEM; 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci h2c.mask_grp[grp] = cpu_to_le32(BIT(sh)); 210462306a36Sopenharmony_ci if (pause) 210562306a36Sopenharmony_ci h2c.pause_grp[grp] = cpu_to_le32(BIT(sh)); 210662306a36Sopenharmony_ci skb_put_data(skb, &h2c, len); 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 210962306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 211062306a36Sopenharmony_ci H2C_FUNC_MAC_MACID_PAUSE, 1, 0, 211162306a36Sopenharmony_ci len); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 211462306a36Sopenharmony_ci if (ret) { 211562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 211662306a36Sopenharmony_ci goto fail; 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci return 0; 212062306a36Sopenharmony_cifail: 212162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci return ret; 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci#define H2C_EDCA_LEN 12 212762306a36Sopenharmony_ciint rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 212862306a36Sopenharmony_ci u8 ac, u32 val) 212962306a36Sopenharmony_ci{ 213062306a36Sopenharmony_ci struct sk_buff *skb; 213162306a36Sopenharmony_ci int ret; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_EDCA_LEN); 213462306a36Sopenharmony_ci if (!skb) { 213562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c edca\n"); 213662306a36Sopenharmony_ci return -ENOMEM; 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci skb_put(skb, H2C_EDCA_LEN); 213962306a36Sopenharmony_ci RTW89_SET_EDCA_SEL(skb->data, 0); 214062306a36Sopenharmony_ci RTW89_SET_EDCA_BAND(skb->data, rtwvif->mac_idx); 214162306a36Sopenharmony_ci RTW89_SET_EDCA_WMM(skb->data, 0); 214262306a36Sopenharmony_ci RTW89_SET_EDCA_AC(skb->data, ac); 214362306a36Sopenharmony_ci RTW89_SET_EDCA_PARAM(skb->data, val); 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 214662306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 214762306a36Sopenharmony_ci H2C_FUNC_USR_EDCA, 0, 1, 214862306a36Sopenharmony_ci H2C_EDCA_LEN); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 215162306a36Sopenharmony_ci if (ret) { 215262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 215362306a36Sopenharmony_ci goto fail; 215462306a36Sopenharmony_ci } 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci return 0; 215762306a36Sopenharmony_cifail: 215862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci return ret; 216162306a36Sopenharmony_ci} 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci#define H2C_TSF32_TOGL_LEN 4 216462306a36Sopenharmony_ciint rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 216562306a36Sopenharmony_ci bool en) 216662306a36Sopenharmony_ci{ 216762306a36Sopenharmony_ci struct sk_buff *skb; 216862306a36Sopenharmony_ci u16 early_us = en ? 2000 : 0; 216962306a36Sopenharmony_ci u8 *cmd; 217062306a36Sopenharmony_ci int ret; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_TSF32_TOGL_LEN); 217362306a36Sopenharmony_ci if (!skb) { 217462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c p2p act\n"); 217562306a36Sopenharmony_ci return -ENOMEM; 217662306a36Sopenharmony_ci } 217762306a36Sopenharmony_ci skb_put(skb, H2C_TSF32_TOGL_LEN); 217862306a36Sopenharmony_ci cmd = skb->data; 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif->mac_idx); 218162306a36Sopenharmony_ci RTW89_SET_FWCMD_TSF32_TOGL_EN(cmd, en); 218262306a36Sopenharmony_ci RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif->port); 218362306a36Sopenharmony_ci RTW89_SET_FWCMD_TSF32_TOGL_EARLY(cmd, early_us); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 218662306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 218762306a36Sopenharmony_ci H2C_FUNC_TSF32_TOGL, 0, 0, 218862306a36Sopenharmony_ci H2C_TSF32_TOGL_LEN); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 219162306a36Sopenharmony_ci if (ret) { 219262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 219362306a36Sopenharmony_ci goto fail; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci return 0; 219762306a36Sopenharmony_cifail: 219862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci return ret; 220162306a36Sopenharmony_ci} 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci#define H2C_OFLD_CFG_LEN 8 220462306a36Sopenharmony_ciint rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev) 220562306a36Sopenharmony_ci{ 220662306a36Sopenharmony_ci static const u8 cfg[] = {0x09, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00}; 220762306a36Sopenharmony_ci struct sk_buff *skb; 220862306a36Sopenharmony_ci int ret; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_OFLD_CFG_LEN); 221162306a36Sopenharmony_ci if (!skb) { 221262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c ofld\n"); 221362306a36Sopenharmony_ci return -ENOMEM; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci skb_put_data(skb, cfg, H2C_OFLD_CFG_LEN); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 221862306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 221962306a36Sopenharmony_ci H2C_FUNC_OFLD_CFG, 0, 1, 222062306a36Sopenharmony_ci H2C_OFLD_CFG_LEN); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 222362306a36Sopenharmony_ci if (ret) { 222462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 222562306a36Sopenharmony_ci goto fail; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci return 0; 222962306a36Sopenharmony_cifail: 223062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci return ret; 223362306a36Sopenharmony_ci} 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ciint rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, 223662306a36Sopenharmony_ci struct ieee80211_vif *vif, 223762306a36Sopenharmony_ci bool connect) 223862306a36Sopenharmony_ci{ 223962306a36Sopenharmony_ci struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 224062306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf = vif ? &vif->bss_conf : NULL; 224162306a36Sopenharmony_ci struct rtw89_h2c_bcnfltr *h2c; 224262306a36Sopenharmony_ci u32 len = sizeof(*h2c); 224362306a36Sopenharmony_ci struct sk_buff *skb; 224462306a36Sopenharmony_ci int ret; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci if (!RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) 224762306a36Sopenharmony_ci return -EINVAL; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci if (!rtwvif || !bss_conf || rtwvif->net_type != RTW89_NET_TYPE_INFRA) 225062306a36Sopenharmony_ci return -EINVAL; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 225362306a36Sopenharmony_ci if (!skb) { 225462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c bcn filter\n"); 225562306a36Sopenharmony_ci return -ENOMEM; 225662306a36Sopenharmony_ci } 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci skb_put(skb, len); 225962306a36Sopenharmony_ci h2c = (struct rtw89_h2c_bcnfltr *)skb->data; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) | 226262306a36Sopenharmony_ci le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) | 226362306a36Sopenharmony_ci le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) | 226462306a36Sopenharmony_ci le32_encode_bits(RTW89_BCN_FLTR_OFFLOAD_MODE_DEFAULT, 226562306a36Sopenharmony_ci RTW89_H2C_BCNFLTR_W0_MODE) | 226662306a36Sopenharmony_ci le32_encode_bits(RTW89_BCN_LOSS_CNT, RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT) | 226762306a36Sopenharmony_ci le32_encode_bits(bss_conf->cqm_rssi_hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) | 226862306a36Sopenharmony_ci le32_encode_bits(bss_conf->cqm_rssi_thold + MAX_RSSI, 226962306a36Sopenharmony_ci RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) | 227062306a36Sopenharmony_ci le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID); 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 227362306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 227462306a36Sopenharmony_ci H2C_FUNC_CFG_BCNFLTR, 0, 1, len); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 227762306a36Sopenharmony_ci if (ret) { 227862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 227962306a36Sopenharmony_ci goto fail; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci return 0; 228362306a36Sopenharmony_cifail: 228462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci return ret; 228762306a36Sopenharmony_ci} 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ciint rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev, 229062306a36Sopenharmony_ci struct rtw89_rx_phy_ppdu *phy_ppdu) 229162306a36Sopenharmony_ci{ 229262306a36Sopenharmony_ci struct rtw89_h2c_ofld_rssi *h2c; 229362306a36Sopenharmony_ci u32 len = sizeof(*h2c); 229462306a36Sopenharmony_ci struct sk_buff *skb; 229562306a36Sopenharmony_ci s8 rssi; 229662306a36Sopenharmony_ci int ret; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci if (!RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) 229962306a36Sopenharmony_ci return -EINVAL; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci if (!phy_ppdu) 230262306a36Sopenharmony_ci return -EINVAL; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 230562306a36Sopenharmony_ci if (!skb) { 230662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c rssi\n"); 230762306a36Sopenharmony_ci return -ENOMEM; 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci rssi = phy_ppdu->rssi_avg >> RSSI_FACTOR; 231162306a36Sopenharmony_ci skb_put(skb, len); 231262306a36Sopenharmony_ci h2c = (struct rtw89_h2c_ofld_rssi *)skb->data; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci h2c->w0 = le32_encode_bits(phy_ppdu->mac_id, RTW89_H2C_OFLD_RSSI_W0_MACID) | 231562306a36Sopenharmony_ci le32_encode_bits(1, RTW89_H2C_OFLD_RSSI_W0_NUM); 231662306a36Sopenharmony_ci h2c->w1 = le32_encode_bits(rssi, RTW89_H2C_OFLD_RSSI_W1_VAL); 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 231962306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 232062306a36Sopenharmony_ci H2C_FUNC_OFLD_RSSI, 0, 1, len); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 232362306a36Sopenharmony_ci if (ret) { 232462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 232562306a36Sopenharmony_ci goto fail; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci return 0; 232962306a36Sopenharmony_cifail: 233062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci return ret; 233362306a36Sopenharmony_ci} 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ciint rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 233662306a36Sopenharmony_ci{ 233762306a36Sopenharmony_ci struct rtw89_traffic_stats *stats = &rtwvif->stats; 233862306a36Sopenharmony_ci struct rtw89_h2c_ofld *h2c; 233962306a36Sopenharmony_ci u32 len = sizeof(*h2c); 234062306a36Sopenharmony_ci struct sk_buff *skb; 234162306a36Sopenharmony_ci int ret; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci if (rtwvif->net_type != RTW89_NET_TYPE_INFRA) 234462306a36Sopenharmony_ci return -EINVAL; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 234762306a36Sopenharmony_ci if (!skb) { 234862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c tp\n"); 234962306a36Sopenharmony_ci return -ENOMEM; 235062306a36Sopenharmony_ci } 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci skb_put(skb, len); 235362306a36Sopenharmony_ci h2c = (struct rtw89_h2c_ofld *)skb->data; 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_OFLD_W0_MAC_ID) | 235662306a36Sopenharmony_ci le32_encode_bits(stats->tx_throughput, RTW89_H2C_OFLD_W0_TX_TP) | 235762306a36Sopenharmony_ci le32_encode_bits(stats->rx_throughput, RTW89_H2C_OFLD_W0_RX_TP); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 236062306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 236162306a36Sopenharmony_ci H2C_FUNC_OFLD_TP, 0, 1, len); 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 236462306a36Sopenharmony_ci if (ret) { 236562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 236662306a36Sopenharmony_ci goto fail; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci return 0; 237062306a36Sopenharmony_cifail: 237162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci return ret; 237462306a36Sopenharmony_ci} 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ciint rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi) 237762306a36Sopenharmony_ci{ 237862306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 237962306a36Sopenharmony_ci struct rtw89_h2c_ra_v1 *h2c_v1; 238062306a36Sopenharmony_ci struct rtw89_h2c_ra *h2c; 238162306a36Sopenharmony_ci u32 len = sizeof(*h2c); 238262306a36Sopenharmony_ci bool format_v1 = false; 238362306a36Sopenharmony_ci struct sk_buff *skb; 238462306a36Sopenharmony_ci int ret; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci if (chip->chip_gen == RTW89_CHIP_BE) { 238762306a36Sopenharmony_ci len = sizeof(*h2c_v1); 238862306a36Sopenharmony_ci format_v1 = true; 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 239262306a36Sopenharmony_ci if (!skb) { 239362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); 239462306a36Sopenharmony_ci return -ENOMEM; 239562306a36Sopenharmony_ci } 239662306a36Sopenharmony_ci skb_put(skb, len); 239762306a36Sopenharmony_ci h2c = (struct rtw89_h2c_ra *)skb->data; 239862306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_RA, 239962306a36Sopenharmony_ci "ra cmd msk: %llx ", ra->ra_mask); 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci h2c->w0 = le32_encode_bits(ra->mode_ctrl, RTW89_H2C_RA_W0_MODE) | 240262306a36Sopenharmony_ci le32_encode_bits(ra->bw_cap, RTW89_H2C_RA_W0_BW_CAP) | 240362306a36Sopenharmony_ci le32_encode_bits(ra->macid, RTW89_H2C_RA_W0_MACID) | 240462306a36Sopenharmony_ci le32_encode_bits(ra->dcm_cap, RTW89_H2C_RA_W0_DCM) | 240562306a36Sopenharmony_ci le32_encode_bits(ra->er_cap, RTW89_H2C_RA_W0_ER) | 240662306a36Sopenharmony_ci le32_encode_bits(ra->init_rate_lv, RTW89_H2C_RA_W0_INIT_RATE_LV) | 240762306a36Sopenharmony_ci le32_encode_bits(ra->upd_all, RTW89_H2C_RA_W0_UPD_ALL) | 240862306a36Sopenharmony_ci le32_encode_bits(ra->en_sgi, RTW89_H2C_RA_W0_SGI) | 240962306a36Sopenharmony_ci le32_encode_bits(ra->ldpc_cap, RTW89_H2C_RA_W0_LDPC) | 241062306a36Sopenharmony_ci le32_encode_bits(ra->stbc_cap, RTW89_H2C_RA_W0_STBC) | 241162306a36Sopenharmony_ci le32_encode_bits(ra->ss_num, RTW89_H2C_RA_W0_SS_NUM) | 241262306a36Sopenharmony_ci le32_encode_bits(ra->giltf, RTW89_H2C_RA_W0_GILTF) | 241362306a36Sopenharmony_ci le32_encode_bits(ra->upd_bw_nss_mask, RTW89_H2C_RA_W0_UPD_BW_NSS_MASK) | 241462306a36Sopenharmony_ci le32_encode_bits(ra->upd_mask, RTW89_H2C_RA_W0_UPD_MASK); 241562306a36Sopenharmony_ci h2c->w1 = le32_encode_bits(ra->ra_mask, RTW89_H2C_RA_W1_RAMASK_LO32); 241662306a36Sopenharmony_ci h2c->w2 = le32_encode_bits(ra->ra_mask >> 32, RTW89_H2C_RA_W2_RAMASK_HI32); 241762306a36Sopenharmony_ci h2c->w3 = le32_encode_bits(ra->fix_giltf_en, RTW89_H2C_RA_W3_FIX_GILTF_EN) | 241862306a36Sopenharmony_ci le32_encode_bits(ra->fix_giltf, RTW89_H2C_RA_W3_FIX_GILTF); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci if (!format_v1) 242162306a36Sopenharmony_ci goto csi; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci h2c_v1 = (struct rtw89_h2c_ra_v1 *)h2c; 242462306a36Sopenharmony_ci h2c_v1->w4 = le32_encode_bits(ra->mode_ctrl, RTW89_H2C_RA_V1_W4_MODE_EHT) | 242562306a36Sopenharmony_ci le32_encode_bits(ra->bw_cap, RTW89_H2C_RA_V1_W4_BW_EHT); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_cicsi: 242862306a36Sopenharmony_ci if (!csi) 242962306a36Sopenharmony_ci goto done; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci h2c->w2 |= le32_encode_bits(1, RTW89_H2C_RA_W2_BFEE_CSI_CTL); 243262306a36Sopenharmony_ci h2c->w3 |= le32_encode_bits(ra->band_num, RTW89_H2C_RA_W3_BAND_NUM) | 243362306a36Sopenharmony_ci le32_encode_bits(ra->cr_tbl_sel, RTW89_H2C_RA_W3_CR_TBL_SEL) | 243462306a36Sopenharmony_ci le32_encode_bits(ra->fixed_csi_rate_en, RTW89_H2C_RA_W3_FIXED_CSI_RATE_EN) | 243562306a36Sopenharmony_ci le32_encode_bits(ra->ra_csi_rate_en, RTW89_H2C_RA_W3_RA_CSI_RATE_EN) | 243662306a36Sopenharmony_ci le32_encode_bits(ra->csi_mcs_ss_idx, RTW89_H2C_RA_W3_FIXED_CSI_MCS_SS_IDX) | 243762306a36Sopenharmony_ci le32_encode_bits(ra->csi_mode, RTW89_H2C_RA_W3_FIXED_CSI_MODE) | 243862306a36Sopenharmony_ci le32_encode_bits(ra->csi_gi_ltf, RTW89_H2C_RA_W3_FIXED_CSI_GI_LTF) | 243962306a36Sopenharmony_ci le32_encode_bits(ra->csi_bw, RTW89_H2C_RA_W3_FIXED_CSI_BW); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_cidone: 244262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 244362306a36Sopenharmony_ci H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RA, 244462306a36Sopenharmony_ci H2C_FUNC_OUTSRC_RA_MACIDCFG, 0, 0, 244562306a36Sopenharmony_ci len); 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 244862306a36Sopenharmony_ci if (ret) { 244962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 245062306a36Sopenharmony_ci goto fail; 245162306a36Sopenharmony_ci } 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci return 0; 245462306a36Sopenharmony_cifail: 245562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci return ret; 245862306a36Sopenharmony_ci} 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ciint rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev) 246162306a36Sopenharmony_ci{ 246262306a36Sopenharmony_ci struct rtw89_btc *btc = &rtwdev->btc; 246362306a36Sopenharmony_ci struct rtw89_btc_dm *dm = &btc->dm; 246462306a36Sopenharmony_ci struct rtw89_btc_init_info *init_info = &dm->init_info; 246562306a36Sopenharmony_ci struct rtw89_btc_module *module = &init_info->module; 246662306a36Sopenharmony_ci struct rtw89_btc_ant_info *ant = &module->ant; 246762306a36Sopenharmony_ci struct rtw89_h2c_cxinit *h2c; 246862306a36Sopenharmony_ci u32 len = sizeof(*h2c); 246962306a36Sopenharmony_ci struct sk_buff *skb; 247062306a36Sopenharmony_ci int ret; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 247362306a36Sopenharmony_ci if (!skb) { 247462306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_init\n"); 247562306a36Sopenharmony_ci return -ENOMEM; 247662306a36Sopenharmony_ci } 247762306a36Sopenharmony_ci skb_put(skb, len); 247862306a36Sopenharmony_ci h2c = (struct rtw89_h2c_cxinit *)skb->data; 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci h2c->hdr.type = CXDRVINFO_INIT; 248162306a36Sopenharmony_ci h2c->hdr.len = len - H2C_LEN_CXDRVHDR; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci h2c->ant_type = ant->type; 248462306a36Sopenharmony_ci h2c->ant_num = ant->num; 248562306a36Sopenharmony_ci h2c->ant_iso = ant->isolation; 248662306a36Sopenharmony_ci h2c->ant_info = 248762306a36Sopenharmony_ci u8_encode_bits(ant->single_pos, RTW89_H2C_CXINIT_ANT_INFO_POS) | 248862306a36Sopenharmony_ci u8_encode_bits(ant->diversity, RTW89_H2C_CXINIT_ANT_INFO_DIVERSITY) | 248962306a36Sopenharmony_ci u8_encode_bits(ant->btg_pos, RTW89_H2C_CXINIT_ANT_INFO_BTG_POS) | 249062306a36Sopenharmony_ci u8_encode_bits(ant->stream_cnt, RTW89_H2C_CXINIT_ANT_INFO_STREAM_CNT); 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci h2c->mod_rfe = module->rfe_type; 249362306a36Sopenharmony_ci h2c->mod_cv = module->cv; 249462306a36Sopenharmony_ci h2c->mod_info = 249562306a36Sopenharmony_ci u8_encode_bits(module->bt_solo, RTW89_H2C_CXINIT_MOD_INFO_BT_SOLO) | 249662306a36Sopenharmony_ci u8_encode_bits(module->bt_pos, RTW89_H2C_CXINIT_MOD_INFO_BT_POS) | 249762306a36Sopenharmony_ci u8_encode_bits(module->switch_type, RTW89_H2C_CXINIT_MOD_INFO_SW_TYPE) | 249862306a36Sopenharmony_ci u8_encode_bits(module->wa_type, RTW89_H2C_CXINIT_MOD_INFO_WA_TYPE); 249962306a36Sopenharmony_ci h2c->mod_adie_kt = module->kt_ver_adie; 250062306a36Sopenharmony_ci h2c->wl_gch = init_info->wl_guard_ch; 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci h2c->info = 250362306a36Sopenharmony_ci u8_encode_bits(init_info->wl_only, RTW89_H2C_CXINIT_INFO_WL_ONLY) | 250462306a36Sopenharmony_ci u8_encode_bits(init_info->wl_init_ok, RTW89_H2C_CXINIT_INFO_WL_INITOK) | 250562306a36Sopenharmony_ci u8_encode_bits(init_info->dbcc_en, RTW89_H2C_CXINIT_INFO_DBCC_EN) | 250662306a36Sopenharmony_ci u8_encode_bits(init_info->cx_other, RTW89_H2C_CXINIT_INFO_CX_OTHER) | 250762306a36Sopenharmony_ci u8_encode_bits(init_info->bt_only, RTW89_H2C_CXINIT_INFO_BT_ONLY); 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 251062306a36Sopenharmony_ci H2C_CAT_OUTSRC, BTFC_SET, 251162306a36Sopenharmony_ci SET_DRV_INFO, 0, 0, 251262306a36Sopenharmony_ci len); 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 251562306a36Sopenharmony_ci if (ret) { 251662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 251762306a36Sopenharmony_ci goto fail; 251862306a36Sopenharmony_ci } 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci return 0; 252162306a36Sopenharmony_cifail: 252262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci return ret; 252562306a36Sopenharmony_ci} 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci#define PORT_DATA_OFFSET 4 252862306a36Sopenharmony_ci#define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12 252962306a36Sopenharmony_ci#define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \ 253062306a36Sopenharmony_ci (4 + 12 * (max_role_num) + H2C_LEN_CXDRVHDR) 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ciint rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) 253362306a36Sopenharmony_ci{ 253462306a36Sopenharmony_ci struct rtw89_btc *btc = &rtwdev->btc; 253562306a36Sopenharmony_ci const struct rtw89_btc_ver *ver = btc->ver; 253662306a36Sopenharmony_ci struct rtw89_btc_wl_info *wl = &btc->cx.wl; 253762306a36Sopenharmony_ci struct rtw89_btc_wl_role_info *role_info = &wl->role_info; 253862306a36Sopenharmony_ci struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; 253962306a36Sopenharmony_ci struct rtw89_btc_wl_active_role *active = role_info->active_role; 254062306a36Sopenharmony_ci struct sk_buff *skb; 254162306a36Sopenharmony_ci u32 len; 254262306a36Sopenharmony_ci u8 offset = 0; 254362306a36Sopenharmony_ci u8 *cmd; 254462306a36Sopenharmony_ci int ret; 254562306a36Sopenharmony_ci int i; 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci len = H2C_LEN_CXDRVINFO_ROLE_SIZE(ver->max_role_num); 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 255062306a36Sopenharmony_ci if (!skb) { 255162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); 255262306a36Sopenharmony_ci return -ENOMEM; 255362306a36Sopenharmony_ci } 255462306a36Sopenharmony_ci skb_put(skb, len); 255562306a36Sopenharmony_ci cmd = skb->data; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); 255862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); 256162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_NONE(cmd, bpos->none); 256462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_STA(cmd, bpos->station); 256562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_AP(cmd, bpos->ap); 256662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_VAP(cmd, bpos->vap); 256762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC(cmd, bpos->adhoc); 256862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC_MASTER(cmd, bpos->adhoc_master); 256962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_MESH(cmd, bpos->mesh); 257062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_MONITOR(cmd, bpos->moniter); 257162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_DEV(cmd, bpos->p2p_device); 257262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GC(cmd, bpos->p2p_gc); 257362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GO(cmd, bpos->p2p_go); 257462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_NAN(cmd, bpos->nan); 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci for (i = 0; i < RTW89_PORT_NUM; i++, active++) { 257762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CONNECTED(cmd, active->connected, i, offset); 257862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_PID(cmd, active->pid, i, offset); 257962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_PHY(cmd, active->phy, i, offset); 258062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_NOA(cmd, active->noa, i, offset); 258162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_BAND(cmd, active->band, i, offset); 258262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CLIENT_PS(cmd, active->client_ps, i, offset); 258362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_BW(cmd, active->bw, i, offset); 258462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_ROLE(cmd, active->role, i, offset); 258562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CH(cmd, active->ch, i, offset); 258662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_TX_LVL(cmd, active->tx_lvl, i, offset); 258762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_RX_LVL(cmd, active->rx_lvl, i, offset); 258862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_TX_RATE(cmd, active->tx_rate, i, offset); 258962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_RX_RATE(cmd, active->rx_rate, i, offset); 259062306a36Sopenharmony_ci } 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 259362306a36Sopenharmony_ci H2C_CAT_OUTSRC, BTFC_SET, 259462306a36Sopenharmony_ci SET_DRV_INFO, 0, 0, 259562306a36Sopenharmony_ci len); 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 259862306a36Sopenharmony_ci if (ret) { 259962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 260062306a36Sopenharmony_ci goto fail; 260162306a36Sopenharmony_ci } 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci return 0; 260462306a36Sopenharmony_cifail: 260562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci return ret; 260862306a36Sopenharmony_ci} 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci#define H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(max_role_num) \ 261162306a36Sopenharmony_ci (4 + 16 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR) 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ciint rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) 261462306a36Sopenharmony_ci{ 261562306a36Sopenharmony_ci struct rtw89_btc *btc = &rtwdev->btc; 261662306a36Sopenharmony_ci const struct rtw89_btc_ver *ver = btc->ver; 261762306a36Sopenharmony_ci struct rtw89_btc_wl_info *wl = &btc->cx.wl; 261862306a36Sopenharmony_ci struct rtw89_btc_wl_role_info_v1 *role_info = &wl->role_info_v1; 261962306a36Sopenharmony_ci struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; 262062306a36Sopenharmony_ci struct rtw89_btc_wl_active_role_v1 *active = role_info->active_role_v1; 262162306a36Sopenharmony_ci struct sk_buff *skb; 262262306a36Sopenharmony_ci u32 len; 262362306a36Sopenharmony_ci u8 *cmd, offset; 262462306a36Sopenharmony_ci int ret; 262562306a36Sopenharmony_ci int i; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci len = H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(ver->max_role_num); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 263062306a36Sopenharmony_ci if (!skb) { 263162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); 263262306a36Sopenharmony_ci return -ENOMEM; 263362306a36Sopenharmony_ci } 263462306a36Sopenharmony_ci skb_put(skb, len); 263562306a36Sopenharmony_ci cmd = skb->data; 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); 263862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); 264162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_NONE(cmd, bpos->none); 264462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_STA(cmd, bpos->station); 264562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_AP(cmd, bpos->ap); 264662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_VAP(cmd, bpos->vap); 264762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC(cmd, bpos->adhoc); 264862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC_MASTER(cmd, bpos->adhoc_master); 264962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_MESH(cmd, bpos->mesh); 265062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_MONITOR(cmd, bpos->moniter); 265162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_DEV(cmd, bpos->p2p_device); 265262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GC(cmd, bpos->p2p_gc); 265362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GO(cmd, bpos->p2p_go); 265462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_NAN(cmd, bpos->nan); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci offset = PORT_DATA_OFFSET; 265762306a36Sopenharmony_ci for (i = 0; i < RTW89_PORT_NUM; i++, active++) { 265862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CONNECTED(cmd, active->connected, i, offset); 265962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_PID(cmd, active->pid, i, offset); 266062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_PHY(cmd, active->phy, i, offset); 266162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_NOA(cmd, active->noa, i, offset); 266262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_BAND(cmd, active->band, i, offset); 266362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CLIENT_PS(cmd, active->client_ps, i, offset); 266462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_BW(cmd, active->bw, i, offset); 266562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_ROLE(cmd, active->role, i, offset); 266662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CH(cmd, active->ch, i, offset); 266762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_TX_LVL(cmd, active->tx_lvl, i, offset); 266862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_RX_LVL(cmd, active->rx_lvl, i, offset); 266962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_TX_RATE(cmd, active->tx_rate, i, offset); 267062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_RX_RATE(cmd, active->rx_rate, i, offset); 267162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_NOA_DUR(cmd, active->noa_duration, i, offset); 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci offset = len - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN; 267562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_MROLE_TYPE(cmd, role_info->mrole_type, offset); 267662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_MROLE_NOA(cmd, role_info->mrole_noa_duration, offset); 267762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_DBCC_EN(cmd, role_info->dbcc_en, offset); 267862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_DBCC_CHG(cmd, role_info->dbcc_chg, offset); 267962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_DBCC_2G_PHY(cmd, role_info->dbcc_2g_phy, offset); 268062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_LINK_MODE_CHG(cmd, role_info->link_mode_chg, offset); 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 268362306a36Sopenharmony_ci H2C_CAT_OUTSRC, BTFC_SET, 268462306a36Sopenharmony_ci SET_DRV_INFO, 0, 0, 268562306a36Sopenharmony_ci len); 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 268862306a36Sopenharmony_ci if (ret) { 268962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 269062306a36Sopenharmony_ci goto fail; 269162306a36Sopenharmony_ci } 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci return 0; 269462306a36Sopenharmony_cifail: 269562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci return ret; 269862306a36Sopenharmony_ci} 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci#define H2C_LEN_CXDRVINFO_ROLE_SIZE_V2(max_role_num) \ 270162306a36Sopenharmony_ci (4 + 8 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR) 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ciint rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev) 270462306a36Sopenharmony_ci{ 270562306a36Sopenharmony_ci struct rtw89_btc *btc = &rtwdev->btc; 270662306a36Sopenharmony_ci const struct rtw89_btc_ver *ver = btc->ver; 270762306a36Sopenharmony_ci struct rtw89_btc_wl_info *wl = &btc->cx.wl; 270862306a36Sopenharmony_ci struct rtw89_btc_wl_role_info_v2 *role_info = &wl->role_info_v2; 270962306a36Sopenharmony_ci struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; 271062306a36Sopenharmony_ci struct rtw89_btc_wl_active_role_v2 *active = role_info->active_role_v2; 271162306a36Sopenharmony_ci struct sk_buff *skb; 271262306a36Sopenharmony_ci u32 len; 271362306a36Sopenharmony_ci u8 *cmd, offset; 271462306a36Sopenharmony_ci int ret; 271562306a36Sopenharmony_ci int i; 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci len = H2C_LEN_CXDRVINFO_ROLE_SIZE_V2(ver->max_role_num); 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 272062306a36Sopenharmony_ci if (!skb) { 272162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); 272262306a36Sopenharmony_ci return -ENOMEM; 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci skb_put(skb, len); 272562306a36Sopenharmony_ci cmd = skb->data; 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); 272862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); 273162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_NONE(cmd, bpos->none); 273462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_STA(cmd, bpos->station); 273562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_AP(cmd, bpos->ap); 273662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_VAP(cmd, bpos->vap); 273762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC(cmd, bpos->adhoc); 273862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC_MASTER(cmd, bpos->adhoc_master); 273962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_MESH(cmd, bpos->mesh); 274062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_MONITOR(cmd, bpos->moniter); 274162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_DEV(cmd, bpos->p2p_device); 274262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GC(cmd, bpos->p2p_gc); 274362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GO(cmd, bpos->p2p_go); 274462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ROLE_NAN(cmd, bpos->nan); 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci offset = PORT_DATA_OFFSET; 274762306a36Sopenharmony_ci for (i = 0; i < RTW89_PORT_NUM; i++, active++) { 274862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CONNECTED_V2(cmd, active->connected, i, offset); 274962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_PID_V2(cmd, active->pid, i, offset); 275062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_PHY_V2(cmd, active->phy, i, offset); 275162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_NOA_V2(cmd, active->noa, i, offset); 275262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_BAND_V2(cmd, active->band, i, offset); 275362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CLIENT_PS_V2(cmd, active->client_ps, i, offset); 275462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_BW_V2(cmd, active->bw, i, offset); 275562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_ROLE_V2(cmd, active->role, i, offset); 275662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_CH_V2(cmd, active->ch, i, offset); 275762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_ACT_NOA_DUR_V2(cmd, active->noa_duration, i, offset); 275862306a36Sopenharmony_ci } 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci offset = len - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN; 276162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_MROLE_TYPE(cmd, role_info->mrole_type, offset); 276262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_MROLE_NOA(cmd, role_info->mrole_noa_duration, offset); 276362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_DBCC_EN(cmd, role_info->dbcc_en, offset); 276462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_DBCC_CHG(cmd, role_info->dbcc_chg, offset); 276562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_DBCC_2G_PHY(cmd, role_info->dbcc_2g_phy, offset); 276662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXROLE_LINK_MODE_CHG(cmd, role_info->link_mode_chg, offset); 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 276962306a36Sopenharmony_ci H2C_CAT_OUTSRC, BTFC_SET, 277062306a36Sopenharmony_ci SET_DRV_INFO, 0, 0, 277162306a36Sopenharmony_ci len); 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 277462306a36Sopenharmony_ci if (ret) { 277562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 277662306a36Sopenharmony_ci goto fail; 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci return 0; 278062306a36Sopenharmony_cifail: 278162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci return ret; 278462306a36Sopenharmony_ci} 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci#define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR) 278762306a36Sopenharmony_ciint rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) 278862306a36Sopenharmony_ci{ 278962306a36Sopenharmony_ci struct rtw89_btc *btc = &rtwdev->btc; 279062306a36Sopenharmony_ci const struct rtw89_btc_ver *ver = btc->ver; 279162306a36Sopenharmony_ci struct rtw89_btc_ctrl *ctrl = &btc->ctrl; 279262306a36Sopenharmony_ci struct sk_buff *skb; 279362306a36Sopenharmony_ci u8 *cmd; 279462306a36Sopenharmony_ci int ret; 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_CTRL); 279762306a36Sopenharmony_ci if (!skb) { 279862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n"); 279962306a36Sopenharmony_ci return -ENOMEM; 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci skb_put(skb, H2C_LEN_CXDRVINFO_CTRL); 280262306a36Sopenharmony_ci cmd = skb->data; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_CTRL); 280562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_CTRL - H2C_LEN_CXDRVHDR); 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, ctrl->manual); 280862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXCTRL_IGNORE_BT(cmd, ctrl->igno_bt); 280962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXCTRL_ALWAYS_FREERUN(cmd, ctrl->always_freerun); 281062306a36Sopenharmony_ci if (ver->fcxctrl == 0) 281162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXCTRL_TRACE_STEP(cmd, ctrl->trace_step); 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 281462306a36Sopenharmony_ci H2C_CAT_OUTSRC, BTFC_SET, 281562306a36Sopenharmony_ci SET_DRV_INFO, 0, 0, 281662306a36Sopenharmony_ci H2C_LEN_CXDRVINFO_CTRL); 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 281962306a36Sopenharmony_ci if (ret) { 282062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 282162306a36Sopenharmony_ci goto fail; 282262306a36Sopenharmony_ci } 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci return 0; 282562306a36Sopenharmony_cifail: 282662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci return ret; 282962306a36Sopenharmony_ci} 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci#define H2C_LEN_CXDRVINFO_TRX (28 + H2C_LEN_CXDRVHDR) 283262306a36Sopenharmony_ciint rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev) 283362306a36Sopenharmony_ci{ 283462306a36Sopenharmony_ci struct rtw89_btc *btc = &rtwdev->btc; 283562306a36Sopenharmony_ci struct rtw89_btc_trx_info *trx = &btc->dm.trx_info; 283662306a36Sopenharmony_ci struct sk_buff *skb; 283762306a36Sopenharmony_ci u8 *cmd; 283862306a36Sopenharmony_ci int ret; 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_TRX); 284162306a36Sopenharmony_ci if (!skb) { 284262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_trx\n"); 284362306a36Sopenharmony_ci return -ENOMEM; 284462306a36Sopenharmony_ci } 284562306a36Sopenharmony_ci skb_put(skb, H2C_LEN_CXDRVINFO_TRX); 284662306a36Sopenharmony_ci cmd = skb->data; 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_TRX); 284962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_TRX - H2C_LEN_CXDRVHDR); 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_TXLV(cmd, trx->tx_lvl); 285262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_RXLV(cmd, trx->rx_lvl); 285362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_WLRSSI(cmd, trx->wl_rssi); 285462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_BTRSSI(cmd, trx->bt_rssi); 285562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_TXPWR(cmd, trx->tx_power); 285662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_RXGAIN(cmd, trx->rx_gain); 285762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_BTTXPWR(cmd, trx->bt_tx_power); 285862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_BTRXGAIN(cmd, trx->bt_rx_gain); 285962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_CN(cmd, trx->cn); 286062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_NHM(cmd, trx->nhm); 286162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_BTPROFILE(cmd, trx->bt_profile); 286262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_RSVD2(cmd, trx->rsvd2); 286362306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_TXRATE(cmd, trx->tx_rate); 286462306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_RXRATE(cmd, trx->rx_rate); 286562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_TXTP(cmd, trx->tx_tp); 286662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_RXTP(cmd, trx->rx_tp); 286762306a36Sopenharmony_ci RTW89_SET_FWCMD_CXTRX_RXERRRA(cmd, trx->rx_err_ratio); 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 287062306a36Sopenharmony_ci H2C_CAT_OUTSRC, BTFC_SET, 287162306a36Sopenharmony_ci SET_DRV_INFO, 0, 0, 287262306a36Sopenharmony_ci H2C_LEN_CXDRVINFO_TRX); 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 287562306a36Sopenharmony_ci if (ret) { 287662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 287762306a36Sopenharmony_ci goto fail; 287862306a36Sopenharmony_ci } 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci return 0; 288162306a36Sopenharmony_cifail: 288262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci return ret; 288562306a36Sopenharmony_ci} 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci#define H2C_LEN_CXDRVINFO_RFK (4 + H2C_LEN_CXDRVHDR) 288862306a36Sopenharmony_ciint rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev) 288962306a36Sopenharmony_ci{ 289062306a36Sopenharmony_ci struct rtw89_btc *btc = &rtwdev->btc; 289162306a36Sopenharmony_ci struct rtw89_btc_wl_info *wl = &btc->cx.wl; 289262306a36Sopenharmony_ci struct rtw89_btc_wl_rfk_info *rfk_info = &wl->rfk_info; 289362306a36Sopenharmony_ci struct sk_buff *skb; 289462306a36Sopenharmony_ci u8 *cmd; 289562306a36Sopenharmony_ci int ret; 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_RFK); 289862306a36Sopenharmony_ci if (!skb) { 289962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n"); 290062306a36Sopenharmony_ci return -ENOMEM; 290162306a36Sopenharmony_ci } 290262306a36Sopenharmony_ci skb_put(skb, H2C_LEN_CXDRVINFO_RFK); 290362306a36Sopenharmony_ci cmd = skb->data; 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_RFK); 290662306a36Sopenharmony_ci RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_RFK - H2C_LEN_CXDRVHDR); 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci RTW89_SET_FWCMD_CXRFK_STATE(cmd, rfk_info->state); 290962306a36Sopenharmony_ci RTW89_SET_FWCMD_CXRFK_PATH_MAP(cmd, rfk_info->path_map); 291062306a36Sopenharmony_ci RTW89_SET_FWCMD_CXRFK_PHY_MAP(cmd, rfk_info->phy_map); 291162306a36Sopenharmony_ci RTW89_SET_FWCMD_CXRFK_BAND(cmd, rfk_info->band); 291262306a36Sopenharmony_ci RTW89_SET_FWCMD_CXRFK_TYPE(cmd, rfk_info->type); 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 291562306a36Sopenharmony_ci H2C_CAT_OUTSRC, BTFC_SET, 291662306a36Sopenharmony_ci SET_DRV_INFO, 0, 0, 291762306a36Sopenharmony_ci H2C_LEN_CXDRVINFO_RFK); 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 292062306a36Sopenharmony_ci if (ret) { 292162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 292262306a36Sopenharmony_ci goto fail; 292362306a36Sopenharmony_ci } 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci return 0; 292662306a36Sopenharmony_cifail: 292762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci return ret; 293062306a36Sopenharmony_ci} 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci#define H2C_LEN_PKT_OFLD 4 293362306a36Sopenharmony_ciint rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id) 293462306a36Sopenharmony_ci{ 293562306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; 293662306a36Sopenharmony_ci struct sk_buff *skb; 293762306a36Sopenharmony_ci unsigned int cond; 293862306a36Sopenharmony_ci u8 *cmd; 293962306a36Sopenharmony_ci int ret; 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_PKT_OFLD); 294262306a36Sopenharmony_ci if (!skb) { 294362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c pkt offload\n"); 294462306a36Sopenharmony_ci return -ENOMEM; 294562306a36Sopenharmony_ci } 294662306a36Sopenharmony_ci skb_put(skb, H2C_LEN_PKT_OFLD); 294762306a36Sopenharmony_ci cmd = skb->data; 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci RTW89_SET_FWCMD_PACKET_OFLD_PKT_IDX(cmd, id); 295062306a36Sopenharmony_ci RTW89_SET_FWCMD_PACKET_OFLD_PKT_OP(cmd, RTW89_PKT_OFLD_OP_DEL); 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 295362306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 295462306a36Sopenharmony_ci H2C_FUNC_PACKET_OFLD, 1, 1, 295562306a36Sopenharmony_ci H2C_LEN_PKT_OFLD); 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(id, RTW89_PKT_OFLD_OP_DEL); 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 296062306a36Sopenharmony_ci if (ret < 0) { 296162306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, 296262306a36Sopenharmony_ci "failed to del pkt ofld: id %d, ret %d\n", 296362306a36Sopenharmony_ci id, ret); 296462306a36Sopenharmony_ci return ret; 296562306a36Sopenharmony_ci } 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci rtw89_core_release_bit_map(rtwdev->pkt_offload, id); 296862306a36Sopenharmony_ci return 0; 296962306a36Sopenharmony_ci} 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ciint rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, 297262306a36Sopenharmony_ci struct sk_buff *skb_ofld) 297362306a36Sopenharmony_ci{ 297462306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; 297562306a36Sopenharmony_ci struct sk_buff *skb; 297662306a36Sopenharmony_ci unsigned int cond; 297762306a36Sopenharmony_ci u8 *cmd; 297862306a36Sopenharmony_ci u8 alloc_id; 297962306a36Sopenharmony_ci int ret; 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci alloc_id = rtw89_core_acquire_bit_map(rtwdev->pkt_offload, 298262306a36Sopenharmony_ci RTW89_MAX_PKT_OFLD_NUM); 298362306a36Sopenharmony_ci if (alloc_id == RTW89_MAX_PKT_OFLD_NUM) 298462306a36Sopenharmony_ci return -ENOSPC; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci *id = alloc_id; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_PKT_OFLD + skb_ofld->len); 298962306a36Sopenharmony_ci if (!skb) { 299062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c pkt offload\n"); 299162306a36Sopenharmony_ci rtw89_core_release_bit_map(rtwdev->pkt_offload, alloc_id); 299262306a36Sopenharmony_ci return -ENOMEM; 299362306a36Sopenharmony_ci } 299462306a36Sopenharmony_ci skb_put(skb, H2C_LEN_PKT_OFLD); 299562306a36Sopenharmony_ci cmd = skb->data; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci RTW89_SET_FWCMD_PACKET_OFLD_PKT_IDX(cmd, alloc_id); 299862306a36Sopenharmony_ci RTW89_SET_FWCMD_PACKET_OFLD_PKT_OP(cmd, RTW89_PKT_OFLD_OP_ADD); 299962306a36Sopenharmony_ci RTW89_SET_FWCMD_PACKET_OFLD_PKT_LENGTH(cmd, skb_ofld->len); 300062306a36Sopenharmony_ci skb_put_data(skb, skb_ofld->data, skb_ofld->len); 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 300362306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 300462306a36Sopenharmony_ci H2C_FUNC_PACKET_OFLD, 1, 1, 300562306a36Sopenharmony_ci H2C_LEN_PKT_OFLD + skb_ofld->len); 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(alloc_id, RTW89_PKT_OFLD_OP_ADD); 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 301062306a36Sopenharmony_ci if (ret < 0) { 301162306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, 301262306a36Sopenharmony_ci "failed to add pkt ofld: id %d, ret %d\n", 301362306a36Sopenharmony_ci alloc_id, ret); 301462306a36Sopenharmony_ci rtw89_core_release_bit_map(rtwdev->pkt_offload, alloc_id); 301562306a36Sopenharmony_ci return ret; 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci return 0; 301962306a36Sopenharmony_ci} 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci#define H2C_LEN_SCAN_LIST_OFFLOAD 4 302262306a36Sopenharmony_ciint rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len, 302362306a36Sopenharmony_ci struct list_head *chan_list) 302462306a36Sopenharmony_ci{ 302562306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; 302662306a36Sopenharmony_ci struct rtw89_mac_chinfo *ch_info; 302762306a36Sopenharmony_ci struct sk_buff *skb; 302862306a36Sopenharmony_ci int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE; 302962306a36Sopenharmony_ci unsigned int cond; 303062306a36Sopenharmony_ci u8 *cmd; 303162306a36Sopenharmony_ci int ret; 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, skb_len); 303462306a36Sopenharmony_ci if (!skb) { 303562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n"); 303662306a36Sopenharmony_ci return -ENOMEM; 303762306a36Sopenharmony_ci } 303862306a36Sopenharmony_ci skb_put(skb, H2C_LEN_SCAN_LIST_OFFLOAD); 303962306a36Sopenharmony_ci cmd = skb->data; 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci RTW89_SET_FWCMD_SCANOFLD_CH_NUM(cmd, len); 304262306a36Sopenharmony_ci /* in unit of 4 bytes */ 304362306a36Sopenharmony_ci RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(cmd, RTW89_MAC_CHINFO_SIZE / 4); 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci list_for_each_entry(ch_info, chan_list, list) { 304662306a36Sopenharmony_ci cmd = skb_put(skb, RTW89_MAC_CHINFO_SIZE); 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PERIOD(cmd, ch_info->period); 304962306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_DWELL(cmd, ch_info->dwell_time); 305062306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_CENTER_CH(cmd, ch_info->central_ch); 305162306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PRI_CH(cmd, ch_info->pri_ch); 305262306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_BW(cmd, ch_info->bw); 305362306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_ACTION(cmd, ch_info->notify_action); 305462306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_NUM_PKT(cmd, ch_info->num_pkt); 305562306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_TX(cmd, ch_info->tx_pkt); 305662306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(cmd, ch_info->pause_data); 305762306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_BAND(cmd, ch_info->ch_band); 305862306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT_ID(cmd, ch_info->probe_id); 305962306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_DFS(cmd, ch_info->dfs_ch); 306062306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_TX_NULL(cmd, ch_info->tx_null); 306162306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_RANDOM(cmd, ch_info->rand_seq_num); 306262306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT0(cmd, ch_info->pkt_id[0]); 306362306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT1(cmd, ch_info->pkt_id[1]); 306462306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT2(cmd, ch_info->pkt_id[2]); 306562306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT3(cmd, ch_info->pkt_id[3]); 306662306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT4(cmd, ch_info->pkt_id[4]); 306762306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT5(cmd, ch_info->pkt_id[5]); 306862306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT6(cmd, ch_info->pkt_id[6]); 306962306a36Sopenharmony_ci RTW89_SET_FWCMD_CHINFO_PKT7(cmd, ch_info->pkt_id[7]); 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 307362306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 307462306a36Sopenharmony_ci H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len); 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 307962306a36Sopenharmony_ci if (ret) { 308062306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to add scan ofld ch\n"); 308162306a36Sopenharmony_ci return ret; 308262306a36Sopenharmony_ci } 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci return 0; 308562306a36Sopenharmony_ci} 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ciint rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, 308862306a36Sopenharmony_ci struct rtw89_scan_option *option, 308962306a36Sopenharmony_ci struct rtw89_vif *rtwvif) 309062306a36Sopenharmony_ci{ 309162306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; 309262306a36Sopenharmony_ci struct rtw89_chan *op = &rtwdev->scan_info.op_chan; 309362306a36Sopenharmony_ci struct rtw89_h2c_scanofld *h2c; 309462306a36Sopenharmony_ci u32 len = sizeof(*h2c); 309562306a36Sopenharmony_ci struct sk_buff *skb; 309662306a36Sopenharmony_ci unsigned int cond; 309762306a36Sopenharmony_ci int ret; 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 310062306a36Sopenharmony_ci if (!skb) { 310162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c scan offload\n"); 310262306a36Sopenharmony_ci return -ENOMEM; 310362306a36Sopenharmony_ci } 310462306a36Sopenharmony_ci skb_put(skb, len); 310562306a36Sopenharmony_ci h2c = (struct rtw89_h2c_scanofld *)skb->data; 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) | 310862306a36Sopenharmony_ci le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) | 310962306a36Sopenharmony_ci le32_encode_bits(RTW89_PHY_0, RTW89_H2C_SCANOFLD_W0_BAND) | 311062306a36Sopenharmony_ci le32_encode_bits(option->enable, RTW89_H2C_SCANOFLD_W0_OPERATION); 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci h2c->w1 = le32_encode_bits(true, RTW89_H2C_SCANOFLD_W1_NOTIFY_END) | 311362306a36Sopenharmony_ci le32_encode_bits(option->target_ch_mode, 311462306a36Sopenharmony_ci RTW89_H2C_SCANOFLD_W1_TARGET_CH_MODE) | 311562306a36Sopenharmony_ci le32_encode_bits(RTW89_SCAN_IMMEDIATE, 311662306a36Sopenharmony_ci RTW89_H2C_SCANOFLD_W1_START_MODE) | 311762306a36Sopenharmony_ci le32_encode_bits(RTW89_SCAN_ONCE, RTW89_H2C_SCANOFLD_W1_SCAN_TYPE); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (option->target_ch_mode) { 312062306a36Sopenharmony_ci h2c->w1 |= le32_encode_bits(op->band_width, 312162306a36Sopenharmony_ci RTW89_H2C_SCANOFLD_W1_TARGET_CH_BW) | 312262306a36Sopenharmony_ci le32_encode_bits(op->primary_channel, 312362306a36Sopenharmony_ci RTW89_H2C_SCANOFLD_W1_TARGET_PRI_CH) | 312462306a36Sopenharmony_ci le32_encode_bits(op->channel, 312562306a36Sopenharmony_ci RTW89_H2C_SCANOFLD_W1_TARGET_CENTRAL_CH); 312662306a36Sopenharmony_ci h2c->w0 |= le32_encode_bits(op->band_type, 312762306a36Sopenharmony_ci RTW89_H2C_SCANOFLD_W0_TARGET_CH_BAND); 312862306a36Sopenharmony_ci } 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 313162306a36Sopenharmony_ci H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, 313262306a36Sopenharmony_ci H2C_FUNC_SCANOFLD, 1, 1, 313362306a36Sopenharmony_ci len); 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD); 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 313862306a36Sopenharmony_ci if (ret) { 313962306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to scan ofld\n"); 314062306a36Sopenharmony_ci return ret; 314162306a36Sopenharmony_ci } 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci return 0; 314462306a36Sopenharmony_ci} 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ciint rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, 314762306a36Sopenharmony_ci struct rtw89_fw_h2c_rf_reg_info *info, 314862306a36Sopenharmony_ci u16 len, u8 page) 314962306a36Sopenharmony_ci{ 315062306a36Sopenharmony_ci struct sk_buff *skb; 315162306a36Sopenharmony_ci u8 class = info->rf_path == RF_PATH_A ? 315262306a36Sopenharmony_ci H2C_CL_OUTSRC_RF_REG_A : H2C_CL_OUTSRC_RF_REG_B; 315362306a36Sopenharmony_ci int ret; 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 315662306a36Sopenharmony_ci if (!skb) { 315762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c rf reg\n"); 315862306a36Sopenharmony_ci return -ENOMEM; 315962306a36Sopenharmony_ci } 316062306a36Sopenharmony_ci skb_put_data(skb, info->rtw89_phy_config_rf_h2c[page], len); 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 316362306a36Sopenharmony_ci H2C_CAT_OUTSRC, class, page, 0, 0, 316462306a36Sopenharmony_ci len); 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 316762306a36Sopenharmony_ci if (ret) { 316862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 316962306a36Sopenharmony_ci goto fail; 317062306a36Sopenharmony_ci } 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci return 0; 317362306a36Sopenharmony_cifail: 317462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci return ret; 317762306a36Sopenharmony_ci} 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ciint rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) 318062306a36Sopenharmony_ci{ 318162306a36Sopenharmony_ci const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); 318262306a36Sopenharmony_ci struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; 318362306a36Sopenharmony_ci struct rtw89_fw_h2c_rf_get_mccch *mccch; 318462306a36Sopenharmony_ci struct sk_buff *skb; 318562306a36Sopenharmony_ci int ret; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, sizeof(*mccch)); 318862306a36Sopenharmony_ci if (!skb) { 318962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n"); 319062306a36Sopenharmony_ci return -ENOMEM; 319162306a36Sopenharmony_ci } 319262306a36Sopenharmony_ci skb_put(skb, sizeof(*mccch)); 319362306a36Sopenharmony_ci mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci mccch->ch_0 = cpu_to_le32(rfk_mcc->ch[0]); 319662306a36Sopenharmony_ci mccch->ch_1 = cpu_to_le32(rfk_mcc->ch[1]); 319762306a36Sopenharmony_ci mccch->band_0 = cpu_to_le32(rfk_mcc->band[0]); 319862306a36Sopenharmony_ci mccch->band_1 = cpu_to_le32(rfk_mcc->band[1]); 319962306a36Sopenharmony_ci mccch->current_channel = cpu_to_le32(chan->channel); 320062306a36Sopenharmony_ci mccch->current_band_type = cpu_to_le32(chan->band_type); 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 320362306a36Sopenharmony_ci H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, 320462306a36Sopenharmony_ci H2C_FUNC_OUTSRC_RF_GET_MCCCH, 0, 0, 320562306a36Sopenharmony_ci sizeof(*mccch)); 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 320862306a36Sopenharmony_ci if (ret) { 320962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 321062306a36Sopenharmony_ci goto fail; 321162306a36Sopenharmony_ci } 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_ci return 0; 321462306a36Sopenharmony_cifail: 321562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci return ret; 321862306a36Sopenharmony_ci} 321962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc); 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ciint rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, 322262306a36Sopenharmony_ci u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, 322362306a36Sopenharmony_ci bool rack, bool dack) 322462306a36Sopenharmony_ci{ 322562306a36Sopenharmony_ci struct sk_buff *skb; 322662306a36Sopenharmony_ci int ret; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); 322962306a36Sopenharmony_ci if (!skb) { 323062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for raw with hdr\n"); 323162306a36Sopenharmony_ci return -ENOMEM; 323262306a36Sopenharmony_ci } 323362306a36Sopenharmony_ci skb_put_data(skb, buf, len); 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 323662306a36Sopenharmony_ci H2C_CAT_OUTSRC, h2c_class, h2c_func, rack, dack, 323762306a36Sopenharmony_ci len); 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 324062306a36Sopenharmony_ci if (ret) { 324162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 324262306a36Sopenharmony_ci goto fail; 324362306a36Sopenharmony_ci } 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci return 0; 324662306a36Sopenharmony_cifail: 324762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci return ret; 325062306a36Sopenharmony_ci} 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ciint rtw89_fw_h2c_raw(struct rtw89_dev *rtwdev, const u8 *buf, u16 len) 325362306a36Sopenharmony_ci{ 325462306a36Sopenharmony_ci struct sk_buff *skb; 325562306a36Sopenharmony_ci int ret; 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_no_hdr(rtwdev, len); 325862306a36Sopenharmony_ci if (!skb) { 325962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for h2c raw\n"); 326062306a36Sopenharmony_ci return -ENOMEM; 326162306a36Sopenharmony_ci } 326262306a36Sopenharmony_ci skb_put_data(skb, buf, len); 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 326562306a36Sopenharmony_ci if (ret) { 326662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 326762306a36Sopenharmony_ci goto fail; 326862306a36Sopenharmony_ci } 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci return 0; 327162306a36Sopenharmony_cifail: 327262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci return ret; 327562306a36Sopenharmony_ci} 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_civoid rtw89_fw_send_all_early_h2c(struct rtw89_dev *rtwdev) 327862306a36Sopenharmony_ci{ 327962306a36Sopenharmony_ci struct rtw89_early_h2c *early_h2c; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci lockdep_assert_held(&rtwdev->mutex); 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci list_for_each_entry(early_h2c, &rtwdev->early_h2c_list, list) { 328462306a36Sopenharmony_ci rtw89_fw_h2c_raw(rtwdev, early_h2c->h2c, early_h2c->h2c_len); 328562306a36Sopenharmony_ci } 328662306a36Sopenharmony_ci} 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_civoid rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev) 328962306a36Sopenharmony_ci{ 329062306a36Sopenharmony_ci struct rtw89_early_h2c *early_h2c, *tmp; 329162306a36Sopenharmony_ci 329262306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 329362306a36Sopenharmony_ci list_for_each_entry_safe(early_h2c, tmp, &rtwdev->early_h2c_list, list) { 329462306a36Sopenharmony_ci list_del(&early_h2c->list); 329562306a36Sopenharmony_ci kfree(early_h2c->h2c); 329662306a36Sopenharmony_ci kfree(early_h2c); 329762306a36Sopenharmony_ci } 329862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 329962306a36Sopenharmony_ci} 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_cistatic void rtw89_fw_c2h_parse_attr(struct sk_buff *c2h) 330262306a36Sopenharmony_ci{ 330362306a36Sopenharmony_ci const struct rtw89_c2h_hdr *hdr = (const struct rtw89_c2h_hdr *)c2h->data; 330462306a36Sopenharmony_ci struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h); 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci attr->category = le32_get_bits(hdr->w0, RTW89_C2H_HDR_W0_CATEGORY); 330762306a36Sopenharmony_ci attr->class = le32_get_bits(hdr->w0, RTW89_C2H_HDR_W0_CLASS); 330862306a36Sopenharmony_ci attr->func = le32_get_bits(hdr->w0, RTW89_C2H_HDR_W0_FUNC); 330962306a36Sopenharmony_ci attr->len = le32_get_bits(hdr->w1, RTW89_C2H_HDR_W1_LEN); 331062306a36Sopenharmony_ci} 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_cistatic bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev, 331362306a36Sopenharmony_ci struct sk_buff *c2h) 331462306a36Sopenharmony_ci{ 331562306a36Sopenharmony_ci struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h); 331662306a36Sopenharmony_ci u8 category = attr->category; 331762306a36Sopenharmony_ci u8 class = attr->class; 331862306a36Sopenharmony_ci u8 func = attr->func; 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci switch (category) { 332162306a36Sopenharmony_ci default: 332262306a36Sopenharmony_ci return false; 332362306a36Sopenharmony_ci case RTW89_C2H_CAT_MAC: 332462306a36Sopenharmony_ci return rtw89_mac_c2h_chk_atomic(rtwdev, class, func); 332562306a36Sopenharmony_ci } 332662306a36Sopenharmony_ci} 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_civoid rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h) 332962306a36Sopenharmony_ci{ 333062306a36Sopenharmony_ci rtw89_fw_c2h_parse_attr(c2h); 333162306a36Sopenharmony_ci if (!rtw89_fw_c2h_chk_atomic(rtwdev, c2h)) 333262306a36Sopenharmony_ci goto enqueue; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci rtw89_fw_c2h_cmd_handle(rtwdev, c2h); 333562306a36Sopenharmony_ci dev_kfree_skb_any(c2h); 333662306a36Sopenharmony_ci return; 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_cienqueue: 333962306a36Sopenharmony_ci skb_queue_tail(&rtwdev->c2h_queue, c2h); 334062306a36Sopenharmony_ci ieee80211_queue_work(rtwdev->hw, &rtwdev->c2h_work); 334162306a36Sopenharmony_ci} 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_cistatic void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, 334462306a36Sopenharmony_ci struct sk_buff *skb) 334562306a36Sopenharmony_ci{ 334662306a36Sopenharmony_ci struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); 334762306a36Sopenharmony_ci u8 category = attr->category; 334862306a36Sopenharmony_ci u8 class = attr->class; 334962306a36Sopenharmony_ci u8 func = attr->func; 335062306a36Sopenharmony_ci u16 len = attr->len; 335162306a36Sopenharmony_ci bool dump = true; 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) 335462306a36Sopenharmony_ci return; 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci switch (category) { 335762306a36Sopenharmony_ci case RTW89_C2H_CAT_TEST: 335862306a36Sopenharmony_ci break; 335962306a36Sopenharmony_ci case RTW89_C2H_CAT_MAC: 336062306a36Sopenharmony_ci rtw89_mac_c2h_handle(rtwdev, skb, len, class, func); 336162306a36Sopenharmony_ci if (class == RTW89_MAC_C2H_CLASS_INFO && 336262306a36Sopenharmony_ci func == RTW89_MAC_C2H_FUNC_C2H_LOG) 336362306a36Sopenharmony_ci dump = false; 336462306a36Sopenharmony_ci break; 336562306a36Sopenharmony_ci case RTW89_C2H_CAT_OUTSRC: 336662306a36Sopenharmony_ci if (class >= RTW89_PHY_C2H_CLASS_BTC_MIN && 336762306a36Sopenharmony_ci class <= RTW89_PHY_C2H_CLASS_BTC_MAX) 336862306a36Sopenharmony_ci rtw89_btc_c2h_handle(rtwdev, skb, len, class, func); 336962306a36Sopenharmony_ci else 337062306a36Sopenharmony_ci rtw89_phy_c2h_handle(rtwdev, skb, len, class, func); 337162306a36Sopenharmony_ci break; 337262306a36Sopenharmony_ci } 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci if (dump) 337562306a36Sopenharmony_ci rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "C2H: ", skb->data, skb->len); 337662306a36Sopenharmony_ci} 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_civoid rtw89_fw_c2h_work(struct work_struct *work) 337962306a36Sopenharmony_ci{ 338062306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, 338162306a36Sopenharmony_ci c2h_work); 338262306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) { 338562306a36Sopenharmony_ci skb_unlink(skb, &rtwdev->c2h_queue); 338662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 338762306a36Sopenharmony_ci rtw89_fw_c2h_cmd_handle(rtwdev, skb); 338862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 338962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 339062306a36Sopenharmony_ci } 339162306a36Sopenharmony_ci} 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_cistatic int rtw89_fw_write_h2c_reg(struct rtw89_dev *rtwdev, 339462306a36Sopenharmony_ci struct rtw89_mac_h2c_info *info) 339562306a36Sopenharmony_ci{ 339662306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 339762306a36Sopenharmony_ci struct rtw89_fw_info *fw_info = &rtwdev->fw; 339862306a36Sopenharmony_ci const u32 *h2c_reg = chip->h2c_regs; 339962306a36Sopenharmony_ci u8 i, val, len; 340062306a36Sopenharmony_ci int ret; 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci ret = read_poll_timeout(rtw89_read8, val, val == 0, 1000, 5000, false, 340362306a36Sopenharmony_ci rtwdev, chip->h2c_ctrl_reg); 340462306a36Sopenharmony_ci if (ret) { 340562306a36Sopenharmony_ci rtw89_warn(rtwdev, "FW does not process h2c registers\n"); 340662306a36Sopenharmony_ci return ret; 340762306a36Sopenharmony_ci } 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci len = DIV_ROUND_UP(info->content_len + RTW89_H2CREG_HDR_LEN, 341062306a36Sopenharmony_ci sizeof(info->u.h2creg[0])); 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci u32p_replace_bits(&info->u.hdr.w0, info->id, RTW89_H2CREG_HDR_FUNC_MASK); 341362306a36Sopenharmony_ci u32p_replace_bits(&info->u.hdr.w0, len, RTW89_H2CREG_HDR_LEN_MASK); 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci for (i = 0; i < RTW89_H2CREG_MAX; i++) 341662306a36Sopenharmony_ci rtw89_write32(rtwdev, h2c_reg[i], info->u.h2creg[i]); 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci fw_info->h2c_counter++; 341962306a36Sopenharmony_ci rtw89_write8_mask(rtwdev, chip->h2c_counter_reg.addr, 342062306a36Sopenharmony_ci chip->h2c_counter_reg.mask, fw_info->h2c_counter); 342162306a36Sopenharmony_ci rtw89_write8(rtwdev, chip->h2c_ctrl_reg, B_AX_H2CREG_TRIGGER); 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci return 0; 342462306a36Sopenharmony_ci} 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_cistatic int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev, 342762306a36Sopenharmony_ci struct rtw89_mac_c2h_info *info) 342862306a36Sopenharmony_ci{ 342962306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 343062306a36Sopenharmony_ci struct rtw89_fw_info *fw_info = &rtwdev->fw; 343162306a36Sopenharmony_ci const u32 *c2h_reg = chip->c2h_regs; 343262306a36Sopenharmony_ci u32 ret; 343362306a36Sopenharmony_ci u8 i, val; 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci info->id = RTW89_FWCMD_C2HREG_FUNC_NULL; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci ret = read_poll_timeout_atomic(rtw89_read8, val, val, 1, 343862306a36Sopenharmony_ci RTW89_C2H_TIMEOUT, false, rtwdev, 343962306a36Sopenharmony_ci chip->c2h_ctrl_reg); 344062306a36Sopenharmony_ci if (ret) { 344162306a36Sopenharmony_ci rtw89_warn(rtwdev, "c2h reg timeout\n"); 344262306a36Sopenharmony_ci return ret; 344362306a36Sopenharmony_ci } 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci for (i = 0; i < RTW89_C2HREG_MAX; i++) 344662306a36Sopenharmony_ci info->u.c2hreg[i] = rtw89_read32(rtwdev, c2h_reg[i]); 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci rtw89_write8(rtwdev, chip->c2h_ctrl_reg, 0); 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci info->id = u32_get_bits(info->u.hdr.w0, RTW89_C2HREG_HDR_FUNC_MASK); 345162306a36Sopenharmony_ci info->content_len = 345262306a36Sopenharmony_ci (u32_get_bits(info->u.hdr.w0, RTW89_C2HREG_HDR_LEN_MASK) << 2) - 345362306a36Sopenharmony_ci RTW89_C2HREG_HDR_LEN; 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci fw_info->c2h_counter++; 345662306a36Sopenharmony_ci rtw89_write8_mask(rtwdev, chip->c2h_counter_reg.addr, 345762306a36Sopenharmony_ci chip->c2h_counter_reg.mask, fw_info->c2h_counter); 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci return 0; 346062306a36Sopenharmony_ci} 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ciint rtw89_fw_msg_reg(struct rtw89_dev *rtwdev, 346362306a36Sopenharmony_ci struct rtw89_mac_h2c_info *h2c_info, 346462306a36Sopenharmony_ci struct rtw89_mac_c2h_info *c2h_info) 346562306a36Sopenharmony_ci{ 346662306a36Sopenharmony_ci u32 ret; 346762306a36Sopenharmony_ci 346862306a36Sopenharmony_ci if (h2c_info && h2c_info->id != RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE) 346962306a36Sopenharmony_ci lockdep_assert_held(&rtwdev->mutex); 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci if (!h2c_info && !c2h_info) 347262306a36Sopenharmony_ci return -EINVAL; 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci if (!h2c_info) 347562306a36Sopenharmony_ci goto recv_c2h; 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci ret = rtw89_fw_write_h2c_reg(rtwdev, h2c_info); 347862306a36Sopenharmony_ci if (ret) 347962306a36Sopenharmony_ci return ret; 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_cirecv_c2h: 348262306a36Sopenharmony_ci if (!c2h_info) 348362306a36Sopenharmony_ci return 0; 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci ret = rtw89_fw_read_c2h_reg(rtwdev, c2h_info); 348662306a36Sopenharmony_ci if (ret) 348762306a36Sopenharmony_ci return ret; 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci return 0; 349062306a36Sopenharmony_ci} 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_civoid rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev) 349362306a36Sopenharmony_ci{ 349462306a36Sopenharmony_ci if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) { 349562306a36Sopenharmony_ci rtw89_err(rtwdev, "[ERR]pwr is off\n"); 349662306a36Sopenharmony_ci return; 349762306a36Sopenharmony_ci } 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci rtw89_info(rtwdev, "FW status = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM0)); 350062306a36Sopenharmony_ci rtw89_info(rtwdev, "FW BADADDR = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM1)); 350162306a36Sopenharmony_ci rtw89_info(rtwdev, "FW EPC/RA = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM2)); 350262306a36Sopenharmony_ci rtw89_info(rtwdev, "FW MISC = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM3)); 350362306a36Sopenharmony_ci rtw89_info(rtwdev, "R_AX_HALT_C2H = 0x%x\n", 350462306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_HALT_C2H)); 350562306a36Sopenharmony_ci rtw89_info(rtwdev, "R_AX_SER_DBG_INFO = 0x%x\n", 350662306a36Sopenharmony_ci rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci rtw89_fw_prog_cnt_dump(rtwdev); 350962306a36Sopenharmony_ci} 351062306a36Sopenharmony_ci 351162306a36Sopenharmony_cistatic void rtw89_release_pkt_list(struct rtw89_dev *rtwdev) 351262306a36Sopenharmony_ci{ 351362306a36Sopenharmony_ci struct list_head *pkt_list = rtwdev->scan_info.pkt_list; 351462306a36Sopenharmony_ci struct rtw89_pktofld_info *info, *tmp; 351562306a36Sopenharmony_ci u8 idx; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci for (idx = NL80211_BAND_2GHZ; idx < NUM_NL80211_BANDS; idx++) { 351862306a36Sopenharmony_ci if (!(rtwdev->chip->support_bands & BIT(idx))) 351962306a36Sopenharmony_ci continue; 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci list_for_each_entry_safe(info, tmp, &pkt_list[idx], list) { 352262306a36Sopenharmony_ci if (test_bit(info->id, rtwdev->pkt_offload)) 352362306a36Sopenharmony_ci rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); 352462306a36Sopenharmony_ci list_del(&info->list); 352562306a36Sopenharmony_ci kfree(info); 352662306a36Sopenharmony_ci } 352762306a36Sopenharmony_ci } 352862306a36Sopenharmony_ci} 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_cistatic bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, 353162306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 353262306a36Sopenharmony_ci struct rtw89_pktofld_info *info, 353362306a36Sopenharmony_ci enum nl80211_band band, u8 ssid_idx) 353462306a36Sopenharmony_ci{ 353562306a36Sopenharmony_ci struct cfg80211_scan_request *req = rtwvif->scan_req; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci if (band != NL80211_BAND_6GHZ) 353862306a36Sopenharmony_ci return false; 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci if (req->ssids[ssid_idx].ssid_len) { 354162306a36Sopenharmony_ci memcpy(info->ssid, req->ssids[ssid_idx].ssid, 354262306a36Sopenharmony_ci req->ssids[ssid_idx].ssid_len); 354362306a36Sopenharmony_ci info->ssid_len = req->ssids[ssid_idx].ssid_len; 354462306a36Sopenharmony_ci return false; 354562306a36Sopenharmony_ci } else { 354662306a36Sopenharmony_ci return true; 354762306a36Sopenharmony_ci } 354862306a36Sopenharmony_ci} 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_cistatic int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, 355162306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 355262306a36Sopenharmony_ci struct sk_buff *skb, u8 ssid_idx) 355362306a36Sopenharmony_ci{ 355462306a36Sopenharmony_ci struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; 355562306a36Sopenharmony_ci struct ieee80211_scan_ies *ies = rtwvif->scan_ies; 355662306a36Sopenharmony_ci struct rtw89_pktofld_info *info; 355762306a36Sopenharmony_ci struct sk_buff *new; 355862306a36Sopenharmony_ci int ret = 0; 355962306a36Sopenharmony_ci u8 band; 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { 356262306a36Sopenharmony_ci if (!(rtwdev->chip->support_bands & BIT(band))) 356362306a36Sopenharmony_ci continue; 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci new = skb_copy(skb, GFP_KERNEL); 356662306a36Sopenharmony_ci if (!new) { 356762306a36Sopenharmony_ci ret = -ENOMEM; 356862306a36Sopenharmony_ci goto out; 356962306a36Sopenharmony_ci } 357062306a36Sopenharmony_ci skb_put_data(new, ies->ies[band], ies->len[band]); 357162306a36Sopenharmony_ci skb_put_data(new, ies->common_ies, ies->common_ie_len); 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 357462306a36Sopenharmony_ci if (!info) { 357562306a36Sopenharmony_ci ret = -ENOMEM; 357662306a36Sopenharmony_ci kfree_skb(new); 357762306a36Sopenharmony_ci goto out; 357862306a36Sopenharmony_ci } 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci if (rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band, 358162306a36Sopenharmony_ci ssid_idx)) { 358262306a36Sopenharmony_ci kfree_skb(new); 358362306a36Sopenharmony_ci kfree(info); 358462306a36Sopenharmony_ci goto out; 358562306a36Sopenharmony_ci } 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_ci ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new); 358862306a36Sopenharmony_ci if (ret) { 358962306a36Sopenharmony_ci kfree_skb(new); 359062306a36Sopenharmony_ci kfree(info); 359162306a36Sopenharmony_ci goto out; 359262306a36Sopenharmony_ci } 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci list_add_tail(&info->list, &scan_info->pkt_list[band]); 359562306a36Sopenharmony_ci kfree_skb(new); 359662306a36Sopenharmony_ci } 359762306a36Sopenharmony_ciout: 359862306a36Sopenharmony_ci return ret; 359962306a36Sopenharmony_ci} 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_cistatic int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev, 360262306a36Sopenharmony_ci struct rtw89_vif *rtwvif) 360362306a36Sopenharmony_ci{ 360462306a36Sopenharmony_ci struct cfg80211_scan_request *req = rtwvif->scan_req; 360562306a36Sopenharmony_ci struct sk_buff *skb; 360662306a36Sopenharmony_ci u8 num = req->n_ssids, i; 360762306a36Sopenharmony_ci int ret; 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_ci for (i = 0; i < num; i++) { 361062306a36Sopenharmony_ci skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, 361162306a36Sopenharmony_ci req->ssids[i].ssid, 361262306a36Sopenharmony_ci req->ssids[i].ssid_len, 361362306a36Sopenharmony_ci req->ie_len); 361462306a36Sopenharmony_ci if (!skb) 361562306a36Sopenharmony_ci return -ENOMEM; 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_ci ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb, i); 361862306a36Sopenharmony_ci kfree_skb(skb); 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci if (ret) 362162306a36Sopenharmony_ci return ret; 362262306a36Sopenharmony_ci } 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci return 0; 362562306a36Sopenharmony_ci} 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_cistatic int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev, 362862306a36Sopenharmony_ci struct cfg80211_scan_request *req, 362962306a36Sopenharmony_ci struct rtw89_mac_chinfo *ch_info) 363062306a36Sopenharmony_ci{ 363162306a36Sopenharmony_ci struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; 363262306a36Sopenharmony_ci struct list_head *pkt_list = rtwdev->scan_info.pkt_list; 363362306a36Sopenharmony_ci struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 363462306a36Sopenharmony_ci struct ieee80211_scan_ies *ies = rtwvif->scan_ies; 363562306a36Sopenharmony_ci struct cfg80211_scan_6ghz_params *params; 363662306a36Sopenharmony_ci struct rtw89_pktofld_info *info, *tmp; 363762306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 363862306a36Sopenharmony_ci struct sk_buff *skb; 363962306a36Sopenharmony_ci bool found; 364062306a36Sopenharmony_ci int ret = 0; 364162306a36Sopenharmony_ci u8 i; 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci if (!req->n_6ghz_params) 364462306a36Sopenharmony_ci return 0; 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci for (i = 0; i < req->n_6ghz_params; i++) { 364762306a36Sopenharmony_ci params = &req->scan_6ghz_params[i]; 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ci if (req->channels[params->channel_idx]->hw_value != 365062306a36Sopenharmony_ci ch_info->pri_ch) 365162306a36Sopenharmony_ci continue; 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci found = false; 365462306a36Sopenharmony_ci list_for_each_entry(tmp, &pkt_list[NL80211_BAND_6GHZ], list) { 365562306a36Sopenharmony_ci if (ether_addr_equal(tmp->bssid, params->bssid)) { 365662306a36Sopenharmony_ci found = true; 365762306a36Sopenharmony_ci break; 365862306a36Sopenharmony_ci } 365962306a36Sopenharmony_ci } 366062306a36Sopenharmony_ci if (found) 366162306a36Sopenharmony_ci continue; 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, 366462306a36Sopenharmony_ci NULL, 0, req->ie_len); 366562306a36Sopenharmony_ci skb_put_data(skb, ies->ies[NL80211_BAND_6GHZ], ies->len[NL80211_BAND_6GHZ]); 366662306a36Sopenharmony_ci skb_put_data(skb, ies->common_ies, ies->common_ie_len); 366762306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 366862306a36Sopenharmony_ci ether_addr_copy(hdr->addr3, params->bssid); 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 367162306a36Sopenharmony_ci if (!info) { 367262306a36Sopenharmony_ci ret = -ENOMEM; 367362306a36Sopenharmony_ci kfree_skb(skb); 367462306a36Sopenharmony_ci goto out; 367562306a36Sopenharmony_ci } 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_ci ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, skb); 367862306a36Sopenharmony_ci if (ret) { 367962306a36Sopenharmony_ci kfree_skb(skb); 368062306a36Sopenharmony_ci kfree(info); 368162306a36Sopenharmony_ci goto out; 368262306a36Sopenharmony_ci } 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci ether_addr_copy(info->bssid, params->bssid); 368562306a36Sopenharmony_ci info->channel_6ghz = req->channels[params->channel_idx]->hw_value; 368662306a36Sopenharmony_ci list_add_tail(&info->list, &rtwdev->scan_info.pkt_list[NL80211_BAND_6GHZ]); 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_ci ch_info->tx_pkt = true; 368962306a36Sopenharmony_ci ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G; 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci kfree_skb(skb); 369262306a36Sopenharmony_ci } 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_ciout: 369562306a36Sopenharmony_ci return ret; 369662306a36Sopenharmony_ci} 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_cistatic void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, 369962306a36Sopenharmony_ci int ssid_num, 370062306a36Sopenharmony_ci struct rtw89_mac_chinfo *ch_info) 370162306a36Sopenharmony_ci{ 370262306a36Sopenharmony_ci struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; 370362306a36Sopenharmony_ci struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; 370462306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 370562306a36Sopenharmony_ci struct cfg80211_scan_request *req = rtwvif->scan_req; 370662306a36Sopenharmony_ci struct rtw89_chan *op = &rtwdev->scan_info.op_chan; 370762306a36Sopenharmony_ci struct rtw89_pktofld_info *info; 370862306a36Sopenharmony_ci u8 band, probe_count = 0; 370962306a36Sopenharmony_ci int ret; 371062306a36Sopenharmony_ci 371162306a36Sopenharmony_ci ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; 371262306a36Sopenharmony_ci ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; 371362306a36Sopenharmony_ci ch_info->bw = RTW89_SCAN_WIDTH; 371462306a36Sopenharmony_ci ch_info->tx_pkt = true; 371562306a36Sopenharmony_ci ch_info->cfg_tx_pwr = false; 371662306a36Sopenharmony_ci ch_info->tx_pwr_idx = 0; 371762306a36Sopenharmony_ci ch_info->tx_null = false; 371862306a36Sopenharmony_ci ch_info->pause_data = false; 371962306a36Sopenharmony_ci ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE; 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci if (ch_info->ch_band == RTW89_BAND_6G) { 372262306a36Sopenharmony_ci if ((ssid_num == 1 && req->ssids[0].ssid_len == 0) || 372362306a36Sopenharmony_ci !ch_info->is_psc) { 372462306a36Sopenharmony_ci ch_info->tx_pkt = false; 372562306a36Sopenharmony_ci if (!req->duration_mandatory) 372662306a36Sopenharmony_ci ch_info->period -= RTW89_DWELL_TIME_6G; 372762306a36Sopenharmony_ci } 372862306a36Sopenharmony_ci } 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci ret = rtw89_update_6ghz_rnr_chan(rtwdev, req, ch_info); 373162306a36Sopenharmony_ci if (ret) 373262306a36Sopenharmony_ci rtw89_warn(rtwdev, "RNR fails: %d\n", ret); 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci if (ssid_num) { 373562306a36Sopenharmony_ci band = rtw89_hw_to_nl80211_band(ch_info->ch_band); 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci list_for_each_entry(info, &scan_info->pkt_list[band], list) { 373862306a36Sopenharmony_ci if (info->channel_6ghz && 373962306a36Sopenharmony_ci ch_info->pri_ch != info->channel_6ghz) 374062306a36Sopenharmony_ci continue; 374162306a36Sopenharmony_ci ch_info->pkt_id[probe_count++] = info->id; 374262306a36Sopenharmony_ci if (probe_count >= RTW89_SCANOFLD_MAX_SSID) 374362306a36Sopenharmony_ci break; 374462306a36Sopenharmony_ci } 374562306a36Sopenharmony_ci ch_info->num_pkt = probe_count; 374662306a36Sopenharmony_ci } 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci switch (chan_type) { 374962306a36Sopenharmony_ci case RTW89_CHAN_OPERATE: 375062306a36Sopenharmony_ci ch_info->central_ch = op->channel; 375162306a36Sopenharmony_ci ch_info->pri_ch = op->primary_channel; 375262306a36Sopenharmony_ci ch_info->ch_band = op->band_type; 375362306a36Sopenharmony_ci ch_info->bw = op->band_width; 375462306a36Sopenharmony_ci ch_info->tx_null = true; 375562306a36Sopenharmony_ci ch_info->num_pkt = 0; 375662306a36Sopenharmony_ci break; 375762306a36Sopenharmony_ci case RTW89_CHAN_DFS: 375862306a36Sopenharmony_ci if (ch_info->ch_band != RTW89_BAND_6G) 375962306a36Sopenharmony_ci ch_info->period = max_t(u8, ch_info->period, 376062306a36Sopenharmony_ci RTW89_DFS_CHAN_TIME); 376162306a36Sopenharmony_ci ch_info->dwell_time = RTW89_DWELL_TIME; 376262306a36Sopenharmony_ci break; 376362306a36Sopenharmony_ci case RTW89_CHAN_ACTIVE: 376462306a36Sopenharmony_ci break; 376562306a36Sopenharmony_ci default: 376662306a36Sopenharmony_ci rtw89_err(rtwdev, "Channel type out of bound\n"); 376762306a36Sopenharmony_ci } 376862306a36Sopenharmony_ci} 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_cistatic int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, 377162306a36Sopenharmony_ci struct rtw89_vif *rtwvif, bool connected) 377262306a36Sopenharmony_ci{ 377362306a36Sopenharmony_ci struct cfg80211_scan_request *req = rtwvif->scan_req; 377462306a36Sopenharmony_ci struct rtw89_mac_chinfo *ch_info, *tmp; 377562306a36Sopenharmony_ci struct ieee80211_channel *channel; 377662306a36Sopenharmony_ci struct list_head chan_list; 377762306a36Sopenharmony_ci bool random_seq = req->flags & NL80211_SCAN_FLAG_RANDOM_SN; 377862306a36Sopenharmony_ci int list_len, off_chan_time = 0; 377962306a36Sopenharmony_ci enum rtw89_chan_type type; 378062306a36Sopenharmony_ci int ret = 0; 378162306a36Sopenharmony_ci u32 idx; 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci INIT_LIST_HEAD(&chan_list); 378462306a36Sopenharmony_ci for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0; 378562306a36Sopenharmony_ci idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT; 378662306a36Sopenharmony_ci idx++, list_len++) { 378762306a36Sopenharmony_ci channel = req->channels[idx]; 378862306a36Sopenharmony_ci ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); 378962306a36Sopenharmony_ci if (!ch_info) { 379062306a36Sopenharmony_ci ret = -ENOMEM; 379162306a36Sopenharmony_ci goto out; 379262306a36Sopenharmony_ci } 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_ci if (req->duration_mandatory) 379562306a36Sopenharmony_ci ch_info->period = req->duration; 379662306a36Sopenharmony_ci else if (channel->band == NL80211_BAND_6GHZ) 379762306a36Sopenharmony_ci ch_info->period = RTW89_CHANNEL_TIME_6G + 379862306a36Sopenharmony_ci RTW89_DWELL_TIME_6G; 379962306a36Sopenharmony_ci else 380062306a36Sopenharmony_ci ch_info->period = RTW89_CHANNEL_TIME; 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci ch_info->ch_band = rtw89_nl80211_to_hw_band(channel->band); 380362306a36Sopenharmony_ci ch_info->central_ch = channel->hw_value; 380462306a36Sopenharmony_ci ch_info->pri_ch = channel->hw_value; 380562306a36Sopenharmony_ci ch_info->rand_seq_num = random_seq; 380662306a36Sopenharmony_ci ch_info->is_psc = cfg80211_channel_is_psc(channel); 380762306a36Sopenharmony_ci 380862306a36Sopenharmony_ci if (channel->flags & 380962306a36Sopenharmony_ci (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)) 381062306a36Sopenharmony_ci type = RTW89_CHAN_DFS; 381162306a36Sopenharmony_ci else 381262306a36Sopenharmony_ci type = RTW89_CHAN_ACTIVE; 381362306a36Sopenharmony_ci rtw89_hw_scan_add_chan(rtwdev, type, req->n_ssids, ch_info); 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci if (connected && 381662306a36Sopenharmony_ci off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME) { 381762306a36Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 381862306a36Sopenharmony_ci if (!tmp) { 381962306a36Sopenharmony_ci ret = -ENOMEM; 382062306a36Sopenharmony_ci kfree(ch_info); 382162306a36Sopenharmony_ci goto out; 382262306a36Sopenharmony_ci } 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci type = RTW89_CHAN_OPERATE; 382562306a36Sopenharmony_ci tmp->period = req->duration_mandatory ? 382662306a36Sopenharmony_ci req->duration : RTW89_CHANNEL_TIME; 382762306a36Sopenharmony_ci rtw89_hw_scan_add_chan(rtwdev, type, 0, tmp); 382862306a36Sopenharmony_ci list_add_tail(&tmp->list, &chan_list); 382962306a36Sopenharmony_ci off_chan_time = 0; 383062306a36Sopenharmony_ci list_len++; 383162306a36Sopenharmony_ci } 383262306a36Sopenharmony_ci list_add_tail(&ch_info->list, &chan_list); 383362306a36Sopenharmony_ci off_chan_time += ch_info->period; 383462306a36Sopenharmony_ci } 383562306a36Sopenharmony_ci rtwdev->scan_info.last_chan_idx = idx; 383662306a36Sopenharmony_ci ret = rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list); 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ciout: 383962306a36Sopenharmony_ci list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { 384062306a36Sopenharmony_ci list_del(&ch_info->list); 384162306a36Sopenharmony_ci kfree(ch_info); 384262306a36Sopenharmony_ci } 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci return ret; 384562306a36Sopenharmony_ci} 384662306a36Sopenharmony_ci 384762306a36Sopenharmony_cistatic int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev, 384862306a36Sopenharmony_ci struct rtw89_vif *rtwvif, bool connected) 384962306a36Sopenharmony_ci{ 385062306a36Sopenharmony_ci int ret; 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_ci ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif); 385362306a36Sopenharmony_ci if (ret) { 385462306a36Sopenharmony_ci rtw89_err(rtwdev, "Update probe request failed\n"); 385562306a36Sopenharmony_ci goto out; 385662306a36Sopenharmony_ci } 385762306a36Sopenharmony_ci ret = rtw89_hw_scan_add_chan_list(rtwdev, rtwvif, connected); 385862306a36Sopenharmony_ciout: 385962306a36Sopenharmony_ci return ret; 386062306a36Sopenharmony_ci} 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_civoid rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, 386362306a36Sopenharmony_ci struct ieee80211_scan_request *scan_req) 386462306a36Sopenharmony_ci{ 386562306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 386662306a36Sopenharmony_ci const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; 386762306a36Sopenharmony_ci struct cfg80211_scan_request *req = &scan_req->req; 386862306a36Sopenharmony_ci u32 rx_fltr = rtwdev->hal.rx_fltr; 386962306a36Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 387062306a36Sopenharmony_ci 387162306a36Sopenharmony_ci rtw89_get_channel(rtwdev, rtwvif, &rtwdev->scan_info.op_chan); 387262306a36Sopenharmony_ci rtwdev->scan_info.scanning_vif = vif; 387362306a36Sopenharmony_ci rtwdev->scan_info.last_chan_idx = 0; 387462306a36Sopenharmony_ci rtwvif->scan_ies = &scan_req->ies; 387562306a36Sopenharmony_ci rtwvif->scan_req = req; 387662306a36Sopenharmony_ci ieee80211_stop_queues(rtwdev->hw); 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_ci if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) 387962306a36Sopenharmony_ci get_random_mask_addr(mac_addr, req->mac_addr, 388062306a36Sopenharmony_ci req->mac_addr_mask); 388162306a36Sopenharmony_ci else 388262306a36Sopenharmony_ci ether_addr_copy(mac_addr, vif->addr); 388362306a36Sopenharmony_ci rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, true); 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_ci rx_fltr &= ~B_AX_A_BCN_CHK_EN; 388662306a36Sopenharmony_ci rx_fltr &= ~B_AX_A_BC; 388762306a36Sopenharmony_ci rx_fltr &= ~B_AX_A_A1_MATCH; 388862306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, 388962306a36Sopenharmony_ci rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), 389062306a36Sopenharmony_ci B_AX_RX_FLTR_CFG_MASK, 389162306a36Sopenharmony_ci rx_fltr); 389262306a36Sopenharmony_ci} 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_civoid rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, 389562306a36Sopenharmony_ci bool aborted) 389662306a36Sopenharmony_ci{ 389762306a36Sopenharmony_ci const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; 389862306a36Sopenharmony_ci struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; 389962306a36Sopenharmony_ci struct cfg80211_scan_info info = { 390062306a36Sopenharmony_ci .aborted = aborted, 390162306a36Sopenharmony_ci }; 390262306a36Sopenharmony_ci struct rtw89_vif *rtwvif; 390362306a36Sopenharmony_ci 390462306a36Sopenharmony_ci if (!vif) 390562306a36Sopenharmony_ci return; 390662306a36Sopenharmony_ci 390762306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, 390862306a36Sopenharmony_ci rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), 390962306a36Sopenharmony_ci B_AX_RX_FLTR_CFG_MASK, 391062306a36Sopenharmony_ci rtwdev->hal.rx_fltr); 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci rtw89_core_scan_complete(rtwdev, vif, true); 391362306a36Sopenharmony_ci ieee80211_scan_completed(rtwdev->hw, &info); 391462306a36Sopenharmony_ci ieee80211_wake_queues(rtwdev->hw); 391562306a36Sopenharmony_ci rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); 391662306a36Sopenharmony_ci 391762306a36Sopenharmony_ci rtw89_release_pkt_list(rtwdev); 391862306a36Sopenharmony_ci rtwvif = (struct rtw89_vif *)vif->drv_priv; 391962306a36Sopenharmony_ci rtwvif->scan_req = NULL; 392062306a36Sopenharmony_ci rtwvif->scan_ies = NULL; 392162306a36Sopenharmony_ci scan_info->last_chan_idx = 0; 392262306a36Sopenharmony_ci scan_info->scanning_vif = NULL; 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci rtw89_set_channel(rtwdev); 392562306a36Sopenharmony_ci} 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_civoid rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) 392862306a36Sopenharmony_ci{ 392962306a36Sopenharmony_ci rtw89_hw_scan_offload(rtwdev, vif, false); 393062306a36Sopenharmony_ci rtw89_hw_scan_complete(rtwdev, vif, true); 393162306a36Sopenharmony_ci} 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_cistatic bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev) 393462306a36Sopenharmony_ci{ 393562306a36Sopenharmony_ci struct rtw89_vif *rtwvif; 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci rtw89_for_each_rtwvif(rtwdev, rtwvif) { 393862306a36Sopenharmony_ci /* This variable implies connected or during attempt to connect */ 393962306a36Sopenharmony_ci if (!is_zero_ether_addr(rtwvif->bssid)) 394062306a36Sopenharmony_ci return true; 394162306a36Sopenharmony_ci } 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci return false; 394462306a36Sopenharmony_ci} 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ciint rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, 394762306a36Sopenharmony_ci bool enable) 394862306a36Sopenharmony_ci{ 394962306a36Sopenharmony_ci struct rtw89_scan_option opt = {0}; 395062306a36Sopenharmony_ci struct rtw89_vif *rtwvif; 395162306a36Sopenharmony_ci bool connected; 395262306a36Sopenharmony_ci int ret = 0; 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_ci rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL; 395562306a36Sopenharmony_ci if (!rtwvif) 395662306a36Sopenharmony_ci return -EINVAL; 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); 395962306a36Sopenharmony_ci opt.enable = enable; 396062306a36Sopenharmony_ci opt.target_ch_mode = connected; 396162306a36Sopenharmony_ci if (enable) { 396262306a36Sopenharmony_ci ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif, connected); 396362306a36Sopenharmony_ci if (ret) 396462306a36Sopenharmony_ci goto out; 396562306a36Sopenharmony_ci } 396662306a36Sopenharmony_ci ret = rtw89_fw_h2c_scan_offload(rtwdev, &opt, rtwvif); 396762306a36Sopenharmony_ciout: 396862306a36Sopenharmony_ci return ret; 396962306a36Sopenharmony_ci} 397062306a36Sopenharmony_ci 397162306a36Sopenharmony_ci#define H2C_FW_CPU_EXCEPTION_LEN 4 397262306a36Sopenharmony_ci#define H2C_FW_CPU_EXCEPTION_TYPE_DEF 0x5566 397362306a36Sopenharmony_ciint rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev) 397462306a36Sopenharmony_ci{ 397562306a36Sopenharmony_ci struct sk_buff *skb; 397662306a36Sopenharmony_ci int ret; 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_FW_CPU_EXCEPTION_LEN); 397962306a36Sopenharmony_ci if (!skb) { 398062306a36Sopenharmony_ci rtw89_err(rtwdev, 398162306a36Sopenharmony_ci "failed to alloc skb for fw cpu exception\n"); 398262306a36Sopenharmony_ci return -ENOMEM; 398362306a36Sopenharmony_ci } 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci skb_put(skb, H2C_FW_CPU_EXCEPTION_LEN); 398662306a36Sopenharmony_ci RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(skb->data, 398762306a36Sopenharmony_ci H2C_FW_CPU_EXCEPTION_TYPE_DEF); 398862306a36Sopenharmony_ci 398962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 399062306a36Sopenharmony_ci H2C_CAT_TEST, 399162306a36Sopenharmony_ci H2C_CL_FW_STATUS_TEST, 399262306a36Sopenharmony_ci H2C_FUNC_CPU_EXCEPTION, 0, 0, 399362306a36Sopenharmony_ci H2C_FW_CPU_EXCEPTION_LEN); 399462306a36Sopenharmony_ci 399562306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 399662306a36Sopenharmony_ci if (ret) { 399762306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 399862306a36Sopenharmony_ci goto fail; 399962306a36Sopenharmony_ci } 400062306a36Sopenharmony_ci 400162306a36Sopenharmony_ci return 0; 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_cifail: 400462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 400562306a36Sopenharmony_ci return ret; 400662306a36Sopenharmony_ci} 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci#define H2C_PKT_DROP_LEN 24 400962306a36Sopenharmony_ciint rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, 401062306a36Sopenharmony_ci const struct rtw89_pkt_drop_params *params) 401162306a36Sopenharmony_ci{ 401262306a36Sopenharmony_ci struct sk_buff *skb; 401362306a36Sopenharmony_ci int ret; 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_PKT_DROP_LEN); 401662306a36Sopenharmony_ci if (!skb) { 401762306a36Sopenharmony_ci rtw89_err(rtwdev, 401862306a36Sopenharmony_ci "failed to alloc skb for packet drop\n"); 401962306a36Sopenharmony_ci return -ENOMEM; 402062306a36Sopenharmony_ci } 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_ci switch (params->sel) { 402362306a36Sopenharmony_ci case RTW89_PKT_DROP_SEL_MACID_BE_ONCE: 402462306a36Sopenharmony_ci case RTW89_PKT_DROP_SEL_MACID_BK_ONCE: 402562306a36Sopenharmony_ci case RTW89_PKT_DROP_SEL_MACID_VI_ONCE: 402662306a36Sopenharmony_ci case RTW89_PKT_DROP_SEL_MACID_VO_ONCE: 402762306a36Sopenharmony_ci case RTW89_PKT_DROP_SEL_BAND_ONCE: 402862306a36Sopenharmony_ci break; 402962306a36Sopenharmony_ci default: 403062306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_FW, 403162306a36Sopenharmony_ci "H2C of pkt drop might not fully support sel: %d yet\n", 403262306a36Sopenharmony_ci params->sel); 403362306a36Sopenharmony_ci break; 403462306a36Sopenharmony_ci } 403562306a36Sopenharmony_ci 403662306a36Sopenharmony_ci skb_put(skb, H2C_PKT_DROP_LEN); 403762306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_SEL(skb->data, params->sel); 403862306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_MACID(skb->data, params->macid); 403962306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_BAND(skb->data, params->mac_band); 404062306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_PORT(skb->data, params->port); 404162306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_MBSSID(skb->data, params->mbssid); 404262306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_ROLE_A_INFO_TF_TRS(skb->data, params->tf_trs); 404362306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_0(skb->data, 404462306a36Sopenharmony_ci params->macid_band_sel[0]); 404562306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_1(skb->data, 404662306a36Sopenharmony_ci params->macid_band_sel[1]); 404762306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_2(skb->data, 404862306a36Sopenharmony_ci params->macid_band_sel[2]); 404962306a36Sopenharmony_ci RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_3(skb->data, 405062306a36Sopenharmony_ci params->macid_band_sel[3]); 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 405362306a36Sopenharmony_ci H2C_CAT_MAC, 405462306a36Sopenharmony_ci H2C_CL_MAC_FW_OFLD, 405562306a36Sopenharmony_ci H2C_FUNC_PKT_DROP, 0, 0, 405662306a36Sopenharmony_ci H2C_PKT_DROP_LEN); 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 405962306a36Sopenharmony_ci if (ret) { 406062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 406162306a36Sopenharmony_ci goto fail; 406262306a36Sopenharmony_ci } 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_ci return 0; 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_cifail: 406762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 406862306a36Sopenharmony_ci return ret; 406962306a36Sopenharmony_ci} 407062306a36Sopenharmony_ci 407162306a36Sopenharmony_ci#define H2C_KEEP_ALIVE_LEN 4 407262306a36Sopenharmony_ciint rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 407362306a36Sopenharmony_ci bool enable) 407462306a36Sopenharmony_ci{ 407562306a36Sopenharmony_ci struct sk_buff *skb; 407662306a36Sopenharmony_ci u8 pkt_id = 0; 407762306a36Sopenharmony_ci int ret; 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci if (enable) { 408062306a36Sopenharmony_ci ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, 408162306a36Sopenharmony_ci RTW89_PKT_OFLD_TYPE_NULL_DATA, 408262306a36Sopenharmony_ci &pkt_id); 408362306a36Sopenharmony_ci if (ret) 408462306a36Sopenharmony_ci return -EPERM; 408562306a36Sopenharmony_ci } 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_KEEP_ALIVE_LEN); 408862306a36Sopenharmony_ci if (!skb) { 408962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); 409062306a36Sopenharmony_ci return -ENOMEM; 409162306a36Sopenharmony_ci } 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci skb_put(skb, H2C_KEEP_ALIVE_LEN); 409462306a36Sopenharmony_ci 409562306a36Sopenharmony_ci RTW89_SET_KEEP_ALIVE_ENABLE(skb->data, enable); 409662306a36Sopenharmony_ci RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(skb->data, pkt_id); 409762306a36Sopenharmony_ci RTW89_SET_KEEP_ALIVE_PERIOD(skb->data, 5); 409862306a36Sopenharmony_ci RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif->mac_id); 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 410162306a36Sopenharmony_ci H2C_CAT_MAC, 410262306a36Sopenharmony_ci H2C_CL_MAC_WOW, 410362306a36Sopenharmony_ci H2C_FUNC_KEEP_ALIVE, 0, 1, 410462306a36Sopenharmony_ci H2C_KEEP_ALIVE_LEN); 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 410762306a36Sopenharmony_ci if (ret) { 410862306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 410962306a36Sopenharmony_ci goto fail; 411062306a36Sopenharmony_ci } 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci return 0; 411362306a36Sopenharmony_ci 411462306a36Sopenharmony_cifail: 411562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci return ret; 411862306a36Sopenharmony_ci} 411962306a36Sopenharmony_ci 412062306a36Sopenharmony_ci#define H2C_DISCONNECT_DETECT_LEN 8 412162306a36Sopenharmony_ciint rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, 412262306a36Sopenharmony_ci struct rtw89_vif *rtwvif, bool enable) 412362306a36Sopenharmony_ci{ 412462306a36Sopenharmony_ci struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 412562306a36Sopenharmony_ci struct sk_buff *skb; 412662306a36Sopenharmony_ci u8 macid = rtwvif->mac_id; 412762306a36Sopenharmony_ci int ret; 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DISCONNECT_DETECT_LEN); 413062306a36Sopenharmony_ci if (!skb) { 413162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); 413262306a36Sopenharmony_ci return -ENOMEM; 413362306a36Sopenharmony_ci } 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci skb_put(skb, H2C_DISCONNECT_DETECT_LEN); 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci if (test_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags)) { 413862306a36Sopenharmony_ci RTW89_SET_DISCONNECT_DETECT_ENABLE(skb->data, enable); 413962306a36Sopenharmony_ci RTW89_SET_DISCONNECT_DETECT_DISCONNECT(skb->data, !enable); 414062306a36Sopenharmony_ci RTW89_SET_DISCONNECT_DETECT_MAC_ID(skb->data, macid); 414162306a36Sopenharmony_ci RTW89_SET_DISCONNECT_DETECT_CHECK_PERIOD(skb->data, 100); 414262306a36Sopenharmony_ci RTW89_SET_DISCONNECT_DETECT_TRY_PKT_COUNT(skb->data, 5); 414362306a36Sopenharmony_ci } 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 414662306a36Sopenharmony_ci H2C_CAT_MAC, 414762306a36Sopenharmony_ci H2C_CL_MAC_WOW, 414862306a36Sopenharmony_ci H2C_FUNC_DISCONNECT_DETECT, 0, 1, 414962306a36Sopenharmony_ci H2C_DISCONNECT_DETECT_LEN); 415062306a36Sopenharmony_ci 415162306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 415262306a36Sopenharmony_ci if (ret) { 415362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 415462306a36Sopenharmony_ci goto fail; 415562306a36Sopenharmony_ci } 415662306a36Sopenharmony_ci 415762306a36Sopenharmony_ci return 0; 415862306a36Sopenharmony_ci 415962306a36Sopenharmony_cifail: 416062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 416162306a36Sopenharmony_ci 416262306a36Sopenharmony_ci return ret; 416362306a36Sopenharmony_ci} 416462306a36Sopenharmony_ci 416562306a36Sopenharmony_ci#define H2C_WOW_GLOBAL_LEN 8 416662306a36Sopenharmony_ciint rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 416762306a36Sopenharmony_ci bool enable) 416862306a36Sopenharmony_ci{ 416962306a36Sopenharmony_ci struct sk_buff *skb; 417062306a36Sopenharmony_ci u8 macid = rtwvif->mac_id; 417162306a36Sopenharmony_ci int ret; 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_GLOBAL_LEN); 417462306a36Sopenharmony_ci if (!skb) { 417562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); 417662306a36Sopenharmony_ci return -ENOMEM; 417762306a36Sopenharmony_ci } 417862306a36Sopenharmony_ci 417962306a36Sopenharmony_ci skb_put(skb, H2C_WOW_GLOBAL_LEN); 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci RTW89_SET_WOW_GLOBAL_ENABLE(skb->data, enable); 418262306a36Sopenharmony_ci RTW89_SET_WOW_GLOBAL_MAC_ID(skb->data, macid); 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 418562306a36Sopenharmony_ci H2C_CAT_MAC, 418662306a36Sopenharmony_ci H2C_CL_MAC_WOW, 418762306a36Sopenharmony_ci H2C_FUNC_WOW_GLOBAL, 0, 1, 418862306a36Sopenharmony_ci H2C_WOW_GLOBAL_LEN); 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 419162306a36Sopenharmony_ci if (ret) { 419262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 419362306a36Sopenharmony_ci goto fail; 419462306a36Sopenharmony_ci } 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci return 0; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_cifail: 419962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci return ret; 420262306a36Sopenharmony_ci} 420362306a36Sopenharmony_ci 420462306a36Sopenharmony_ci#define H2C_WAKEUP_CTRL_LEN 4 420562306a36Sopenharmony_ciint rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, 420662306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 420762306a36Sopenharmony_ci bool enable) 420862306a36Sopenharmony_ci{ 420962306a36Sopenharmony_ci struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 421062306a36Sopenharmony_ci struct sk_buff *skb; 421162306a36Sopenharmony_ci u8 macid = rtwvif->mac_id; 421262306a36Sopenharmony_ci int ret; 421362306a36Sopenharmony_ci 421462306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WAKEUP_CTRL_LEN); 421562306a36Sopenharmony_ci if (!skb) { 421662306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); 421762306a36Sopenharmony_ci return -ENOMEM; 421862306a36Sopenharmony_ci } 421962306a36Sopenharmony_ci 422062306a36Sopenharmony_ci skb_put(skb, H2C_WAKEUP_CTRL_LEN); 422162306a36Sopenharmony_ci 422262306a36Sopenharmony_ci if (rtw_wow->pattern_cnt) 422362306a36Sopenharmony_ci RTW89_SET_WOW_WAKEUP_CTRL_PATTERN_MATCH_ENABLE(skb->data, enable); 422462306a36Sopenharmony_ci if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) 422562306a36Sopenharmony_ci RTW89_SET_WOW_WAKEUP_CTRL_MAGIC_ENABLE(skb->data, enable); 422662306a36Sopenharmony_ci if (test_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags)) 422762306a36Sopenharmony_ci RTW89_SET_WOW_WAKEUP_CTRL_DEAUTH_ENABLE(skb->data, enable); 422862306a36Sopenharmony_ci 422962306a36Sopenharmony_ci RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(skb->data, macid); 423062306a36Sopenharmony_ci 423162306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 423262306a36Sopenharmony_ci H2C_CAT_MAC, 423362306a36Sopenharmony_ci H2C_CL_MAC_WOW, 423462306a36Sopenharmony_ci H2C_FUNC_WAKEUP_CTRL, 0, 1, 423562306a36Sopenharmony_ci H2C_WAKEUP_CTRL_LEN); 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 423862306a36Sopenharmony_ci if (ret) { 423962306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 424062306a36Sopenharmony_ci goto fail; 424162306a36Sopenharmony_ci } 424262306a36Sopenharmony_ci 424362306a36Sopenharmony_ci return 0; 424462306a36Sopenharmony_ci 424562306a36Sopenharmony_cifail: 424662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 424762306a36Sopenharmony_ci 424862306a36Sopenharmony_ci return ret; 424962306a36Sopenharmony_ci} 425062306a36Sopenharmony_ci 425162306a36Sopenharmony_ci#define H2C_WOW_CAM_UPD_LEN 24 425262306a36Sopenharmony_ciint rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, 425362306a36Sopenharmony_ci struct rtw89_wow_cam_info *cam_info) 425462306a36Sopenharmony_ci{ 425562306a36Sopenharmony_ci struct sk_buff *skb; 425662306a36Sopenharmony_ci int ret; 425762306a36Sopenharmony_ci 425862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_CAM_UPD_LEN); 425962306a36Sopenharmony_ci if (!skb) { 426062306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); 426162306a36Sopenharmony_ci return -ENOMEM; 426262306a36Sopenharmony_ci } 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci skb_put(skb, H2C_WOW_CAM_UPD_LEN); 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_R_W(skb->data, cam_info->r_w); 426762306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_IDX(skb->data, cam_info->idx); 426862306a36Sopenharmony_ci if (cam_info->valid) { 426962306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_WKFM1(skb->data, cam_info->mask[0]); 427062306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_WKFM2(skb->data, cam_info->mask[1]); 427162306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_WKFM3(skb->data, cam_info->mask[2]); 427262306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_WKFM4(skb->data, cam_info->mask[3]); 427362306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_CRC(skb->data, cam_info->crc); 427462306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(skb->data, 427562306a36Sopenharmony_ci cam_info->negative_pattern_match); 427662306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(skb->data, 427762306a36Sopenharmony_ci cam_info->skip_mac_hdr); 427862306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_UC(skb->data, cam_info->uc); 427962306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_MC(skb->data, cam_info->mc); 428062306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_BC(skb->data, cam_info->bc); 428162306a36Sopenharmony_ci } 428262306a36Sopenharmony_ci RTW89_SET_WOW_CAM_UPD_VALID(skb->data, cam_info->valid); 428362306a36Sopenharmony_ci 428462306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 428562306a36Sopenharmony_ci H2C_CAT_MAC, 428662306a36Sopenharmony_ci H2C_CL_MAC_WOW, 428762306a36Sopenharmony_ci H2C_FUNC_WOW_CAM_UPD, 0, 1, 428862306a36Sopenharmony_ci H2C_WOW_CAM_UPD_LEN); 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 429162306a36Sopenharmony_ci if (ret) { 429262306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 429362306a36Sopenharmony_ci goto fail; 429462306a36Sopenharmony_ci } 429562306a36Sopenharmony_ci 429662306a36Sopenharmony_ci return 0; 429762306a36Sopenharmony_cifail: 429862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 429962306a36Sopenharmony_ci 430062306a36Sopenharmony_ci return ret; 430162306a36Sopenharmony_ci} 430262306a36Sopenharmony_ci 430362306a36Sopenharmony_ci/* Return < 0, if failures happen during waiting for the condition. 430462306a36Sopenharmony_ci * Return 0, when waiting for the condition succeeds. 430562306a36Sopenharmony_ci * Return > 0, if the wait is considered unreachable due to driver/FW design, 430662306a36Sopenharmony_ci * where 1 means during SER. 430762306a36Sopenharmony_ci */ 430862306a36Sopenharmony_cistatic int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, 430962306a36Sopenharmony_ci struct rtw89_wait_info *wait, unsigned int cond) 431062306a36Sopenharmony_ci{ 431162306a36Sopenharmony_ci int ret; 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci ret = rtw89_h2c_tx(rtwdev, skb, false); 431462306a36Sopenharmony_ci if (ret) { 431562306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to send h2c\n"); 431662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 431762306a36Sopenharmony_ci return -EBUSY; 431862306a36Sopenharmony_ci } 431962306a36Sopenharmony_ci 432062306a36Sopenharmony_ci if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) 432162306a36Sopenharmony_ci return 1; 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_ci return rtw89_wait_for_cond(wait, cond); 432462306a36Sopenharmony_ci} 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci#define H2C_ADD_MCC_LEN 16 432762306a36Sopenharmony_ciint rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev, 432862306a36Sopenharmony_ci const struct rtw89_fw_mcc_add_req *p) 432962306a36Sopenharmony_ci{ 433062306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 433162306a36Sopenharmony_ci struct sk_buff *skb; 433262306a36Sopenharmony_ci unsigned int cond; 433362306a36Sopenharmony_ci 433462306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ADD_MCC_LEN); 433562306a36Sopenharmony_ci if (!skb) { 433662306a36Sopenharmony_ci rtw89_err(rtwdev, 433762306a36Sopenharmony_ci "failed to alloc skb for add mcc\n"); 433862306a36Sopenharmony_ci return -ENOMEM; 433962306a36Sopenharmony_ci } 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_ci skb_put(skb, H2C_ADD_MCC_LEN); 434262306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_MACID(skb->data, p->macid); 434362306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG0(skb->data, p->central_ch_seg0); 434462306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG1(skb->data, p->central_ch_seg1); 434562306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_PRIMARY_CH(skb->data, p->primary_ch); 434662306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_BANDWIDTH(skb->data, p->bandwidth); 434762306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_GROUP(skb->data, p->group); 434862306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_C2H_RPT(skb->data, p->c2h_rpt); 434962306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_DIS_TX_NULL(skb->data, p->dis_tx_null); 435062306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_DIS_SW_RETRY(skb->data, p->dis_sw_retry); 435162306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_IN_CURR_CH(skb->data, p->in_curr_ch); 435262306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_SW_RETRY_COUNT(skb->data, p->sw_retry_count); 435362306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_TX_NULL_EARLY(skb->data, p->tx_null_early); 435462306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_BTC_IN_2G(skb->data, p->btc_in_2g); 435562306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_PTA_EN(skb->data, p->pta_en); 435662306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_RFK_BY_PASS(skb->data, p->rfk_by_pass); 435762306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_CH_BAND_TYPE(skb->data, p->ch_band_type); 435862306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_DURATION(skb->data, p->duration); 435962306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_COURTESY_EN(skb->data, p->courtesy_en); 436062306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_COURTESY_NUM(skb->data, p->courtesy_num); 436162306a36Sopenharmony_ci RTW89_SET_FWCMD_ADD_MCC_COURTESY_TARGET(skb->data, p->courtesy_target); 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 436462306a36Sopenharmony_ci H2C_CAT_MAC, 436562306a36Sopenharmony_ci H2C_CL_MCC, 436662306a36Sopenharmony_ci H2C_FUNC_ADD_MCC, 0, 0, 436762306a36Sopenharmony_ci H2C_ADD_MCC_LEN); 436862306a36Sopenharmony_ci 436962306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_ADD_MCC); 437062306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 437162306a36Sopenharmony_ci} 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci#define H2C_START_MCC_LEN 12 437462306a36Sopenharmony_ciint rtw89_fw_h2c_start_mcc(struct rtw89_dev *rtwdev, 437562306a36Sopenharmony_ci const struct rtw89_fw_mcc_start_req *p) 437662306a36Sopenharmony_ci{ 437762306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 437862306a36Sopenharmony_ci struct sk_buff *skb; 437962306a36Sopenharmony_ci unsigned int cond; 438062306a36Sopenharmony_ci 438162306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_START_MCC_LEN); 438262306a36Sopenharmony_ci if (!skb) { 438362306a36Sopenharmony_ci rtw89_err(rtwdev, 438462306a36Sopenharmony_ci "failed to alloc skb for start mcc\n"); 438562306a36Sopenharmony_ci return -ENOMEM; 438662306a36Sopenharmony_ci } 438762306a36Sopenharmony_ci 438862306a36Sopenharmony_ci skb_put(skb, H2C_START_MCC_LEN); 438962306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_GROUP(skb->data, p->group); 439062306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_BTC_IN_GROUP(skb->data, p->btc_in_group); 439162306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_OLD_GROUP_ACTION(skb->data, p->old_group_action); 439262306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_OLD_GROUP(skb->data, p->old_group); 439362306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_NOTIFY_CNT(skb->data, p->notify_cnt); 439462306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_NOTIFY_RXDBG_EN(skb->data, p->notify_rxdbg_en); 439562306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_MACID(skb->data, p->macid); 439662306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_TSF_LOW(skb->data, p->tsf_low); 439762306a36Sopenharmony_ci RTW89_SET_FWCMD_START_MCC_TSF_HIGH(skb->data, p->tsf_high); 439862306a36Sopenharmony_ci 439962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 440062306a36Sopenharmony_ci H2C_CAT_MAC, 440162306a36Sopenharmony_ci H2C_CL_MCC, 440262306a36Sopenharmony_ci H2C_FUNC_START_MCC, 0, 0, 440362306a36Sopenharmony_ci H2C_START_MCC_LEN); 440462306a36Sopenharmony_ci 440562306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_START_MCC); 440662306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 440762306a36Sopenharmony_ci} 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_ci#define H2C_STOP_MCC_LEN 4 441062306a36Sopenharmony_ciint rtw89_fw_h2c_stop_mcc(struct rtw89_dev *rtwdev, u8 group, u8 macid, 441162306a36Sopenharmony_ci bool prev_groups) 441262306a36Sopenharmony_ci{ 441362306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 441462306a36Sopenharmony_ci struct sk_buff *skb; 441562306a36Sopenharmony_ci unsigned int cond; 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_STOP_MCC_LEN); 441862306a36Sopenharmony_ci if (!skb) { 441962306a36Sopenharmony_ci rtw89_err(rtwdev, 442062306a36Sopenharmony_ci "failed to alloc skb for stop mcc\n"); 442162306a36Sopenharmony_ci return -ENOMEM; 442262306a36Sopenharmony_ci } 442362306a36Sopenharmony_ci 442462306a36Sopenharmony_ci skb_put(skb, H2C_STOP_MCC_LEN); 442562306a36Sopenharmony_ci RTW89_SET_FWCMD_STOP_MCC_MACID(skb->data, macid); 442662306a36Sopenharmony_ci RTW89_SET_FWCMD_STOP_MCC_GROUP(skb->data, group); 442762306a36Sopenharmony_ci RTW89_SET_FWCMD_STOP_MCC_PREV_GROUPS(skb->data, prev_groups); 442862306a36Sopenharmony_ci 442962306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 443062306a36Sopenharmony_ci H2C_CAT_MAC, 443162306a36Sopenharmony_ci H2C_CL_MCC, 443262306a36Sopenharmony_ci H2C_FUNC_STOP_MCC, 0, 0, 443362306a36Sopenharmony_ci H2C_STOP_MCC_LEN); 443462306a36Sopenharmony_ci 443562306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_STOP_MCC); 443662306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 443762306a36Sopenharmony_ci} 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci#define H2C_DEL_MCC_GROUP_LEN 4 444062306a36Sopenharmony_ciint rtw89_fw_h2c_del_mcc_group(struct rtw89_dev *rtwdev, u8 group, 444162306a36Sopenharmony_ci bool prev_groups) 444262306a36Sopenharmony_ci{ 444362306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 444462306a36Sopenharmony_ci struct sk_buff *skb; 444562306a36Sopenharmony_ci unsigned int cond; 444662306a36Sopenharmony_ci 444762306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DEL_MCC_GROUP_LEN); 444862306a36Sopenharmony_ci if (!skb) { 444962306a36Sopenharmony_ci rtw89_err(rtwdev, 445062306a36Sopenharmony_ci "failed to alloc skb for del mcc group\n"); 445162306a36Sopenharmony_ci return -ENOMEM; 445262306a36Sopenharmony_ci } 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci skb_put(skb, H2C_DEL_MCC_GROUP_LEN); 445562306a36Sopenharmony_ci RTW89_SET_FWCMD_DEL_MCC_GROUP_GROUP(skb->data, group); 445662306a36Sopenharmony_ci RTW89_SET_FWCMD_DEL_MCC_GROUP_PREV_GROUPS(skb->data, prev_groups); 445762306a36Sopenharmony_ci 445862306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 445962306a36Sopenharmony_ci H2C_CAT_MAC, 446062306a36Sopenharmony_ci H2C_CL_MCC, 446162306a36Sopenharmony_ci H2C_FUNC_DEL_MCC_GROUP, 0, 0, 446262306a36Sopenharmony_ci H2C_DEL_MCC_GROUP_LEN); 446362306a36Sopenharmony_ci 446462306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_DEL_MCC_GROUP); 446562306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 446662306a36Sopenharmony_ci} 446762306a36Sopenharmony_ci 446862306a36Sopenharmony_ci#define H2C_RESET_MCC_GROUP_LEN 4 446962306a36Sopenharmony_ciint rtw89_fw_h2c_reset_mcc_group(struct rtw89_dev *rtwdev, u8 group) 447062306a36Sopenharmony_ci{ 447162306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 447262306a36Sopenharmony_ci struct sk_buff *skb; 447362306a36Sopenharmony_ci unsigned int cond; 447462306a36Sopenharmony_ci 447562306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_RESET_MCC_GROUP_LEN); 447662306a36Sopenharmony_ci if (!skb) { 447762306a36Sopenharmony_ci rtw89_err(rtwdev, 447862306a36Sopenharmony_ci "failed to alloc skb for reset mcc group\n"); 447962306a36Sopenharmony_ci return -ENOMEM; 448062306a36Sopenharmony_ci } 448162306a36Sopenharmony_ci 448262306a36Sopenharmony_ci skb_put(skb, H2C_RESET_MCC_GROUP_LEN); 448362306a36Sopenharmony_ci RTW89_SET_FWCMD_RESET_MCC_GROUP_GROUP(skb->data, group); 448462306a36Sopenharmony_ci 448562306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 448662306a36Sopenharmony_ci H2C_CAT_MAC, 448762306a36Sopenharmony_ci H2C_CL_MCC, 448862306a36Sopenharmony_ci H2C_FUNC_RESET_MCC_GROUP, 0, 0, 448962306a36Sopenharmony_ci H2C_RESET_MCC_GROUP_LEN); 449062306a36Sopenharmony_ci 449162306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_RESET_MCC_GROUP); 449262306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 449362306a36Sopenharmony_ci} 449462306a36Sopenharmony_ci 449562306a36Sopenharmony_ci#define H2C_MCC_REQ_TSF_LEN 4 449662306a36Sopenharmony_ciint rtw89_fw_h2c_mcc_req_tsf(struct rtw89_dev *rtwdev, 449762306a36Sopenharmony_ci const struct rtw89_fw_mcc_tsf_req *req, 449862306a36Sopenharmony_ci struct rtw89_mac_mcc_tsf_rpt *rpt) 449962306a36Sopenharmony_ci{ 450062306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 450162306a36Sopenharmony_ci struct rtw89_mac_mcc_tsf_rpt *tmp; 450262306a36Sopenharmony_ci struct sk_buff *skb; 450362306a36Sopenharmony_ci unsigned int cond; 450462306a36Sopenharmony_ci int ret; 450562306a36Sopenharmony_ci 450662306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_REQ_TSF_LEN); 450762306a36Sopenharmony_ci if (!skb) { 450862306a36Sopenharmony_ci rtw89_err(rtwdev, 450962306a36Sopenharmony_ci "failed to alloc skb for mcc req tsf\n"); 451062306a36Sopenharmony_ci return -ENOMEM; 451162306a36Sopenharmony_ci } 451262306a36Sopenharmony_ci 451362306a36Sopenharmony_ci skb_put(skb, H2C_MCC_REQ_TSF_LEN); 451462306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_REQ_TSF_GROUP(skb->data, req->group); 451562306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_X(skb->data, req->macid_x); 451662306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_Y(skb->data, req->macid_y); 451762306a36Sopenharmony_ci 451862306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 451962306a36Sopenharmony_ci H2C_CAT_MAC, 452062306a36Sopenharmony_ci H2C_CL_MCC, 452162306a36Sopenharmony_ci H2C_FUNC_MCC_REQ_TSF, 0, 0, 452262306a36Sopenharmony_ci H2C_MCC_REQ_TSF_LEN); 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(req->group, H2C_FUNC_MCC_REQ_TSF); 452562306a36Sopenharmony_ci ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 452662306a36Sopenharmony_ci if (ret) 452762306a36Sopenharmony_ci return ret; 452862306a36Sopenharmony_ci 452962306a36Sopenharmony_ci tmp = (struct rtw89_mac_mcc_tsf_rpt *)wait->data.buf; 453062306a36Sopenharmony_ci *rpt = *tmp; 453162306a36Sopenharmony_ci 453262306a36Sopenharmony_ci return 0; 453362306a36Sopenharmony_ci} 453462306a36Sopenharmony_ci 453562306a36Sopenharmony_ci#define H2C_MCC_MACID_BITMAP_DSC_LEN 4 453662306a36Sopenharmony_ciint rtw89_fw_h2c_mcc_macid_bitamp(struct rtw89_dev *rtwdev, u8 group, u8 macid, 453762306a36Sopenharmony_ci u8 *bitmap) 453862306a36Sopenharmony_ci{ 453962306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 454062306a36Sopenharmony_ci struct sk_buff *skb; 454162306a36Sopenharmony_ci unsigned int cond; 454262306a36Sopenharmony_ci u8 map_len; 454362306a36Sopenharmony_ci u8 h2c_len; 454462306a36Sopenharmony_ci 454562306a36Sopenharmony_ci BUILD_BUG_ON(RTW89_MAX_MAC_ID_NUM % 8); 454662306a36Sopenharmony_ci map_len = RTW89_MAX_MAC_ID_NUM / 8; 454762306a36Sopenharmony_ci h2c_len = H2C_MCC_MACID_BITMAP_DSC_LEN + map_len; 454862306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, h2c_len); 454962306a36Sopenharmony_ci if (!skb) { 455062306a36Sopenharmony_ci rtw89_err(rtwdev, 455162306a36Sopenharmony_ci "failed to alloc skb for mcc macid bitmap\n"); 455262306a36Sopenharmony_ci return -ENOMEM; 455362306a36Sopenharmony_ci } 455462306a36Sopenharmony_ci 455562306a36Sopenharmony_ci skb_put(skb, h2c_len); 455662306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_MACID_BITMAP_GROUP(skb->data, group); 455762306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_MACID_BITMAP_MACID(skb->data, macid); 455862306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP_LENGTH(skb->data, map_len); 455962306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP(skb->data, bitmap, map_len); 456062306a36Sopenharmony_ci 456162306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 456262306a36Sopenharmony_ci H2C_CAT_MAC, 456362306a36Sopenharmony_ci H2C_CL_MCC, 456462306a36Sopenharmony_ci H2C_FUNC_MCC_MACID_BITMAP, 0, 0, 456562306a36Sopenharmony_ci h2c_len); 456662306a36Sopenharmony_ci 456762306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_MACID_BITMAP); 456862306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 456962306a36Sopenharmony_ci} 457062306a36Sopenharmony_ci 457162306a36Sopenharmony_ci#define H2C_MCC_SYNC_LEN 4 457262306a36Sopenharmony_ciint rtw89_fw_h2c_mcc_sync(struct rtw89_dev *rtwdev, u8 group, u8 source, 457362306a36Sopenharmony_ci u8 target, u8 offset) 457462306a36Sopenharmony_ci{ 457562306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 457662306a36Sopenharmony_ci struct sk_buff *skb; 457762306a36Sopenharmony_ci unsigned int cond; 457862306a36Sopenharmony_ci 457962306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_SYNC_LEN); 458062306a36Sopenharmony_ci if (!skb) { 458162306a36Sopenharmony_ci rtw89_err(rtwdev, 458262306a36Sopenharmony_ci "failed to alloc skb for mcc sync\n"); 458362306a36Sopenharmony_ci return -ENOMEM; 458462306a36Sopenharmony_ci } 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci skb_put(skb, H2C_MCC_SYNC_LEN); 458762306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SYNC_GROUP(skb->data, group); 458862306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SYNC_MACID_SOURCE(skb->data, source); 458962306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SYNC_MACID_TARGET(skb->data, target); 459062306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SYNC_SYNC_OFFSET(skb->data, offset); 459162306a36Sopenharmony_ci 459262306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 459362306a36Sopenharmony_ci H2C_CAT_MAC, 459462306a36Sopenharmony_ci H2C_CL_MCC, 459562306a36Sopenharmony_ci H2C_FUNC_MCC_SYNC, 0, 0, 459662306a36Sopenharmony_ci H2C_MCC_SYNC_LEN); 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_SYNC); 459962306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 460062306a36Sopenharmony_ci} 460162306a36Sopenharmony_ci 460262306a36Sopenharmony_ci#define H2C_MCC_SET_DURATION_LEN 20 460362306a36Sopenharmony_ciint rtw89_fw_h2c_mcc_set_duration(struct rtw89_dev *rtwdev, 460462306a36Sopenharmony_ci const struct rtw89_fw_mcc_duration *p) 460562306a36Sopenharmony_ci{ 460662306a36Sopenharmony_ci struct rtw89_wait_info *wait = &rtwdev->mcc.wait; 460762306a36Sopenharmony_ci struct sk_buff *skb; 460862306a36Sopenharmony_ci unsigned int cond; 460962306a36Sopenharmony_ci 461062306a36Sopenharmony_ci skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_SET_DURATION_LEN); 461162306a36Sopenharmony_ci if (!skb) { 461262306a36Sopenharmony_ci rtw89_err(rtwdev, 461362306a36Sopenharmony_ci "failed to alloc skb for mcc set duration\n"); 461462306a36Sopenharmony_ci return -ENOMEM; 461562306a36Sopenharmony_ci } 461662306a36Sopenharmony_ci 461762306a36Sopenharmony_ci skb_put(skb, H2C_MCC_SET_DURATION_LEN); 461862306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_GROUP(skb->data, p->group); 461962306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_BTC_IN_GROUP(skb->data, p->btc_in_group); 462062306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_START_MACID(skb->data, p->start_macid); 462162306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_X(skb->data, p->macid_x); 462262306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_Y(skb->data, p->macid_y); 462362306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_LOW(skb->data, 462462306a36Sopenharmony_ci p->start_tsf_low); 462562306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_HIGH(skb->data, 462662306a36Sopenharmony_ci p->start_tsf_high); 462762306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_X(skb->data, p->duration_x); 462862306a36Sopenharmony_ci RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_Y(skb->data, p->duration_y); 462962306a36Sopenharmony_ci 463062306a36Sopenharmony_ci rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 463162306a36Sopenharmony_ci H2C_CAT_MAC, 463262306a36Sopenharmony_ci H2C_CL_MCC, 463362306a36Sopenharmony_ci H2C_FUNC_MCC_SET_DURATION, 0, 0, 463462306a36Sopenharmony_ci H2C_MCC_SET_DURATION_LEN); 463562306a36Sopenharmony_ci 463662306a36Sopenharmony_ci cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_MCC_SET_DURATION); 463762306a36Sopenharmony_ci return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); 463862306a36Sopenharmony_ci} 4639