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