aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rtlwifi/usb.c
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2012-07-11 15:37:28 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-07-12 15:27:18 -0400
commit3ce4d85b76010525adedcc2555fa164bf706a2f3 (patch)
tree05f3f6410bc376e7a28f0d9fcca686993e65591a /drivers/net/wireless/rtlwifi/usb.c
parent2a00def4d6e50cbfa7588887fdbe2a97042e42bb (diff)
rtlwifi: rtl8192cu: Change buffer allocation for synchronous reads
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> Cc: Stable <stable@vger.kernel.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rtlwifi/usb.c')
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c14
1 files changed, 11 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)
131 u8 request; 131 u8 request;
132 u16 wvalue; 132 u16 wvalue;
133 u16 index; 133 u16 index;
134 __le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; 134 __le32 *data;
135 unsigned long flags;
135 136
137 spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags);
138 if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT)
139 rtlpriv->usb_data_index = 0;
140 data = &rtlpriv->usb_data[rtlpriv->usb_data_index];
141 spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags);
136 request = REALTEK_USB_VENQT_CMD_REQ; 142 request = REALTEK_USB_VENQT_CMD_REQ;
137 index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ 143 index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */
138 144
139 wvalue = (u16)addr; 145 wvalue = (u16)addr;
140 _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); 146 _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len);
141 if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT)
142 rtlpriv->usb_data_index = 0;
143 return le32_to_cpu(*data); 147 return le32_to_cpu(*data);
144} 148}
145 149
@@ -951,6 +955,10 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
951 GFP_KERNEL); 955 GFP_KERNEL);
952 if (!rtlpriv->usb_data) 956 if (!rtlpriv->usb_data)
953 return -ENOMEM; 957 return -ENOMEM;
958
959 /* this spin lock must be initialized early */
960 spin_lock_init(&rtlpriv->locks.usb_lock);
961
954 rtlpriv->usb_data_index = 0; 962 rtlpriv->usb_data_index = 0;
955 init_completion(&rtlpriv->firmware_loading_complete); 963 init_completion(&rtlpriv->firmware_loading_complete);
956 SET_IEEE80211_DEV(hw, &intf->dev); 964 SET_IEEE80211_DEV(hw, &intf->dev);