diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2011-11-17 13:14:43 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-21 16:20:45 -0500 |
commit | ff6ff96b5ba5b39f7ab3d8ea0cf9ec414452ac92 (patch) | |
tree | ad1c3294691a2860f9b8205ece269a1b36ac2f77 | |
parent | 040a72785cf19fd8032f24d584ee305158c87ac7 (diff) |
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 <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/usb.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/wifi.h | 7 |
5 files changed, 64 insertions, 3 deletions
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 49a064bdbce6..ebb73a2fae91 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | |||
@@ -72,6 +72,34 @@ static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable) | |||
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
75 | static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer, | ||
76 | u32 size) | ||
77 | { | ||
78 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
79 | u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20; | ||
80 | u8 *bufferPtr = (u8 *) buffer; | ||
81 | u32 i, offset, blockCount, remainSize; | ||
82 | |||
83 | blockCount = size / blockSize; | ||
84 | remainSize = size % blockSize; | ||
85 | |||
86 | for (i = 0; i < blockCount; i++) { | ||
87 | offset = i * blockSize; | ||
88 | rtlpriv->io.writeN_sync(rtlpriv, | ||
89 | (FW_8192C_START_ADDRESS + offset), | ||
90 | (void *)(bufferPtr + offset), | ||
91 | blockSize); | ||
92 | } | ||
93 | |||
94 | if (remainSize) { | ||
95 | offset = blockCount * blockSize; | ||
96 | rtlpriv->io.writeN_sync(rtlpriv, | ||
97 | (FW_8192C_START_ADDRESS + offset), | ||
98 | (void *)(bufferPtr + offset), | ||
99 | remainSize); | ||
100 | } | ||
101 | } | ||
102 | |||
75 | static void _rtl92c_fw_block_write(struct ieee80211_hw *hw, | 103 | static void _rtl92c_fw_block_write(struct ieee80211_hw *hw, |
76 | const u8 *buffer, u32 size) | 104 | const u8 *buffer, u32 size) |
77 | { | 105 | { |
@@ -81,6 +109,10 @@ static void _rtl92c_fw_block_write(struct ieee80211_hw *hw, | |||
81 | u32 *pu4BytePtr = (u32 *) buffer; | 109 | u32 *pu4BytePtr = (u32 *) buffer; |
82 | u32 i, offset, blockCount, remainSize; | 110 | u32 i, offset, blockCount, remainSize; |
83 | 111 | ||
112 | if (rtlpriv->io.writeN_sync) { | ||
113 | rtl_block_fw_writeN(hw, buffer, size); | ||
114 | return; | ||
115 | } | ||
84 | blockCount = size / blockSize; | 116 | blockCount = size / blockSize; |
85 | remainSize = size % blockSize; | 117 | remainSize = size % blockSize; |
86 | 118 | ||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index fcc4032585dc..c55c0541ff15 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h | |||
@@ -94,5 +94,6 @@ void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); | |||
94 | void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); | 94 | void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); |
95 | void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); | 95 | void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); |
96 | void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); | 96 | void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); |
97 | void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len); | ||
97 | 98 | ||
98 | #endif | 99 | #endif |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 060a06f4a885..9e0c8fcdf90f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | |||
@@ -84,6 +84,7 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) | |||
84 | } | 84 | } |
85 | } | 85 | } |
86 | rtlhal->version = (enum version_8192c)chip_version; | 86 | rtlhal->version = (enum version_8192c)chip_version; |
87 | pr_info("rtl8192cu: Chip version 0x%x\n", chip_version); | ||
87 | switch (rtlhal->version) { | 88 | switch (rtlhal->version) { |
88 | case VERSION_NORMAL_TSMC_CHIP_92C_1T2R: | 89 | case VERSION_NORMAL_TSMC_CHIP_92C_1T2R: |
89 | RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, | 90 | RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, |
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 @@ | |||
40 | #define REALTEK_USB_VENQT_CMD_REQ 0x05 | 40 | #define REALTEK_USB_VENQT_CMD_REQ 0x05 |
41 | #define REALTEK_USB_VENQT_CMD_IDX 0x00 | 41 | #define REALTEK_USB_VENQT_CMD_IDX 0x00 |
42 | 42 | ||
43 | #define REALTEK_USB_VENQT_MAX_BUF_SIZE 254 | ||
44 | #define MAX_USBCTRL_VENDORREQ_TIMES 10 | 43 | #define MAX_USBCTRL_VENDORREQ_TIMES 10 |
45 | 44 | ||
46 | static void usbctrl_async_callback(struct urb *urb) | 45 | 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 | _usb_write_async(to_usb_device(dev), addr, val, 4); | 202 | _usb_write_async(to_usb_device(dev), addr, val, 4); |
204 | } | 203 | } |
205 | 204 | ||
205 | static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data, | ||
206 | u16 len) | ||
207 | { | ||
208 | struct device *dev = rtlpriv->io.dev; | ||
209 | struct usb_device *udev = to_usb_device(dev); | ||
210 | u8 request = REALTEK_USB_VENQT_CMD_REQ; | ||
211 | u8 reqtype = REALTEK_USB_VENQT_WRITE; | ||
212 | u16 wvalue; | ||
213 | u16 index = REALTEK_USB_VENQT_CMD_IDX; | ||
214 | int pipe = usb_sndctrlpipe(udev, 0); /* write_out */ | ||
215 | u8 *buffer; | ||
216 | dma_addr_t dma_addr; | ||
217 | |||
218 | wvalue = (u16)(addr&0x0000ffff); | ||
219 | buffer = usb_alloc_coherent(udev, (size_t)len, GFP_ATOMIC, &dma_addr); | ||
220 | if (!buffer) | ||
221 | return; | ||
222 | memcpy(buffer, data, len); | ||
223 | usb_control_msg(udev, pipe, request, reqtype, wvalue, | ||
224 | index, buffer, len, 50); | ||
225 | |||
226 | usb_free_coherent(udev, (size_t)len, buffer, dma_addr); | ||
227 | } | ||
228 | |||
206 | static void _rtl_usb_io_handler_init(struct device *dev, | 229 | static void _rtl_usb_io_handler_init(struct device *dev, |
207 | struct ieee80211_hw *hw) | 230 | struct ieee80211_hw *hw) |
208 | { | 231 | { |
@@ -216,6 +239,7 @@ static void _rtl_usb_io_handler_init(struct device *dev, | |||
216 | rtlpriv->io.read8_sync = _usb_read8_sync; | 239 | rtlpriv->io.read8_sync = _usb_read8_sync; |
217 | rtlpriv->io.read16_sync = _usb_read16_sync; | 240 | rtlpriv->io.read16_sync = _usb_read16_sync; |
218 | rtlpriv->io.read32_sync = _usb_read32_sync; | 241 | rtlpriv->io.read32_sync = _usb_read32_sync; |
242 | rtlpriv->io.writeN_sync = _usb_writeN_sync; | ||
219 | } | 243 | } |
220 | 244 | ||
221 | static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) | 245 | static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) |
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 713c7ddba8eb..f3c132b55d42 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h | |||
@@ -63,6 +63,7 @@ | |||
63 | #define AC_MAX 4 | 63 | #define AC_MAX 4 |
64 | #define QOS_QUEUE_NUM 4 | 64 | #define QOS_QUEUE_NUM 4 |
65 | #define RTL_MAC80211_NUM_QUEUE 5 | 65 | #define RTL_MAC80211_NUM_QUEUE 5 |
66 | #define REALTEK_USB_VENQT_MAX_BUF_SIZE 254 | ||
66 | 67 | ||
67 | #define QBSS_LOAD_SIZE 5 | 68 | #define QBSS_LOAD_SIZE 5 |
68 | #define MAX_WMMELE_LENGTH 64 | 69 | #define MAX_WMMELE_LENGTH 64 |
@@ -943,8 +944,10 @@ struct rtl_io { | |||
943 | unsigned long pci_base_addr; /*device I/O address */ | 944 | unsigned long pci_base_addr; /*device I/O address */ |
944 | 945 | ||
945 | void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val); | 946 | void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val); |
946 | void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val); | 947 | void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val); |
947 | void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val); | 948 | void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val); |
949 | void (*writeN_sync) (struct rtl_priv *rtlpriv, u32 addr, void *buf, | ||
950 | u16 len); | ||
948 | 951 | ||
949 | u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr); | 952 | u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr); |
950 | u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr); | 953 | u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr); |