wifi: rtw88: usb: Upload the firmware in bigger chunks
commit 80fe0bc1659c0ccc79d082e426fa376be5df9c04 upstream. RTL8811AU stops responding during the firmware download on some systems: [ 809.256440] rtw_8821au 5-2.1:1.0: Firmware version 42.4.0, H2C version 0 [ 812.759142] rtw_8821au 5-2.1:1.0 wlp48s0f4u2u1: renamed from wlan0 [ 837.315388] rtw_8821au 1-4:1.0: write register 0x1ef4 failed with -110 [ 867.524259] rtw_8821au 1-4:1.0: write register 0x1ef8 failed with -110 [ 868.930976] rtw_8821au 5-2.1:1.0 wlp48s0f4u2u1: entered promiscuous mode [ 897.730952] rtw_8821au 1-4:1.0: write register 0x1efc failed with -110 Maybe it takes too long when writing the firmware 4 bytes at a time. Write 196 bytes at a time for RTL8821AU, RTL8811AU, and RTL8812AU, and 254 bytes at a time for RTL8723DU. These are the sizes used in their official drivers. Tested with all these chips. Cc: stable@vger.kernel.org Link: https://github.com/lwfinger/rtw88/issues/344 Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com> Acked-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/43f1daad-3ec0-4a3b-a50c-9cd9eb2c2f52@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
314053de3a
commit
09f7616cb5
@@ -19,6 +19,8 @@ struct rtw_hci_ops {
|
|||||||
void (*link_ps)(struct rtw_dev *rtwdev, bool enter);
|
void (*link_ps)(struct rtw_dev *rtwdev, bool enter);
|
||||||
void (*interface_cfg)(struct rtw_dev *rtwdev);
|
void (*interface_cfg)(struct rtw_dev *rtwdev);
|
||||||
void (*dynamic_rx_agg)(struct rtw_dev *rtwdev, bool enable);
|
void (*dynamic_rx_agg)(struct rtw_dev *rtwdev, bool enable);
|
||||||
|
void (*write_firmware_page)(struct rtw_dev *rtwdev, u32 page,
|
||||||
|
const u8 *data, u32 size);
|
||||||
|
|
||||||
int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
|
int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
|
||||||
int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
|
int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
|
||||||
@@ -79,6 +81,12 @@ static inline void rtw_hci_dynamic_rx_agg(struct rtw_dev *rtwdev, bool enable)
|
|||||||
rtwdev->hci.ops->dynamic_rx_agg(rtwdev, enable);
|
rtwdev->hci.ops->dynamic_rx_agg(rtwdev, enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void rtw_hci_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
|
||||||
|
const u8 *data, u32 size)
|
||||||
|
{
|
||||||
|
rtwdev->hci.ops->write_firmware_page(rtwdev, page, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
|
rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -854,8 +854,8 @@ fwdl_ready:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
|
||||||
write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size)
|
const u8 *data, u32 size)
|
||||||
{
|
{
|
||||||
u32 val32;
|
u32 val32;
|
||||||
u32 block_nr;
|
u32 block_nr;
|
||||||
@@ -885,6 +885,7 @@ write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size)
|
|||||||
rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data));
|
rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(rtw_write_firmware_page);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size)
|
download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size)
|
||||||
@@ -902,11 +903,13 @@ download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size)
|
|||||||
rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT);
|
rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT);
|
||||||
|
|
||||||
for (page = 0; page < total_page; page++) {
|
for (page = 0; page < total_page; page++) {
|
||||||
write_firmware_page(rtwdev, page, data, DLFW_PAGE_SIZE_LEGACY);
|
rtw_hci_write_firmware_page(rtwdev, page, data,
|
||||||
|
DLFW_PAGE_SIZE_LEGACY);
|
||||||
data += DLFW_PAGE_SIZE_LEGACY;
|
data += DLFW_PAGE_SIZE_LEGACY;
|
||||||
}
|
}
|
||||||
if (last_page_size)
|
if (last_page_size)
|
||||||
write_firmware_page(rtwdev, page, data, last_page_size);
|
rtw_hci_write_firmware_page(rtwdev, page, data,
|
||||||
|
last_page_size);
|
||||||
|
|
||||||
if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) {
|
if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) {
|
||||||
rtw_err(rtwdev, "failed to check download firmware report\n");
|
rtw_err(rtwdev, "failed to check download firmware report\n");
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw,
|
|||||||
u8 primary_ch_idx);
|
u8 primary_ch_idx);
|
||||||
int rtw_mac_power_on(struct rtw_dev *rtwdev);
|
int rtw_mac_power_on(struct rtw_dev *rtwdev);
|
||||||
void rtw_mac_power_off(struct rtw_dev *rtwdev);
|
void rtw_mac_power_off(struct rtw_dev *rtwdev);
|
||||||
|
void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
|
||||||
|
const u8 *data, u32 size);
|
||||||
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw);
|
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw);
|
||||||
int rtw_mac_init(struct rtw_dev *rtwdev);
|
int rtw_mac_init(struct rtw_dev *rtwdev);
|
||||||
void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop);
|
void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "fw.h"
|
#include "fw.h"
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "mac.h"
|
||||||
|
|
||||||
static bool rtw_disable_msi;
|
static bool rtw_disable_msi;
|
||||||
static bool rtw_pci_disable_aspm;
|
static bool rtw_pci_disable_aspm;
|
||||||
@@ -1602,6 +1603,7 @@ static struct rtw_hci_ops rtw_pci_ops = {
|
|||||||
.link_ps = rtw_pci_link_ps,
|
.link_ps = rtw_pci_link_ps,
|
||||||
.interface_cfg = rtw_pci_interface_cfg,
|
.interface_cfg = rtw_pci_interface_cfg,
|
||||||
.dynamic_rx_agg = NULL,
|
.dynamic_rx_agg = NULL,
|
||||||
|
.write_firmware_page = rtw_write_firmware_page,
|
||||||
|
|
||||||
.read8 = rtw_pci_read8,
|
.read8 = rtw_pci_read8,
|
||||||
.read16 = rtw_pci_read16,
|
.read16 = rtw_pci_read16,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <linux/mmc/host.h>
|
#include <linux/mmc/host.h>
|
||||||
#include <linux/mmc/sdio_func.h>
|
#include <linux/mmc/sdio_func.h>
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "mac.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "fw.h"
|
#include "fw.h"
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
@@ -1155,6 +1156,7 @@ static struct rtw_hci_ops rtw_sdio_ops = {
|
|||||||
.link_ps = rtw_sdio_link_ps,
|
.link_ps = rtw_sdio_link_ps,
|
||||||
.interface_cfg = rtw_sdio_interface_cfg,
|
.interface_cfg = rtw_sdio_interface_cfg,
|
||||||
.dynamic_rx_agg = NULL,
|
.dynamic_rx_agg = NULL,
|
||||||
|
.write_firmware_page = rtw_write_firmware_page,
|
||||||
|
|
||||||
.read8 = rtw_sdio_read8,
|
.read8 = rtw_sdio_read8,
|
||||||
.read16 = rtw_sdio_read16,
|
.read16 = rtw_sdio_read16,
|
||||||
|
|||||||
@@ -164,6 +164,60 @@ static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
|
|||||||
rtw_usb_write(rtwdev, addr, val, 4);
|
rtw_usb_write(rtwdev, addr, val, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtw_usb_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
|
||||||
|
const u8 *data, u32 size)
|
||||||
|
{
|
||||||
|
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
|
||||||
|
struct usb_device *udev = rtwusb->udev;
|
||||||
|
u32 addr = FW_START_ADDR_LEGACY;
|
||||||
|
u8 *data_dup, *buf;
|
||||||
|
u32 n, block_size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (rtwdev->chip->id) {
|
||||||
|
case RTW_CHIP_TYPE_8723D:
|
||||||
|
block_size = 254;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
block_size = 196;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_dup = kmemdup(data, size, GFP_KERNEL);
|
||||||
|
if (!data_dup)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf = data_dup;
|
||||||
|
|
||||||
|
rtw_write32_mask(rtwdev, REG_MCUFW_CTRL, BIT_ROM_PGE, page);
|
||||||
|
|
||||||
|
while (size > 0) {
|
||||||
|
if (size >= block_size)
|
||||||
|
n = block_size;
|
||||||
|
else if (size >= 8)
|
||||||
|
n = 8;
|
||||||
|
else
|
||||||
|
n = 1;
|
||||||
|
|
||||||
|
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||||
|
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
|
||||||
|
addr, 0, buf, n, 500);
|
||||||
|
if (ret != n) {
|
||||||
|
if (ret != -ENODEV)
|
||||||
|
rtw_err(rtwdev,
|
||||||
|
"write 0x%x len %d failed: %d\n",
|
||||||
|
addr, n, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr += n;
|
||||||
|
buf += n;
|
||||||
|
size -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(data_dup);
|
||||||
|
}
|
||||||
|
|
||||||
static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping)
|
static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping)
|
||||||
{
|
{
|
||||||
switch (dma_mapping) {
|
switch (dma_mapping) {
|
||||||
@@ -815,6 +869,7 @@ static struct rtw_hci_ops rtw_usb_ops = {
|
|||||||
.link_ps = rtw_usb_link_ps,
|
.link_ps = rtw_usb_link_ps,
|
||||||
.interface_cfg = rtw_usb_interface_cfg,
|
.interface_cfg = rtw_usb_interface_cfg,
|
||||||
.dynamic_rx_agg = rtw_usb_dynamic_rx_agg,
|
.dynamic_rx_agg = rtw_usb_dynamic_rx_agg,
|
||||||
|
.write_firmware_page = rtw_usb_write_firmware_page,
|
||||||
|
|
||||||
.write8 = rtw_usb_write8,
|
.write8 = rtw_usb_write8,
|
||||||
.write16 = rtw_usb_write16,
|
.write16 = rtw_usb_write16,
|
||||||
|
|||||||
Reference in New Issue
Block a user