lkml.org 
[lkml]   [2012]   [Apr]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[ 08/75] rtlwifi: Preallocate USB read buffers and eliminate kalloc in read routine
    3.3-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Larry Finger <Larry.Finger@lwfinger.net>

    commit a7959c1394d4126a70a53b914ce4105f5173d0aa upstream.

    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 https://bugzilla.kernel.org/show_bug.cgi?id=42775.
    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: Larry Finger <Larry.Finger@lwfinger.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/net/wireless/rtlwifi/usb.c | 34 ++++++++++++++++------------------
    drivers/net/wireless/rtlwifi/wifi.h | 6 +++++-
    2 files changed, 21 insertions(+), 19 deletions(-)

    --- a/drivers/net/wireless/rtlwifi/usb.c
    +++ b/drivers/net/wireless/rtlwifi/usb.c
    @@ -127,46 +127,38 @@ static int _usbctrl_vendorreq_sync_read(
    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->io.dev;
    + 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;
    request = REALTEK_USB_VENQT_CMD_REQ;
    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);
    - kfree(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->io.dev;
    -
    - 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->io.dev;
    -
    - 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->io.dev;
    -
    - 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,
    @@ -954,6 +946,11 @@ int __devinit rtl_usb_probe(struct usb_i
    return -ENOMEM;
    }
    rtlpriv = hw->priv;
    + rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32),
    + GFP_KERNEL);
    + if (!rtlpriv->usb_data)
    + return -ENOMEM;
    + rtlpriv->usb_data_index = 0;
    init_completion(&rtlpriv->firmware_loading_complete);
    SET_IEEE80211_DEV(hw, &intf->dev);
    udev = interface_to_usbdev(intf);
    @@ -1023,6 +1020,7 @@ void rtl_usb_disconnect(struct usb_inter
    /* rtl_deinit_rfkill(hw); */
    rtl_usb_deinit(hw);
    rtl_deinit_core(hw);
    + kfree(rtlpriv->usb_data);
    rtlpriv->cfg->ops->deinit_sw_leds(hw);
    rtlpriv->cfg->ops->deinit_sw_vars(hw);
    _rtl_usb_io_handler_release(hw);
    --- a/drivers/net/wireless/rtlwifi/wifi.h
    +++ b/drivers/net/wireless/rtlwifi/wifi.h
    @@ -65,7 +65,7 @@
    #define QOS_QUEUE_NUM 4
    #define RTL_MAC80211_NUM_QUEUE 5
    #define REALTEK_USB_VENQT_MAX_BUF_SIZE 254
    -
    +#define RTL_USB_MAX_RX_COUNT 100
    #define QBSS_LOAD_SIZE 5
    #define MAX_WMMELE_LENGTH 64

    @@ -1627,6 +1627,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:



    \
     
     \ /
      Last update: 2012-04-19 23:15    [W:3.948 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site