WiFi 7 chips can download BB MCU firmware via the same path as existing
WiFi CPU firmware, and we need to check them successful after downloading,
so use a corresponding hardware bit to confirm certain firmware is ready.
To reuse the flow, uses mac_gen pointers to adapt WiFi 6/7 chips with
different settings and checking rules. Also, refine flow to support
download firmware one by one. Then, changes of flow look like
1. initial setup --> no logic change
2. download WiFi CPU firmware --> 2. for all firmware suits
2.1. download WiFi CPU firmware &
check ready
2.2. download BB MCU firmware &
check ready
3. check ready by status code --> no logic change
v2:
- correct patch 3/8 that I miss a change from internal commit
Ping-Ke Shih (8):
wifi: rtw89: fw: move polling function of firmware path ready to an
individual function
wifi: rtw89: fw: generalize download firmware flow by mac_gen pointers
wifi: rtw89: fw: implement supported functions of download firmware
for WiFi 7 chips
wifi: rtw89: fw: add checking type for variant type of firmware
wifi: rtw89: fw: propagate an argument include_bb for BB MCU firmware
wifi: rtw89: 8922a: add chip_ops::bb_preinit to enable BB before
downloading firmware
wifi: rtw89: fw: refine download flow to support variant firmware
suits
wifi: rtw89: 8922a: set memory heap address for secure firmware
drivers/net/wireless/realtek/rtw89/core.c | 2 +-
drivers/net/wireless/realtek/rtw89/core.h | 19 +++
drivers/net/wireless/realtek/rtw89/fw.c | 122 +++++++++-----
drivers/net/wireless/realtek/rtw89/fw.h | 7 +-
drivers/net/wireless/realtek/rtw89/mac.c | 45 ++++-
drivers/net/wireless/realtek/rtw89/mac.h | 10 +-
drivers/net/wireless/realtek/rtw89/mac_be.c | 156 ++++++++++++++++++
drivers/net/wireless/realtek/rtw89/reg.h | 109 ++++++++++++
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 +
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 +
drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 +
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +
drivers/net/wireless/realtek/rtw89/wow.c | 4 +-
13 files changed, 429 insertions(+), 53 deletions(-)
--
2.25.1
In order to reuse the flow to download firmware, define some mac_gen::ops
to implement them for WiFi 6 and 7 chips individually. This doesn't change
logic at all.
Signed-off-by: Ping-Ke Shih <[email protected]>
---
v2: no change
---
drivers/net/wireless/realtek/rtw89/fw.c | 21 +++++++++------------
drivers/net/wireless/realtek/rtw89/mac.c | 17 +++++++++++++++--
drivers/net/wireless/realtek/rtw89/mac.h | 9 +++++----
3 files changed, 29 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 7c2fa732db18..459597c28bc9 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -47,19 +47,13 @@ struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len)
return rtw89_fw_h2c_alloc_skb(rtwdev, len, false);
}
-static u8 _fw_get_rdy(struct rtw89_dev *rtwdev)
-{
- u8 val = rtw89_read8(rtwdev, R_AX_WCPU_FW_CTRL);
-
- return FIELD_GET(B_AX_WCPU_FWDL_STS_MASK, val);
-}
-
int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
u8 val;
int ret;
- ret = read_poll_timeout_atomic(_fw_get_rdy, val,
+ ret = read_poll_timeout_atomic(mac->fwdl_get_status, val,
val == RTW89_FWDL_WCPU_FW_INIT_RDY,
1, FWDL_WAIT_CNT, false, rtwdev);
if (ret) {
@@ -77,6 +71,7 @@ int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
return -EINVAL;
default:
+ rtw89_err(rtwdev, "fw unexpected status %d\n", val);
return -EBUSY;
}
}
@@ -767,6 +762,7 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l
static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
ret = __rtw89_fw_download_hdr(rtwdev, fw, len);
@@ -775,7 +771,7 @@ static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len
return ret;
}
- ret = rtw89_fwdl_check_path_ready_ax(rtwdev, false);
+ ret = mac->fwdl_check_path_ready(rtwdev, false);
if (ret) {
rtw89_err(rtwdev, "[ERR]FWDL path ready\n");
return ret;
@@ -885,13 +881,14 @@ static void rtw89_fw_dl_fail_dump(struct rtw89_dev *rtwdev)
int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_fw_info *fw_info = &rtwdev->fw;
struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type);
struct rtw89_fw_bin_info info;
int ret;
- rtw89_mac_disable_cpu(rtwdev);
- ret = rtw89_mac_enable_cpu(rtwdev, 0, true);
+ mac->disable_cpu(rtwdev);
+ ret = mac->fwdl_enable_wcpu(rtwdev, 0, true);
if (ret)
return ret;
@@ -901,7 +898,7 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
goto fwdl_err;
}
- ret = rtw89_fwdl_check_path_ready_ax(rtwdev, true);
+ ret = mac->fwdl_check_path_ready(rtwdev, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]H2C path ready\n");
goto fwdl_err;
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index 013114fd9d19..fe8dbb2fe8e1 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -3452,7 +3452,7 @@ static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev)
rtw89_mac_mem_write(rtwdev, R_AX_WDT_STATUS, val32, RTW89_MAC_MEM_CPU_LOCAL);
}
-void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev)
+static void rtw89_mac_disable_cpu_ax(struct rtw89_dev *rtwdev)
{
clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags);
@@ -3467,7 +3467,7 @@ void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev)
rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN);
}
-int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw)
+static int rtw89_mac_enable_cpu_ax(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw)
{
u32 val;
int ret;
@@ -5684,6 +5684,14 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
return ret;
}
+static u8 rtw89_fw_get_rdy_ax(struct rtw89_dev *rtwdev)
+{
+ u8 val = rtw89_read8(rtwdev, R_AX_WCPU_FW_CTRL);
+
+ return FIELD_GET(B_AX_WCPU_FWDL_STS_MASK, val);
+}
+
+static
int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev,
bool h2c_or_fwdl)
{
@@ -5701,5 +5709,10 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.indir_access_addr = R_AX_INDIR_ACCESS_ENTRY,
.mem_base_addrs = rtw89_mac_mem_base_addrs_ax,
.rx_fltr = R_AX_RX_FLTR_OPT,
+
+ .disable_cpu = rtw89_mac_disable_cpu_ax,
+ .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax,
+ .fwdl_get_status = rtw89_fw_get_rdy_ax,
+ .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_ax,
};
EXPORT_SYMBOL(rtw89_mac_gen_ax);
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index a9a571df3a77..ecf143a671c6 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -858,6 +858,11 @@ struct rtw89_mac_gen_def {
u32 indir_access_addr;
const u32 *mem_base_addrs;
u32 rx_fltr;
+
+ void (*disable_cpu)(struct rtw89_dev *rtwdev);
+ int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw);
+ u8 (*fwdl_get_status)(struct rtw89_dev *rtwdev);
+ int (*fwdl_check_path_ready)(struct rtw89_dev *rtwdev, bool h2c_or_fwdl);
};
extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax;
@@ -975,8 +980,6 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif);
void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
-void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev);
-int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw);
int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev);
int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev);
@@ -1207,7 +1210,5 @@ int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow);
int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
enum rtw89_mac_idx band);
void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow);
-int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev,
- bool h2c_or_fwdl);
#endif
--
2.25.1
To support download more than one firmware, adjust flow to download
firmware by unit of firmware suit. Then, flow becomes
1. initial setup - disable/enable_wcpu
2. for all firmware suits
2.1. download WiFi CPU, and check ready
2.2. download BB MCU, and check ready
3. check status code to make sure all ready
Signed-off-by: Ping-Ke Shih <[email protected]>
---
v2: no change
---
drivers/net/wireless/realtek/rtw89/fw.c | 84 +++++++++++++++++++------
1 file changed, 65 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 2878954abe1f..b27d3cb6f1d9 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -823,10 +823,27 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev,
return ret;
}
-static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, const u8 *fw,
+static enum rtw89_fwdl_check_type
+rtw89_fw_get_fwdl_chk_type_from_suit(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_suit *fw_suit)
+{
+ switch (fw_suit->type) {
+ case RTW89_FW_BBMCU0:
+ return RTW89_FWDL_CHECK_BB0_FWDL_DONE;
+ case RTW89_FW_BBMCU1:
+ return RTW89_FWDL_CHECK_BB1_FWDL_DONE;
+ default:
+ return RTW89_FWDL_CHECK_WCPU_FWDL_DONE;
+ }
+}
+
+static int rtw89_fw_download_main(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_suit *fw_suit,
struct rtw89_fw_bin_info *info)
{
struct rtw89_fw_hdr_section_info *section_info = info->section_info;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ enum rtw89_fwdl_check_type chk_type;
u8 section_num = info->section_num;
int ret;
@@ -837,6 +854,16 @@ static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, const u8 *fw,
section_info++;
}
+ if (chip->chip_gen == RTW89_CHIP_AX)
+ return 0;
+
+ chk_type = rtw89_fw_get_fwdl_chk_type_from_suit(rtwdev, fw_suit);
+ ret = rtw89_fw_check_rdy(rtwdev, chk_type);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to download firmware type %u\n",
+ fw_suit->type);
+ return ret;
+ }
return 0;
}
@@ -872,43 +899,62 @@ static void rtw89_fw_dl_fail_dump(struct rtw89_dev *rtwdev)
rtw89_fw_prog_cnt_dump(rtwdev);
}
-int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
- bool include_bb)
+static int rtw89_fw_download_suit(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_suit *fw_suit)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
- struct rtw89_fw_info *fw_info = &rtwdev->fw;
- struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type);
struct rtw89_fw_bin_info info;
int ret;
- mac->disable_cpu(rtwdev);
- ret = mac->fwdl_enable_wcpu(rtwdev, 0, true, include_bb);
- if (ret)
- return ret;
-
ret = rtw89_fw_hdr_parser(rtwdev, fw_suit, &info);
if (ret) {
rtw89_err(rtwdev, "parse fw header fail\n");
- goto fwdl_err;
+ return ret;
}
ret = mac->fwdl_check_path_ready(rtwdev, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]H2C path ready\n");
- goto fwdl_err;
+ return ret;
}
ret = rtw89_fw_download_hdr(rtwdev, fw_suit->data, info.hdr_len -
info.dynamic_hdr_len);
- if (ret) {
- ret = -EBUSY;
- goto fwdl_err;
- }
+ if (ret)
+ return ret;
- ret = rtw89_fw_download_main(rtwdev, fw_suit->data, &info);
- if (ret) {
- ret = -EBUSY;
+ ret = rtw89_fw_download_main(rtwdev, fw_suit, &info);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
+ bool include_bb)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ struct rtw89_fw_info *fw_info = &rtwdev->fw;
+ struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type);
+ u8 bbmcu_nr = rtwdev->chip->bbmcu_nr;
+ int ret;
+ int i;
+
+ mac->disable_cpu(rtwdev);
+ ret = mac->fwdl_enable_wcpu(rtwdev, 0, true, include_bb);
+ if (ret)
+ return ret;
+
+ ret = rtw89_fw_download_suit(rtwdev, fw_suit);
+ if (ret)
goto fwdl_err;
+
+ for (i = 0; i < bbmcu_nr && include_bb; i++) {
+ fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_BBMCU0 + i);
+
+ ret = rtw89_fw_download_suit(rtwdev, fw_suit);
+ if (ret)
+ goto fwdl_err;
}
fw_info->h2c_seq = 0;
--
2.25.1
To download firmware, we need to check path is ready. There are two kinds
of path -- one is to download firmware header, and the other is to download
firmware body.
Since the polling method is different from WiFi 7 chips, make it to be
an individual function, and then we can reuse the download flow.
Signed-off-by: Ping-Ke Shih <[email protected]>
---
v2: no change
---
drivers/net/wireless/realtek/rtw89/fw.c | 11 ++---------
drivers/net/wireless/realtek/rtw89/fw.h | 2 ++
drivers/net/wireless/realtek/rtw89/mac.c | 11 +++++++++++
drivers/net/wireless/realtek/rtw89/mac.h | 2 ++
4 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index df1dc2f43c86..7c2fa732db18 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -54,7 +54,6 @@ static u8 _fw_get_rdy(struct rtw89_dev *rtwdev)
return FIELD_GET(B_AX_WCPU_FWDL_STS_MASK, val);
}
-#define FWDL_WAIT_CNT 400000
int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
{
u8 val;
@@ -768,7 +767,6 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l
static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len)
{
- u8 val;
int ret;
ret = __rtw89_fw_download_hdr(rtwdev, fw, len);
@@ -777,9 +775,7 @@ static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len
return ret;
}
- ret = read_poll_timeout_atomic(rtw89_read8, val, val & B_AX_FWDL_PATH_RDY,
- 1, FWDL_WAIT_CNT, false,
- rtwdev, R_AX_WCPU_FW_CTRL);
+ ret = rtw89_fwdl_check_path_ready_ax(rtwdev, false);
if (ret) {
rtw89_err(rtwdev, "[ERR]FWDL path ready\n");
return ret;
@@ -892,7 +888,6 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
struct rtw89_fw_info *fw_info = &rtwdev->fw;
struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type);
struct rtw89_fw_bin_info info;
- u8 val;
int ret;
rtw89_mac_disable_cpu(rtwdev);
@@ -906,9 +901,7 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
goto fwdl_err;
}
- ret = read_poll_timeout_atomic(rtw89_read8, val, val & B_AX_H2C_PATH_RDY,
- 1, FWDL_WAIT_CNT, false,
- rtwdev, R_AX_WCPU_FW_CTRL);
+ ret = rtw89_fwdl_check_path_ready_ax(rtwdev, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]H2C path ready\n");
goto fwdl_err;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 775f4e8fbda4..ed2619fec419 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -3618,6 +3618,8 @@ struct rtw89_fw_h2c_rf_get_mccch {
#define RTW89_FW_BACKTRACE_MAX_SIZE 512 /* 8 * 64 (entries) */
#define RTW89_FW_BACKTRACE_KEY 0xBACEBACE
+#define FWDL_WAIT_CNT 400000
+
int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev);
int rtw89_fw_recognize(struct rtw89_dev *rtwdev);
int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index fab9f5004a75..013114fd9d19 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -5684,6 +5684,17 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
return ret;
}
+int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev,
+ bool h2c_or_fwdl)
+{
+ u8 check = h2c_or_fwdl ? B_AX_H2C_PATH_RDY : B_AX_FWDL_PATH_RDY;
+ u8 val;
+
+ return read_poll_timeout_atomic(rtw89_read8, val, val & check,
+ 1, FWDL_WAIT_CNT, false,
+ rtwdev, R_AX_WCPU_FW_CTRL);
+}
+
const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.band1_offset = RTW89_MAC_AX_BAND_REG_OFFSET,
.filter_model_addr = R_AX_FILTER_MODEL_ADDR,
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index 7cf34137c0bc..a9a571df3a77 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -1207,5 +1207,7 @@ int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow);
int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
enum rtw89_mac_idx band);
void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow);
+int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev,
+ bool h2c_or_fwdl);
#endif
--
2.25.1