wifi: rtw89: use struct to parse firmware header
A firmware contains basic header, sections and optional dynamic header. Define them by a struct, so it will be easier to understand the layout, and also simply access these elements. Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://lore.kernel.org/r/20230616060601.28460-1-pkshih@realtek.com
This commit is contained in:
parent
b4a283fb62
commit
f072eb39e4
@ -3387,10 +3387,10 @@ struct rtw89_fw_suit {
|
||||
(mfw_hdr)->ver.idx)
|
||||
|
||||
#define RTW89_FW_HDR_VER_CODE(fw_hdr) \
|
||||
RTW89_FW_VER_CODE(GET_FW_HDR_MAJOR_VERSION(fw_hdr), \
|
||||
GET_FW_HDR_MINOR_VERSION(fw_hdr), \
|
||||
GET_FW_HDR_SUBVERSION(fw_hdr), \
|
||||
GET_FW_HDR_SUBINDEX(fw_hdr))
|
||||
RTW89_FW_VER_CODE(le32_get_bits((fw_hdr)->w1, FW_HDR_W1_MAJOR_VERSION), \
|
||||
le32_get_bits((fw_hdr)->w1, FW_HDR_W1_MINOR_VERSION), \
|
||||
le32_get_bits((fw_hdr)->w1, FW_HDR_W1_SUBVERSION), \
|
||||
le32_get_bits((fw_hdr)->w1, FW_HDR_W1_SUBINDEX))
|
||||
|
||||
struct rtw89_fw_req_info {
|
||||
const struct firmware *firmware;
|
||||
|
@ -89,9 +89,11 @@ int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
|
||||
static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
|
||||
struct rtw89_fw_bin_info *info)
|
||||
{
|
||||
const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw;
|
||||
struct rtw89_fw_hdr_section_info *section_info;
|
||||
const struct rtw89_fw_dynhdr_hdr *fwdynhdr;
|
||||
const struct rtw89_fw_hdr_section *section;
|
||||
const u8 *fw_end = fw + len;
|
||||
const u8 *fwdynhdr;
|
||||
const u8 *bin;
|
||||
u32 base_hdr_len;
|
||||
u32 mssc_len = 0;
|
||||
@ -100,16 +102,15 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
info->section_num = GET_FW_HDR_SEC_NUM(fw);
|
||||
base_hdr_len = RTW89_FW_HDR_SIZE +
|
||||
info->section_num * RTW89_FW_SECTION_HDR_SIZE;
|
||||
info->dynamic_hdr_en = GET_FW_HDR_DYN_HDR(fw);
|
||||
info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM);
|
||||
base_hdr_len = struct_size(fw_hdr, sections, info->section_num);
|
||||
info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR);
|
||||
|
||||
if (info->dynamic_hdr_en) {
|
||||
info->hdr_len = GET_FW_HDR_LEN(fw);
|
||||
info->hdr_len = le32_get_bits(fw_hdr->w3, FW_HDR_W3_LEN);
|
||||
info->dynamic_hdr_len = info->hdr_len - base_hdr_len;
|
||||
fwdynhdr = fw + base_hdr_len;
|
||||
if (GET_FW_DYNHDR_LEN(fwdynhdr) != info->dynamic_hdr_len) {
|
||||
fwdynhdr = (const struct rtw89_fw_dynhdr_hdr *)(fw + base_hdr_len);
|
||||
if (le32_to_cpu(fwdynhdr->hdr_len) != info->dynamic_hdr_len) {
|
||||
rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -121,26 +122,27 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
|
||||
bin = fw + info->hdr_len;
|
||||
|
||||
/* jump to section header */
|
||||
fw += RTW89_FW_HDR_SIZE;
|
||||
section_info = info->section_info;
|
||||
for (i = 0; i < info->section_num; i++) {
|
||||
section_info->type = GET_FWSECTION_HDR_SECTIONTYPE(fw);
|
||||
section = &fw_hdr->sections[i];
|
||||
section_info->type =
|
||||
le32_get_bits(section->w1, FWSECTION_HDR_W1_SECTIONTYPE);
|
||||
if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
|
||||
section_info->mssc = GET_FWSECTION_HDR_MSSC(fw);
|
||||
section_info->mssc =
|
||||
le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC);
|
||||
mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN;
|
||||
} else {
|
||||
section_info->mssc = 0;
|
||||
}
|
||||
|
||||
section_info->len = GET_FWSECTION_HDR_SEC_SIZE(fw);
|
||||
if (GET_FWSECTION_HDR_CHECKSUM(fw))
|
||||
section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_W1_SEC_SIZE);
|
||||
if (le32_get_bits(section->w1, FWSECTION_HDR_W1_CHECKSUM))
|
||||
section_info->len += FWDL_SECTION_CHKSUM_LEN;
|
||||
section_info->redl = GET_FWSECTION_HDR_REDL(fw);
|
||||
section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_W1_REDL);
|
||||
section_info->dladdr =
|
||||
GET_FWSECTION_HDR_DL_ADDR(fw) & 0x1fffffff;
|
||||
le32_get_bits(section->w0, FWSECTION_HDR_W0_DL_ADDR) & 0x1fffffff;
|
||||
section_info->addr = bin;
|
||||
bin += section_info->len;
|
||||
fw += RTW89_FW_SECTION_HDR_SIZE;
|
||||
section_info++;
|
||||
}
|
||||
|
||||
@ -195,18 +197,18 @@ static void rtw89_fw_update_ver(struct rtw89_dev *rtwdev,
|
||||
enum rtw89_fw_type type,
|
||||
struct rtw89_fw_suit *fw_suit)
|
||||
{
|
||||
const u8 *hdr = fw_suit->data;
|
||||
const struct rtw89_fw_hdr *hdr = (const struct rtw89_fw_hdr *)fw_suit->data;
|
||||
|
||||
fw_suit->major_ver = GET_FW_HDR_MAJOR_VERSION(hdr);
|
||||
fw_suit->minor_ver = GET_FW_HDR_MINOR_VERSION(hdr);
|
||||
fw_suit->sub_ver = GET_FW_HDR_SUBVERSION(hdr);
|
||||
fw_suit->sub_idex = GET_FW_HDR_SUBINDEX(hdr);
|
||||
fw_suit->build_year = GET_FW_HDR_YEAR(hdr);
|
||||
fw_suit->build_mon = GET_FW_HDR_MONTH(hdr);
|
||||
fw_suit->build_date = GET_FW_HDR_DATE(hdr);
|
||||
fw_suit->build_hour = GET_FW_HDR_HOUR(hdr);
|
||||
fw_suit->build_min = GET_FW_HDR_MIN(hdr);
|
||||
fw_suit->cmd_ver = GET_FW_HDR_CMD_VERSERION(hdr);
|
||||
fw_suit->major_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MAJOR_VERSION);
|
||||
fw_suit->minor_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MINOR_VERSION);
|
||||
fw_suit->sub_ver = le32_get_bits(hdr->w1, FW_HDR_W1_SUBVERSION);
|
||||
fw_suit->sub_idex = le32_get_bits(hdr->w1, FW_HDR_W1_SUBINDEX);
|
||||
fw_suit->build_year = le32_get_bits(hdr->w5, FW_HDR_W5_YEAR);
|
||||
fw_suit->build_mon = le32_get_bits(hdr->w4, FW_HDR_W4_MONTH);
|
||||
fw_suit->build_date = le32_get_bits(hdr->w4, FW_HDR_W4_DATE);
|
||||
fw_suit->build_hour = le32_get_bits(hdr->w4, FW_HDR_W4_HOUR);
|
||||
fw_suit->build_min = le32_get_bits(hdr->w4, FW_HDR_W4_MIN);
|
||||
fw_suit->cmd_ver = le32_get_bits(hdr->w7, FW_HDR_W7_CMD_VERSERION);
|
||||
|
||||
rtw89_info(rtwdev,
|
||||
"Firmware version %u.%u.%u.%u, cmd version %u, type %u\n",
|
||||
|
@ -528,50 +528,58 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val)
|
||||
#define FWDL_SECURITY_SECTION_TYPE 9
|
||||
#define FWDL_SECURITY_SIGLEN 512
|
||||
|
||||
#define GET_FWSECTION_HDR_DL_ADDR(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr)), GENMASK(31, 0))
|
||||
#define GET_FWSECTION_HDR_SECTIONTYPE(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(27, 24))
|
||||
#define GET_FWSECTION_HDR_SEC_SIZE(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 0))
|
||||
#define GET_FWSECTION_HDR_CHECKSUM(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(28))
|
||||
#define GET_FWSECTION_HDR_REDL(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(29))
|
||||
#define GET_FWSECTION_HDR_MSSC(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 2), GENMASK(31, 0))
|
||||
struct rtw89_fw_dynhdr_sec {
|
||||
__le32 w0;
|
||||
u8 content[];
|
||||
} __packed;
|
||||
|
||||
#define GET_FW_HDR_MAJOR_VERSION(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(7, 0))
|
||||
#define GET_FW_HDR_MINOR_VERSION(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(15, 8))
|
||||
#define GET_FW_HDR_SUBVERSION(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 16))
|
||||
#define GET_FW_HDR_SUBINDEX(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(31, 24))
|
||||
#define GET_FW_HDR_LEN(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 3), GENMASK(23, 16))
|
||||
#define GET_FW_HDR_MONTH(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(7, 0))
|
||||
#define GET_FW_HDR_DATE(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(15, 8))
|
||||
#define GET_FW_HDR_HOUR(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(23, 16))
|
||||
#define GET_FW_HDR_MIN(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(31, 24))
|
||||
#define GET_FW_HDR_YEAR(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 5), GENMASK(31, 0))
|
||||
#define GET_FW_HDR_SEC_NUM(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 6), GENMASK(15, 8))
|
||||
#define GET_FW_HDR_DYN_HDR(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 7), BIT(16))
|
||||
#define GET_FW_HDR_CMD_VERSERION(fwhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwhdr) + 7), GENMASK(31, 24))
|
||||
struct rtw89_fw_dynhdr_hdr {
|
||||
__le32 hdr_len;
|
||||
__le32 setcion_count;
|
||||
/* struct rtw89_fw_dynhdr_sec (nested flexible structures) */
|
||||
} __packed;
|
||||
|
||||
#define GET_FW_DYNHDR_LEN(fwdynhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwdynhdr)), GENMASK(31, 0))
|
||||
#define GET_FW_DYNHDR_COUNT(fwdynhdr) \
|
||||
le32_get_bits(*((const __le32 *)(fwdynhdr) + 1), GENMASK(31, 0))
|
||||
struct rtw89_fw_hdr_section {
|
||||
__le32 w0;
|
||||
__le32 w1;
|
||||
__le32 w2;
|
||||
__le32 w3;
|
||||
} __packed;
|
||||
|
||||
#define FWSECTION_HDR_W0_DL_ADDR GENMASK(31, 0)
|
||||
#define FWSECTION_HDR_W1_METADATA GENMASK(31, 24)
|
||||
#define FWSECTION_HDR_W1_SECTIONTYPE GENMASK(27, 24)
|
||||
#define FWSECTION_HDR_W1_SEC_SIZE GENMASK(23, 0)
|
||||
#define FWSECTION_HDR_W1_CHECKSUM BIT(28)
|
||||
#define FWSECTION_HDR_W1_REDL BIT(29)
|
||||
#define FWSECTION_HDR_W2_MSSC GENMASK(31, 0)
|
||||
|
||||
struct rtw89_fw_hdr {
|
||||
__le32 w0;
|
||||
__le32 w1;
|
||||
__le32 w2;
|
||||
__le32 w3;
|
||||
__le32 w4;
|
||||
__le32 w5;
|
||||
__le32 w6;
|
||||
__le32 w7;
|
||||
struct rtw89_fw_hdr_section sections[];
|
||||
/* struct rtw89_fw_dynhdr_hdr (optional) */
|
||||
} __packed;
|
||||
|
||||
#define FW_HDR_W1_MAJOR_VERSION GENMASK(7, 0)
|
||||
#define FW_HDR_W1_MINOR_VERSION GENMASK(15, 8)
|
||||
#define FW_HDR_W1_SUBVERSION GENMASK(23, 16)
|
||||
#define FW_HDR_W1_SUBINDEX GENMASK(31, 24)
|
||||
#define FW_HDR_W3_LEN GENMASK(23, 16)
|
||||
#define FW_HDR_W4_MONTH GENMASK(7, 0)
|
||||
#define FW_HDR_W4_DATE GENMASK(15, 8)
|
||||
#define FW_HDR_W4_HOUR GENMASK(23, 16)
|
||||
#define FW_HDR_W4_MIN GENMASK(31, 24)
|
||||
#define FW_HDR_W5_YEAR GENMASK(31, 0)
|
||||
#define FW_HDR_W6_SEC_NUM GENMASK(15, 8)
|
||||
#define FW_HDR_W7_DYN_HDR BIT(16)
|
||||
#define FW_HDR_W7_CMD_VERSERION GENMASK(31, 24)
|
||||
|
||||
static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val)
|
||||
{
|
||||
@ -3392,9 +3400,6 @@ struct rtw89_h2c_ofld {
|
||||
#define RTW89_H2C_OFLD_W0_TX_TP GENMASK(17, 8)
|
||||
#define RTW89_H2C_OFLD_W0_RX_TP GENMASK(27, 18)
|
||||
|
||||
#define RTW89_FW_HDR_SIZE 32
|
||||
#define RTW89_FW_SECTION_HDR_SIZE 16
|
||||
|
||||
#define RTW89_MFW_SIG 0xFF
|
||||
|
||||
struct rtw89_mfw_info {
|
||||
@ -3428,7 +3433,7 @@ struct fwcmd_hdr {
|
||||
|
||||
union rtw89_compat_fw_hdr {
|
||||
struct rtw89_mfw_hdr mfw_hdr;
|
||||
u8 fw_hdr[RTW89_FW_HDR_SIZE];
|
||||
struct rtw89_fw_hdr fw_hdr;
|
||||
};
|
||||
|
||||
static inline u32 rtw89_compat_fw_hdr_ver_code(const void *fw_buf)
|
||||
|
Loading…
x
Reference in New Issue
Block a user