From 040a72785cf19fd8032f24d584ee305158c87ac7 Mon Sep 17 00:00:00 2001 From: George Date: Thu, 17 Nov 2011 12:14:42 -0600 Subject: rtlwifi: rtl8192cu: Allow retries for USB I/O The USB driver does not retry reads - allow 10 tries. Signed-off-by: George Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/rtlwifi/usb.c') diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index b42c2e2b2055..209105c8e3dc 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -33,6 +33,7 @@ #include "usb.h" #include "base.h" #include "ps.h" +#include "rtl8192c/fw_common.h" #define REALTEK_USB_VENQT_READ 0xC0 #define REALTEK_USB_VENQT_WRITE 0x40 @@ -40,6 +41,7 @@ #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) { @@ -99,13 +101,23 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, unsigned int pipe; int status; u8 reqtype; + int vendorreq_times = 0; pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ reqtype = REALTEK_USB_VENQT_READ; - status = usb_control_msg(udev, pipe, request, reqtype, value, index, - pdata, len, 0); /* max. timeout */ - + while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) { + status = usb_control_msg(udev, pipe, request, reqtype, value, + index, pdata, len, 0); /*max. timeout*/ + if (status < 0) { + /* firmware download is checksumed, don't retry */ + if ((value >= FW_8192C_START_ADDRESS && + value <= FW_8192C_END_ADDRESS)) + break; + } else { + break; + } + } if (status < 0) pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", value, status, *(u32 *)pdata); -- cgit v1.2.3 From ff6ff96b5ba5b39f7ab3d8ea0cf9ec414452ac92 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 17 Nov 2011 12:14:43 -0600 Subject: 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: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rtlwifi/usb.c') diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 209105c8e3dc..a461822c05b3 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -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) -- cgit v1.2.3 From abfabc9b48f6943dbb707fcfc2ef2a04c329e3e8 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 17 Nov 2011 12:14:44 -0600 Subject: rtlwifi: rtl8192cu: Fix endianian issues Driver rtlwifi fails on a big-endian host. These changes have been tested on a Mac PowerBook G4, which has a PPC processor. Although this patch touches some of the code that will affect endian issues on PCI hardware through drivers rtl8192ce, rtl8192se, and rtl8192de, these have not been tested due to lack of suitable hardware. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/rtlwifi/usb.c') diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index a461822c05b3..79889b83287e 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -82,6 +82,7 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, dr->wValue = cpu_to_le16(value); dr->wIndex = cpu_to_le16(index); dr->wLength = cpu_to_le16(len); + /* data are already in little-endian order */ memcpy(buf, pdata, len); usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, buf, len, @@ -101,6 +102,7 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, int status; u8 reqtype; int vendorreq_times = 0; + static int count; pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ reqtype = REALTEK_USB_VENQT_READ; @@ -117,9 +119,9 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, break; } } - if (status < 0) + if (status < 0 && count++ < 4) pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", - value, status, *(u32 *)pdata); + value, status, le32_to_cpu(*(u32 *)pdata)); return status; } @@ -139,7 +141,7 @@ static u32 _usb_read_sync(struct usb_device *udev, u32 addr, u16 len) wvalue = (u16)addr; _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); - ret = *data; + ret = le32_to_cpu(*data); kfree(data); return ret; } @@ -171,12 +173,12 @@ static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, u8 request; u16 wvalue; u16 index; - u32 data; + __le32 data; request = REALTEK_USB_VENQT_CMD_REQ; index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ wvalue = (u16)(addr&0x0000ffff); - data = val; + data = cpu_to_le32(val); _usbctrl_vendorreq_async_write(udev, request, wvalue, index, &data, len); } -- cgit v1.2.3 From eb1852b10593dc3ca73e02bf9ac4753a5a464905 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 21 Nov 2011 16:37:26 -0500 Subject: rtlwifi: squash warning in _usb_read_sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/rtlwifi/usb.c: In function ‘_usb_read_sync’: drivers/net/wireless/rtlwifi/usb.c:102:6: warning: ‘status’ may be used uninitialized in this function drivers/net/wireless/rtlwifi/usb.c:102:6: note: ‘status’ was declared here My compiler is dumb, but better to eliminate the warning than to have anyone waste time evaluating this again... Signed-off-by: John W. Linville Acked-by: Larry Finger --- drivers/net/wireless/rtlwifi/usb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/rtlwifi/usb.c') diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index ad109adcabcb..e956fa71d040 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -108,7 +108,7 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ reqtype = REALTEK_USB_VENQT_READ; - while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) { + do { status = usb_control_msg(udev, pipe, request, reqtype, value, index, pdata, len, 0); /*max. timeout*/ if (status < 0) { @@ -119,7 +119,8 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, } else { break; } - } + } while (++vendorreq_times < MAX_USBCTRL_VENDORREQ_TIMES); + if (status < 0 && count++ < 4) pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", value, status, le32_to_cpu(*(u32 *)pdata)); -- cgit v1.2.3