wifi: rtw89: request full firmware only once if it's early requested
authorZong-Zhe Yang <kevin_yang@realtek.com>
Fri, 2 Dec 2022 06:05:21 +0000 (14:05 +0800)
committerKalle Valo <kvalo@kernel.org>
Thu, 8 Dec 2022 14:47:29 +0000 (16:47 +0200)
Under some condition, we now have to do early request full firmware when
rtw89_early_fw_feature_recognize(). In this case, we can avoid requesting
full firmware twice during probing driver. So, we pass out full firmware
from rtw89_early_fw_feature_recognize() if it's requested successfully.
And then, if firmware is settled, we have no need to request full firmware
again during normal initizating flow.

Setting firmware flow is updated to be as the following.

 platform | early recognizing  | normally initizating
-----------------------------------------------------------------------
 deny reading  | request full FW | (no more FW requesting)
 partial file  | | (obtain FW from early pahse)
-----------------------------------------------------------------------
 able to read | request partial FW | async request full FW
 partial file | (quite small chunk) |

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20221202060521.501512-3-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h

index 5ab95250755dfda3fb88fce98199e86f771b6795..931aff8b5dc95476fc8463878192a76fe19f8dd3 100644 (file)
@@ -3420,6 +3420,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
                                           u32 bus_data_size,
                                           const struct rtw89_chip_info *chip)
 {
+       const struct firmware *firmware;
        struct ieee80211_hw *hw;
        struct rtw89_dev *rtwdev;
        struct ieee80211_ops *ops;
@@ -3427,7 +3428,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
        u32 early_feat_map = 0;
        bool no_chanctx;
 
-       rtw89_early_fw_feature_recognize(device, chip, &early_feat_map);
+       firmware = rtw89_early_fw_feature_recognize(device, chip, &early_feat_map);
 
        ops = kmemdup(&rtw89_ops, sizeof(rtw89_ops), GFP_KERNEL);
        if (!ops)
@@ -3454,6 +3455,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
        rtwdev->dev = device;
        rtwdev->ops = ops;
        rtwdev->chip = chip;
+       rtwdev->fw.firmware = firmware;
 
        rtw89_debug(rtwdev, RTW89_DBG_FW, "probe driver %s chanctx\n",
                    no_chanctx ? "without" : "with");
@@ -3462,6 +3464,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
 
 err:
        kfree(ops);
+       release_firmware(firmware);
        return NULL;
 }
 EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw);
@@ -3469,6 +3472,7 @@ EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw);
 void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev)
 {
        kfree(rtwdev->ops);
+       release_firmware(rtwdev->fw.firmware);
        ieee80211_free_hw(rtwdev->hw);
 }
 EXPORT_SYMBOL(rtw89_free_ieee80211_hw);
index f5daea0d4f93ce7cf67f02d919405015a4958477..de1f23779fc62dd3e19884ea0a98667a73c6f259 100644 (file)
@@ -273,9 +273,10 @@ static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
        }
 }
 
-void rtw89_early_fw_feature_recognize(struct device *device,
-                                     const struct rtw89_chip_info *chip,
-                                     u32 *early_feat_map)
+const struct firmware *
+rtw89_early_fw_feature_recognize(struct device *device,
+                                const struct rtw89_chip_info *chip,
+                                u32 *early_feat_map)
 {
        union rtw89_compat_fw_hdr buf = {};
        const struct firmware *firmware;
@@ -300,7 +301,7 @@ void rtw89_early_fw_feature_recognize(struct device *device,
 
        if (ret) {
                dev_err(device, "failed to early request firmware: %d\n", ret);
-               return;
+               return NULL;
        }
 
        if (full_req)
@@ -322,7 +323,11 @@ void rtw89_early_fw_feature_recognize(struct device *device,
        }
 
 out:
+       if (full_req)
+               return firmware;
+
        release_firmware(firmware);
+       return NULL;
 }
 
 int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
@@ -629,6 +634,13 @@ int rtw89_load_firmware(struct rtw89_dev *rtwdev)
        fw->rtwdev = rtwdev;
        init_completion(&fw->completion);
 
+       if (fw->firmware) {
+               rtw89_debug(rtwdev, RTW89_DBG_FW,
+                           "full firmware has been early requested\n");
+               complete_all(&fw->completion);
+               return 0;
+       }
+
        ret = request_firmware_nowait(THIS_MODULE, true, fw_name, rtwdev->dev,
                                      GFP_KERNEL, fw, rtw89_load_firmware_cb);
        if (ret) {
@@ -645,8 +657,14 @@ void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
 
        rtw89_wait_firmware_completion(rtwdev);
 
-       if (fw->firmware)
+       if (fw->firmware) {
                release_firmware(fw->firmware);
+
+               /* assign NULL back in case rtw89_free_ieee80211_hw()
+                * try to release the same one again.
+                */
+               fw->firmware = NULL;
+       }
 }
 
 #define H2C_CAM_LEN 60
index 5c4c7de1b4f5de1de6be671c31f8bf0d530f0cc8..4d2f9ea9e00225a472f539f313f77ed72927207a 100644 (file)
@@ -3444,9 +3444,10 @@ struct rtw89_fw_h2c_rf_get_mccch {
 
 int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev);
 int rtw89_fw_recognize(struct rtw89_dev *rtwdev);
-void rtw89_early_fw_feature_recognize(struct device *device,
-                                     const struct rtw89_chip_info *chip,
-                                     u32 *early_feat_map);
+const struct firmware *
+rtw89_early_fw_feature_recognize(struct device *device,
+                                const struct rtw89_chip_info *chip,
+                                u32 *early_feat_map);
 int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type);
 int rtw89_load_firmware(struct rtw89_dev *rtwdev);
 void rtw89_unload_firmware(struct rtw89_dev *rtwdev);