diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d21f87e25ae1..548b772eccfe 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -85,15 +85,31 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, { struct rtw89_fw_hdr_section_info *section_info; const u8 *fw_end = fw + len; + const u8 *fwdynhdr; const u8 *bin; + u32 base_hdr_len; u32 i; if (!info) return -EINVAL; info->section_num = GET_FW_HDR_SEC_NUM(fw); - info->hdr_len = RTW89_FW_HDR_SIZE + - info->section_num * RTW89_FW_SECTION_HDR_SIZE; + 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); + + if (info->dynamic_hdr_en) { + info->hdr_len = GET_FW_HDR_LEN(fw); + 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) { + rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n"); + return -EINVAL; + } + } else { + info->hdr_len = base_hdr_len; + info->dynamic_hdr_len = 0; + } bin = fw + info->hdr_len; @@ -534,7 +550,7 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type) goto fwdl_err; } - ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len); + ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len - info.dynamic_hdr_len); if (ret) { ret = -EBUSY; goto fwdl_err; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 6ef392ef9c6f..8563efa5f641 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -176,6 +176,8 @@ struct rtw89_fw_hdr_section_info { struct rtw89_fw_bin_info { u8 section_num; u32 hdr_len; + bool dynamic_hdr_en; + u32 dynamic_hdr_len; struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM]; }; @@ -495,6 +497,8 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) 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) \ @@ -507,8 +511,16 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) 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)) + +#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)) + static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) { le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0));