summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2012-07-11 14:37:28 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-09 08:31:30 -0700
commit74ec52aa07788b9bce2edd6ce9763c0d79bad38a (patch)
tree9212ad804d04566d7dbbf59d0c6dee0e59850158
parenta75b6122aacd06507cae1010e0fb6b06fe53336a (diff)
rtlwifi: rtl8192cu: Change buffer allocation for synchronous reads
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c14
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h1
2 files changed, 12 insertions, 3 deletions
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index a6049d7d51b3..aa970fc18a21 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -131,15 +131,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);
}
@@ -951,6 +955,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;
init_completion(&rtlpriv->firmware_loading_complete);
SET_IEEE80211_DEV(hw, &intf->dev);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 28ebc69218a3..717d3bad17d6 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -1555,6 +1555,7 @@ struct rtl_locks {
spinlock_t rf_ps_lock;
spinlock_t rf_lock;
spinlock_t waitq_lock;
+ spinlock_t usb_lock;
/*Dual mac*/
spinlock_t cck_and_rw_pagea_lock;