summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw89/fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/fw.c')
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c175
1 files changed, 98 insertions, 77 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index b9b675bf9d05..9637f5e48d84 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -14,6 +14,8 @@
static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev,
struct sk_buff *skb);
+static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
+ struct rtw89_wait_info *wait, unsigned int cond);
static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len,
bool header)
@@ -87,9 +89,11 @@ int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
struct rtw89_fw_bin_info *info)
{
+ const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw;
struct rtw89_fw_hdr_section_info *section_info;
+ const struct rtw89_fw_dynhdr_hdr *fwdynhdr;
+ const struct rtw89_fw_hdr_section *section;
const u8 *fw_end = fw + len;
- const u8 *fwdynhdr;
const u8 *bin;
u32 base_hdr_len;
u32 mssc_len = 0;
@@ -98,16 +102,15 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
if (!info)
return -EINVAL;
- info->section_num = GET_FW_HDR_SEC_NUM(fw);
- 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);
+ info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM);
+ base_hdr_len = struct_size(fw_hdr, sections, info->section_num);
+ info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR);
if (info->dynamic_hdr_en) {
- info->hdr_len = GET_FW_HDR_LEN(fw);
+ info->hdr_len = le32_get_bits(fw_hdr->w3, FW_HDR_W3_LEN);
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) {
+ fwdynhdr = (const struct rtw89_fw_dynhdr_hdr *)(fw + base_hdr_len);
+ if (le32_to_cpu(fwdynhdr->hdr_len) != info->dynamic_hdr_len) {
rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n");
return -EINVAL;
}
@@ -119,26 +122,27 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
bin = fw + info->hdr_len;
/* jump to section header */
- fw += RTW89_FW_HDR_SIZE;
section_info = info->section_info;
for (i = 0; i < info->section_num; i++) {
- section_info->type = GET_FWSECTION_HDR_SECTIONTYPE(fw);
+ section = &fw_hdr->sections[i];
+ section_info->type =
+ le32_get_bits(section->w1, FWSECTION_HDR_W1_SECTIONTYPE);
if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
- section_info->mssc = GET_FWSECTION_HDR_MSSC(fw);
+ section_info->mssc =
+ le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC);
mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN;
} else {
section_info->mssc = 0;
}
- section_info->len = GET_FWSECTION_HDR_SEC_SIZE(fw);
- if (GET_FWSECTION_HDR_CHECKSUM(fw))
+ section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_W1_SEC_SIZE);
+ if (le32_get_bits(section->w1, FWSECTION_HDR_W1_CHECKSUM))
section_info->len += FWDL_SECTION_CHKSUM_LEN;
- section_info->redl = GET_FWSECTION_HDR_REDL(fw);
+ section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_W1_REDL);
section_info->dladdr =
- GET_FWSECTION_HDR_DL_ADDR(fw) & 0x1fffffff;
+ le32_get_bits(section->w0, FWSECTION_HDR_W0_DL_ADDR) & 0x1fffffff;
section_info->addr = bin;
bin += section_info->len;
- fw += RTW89_FW_SECTION_HDR_SIZE;
section_info++;
}
@@ -193,18 +197,18 @@ static void rtw89_fw_update_ver(struct rtw89_dev *rtwdev,
enum rtw89_fw_type type,
struct rtw89_fw_suit *fw_suit)
{
- const u8 *hdr = fw_suit->data;
-
- fw_suit->major_ver = GET_FW_HDR_MAJOR_VERSION(hdr);
- fw_suit->minor_ver = GET_FW_HDR_MINOR_VERSION(hdr);
- fw_suit->sub_ver = GET_FW_HDR_SUBVERSION(hdr);
- fw_suit->sub_idex = GET_FW_HDR_SUBINDEX(hdr);
- fw_suit->build_year = GET_FW_HDR_YEAR(hdr);
- fw_suit->build_mon = GET_FW_HDR_MONTH(hdr);
- fw_suit->build_date = GET_FW_HDR_DATE(hdr);
- fw_suit->build_hour = GET_FW_HDR_HOUR(hdr);
- fw_suit->build_min = GET_FW_HDR_MIN(hdr);
- fw_suit->cmd_ver = GET_FW_HDR_CMD_VERSERION(hdr);
+ const struct rtw89_fw_hdr *hdr = (const struct rtw89_fw_hdr *)fw_suit->data;
+
+ fw_suit->major_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MAJOR_VERSION);
+ fw_suit->minor_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MINOR_VERSION);
+ fw_suit->sub_ver = le32_get_bits(hdr->w1, FW_HDR_W1_SUBVERSION);
+ fw_suit->sub_idex = le32_get_bits(hdr->w1, FW_HDR_W1_SUBINDEX);
+ fw_suit->build_year = le32_get_bits(hdr->w5, FW_HDR_W5_YEAR);
+ fw_suit->build_mon = le32_get_bits(hdr->w4, FW_HDR_W4_MONTH);
+ fw_suit->build_date = le32_get_bits(hdr->w4, FW_HDR_W4_DATE);
+ fw_suit->build_hour = le32_get_bits(hdr->w4, FW_HDR_W4_HOUR);
+ fw_suit->build_min = le32_get_bits(hdr->w4, FW_HDR_W4_MIN);
+ fw_suit->cmd_ver = le32_get_bits(hdr->w7, FW_HDR_W7_CMD_VERSERION);
rtw89_info(rtwdev,
"Firmware version %u.%u.%u.%u, cmd version %u, type %u\n",
@@ -254,6 +258,9 @@ struct __fw_feat_cfg {
}
static const struct __fw_feat_cfg fw_feat_tbl[] = {
+ __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE),
+ __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD),
+ __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER),
__CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE),
@@ -807,7 +814,7 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
}
skb_put(skb, H2C_BA_CAM_LEN);
SET_BA_CAM_MACID(skb->data, macid);
- if (chip->bacam_v1)
+ if (chip->bacam_ver == RTW89_BACAM_V0_EXT)
SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx);
else
SET_BA_CAM_ENTRY_IDX(skb->data, entry_idx);
@@ -823,7 +830,7 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
SET_BA_CAM_INIT_REQ(skb->data, 1);
SET_BA_CAM_SSN(skb->data, params->ssn);
- if (chip->bacam_v1) {
+ if (chip->bacam_ver == RTW89_BACAM_V0_EXT) {
SET_BA_CAM_STD_EN(skb->data, 1);
SET_BA_CAM_BAND(skb->data, rtwvif->mac_idx);
}
@@ -848,8 +855,8 @@ fail:
return ret;
}
-static int rtw89_fw_h2c_init_dynamic_ba_cam_v1(struct rtw89_dev *rtwdev,
- u8 entry_idx, u8 uid)
+static int rtw89_fw_h2c_init_ba_cam_v0_ext(struct rtw89_dev *rtwdev,
+ u8 entry_idx, u8 uid)
{
struct sk_buff *skb;
int ret;
@@ -886,7 +893,7 @@ fail:
return ret;
}
-void rtw89_fw_h2c_init_ba_cam_v1(struct rtw89_dev *rtwdev)
+void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
u8 entry_idx = chip->bacam_num;
@@ -894,7 +901,7 @@ void rtw89_fw_h2c_init_ba_cam_v1(struct rtw89_dev *rtwdev)
int i;
for (i = 0; i < chip->bacam_dynamic_num; i++) {
- rtw89_fw_h2c_init_dynamic_ba_cam_v1(rtwdev, entry_idx, uid);
+ rtw89_fw_h2c_init_ba_cam_v0_ext(rtwdev, entry_idx, uid);
entry_idx++;
uid++;
}
@@ -997,8 +1004,8 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev,
list_for_each_entry_safe(info, tmp, pkt_list, list) {
if (notify_fw)
rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
- rtw89_core_release_bit_map(rtwdev->pkt_offload,
- info->id);
+ else
+ rtw89_core_release_bit_map(rtwdev->pkt_offload, info->id);
list_del(&info->list);
kfree(info);
}
@@ -2440,7 +2447,9 @@ fail:
#define H2C_LEN_PKT_OFLD 4
int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id)
{
+ struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct sk_buff *skb;
+ unsigned int cond;
u8 *cmd;
int ret;
@@ -2460,23 +2469,26 @@ int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id)
H2C_FUNC_PACKET_OFLD, 1, 1,
H2C_LEN_PKT_OFLD);
- ret = rtw89_h2c_tx(rtwdev, skb, false);
- if (ret) {
- rtw89_err(rtwdev, "failed to send h2c\n");
- goto fail;
+ cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(id, RTW89_PKT_OFLD_OP_DEL);
+
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+ if (ret < 0) {
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "failed to del pkt ofld: id %d, ret %d\n",
+ id, ret);
+ return ret;
}
+ rtw89_core_release_bit_map(rtwdev->pkt_offload, id);
return 0;
-fail:
- dev_kfree_skb_any(skb);
-
- return ret;
}
int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
struct sk_buff *skb_ofld)
{
+ struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct sk_buff *skb;
+ unsigned int cond;
u8 *cmd;
u8 alloc_id;
int ret;
@@ -2507,27 +2519,29 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
H2C_FUNC_PACKET_OFLD, 1, 1,
H2C_LEN_PKT_OFLD + skb_ofld->len);
- ret = rtw89_h2c_tx(rtwdev, skb, false);
- if (ret) {
- rtw89_err(rtwdev, "failed to send h2c\n");
+ cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(alloc_id, RTW89_PKT_OFLD_OP_ADD);
+
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+ if (ret < 0) {
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "failed to add pkt ofld: id %d, ret %d\n",
+ alloc_id, ret);
rtw89_core_release_bit_map(rtwdev->pkt_offload, alloc_id);
- goto fail;
+ return ret;
}
return 0;
-fail:
- dev_kfree_skb_any(skb);
-
- return ret;
}
#define H2C_LEN_SCAN_LIST_OFFLOAD 4
int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len,
struct list_head *chan_list)
{
+ struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct rtw89_mac_chinfo *ch_info;
struct sk_buff *skb;
int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE;
+ unsigned int cond;
u8 *cmd;
int ret;
@@ -2574,27 +2588,27 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len,
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len);
- ret = rtw89_h2c_tx(rtwdev, skb, false);
+ cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH);
+
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
if (ret) {
- rtw89_err(rtwdev, "failed to send h2c\n");
- goto fail;
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to add scan ofld ch\n");
+ return ret;
}
return 0;
-fail:
- dev_kfree_skb_any(skb);
-
- return ret;
}
int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *option,
struct rtw89_vif *rtwvif)
{
+ struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct rtw89_chan *op = &rtwdev->scan_info.op_chan;
struct rtw89_h2c_scanofld *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
+ unsigned int cond;
int ret;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
@@ -2633,17 +2647,15 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
H2C_FUNC_SCANOFLD, 1, 1,
len);
- ret = rtw89_h2c_tx(rtwdev, skb, false);
+ cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD);
+
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
if (ret) {
- rtw89_err(rtwdev, "failed to send h2c\n");
- goto fail;
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to scan ofld\n");
+ return ret;
}
return 0;
-fail:
- dev_kfree_skb_any(skb);
-
- return ret;
}
int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
@@ -2909,12 +2921,13 @@ static int rtw89_fw_write_h2c_reg(struct rtw89_dev *rtwdev,
}
len = DIV_ROUND_UP(info->content_len + RTW89_H2CREG_HDR_LEN,
- sizeof(info->h2creg[0]));
+ sizeof(info->u.h2creg[0]));
+
+ u32p_replace_bits(&info->u.hdr.w0, info->id, RTW89_H2CREG_HDR_FUNC_MASK);
+ u32p_replace_bits(&info->u.hdr.w0, len, RTW89_H2CREG_HDR_LEN_MASK);
- RTW89_SET_H2CREG_HDR_FUNC(&info->h2creg[0], info->id);
- RTW89_SET_H2CREG_HDR_LEN(&info->h2creg[0], len);
for (i = 0; i < RTW89_H2CREG_MAX; i++)
- rtw89_write32(rtwdev, h2c_reg[i], info->h2creg[i]);
+ rtw89_write32(rtwdev, h2c_reg[i], info->u.h2creg[i]);
fw_info->h2c_counter++;
rtw89_write8_mask(rtwdev, chip->h2c_counter_reg.addr,
@@ -2944,13 +2957,14 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev,
}
for (i = 0; i < RTW89_C2HREG_MAX; i++)
- info->c2hreg[i] = rtw89_read32(rtwdev, c2h_reg[i]);
+ info->u.c2hreg[i] = rtw89_read32(rtwdev, c2h_reg[i]);
rtw89_write8(rtwdev, chip->c2h_ctrl_reg, 0);
- info->id = RTW89_GET_C2H_HDR_FUNC(*info->c2hreg);
- info->content_len = (RTW89_GET_C2H_HDR_LEN(*info->c2hreg) << 2) -
- RTW89_C2HREG_HDR_LEN;
+ info->id = u32_get_bits(info->u.hdr.w0, RTW89_C2HREG_HDR_FUNC_MASK);
+ info->content_len =
+ (u32_get_bits(info->u.hdr.w0, RTW89_C2HREG_HDR_LEN_MASK) << 2) -
+ RTW89_C2HREG_HDR_LEN;
fw_info->c2h_counter++;
rtw89_write8_mask(rtwdev, chip->c2h_counter_reg.addr,
@@ -3019,9 +3033,8 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
continue;
list_for_each_entry_safe(info, tmp, &pkt_list[idx], list) {
- rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
- rtw89_core_release_bit_map(rtwdev->pkt_offload,
- info->id);
+ if (test_bit(info->id, rtwdev->pkt_offload))
+ rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
list_del(&info->list);
kfree(info);
}
@@ -3786,6 +3799,11 @@ fail:
return ret;
}
+/* Return < 0, if failures happen during waiting for the condition.
+ * Return 0, when waiting for the condition succeeds.
+ * Return > 0, if the wait is considered unreachable due to driver/FW design,
+ * where 1 means during SER.
+ */
static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
struct rtw89_wait_info *wait, unsigned int cond)
{
@@ -3798,6 +3816,9 @@ static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
return -EBUSY;
}
+ if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
+ return 1;
+
return rtw89_wait_for_cond(wait, cond);
}