wifi: rtw89: add firmware format version to backward compatible with older drivers
authorPing-Ke Shih <pkshih@realtek.com>
Mon, 20 Mar 2023 13:06:06 +0000 (21:06 +0800)
committerKalle Valo <kvalo@kernel.org>
Fri, 14 Apr 2023 12:13:59 +0000 (15:13 +0300)
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: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230320130606.20777-4-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/rtw8852a.c
drivers/net/wireless/realtek/rtw89/rtw8852b.c
drivers/net/wireless/realtek/rtw89/rtw8852c.c

index 8e79064c3a7ba939d8bba47cf67e5b51f76f3b2a..79bce458d3a2e032bf2919e80c03cb8730580429 100644 (file)
@@ -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");
index bd5578ca1636e90a6dd48ba4916b30605fc94b69..be937a420c70641d3f523202e77ce10b6f4fadae 100644 (file)
@@ -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;
index 9edc421e176cf607a62d08a7e4d9ba00dfb00099..239dfb33eed5ffee1535c6a6723fd727d345afeb 100644 (file)
@@ -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;
 
-       if (full_req)
-               ret = request_firmware(&firmware, chip->fw_name, device);
-       else
-               ret = request_partial_firmware_into_buf(&firmware, chip->fw_name,
-                                                       device, &buf, sizeof(buf),
-                                                       0);
+       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, fw_name, device);
+               else
+                       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);
 }
index 661e08ae7bc8c815d73e022cf0952accdc03f536..a2ff173e55446ff5da864f00fe690c8827bd6892 100644 (file)
@@ -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);
index 46907748778bd391d319a81393400a8b93fc9fa4..caaaa9f37d6b14055ab448b12acc42d32321abc8 100644 (file)
 #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");
index bae80984cfd511574902725a5b40d525aa3b2c6d..6a3a28d729db6ee12b568dae71b1a1959829c28f 100644 (file)
 #include "rtw8852b_table.h"
 #include "txrx.h"
 
+#define RTW8852B_FW_FORMAT_MAX 1
+#define RTW8852B_FW_BASENAME "rtw89/rtw8852b_fw"
+#define RTW8852B_MODULE_FIRMWARE \
+       RTW8852B_FW_BASENAME "-" __stringify(RTW8852B_FW_FORMAT_MAX) ".bin"
+
 static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_pcie[] = {
        {5, 343, grp_0}, /* ACH 0 */
        {5, 343, grp_0}, /* ACH 1 */
@@ -2480,7 +2485,8 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = {
 const struct rtw89_chip_info rtw8852b_chip_info = {
        .chip_id                = RTL8852B,
        .ops                    = &rtw8852b_chip_ops,
-       .fw_name                = "rtw89/rtw8852b_fw.bin",
+       .fw_basename            = RTW8852B_FW_BASENAME,
+       .fw_format_max          = RTW8852B_FW_FORMAT_MAX,
        .try_ce_fw              = true,
        .fifo_size              = 196608,
        .dle_scc_rsvd_size      = 98304,
@@ -2576,7 +2582,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
 };
 EXPORT_SYMBOL(rtw8852b_chip_info);
 
-MODULE_FIRMWARE("rtw89/rtw8852b_fw.bin");
+MODULE_FIRMWARE(RTW8852B_MODULE_FIRMWARE);
 MODULE_AUTHOR("Realtek Corporation");
 MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852B driver");
 MODULE_LICENSE("Dual BSD/GPL");
index ba728fca9188119fb538bf88431a700260f5a3cc..c5147d965160b103db8e84059ad94afc44eeac67 100644 (file)
 #include "rtw8852c_table.h"
 #include "util.h"
 
+#define RTW8852C_FW_FORMAT_MAX 0
+#define RTW8852C_FW_BASENAME "rtw89/rtw8852c_fw"
+#define RTW8852C_MODULE_FIRMWARE \
+       RTW8852C_FW_BASENAME ".bin"
+
 static const struct rtw89_hfc_ch_cfg rtw8852c_hfc_chcfg_pcie[] = {
        {13, 1614, grp_0}, /* ACH 0 */
        {13, 1614, grp_0}, /* ACH 1 */
@@ -2791,7 +2796,8 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
 const struct rtw89_chip_info rtw8852c_chip_info = {
        .chip_id                = RTL8852C,
        .ops                    = &rtw8852c_chip_ops,
-       .fw_name                = "rtw89/rtw8852c_fw.bin",
+       .fw_basename            = RTW8852C_FW_BASENAME,
+       .fw_format_max          = RTW8852C_FW_FORMAT_MAX,
        .try_ce_fw              = false,
        .fifo_size              = 458752,
        .dle_scc_rsvd_size      = 0,
@@ -2892,7 +2898,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
 };
 EXPORT_SYMBOL(rtw8852c_chip_info);
 
-MODULE_FIRMWARE("rtw89/rtw8852c_fw.bin");
+MODULE_FIRMWARE(RTW8852C_MODULE_FIRMWARE);
 MODULE_AUTHOR("Realtek Corporation");
 MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852C driver");
 MODULE_LICENSE("Dual BSD/GPL");