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

rtlwifi: Preallocate USB read buffers and eliminate kalloc in read routine

The current version of rtlwifi for USB operations uses kmalloc to
acquire a 32-bit buffer for each read of the device. When
_usb_read_sync() is called with the rcu_lock held, the result is
a "sleeping function called from invalid context" BUG. This is
reported for two cases in

The first case has the lock originating from within rtlwifi and could
be fixed by rearranging the locking; however, the second originates from
within mac80211. The kmalloc() call is removed from _usb_read_sync()
by creating a ring buffer pointer in the private area and
allocating the buffer data in the probe routine.
Signed-off-by: default avatarLarry Finger <>
Cc: Stable <> [This version good for 3.3+ - different patch for 3.2 - 2.6.39]
Signed-off-by: default avatarJohn W. Linville <>
parent 011afa1e
......@@ -124,46 +124,38 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request,
return status;
static u32 _usb_read_sync(struct usb_device *udev, u32 addr, u16 len)
static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len)
struct device *dev = rtlpriv->;
struct usb_device *udev = to_usb_device(dev);
u8 request;
u16 wvalue;
u16 index;
u32 *data;
u32 ret;
__le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index];
data = kmalloc(sizeof(u32), GFP_KERNEL);
if (!data)
return -ENOMEM;
index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */
wvalue = (u16)addr;
_usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len);
ret = le32_to_cpu(*data);
return ret;
if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT)
rtlpriv->usb_data_index = 0;
return le32_to_cpu(*data);
static u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
struct device *dev = rtlpriv->;
return (u8)_usb_read_sync(to_usb_device(dev), addr, 1);
return (u8)_usb_read_sync(rtlpriv, addr, 1);
static u16 _usb_read16_sync(struct rtl_priv *rtlpriv, u32 addr)
struct device *dev = rtlpriv->;
return (u16)_usb_read_sync(to_usb_device(dev), addr, 2);
return (u16)_usb_read_sync(rtlpriv, addr, 2);
static u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr)
struct device *dev = rtlpriv->;
return _usb_read_sync(to_usb_device(dev), addr, 4);
return _usb_read_sync(rtlpriv, addr, 4);
static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val,
......@@ -955,6 +947,11 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
return -ENOMEM;
rtlpriv = hw->priv;
rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32),
if (!rtlpriv->usb_data)
return -ENOMEM;
rtlpriv->usb_data_index = 0;
SET_IEEE80211_DEV(hw, &intf->dev);
udev = interface_to_usbdev(intf);
......@@ -1025,6 +1022,7 @@ void rtl_usb_disconnect(struct usb_interface *intf)
/* rtl_deinit_rfkill(hw); */
......@@ -67,7 +67,7 @@
#define QOS_QUEUE_NUM 4
#define RTL_MAC80211_NUM_QUEUE 5
#define RTL_USB_MAX_RX_COUNT 100
#define QBSS_LOAD_SIZE 5
......@@ -1629,6 +1629,10 @@ struct rtl_priv {
interface or hardware */
unsigned long status;
/* data buffer pointer for USB reads */
__le32 *usb_data;
int usb_data_index;
/*This must be the last item so
that it points to the data allocated
beyond this structure like:
Supports Markdown
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