Commit b06439c6 authored by Bitterblue Smith's avatar Bitterblue Smith Committed by Kalle Valo

wifi: rtlwifi: Speed up firmware loading for USB

Currently it takes almost 6 seconds to upload the firmware for RTL8192CU
(and 11 seconds for RTL8192DU). That's because the firmware is uploaded
one byte at a time.

Also, after plugging the device, the firmware gets uploaded three times
before a connection to the AP is established.

Maybe this is fine for most users, but when testing changes to the
driver it's really annoying to wait so long.

Speed up the firmware upload by writing chunks of 64 bytes at a time.
This way it takes about 110 ms for RTL8192CU (and about 210 ms for
RTL8192DU).

PCI devices could upload it in chunks of 4 bytes, but I don't have any
to test and commit 89d32c90 ("rtlwifi: Download firmware as bytes
rather than as dwords") decided otherwise anyway.

Allocate memory for the firmware image with kmalloc instead of vzalloc
because this memory is passed directly to usb_control_msg(), which
can't take memory allocated by vmalloc.
Signed-off-by: default avatarBitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://msgid.link/d9bd4949-6e92-4f35-8b60-3b45f9ad74ab@gmail.com
parent 563d5025
......@@ -1287,18 +1287,44 @@ int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv,
}
EXPORT_SYMBOL_GPL(rtl_get_hwinfo);
void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size)
static void _rtl_fw_block_write_usb(struct ieee80211_hw *hw, u8 *buffer, u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 start = START_ADDRESS;
u32 n;
while (size > 0) {
if (size >= 64)
n = 64;
else if (size >= 8)
n = 8;
else
n = 1;
rtl_write_chunk(rtlpriv, start, n, buffer);
start += n;
buffer += n;
size -= n;
}
}
void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 *pu4byteptr = (u8 *)buffer;
u32 i;
for (i = 0; i < size; i++)
rtl_write_byte(rtlpriv, (START_ADDRESS + i), *(pu4byteptr + i));
if (rtlpriv->rtlhal.interface == INTF_PCI) {
for (i = 0; i < size; i++)
rtl_write_byte(rtlpriv, (START_ADDRESS + i),
*(buffer + i));
} else if (rtlpriv->rtlhal.interface == INTF_USB) {
_rtl_fw_block_write_usb(hw, buffer, size);
}
}
EXPORT_SYMBOL_GPL(rtl_fw_block_write);
void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer,
void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer,
u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
......
......@@ -91,8 +91,8 @@ void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate);
int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv,
int max_size, u8 *hwinfo, int *params);
void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen);
void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer,
void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer,
u32 size);
void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size);
void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size);
void rtl_efuse_ops_init(struct ieee80211_hw *hw);
#endif
......@@ -40,7 +40,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
rtlpriv->dm.thermalvalue = 0;
/* for firmware buf */
rtlpriv->rtlhal.pfirmware = vzalloc(0x4000);
rtlpriv->rtlhal.pfirmware = kmalloc(0x4000, GFP_KERNEL);
if (!rtlpriv->rtlhal.pfirmware) {
pr_err("Can't alloc buffer for fw\n");
return 1;
......@@ -61,7 +61,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
fw_name, rtlpriv->io.dev,
GFP_KERNEL, hw, rtl_fw_cb);
if (err) {
vfree(rtlpriv->rtlhal.pfirmware);
kfree(rtlpriv->rtlhal.pfirmware);
rtlpriv->rtlhal.pfirmware = NULL;
}
return err;
......@@ -72,7 +72,7 @@ static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
if (rtlpriv->rtlhal.pfirmware) {
vfree(rtlpriv->rtlhal.pfirmware);
kfree(rtlpriv->rtlhal.pfirmware);
rtlpriv->rtlhal.pfirmware = NULL;
}
}
......
......@@ -125,6 +125,14 @@ static void _usb_write32_sync(struct rtl_priv *rtlpriv, u32 addr, u32 val)
_usb_write_sync(rtlpriv, addr, val, 4);
}
static void _usb_write_chunk_sync(struct rtl_priv *rtlpriv, u32 addr,
u32 length, u8 *data)
{
struct usb_device *udev = to_usb_device(rtlpriv->io.dev);
_usbctrl_vendorreq_sync(udev, REALTEK_USB_VENQT_WRITE, addr, data, length);
}
static void _rtl_usb_io_handler_init(struct device *dev,
struct ieee80211_hw *hw)
{
......@@ -135,6 +143,7 @@ static void _rtl_usb_io_handler_init(struct device *dev,
rtlpriv->io.write8 = _usb_write8_sync;
rtlpriv->io.write16 = _usb_write16_sync;
rtlpriv->io.write32 = _usb_write32_sync;
rtlpriv->io.write_chunk = _usb_write_chunk_sync;
rtlpriv->io.read8 = _usb_read8_sync;
rtlpriv->io.read16 = _usb_read16_sync;
rtlpriv->io.read32 = _usb_read32_sync;
......
......@@ -1450,6 +1450,8 @@ struct rtl_io {
void (*write8)(struct rtl_priv *rtlpriv, u32 addr, u8 val);
void (*write16)(struct rtl_priv *rtlpriv, u32 addr, u16 val);
void (*write32)(struct rtl_priv *rtlpriv, u32 addr, u32 val);
void (*write_chunk)(struct rtl_priv *rtlpriv, u32 addr, u32 length,
u8 *data);
u8 (*read8)(struct rtl_priv *rtlpriv, u32 addr);
u16 (*read16)(struct rtl_priv *rtlpriv, u32 addr);
......@@ -2962,6 +2964,12 @@ static inline void rtl_write_dword(struct rtl_priv *rtlpriv,
rtlpriv->io.read32(rtlpriv, addr);
}
static inline void rtl_write_chunk(struct rtl_priv *rtlpriv,
u32 addr, u32 length, u8 *data)
{
rtlpriv->io.write_chunk(rtlpriv, addr, length, data);
}
static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw,
u32 regaddr, u32 bitmask)
{
......
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