Commit ffde7f34 authored by Ping-Ke Shih's avatar Ping-Ke Shih Committed by Kalle Valo
Browse files

wifi: rtw89: add firmware format version to backward compatible with older drivers

In the discuss threads [1] [2], new firmware format break user space
because older drivers can't recognize new firmware format. To avoid this,
the new format will be named rtw89/rtw8852b_fw-1.bin and only new driver
try to load it. Old drivers only load original and understandable firmware
rtw89/rtw8852b_fw.bin.

More, new driver will be still backward compatible with old firmware, so
original firmware can be used by new driver.

If there is newer firmware format is introduced, rtw89/rtw8852b_fw-2.bin
will be given. The same rules will be applied like above. So, we will have
firmware like below in linux-firmware in the future.

  rtw89/rtw8852b_fw-2.bin
  rtw89/rtw8852b_fw-1.bin
  rtw89/rtw8852b_fw.bin

After this patch, MODULE_FIRMWARE() of 8852A/B/C become
  rtw89/rtw8852a_fw.bin
  rtw89/rtw8852b_fw-1.bin
  rtw89/rtw8852c_fw.bin

[1] https://lore.kernel.org/linux-wireless/df1ce994-3368-a57e-7078-8bdcccf4a1fd@gmail.com/T/#m24cb43be31a762d0ea70bf07f27ae96c59f6931b
[2] https://bugzilla.kernel.org/show_bug.cgi?id=217207



Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230320130606.20777-4-pkshih@realtek.com
parent b80ad23a
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -3759,9 +3759,10 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
	struct rtw89_dev *rtwdev;
	struct ieee80211_ops *ops;
	u32 driver_data_size;
	int fw_format = -1;
	bool no_chanctx;

	firmware = rtw89_early_fw_feature_recognize(device, chip, &early_fw);
	firmware = rtw89_early_fw_feature_recognize(device, chip, &early_fw, &fw_format);

	ops = kmemdup(&rtw89_ops, sizeof(rtw89_ops), GFP_KERNEL);
	if (!ops)
@@ -3792,6 +3793,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
	rtwdev->ops = ops;
	rtwdev->chip = chip;
	rtwdev->fw.req.firmware = firmware;
	rtwdev->fw.fw_format = fw_format;

	rtw89_debug(rtwdev, RTW89_DBG_FW, "probe driver %s chanctx\n",
		    no_chanctx ? "without" : "with");
+3 −1
Original line number Diff line number Diff line
@@ -3080,7 +3080,8 @@ struct rtw89_phy_ul_tb_info {
struct rtw89_chip_info {
	enum rtw89_core_chip_id chip_id;
	const struct rtw89_chip_ops *ops;
	const char *fw_name;
	const char *fw_basename;
	u8 fw_format_max;
	bool try_ce_fw;
	u32 fifo_size;
	u32 dle_scc_rsvd_size;
@@ -3304,6 +3305,7 @@ struct rtw89_fw_req_info {

struct rtw89_fw_info {
	struct rtw89_fw_req_info req;
	int fw_format;
	u8 h2c_seq;
	u8 rec_seq;
	u8 h2c_counter;
+25 −8
Original line number Diff line number Diff line
@@ -302,11 +302,14 @@ static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
const struct firmware *
rtw89_early_fw_feature_recognize(struct device *device,
				 const struct rtw89_chip_info *chip,
				 struct rtw89_fw_info *early_fw)
				 struct rtw89_fw_info *early_fw,
				 int *used_fw_format)
{
	union rtw89_compat_fw_hdr buf = {};
	const struct firmware *firmware;
	bool full_req = false;
	char fw_name[64];
	int fw_format;
	u32 ver_code;
	int ret;

@@ -317,12 +320,22 @@ rtw89_early_fw_feature_recognize(struct device *device,
	if (IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE))
		full_req = true;

	for (fw_format = chip->fw_format_max; fw_format >= 0; fw_format--) {
		rtw89_fw_get_filename(fw_name, sizeof(fw_name),
				      chip->fw_basename, fw_format);

		if (full_req)
		ret = request_firmware(&firmware, chip->fw_name, device);
			ret = request_firmware(&firmware, fw_name, device);
		else
		ret = request_partial_firmware_into_buf(&firmware, chip->fw_name,
			ret = request_partial_firmware_into_buf(&firmware, fw_name,
								device, &buf, sizeof(buf),
								0);
		if (!ret) {
			dev_info(device, "loaded firmware %s\n", fw_name);
			*used_fw_format = fw_format;
			break;
		}
	}

	if (ret) {
		dev_err(device, "failed to early request firmware: %d\n", ret);
@@ -666,7 +679,11 @@ void rtw89_load_firmware_work(struct work_struct *work)
{
	struct rtw89_dev *rtwdev =
		container_of(work, struct rtw89_dev, load_firmware_work);
	const char *fw_name = rtwdev->chip->fw_name;
	const struct rtw89_chip_info *chip = rtwdev->chip;
	char fw_name[64];

	rtw89_fw_get_filename(fw_name, sizeof(fw_name),
			      chip->fw_basename, rtwdev->fw.fw_format);

	rtw89_load_firmware_req(rtwdev, &rtwdev->fw.req, fw_name, false);
}
+11 −1
Original line number Diff line number Diff line
@@ -3515,6 +3515,15 @@ static inline u32 rtw89_compat_fw_hdr_ver_code(const void *fw_buf)
		return RTW89_FW_HDR_VER_CODE(&compat->fw_hdr);
}

static inline void rtw89_fw_get_filename(char *buf, size_t size,
					 const char *fw_basename, int fw_format)
{
	if (fw_format <= 0)
		snprintf(buf, size, "%s.bin", fw_basename);
	else
		snprintf(buf, size, "%s-%d.bin", fw_basename, fw_format);
}

#define RTW89_H2C_RF_PAGE_SIZE 500
#define RTW89_H2C_RF_PAGE_NUM 3
struct rtw89_fw_h2c_rf_reg_info {
@@ -3658,7 +3667,8 @@ int rtw89_fw_recognize(struct rtw89_dev *rtwdev);
const struct firmware *
rtw89_early_fw_feature_recognize(struct device *device,
				 const struct rtw89_chip_info *chip,
				 struct rtw89_fw_info *early_fw);
				 struct rtw89_fw_info *early_fw,
				 int *used_fw_format);
int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type);
void rtw89_load_firmware_work(struct work_struct *work);
void rtw89_unload_firmware(struct rtw89_dev *rtwdev);
+8 −2
Original line number Diff line number Diff line
@@ -12,6 +12,11 @@
#include "rtw8852a_table.h"
#include "txrx.h"

#define RTW8852A_FW_FORMAT_MAX 0
#define RTW8852A_FW_BASENAME "rtw89/rtw8852a_fw"
#define RTW8852A_MODULE_FIRMWARE \
	RTW8852A_FW_BASENAME ".bin"

static const struct rtw89_hfc_ch_cfg rtw8852a_hfc_chcfg_pcie[] = {
	{128, 1896, grp_0}, /* ACH 0 */
	{128, 1896, grp_0}, /* ACH 1 */
@@ -2059,7 +2064,8 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = {
const struct rtw89_chip_info rtw8852a_chip_info = {
	.chip_id		= RTL8852A,
	.ops			= &rtw8852a_chip_ops,
	.fw_name		= "rtw89/rtw8852a_fw.bin",
	.fw_basename		= RTW8852A_FW_BASENAME,
	.fw_format_max		= RTW8852A_FW_FORMAT_MAX,
	.try_ce_fw		= false,
	.fifo_size		= 458752,
	.dle_scc_rsvd_size	= 0,
@@ -2156,7 +2162,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
};
EXPORT_SYMBOL(rtw8852a_chip_info);

MODULE_FIRMWARE("rtw89/rtw8852a_fw.bin");
MODULE_FIRMWARE(RTW8852A_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852A driver");
MODULE_LICENSE("Dual BSD/GPL");
Loading