Commit ff6ff96b authored by Larry Finger's avatar Larry Finger Committed by John W. Linville

rtlwifi: rtl8192cu: Change firmware upload to use block writes

Driver rtl8192cu writes the firmware with 32-bit asynchronous writes. This
design is OK for USB 2.0 adapters, but the current implementation of
xhcu-hcd has a limited ring size, which is exceeded. By converting to
synchronous block writes, this error is avoided.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 040a7278
...@@ -72,6 +72,34 @@ static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable) ...@@ -72,6 +72,34 @@ static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
} }
} }
static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer,
u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20;
u8 *bufferPtr = (u8 *) buffer;
u32 i, offset, blockCount, remainSize;
blockCount = size / blockSize;
remainSize = size % blockSize;
for (i = 0; i < blockCount; i++) {
offset = i * blockSize;
rtlpriv->io.writeN_sync(rtlpriv,
(FW_8192C_START_ADDRESS + offset),
(void *)(bufferPtr + offset),
blockSize);
}
if (remainSize) {
offset = blockCount * blockSize;
rtlpriv->io.writeN_sync(rtlpriv,
(FW_8192C_START_ADDRESS + offset),
(void *)(bufferPtr + offset),
remainSize);
}
}
static void _rtl92c_fw_block_write(struct ieee80211_hw *hw, static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
const u8 *buffer, u32 size) const u8 *buffer, u32 size)
{ {
...@@ -81,6 +109,10 @@ static void _rtl92c_fw_block_write(struct ieee80211_hw *hw, ...@@ -81,6 +109,10 @@ static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
u32 *pu4BytePtr = (u32 *) buffer; u32 *pu4BytePtr = (u32 *) buffer;
u32 i, offset, blockCount, remainSize; u32 i, offset, blockCount, remainSize;
if (rtlpriv->io.writeN_sync) {
rtl_block_fw_writeN(hw, buffer, size);
return;
}
blockCount = size / blockSize; blockCount = size / blockSize;
remainSize = size % blockSize; remainSize = size % blockSize;
......
...@@ -94,5 +94,6 @@ void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); ...@@ -94,5 +94,6 @@ void rtl92c_firmware_selfreset(struct ieee80211_hw *hw);
void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len);
#endif #endif
...@@ -84,6 +84,7 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) ...@@ -84,6 +84,7 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw)
} }
} }
rtlhal->version = (enum version_8192c)chip_version; rtlhal->version = (enum version_8192c)chip_version;
pr_info("rtl8192cu: Chip version 0x%x\n", chip_version);
switch (rtlhal->version) { switch (rtlhal->version) {
case VERSION_NORMAL_TSMC_CHIP_92C_1T2R: case VERSION_NORMAL_TSMC_CHIP_92C_1T2R:
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#define REALTEK_USB_VENQT_CMD_REQ 0x05 #define REALTEK_USB_VENQT_CMD_REQ 0x05
#define REALTEK_USB_VENQT_CMD_IDX 0x00 #define REALTEK_USB_VENQT_CMD_IDX 0x00
#define REALTEK_USB_VENQT_MAX_BUF_SIZE 254
#define MAX_USBCTRL_VENDORREQ_TIMES 10 #define MAX_USBCTRL_VENDORREQ_TIMES 10
static void usbctrl_async_callback(struct urb *urb) static void usbctrl_async_callback(struct urb *urb)
...@@ -203,6 +202,30 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) ...@@ -203,6 +202,30 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val)
_usb_write_async(to_usb_device(dev), addr, val, 4); _usb_write_async(to_usb_device(dev), addr, val, 4);
} }
static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data,
u16 len)
{
struct device *dev = rtlpriv->io.dev;
struct usb_device *udev = to_usb_device(dev);
u8 request = REALTEK_USB_VENQT_CMD_REQ;
u8 reqtype = REALTEK_USB_VENQT_WRITE;
u16 wvalue;
u16 index = REALTEK_USB_VENQT_CMD_IDX;
int pipe = usb_sndctrlpipe(udev, 0); /* write_out */
u8 *buffer;
dma_addr_t dma_addr;
wvalue = (u16)(addr&0x0000ffff);
buffer = usb_alloc_coherent(udev, (size_t)len, GFP_ATOMIC, &dma_addr);
if (!buffer)
return;
memcpy(buffer, data, len);
usb_control_msg(udev, pipe, request, reqtype, wvalue,
index, buffer, len, 50);
usb_free_coherent(udev, (size_t)len, buffer, dma_addr);
}
static void _rtl_usb_io_handler_init(struct device *dev, static void _rtl_usb_io_handler_init(struct device *dev,
struct ieee80211_hw *hw) struct ieee80211_hw *hw)
{ {
...@@ -216,6 +239,7 @@ static void _rtl_usb_io_handler_init(struct device *dev, ...@@ -216,6 +239,7 @@ static void _rtl_usb_io_handler_init(struct device *dev,
rtlpriv->io.read8_sync = _usb_read8_sync; rtlpriv->io.read8_sync = _usb_read8_sync;
rtlpriv->io.read16_sync = _usb_read16_sync; rtlpriv->io.read16_sync = _usb_read16_sync;
rtlpriv->io.read32_sync = _usb_read32_sync; rtlpriv->io.read32_sync = _usb_read32_sync;
rtlpriv->io.writeN_sync = _usb_writeN_sync;
} }
static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw)
......
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
#define AC_MAX 4 #define AC_MAX 4
#define QOS_QUEUE_NUM 4 #define QOS_QUEUE_NUM 4
#define RTL_MAC80211_NUM_QUEUE 5 #define RTL_MAC80211_NUM_QUEUE 5
#define REALTEK_USB_VENQT_MAX_BUF_SIZE 254
#define QBSS_LOAD_SIZE 5 #define QBSS_LOAD_SIZE 5
#define MAX_WMMELE_LENGTH 64 #define MAX_WMMELE_LENGTH 64
...@@ -943,8 +944,10 @@ struct rtl_io { ...@@ -943,8 +944,10 @@ struct rtl_io {
unsigned long pci_base_addr; /*device I/O address */ unsigned long pci_base_addr; /*device I/O address */
void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val); void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val);
void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val); void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val);
void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val); void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val);
void (*writeN_sync) (struct rtl_priv *rtlpriv, u32 addr, void *buf,
u16 len);
u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr); u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr);
u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr); u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr);
......
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