Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -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,
				   const u8 *buffer, u32 size)
{
@@ -81,6 +109,10 @@ static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
	u32 *pu4BytePtr = (u32 *) buffer;
	u32 i, offset, blockCount, remainSize;

	if (rtlpriv->io.writeN_sync) {
		rtl_block_fw_writeN(hw, buffer, size);
		return;
	}
	blockCount = size / blockSize;
	remainSize = size % blockSize;

+1 −0
Original line number Diff line number Diff line
@@ -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_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
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
+1 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw)
		}
	}
	rtlhal->version  = (enum version_8192c)chip_version;
	pr_info("rtl8192cu: Chip version 0x%x\n", chip_version);
	switch (rtlhal->version) {
	case VERSION_NORMAL_TSMC_CHIP_92C_1T2R:
		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+25 −1
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@
#define REALTEK_USB_VENQT_CMD_REQ		0x05
#define	REALTEK_USB_VENQT_CMD_IDX		0x00

#define REALTEK_USB_VENQT_MAX_BUF_SIZE		254
#define MAX_USBCTRL_VENDORREQ_TIMES		10

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)
	_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,
				     struct ieee80211_hw *hw)
{
@@ -216,6 +239,7 @@ static void _rtl_usb_io_handler_init(struct device *dev,
	rtlpriv->io.read8_sync		= _usb_read8_sync;
	rtlpriv->io.read16_sync		= _usb_read16_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)
+5 −2
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@
#define AC_MAX					4
#define QOS_QUEUE_NUM				4
#define RTL_MAC80211_NUM_QUEUE			5
#define REALTEK_USB_VENQT_MAX_BUF_SIZE		254

#define QBSS_LOAD_SIZE				5
#define MAX_WMMELE_LENGTH			64
@@ -943,8 +944,10 @@ struct rtl_io {
	unsigned long pci_base_addr;	/*device I/O address */

	void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val);
	void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val);
	void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val);
	void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 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);
	u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr);