Commit 823092a5 authored by Ji-Pin Jou's avatar Ji-Pin Jou Committed by Kalle Valo

wifi: rtw88: fix race condition when doing H2C command

For SDIO/USB interface, since the tranferring speed is slower than
that in PCIE, it may have race condition when the driver sets down
H2C command to the FW.

In the function rtw_fw_send_h2c_command, before the patch, box_reg
is written first, then box_ex_reg is written. FW starts to work and
fetch the value of box_ex_reg,  when the most significant byte of
box_reg(4 bytes) is written. Meanwhile, for SDIO/USB interface,
since the transferring speed is slow, the driver is still in writing
the new value of box_ex_reg through the bus, and FW may get the
wrong value of box_ex_reg at the moment.

To prevent the above driver/FW racing situation, box_ex_reg is
written first then box_reg. Furthermore, it is written in 4 bytes at
a time, instead of written in one byte one by one. It can increase
the speed for SDIO/USB interface.
Signed-off-by: default avatarJi-Pin Jou <neo_jou@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Tested-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20221124064442.28042-1-pkshih@realtek.com
parent 3ca7f0b2
...@@ -311,10 +311,10 @@ EXPORT_SYMBOL(rtw_fw_c2h_cmd_isr); ...@@ -311,10 +311,10 @@ EXPORT_SYMBOL(rtw_fw_c2h_cmd_isr);
static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
u8 *h2c) u8 *h2c)
{ {
struct rtw_h2c_cmd *h2c_cmd = (struct rtw_h2c_cmd *)h2c;
u8 box; u8 box;
u8 box_state; u8 box_state;
u32 box_reg, box_ex_reg; u32 box_reg, box_ex_reg;
int idx;
int ret; int ret;
rtw_dbg(rtwdev, RTW_DBG_FW, rtw_dbg(rtwdev, RTW_DBG_FW,
...@@ -356,10 +356,8 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, ...@@ -356,10 +356,8 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
goto out; goto out;
} }
for (idx = 0; idx < 4; idx++) rtw_write32(rtwdev, box_ex_reg, le32_to_cpu(h2c_cmd->msg_ext));
rtw_write8(rtwdev, box_reg + idx, h2c[idx]); rtw_write32(rtwdev, box_reg, le32_to_cpu(h2c_cmd->msg));
for (idx = 0; idx < 4; idx++)
rtw_write8(rtwdev, box_ex_reg + idx, h2c[idx + 4]);
if (++rtwdev->h2c.last_box_num >= 4) if (++rtwdev->h2c.last_box_num >= 4)
rtwdev->h2c.last_box_num = 0; rtwdev->h2c.last_box_num = 0;
......
...@@ -81,6 +81,11 @@ struct rtw_c2h_adaptivity { ...@@ -81,6 +81,11 @@ struct rtw_c2h_adaptivity {
u8 option; u8 option;
} __packed; } __packed;
struct rtw_h2c_cmd {
__le32 msg;
__le32 msg_ext;
} __packed;
enum rtw_rsvd_packet_type { enum rtw_rsvd_packet_type {
RSVD_BEACON, RSVD_BEACON,
RSVD_DUMMY, RSVD_DUMMY,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment