]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
rtlwifi: rtl8192cu: Change buffer allocation for synchronous reads
authorLarry Finger <Larry.Finger@lwfinger.net>
Wed, 11 Jul 2012 19:37:28 +0000 (14:37 -0500)
committerBen Hutchings <ben@decadent.org.uk>
Sun, 19 Aug 2012 17:15:27 +0000 (18:15 +0100)
commit 3ce4d85b76010525adedcc2555fa164bf706a2f3 upstream.

In commit a7959c1, the USB part of rtlwifi was switched to convert
_usb_read_sync() to using a preallocated buffer rather than one
that has been acquired using kmalloc. Although this routine is named
as though it were synchronous, there seem to be simultaneous users,
and the selection of the index to the data buffer is not multi-user
safe. This situation is addressed by adding a new spinlock. The routine
cannot sleep, thus a mutex is not allowed.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h

index db34db6adef45433679fac3ed9b7b23b858b5302..a49e8489538be9631b388aa9eae119b99f0e6982 100644 (file)
@@ -120,15 +120,19 @@ static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len)
        u8 request;
        u16 wvalue;
        u16 index;
-       __le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index];
+       __le32 *data;
+       unsigned long flags;
 
+       spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags);
+       if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT)
+               rtlpriv->usb_data_index = 0;
+       data = &rtlpriv->usb_data[rtlpriv->usb_data_index];
+       spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags);
        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);
-       if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT)
-               rtlpriv->usb_data_index = 0;
        return le32_to_cpu(*data);
 }
 
@@ -909,6 +913,10 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
                                    GFP_KERNEL);
        if (!rtlpriv->usb_data)
                return -ENOMEM;
+
+       /* this spin lock must be initialized early */
+       spin_lock_init(&rtlpriv->locks.usb_lock);
+
        rtlpriv->usb_data_index = 0;
        SET_IEEE80211_DEV(hw, &intf->dev);
        udev = interface_to_usbdev(intf);
index b1e9debc9f0a215a714ddeae55fa6d5b2eaebbef..deb87e959e02876a7938d0b20a2e00df7d8d799b 100644 (file)
@@ -1550,6 +1550,7 @@ struct rtl_locks {
        spinlock_t rf_lock;
        spinlock_t lps_lock;
        spinlock_t waitq_lock;
+       spinlock_t usb_lock;
 
        /*Dual mac*/
        spinlock_t cck_and_rw_pagea_lock;