aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2500usb.c
diff options
context:
space:
mode:
authorAdam Baker <linux@baker-net.org.uk>2007-10-27 07:43:29 -0400
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:03:03 -0500
commit3d82346c5d0ff0a413c387c6edaadc0ca29a0971 (patch)
tree790b3fcc6ccee693d9ac343626d1296c736a7851 /drivers/net/wireless/rt2x00/rt2500usb.c
parent4bd7c452a468af30bb3c4d9c3adcdaf3f3c6048c (diff)
rt2x00: Place mutex around USB register access
There is a buffer, csr_cache which is used to hold copies of data being passed to the USB stack which can get corrupted if multiple threads attempt to access CSR registers simultaneously. There is also the possibility if multiple threads try to access BBP or RF registers for the multiple USB operations needed to get interleaved leading to incorrect results. This patch introduces a mutex to prevent such simultaneous access. The interleaved access problem may also affect the PCI devices but if so that will be handled in a follow-up patch. Signed-off-by: Adam Baker <linux@baker-net.org.uk> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2500usb.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c52
1 files changed, 45 insertions, 7 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index c89103786b1c..a00420e9626b 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -52,6 +52,8 @@
52 * between each attampt. When the busy bit is still set at that time, 52 * between each attampt. When the busy bit is still set at that time,
53 * the access attempt is considered to have failed, 53 * the access attempt is considered to have failed,
54 * and we will print an error. 54 * and we will print an error.
55 * If the usb_cache_mutex is already held then the _lock variants must
56 * be used instead.
55 */ 57 */
56static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, 58static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
57 const unsigned int offset, 59 const unsigned int offset,
@@ -64,6 +66,17 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
64 *value = le16_to_cpu(reg); 66 *value = le16_to_cpu(reg);
65} 67}
66 68
69static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
70 const unsigned int offset,
71 u16 *value)
72{
73 __le16 reg;
74 rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
75 USB_VENDOR_REQUEST_IN, offset,
76 &reg, sizeof(u16), REGISTER_TIMEOUT);
77 *value = le16_to_cpu(reg);
78}
79
67static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev, 80static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev,
68 const unsigned int offset, 81 const unsigned int offset,
69 void *value, const u16 length) 82 void *value, const u16 length)
@@ -84,6 +97,16 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
84 &reg, sizeof(u16), REGISTER_TIMEOUT); 97 &reg, sizeof(u16), REGISTER_TIMEOUT);
85} 98}
86 99
100static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
101 const unsigned int offset,
102 u16 value)
103{
104 __le16 reg = cpu_to_le16(value);
105 rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
106 USB_VENDOR_REQUEST_OUT, offset,
107 &reg, sizeof(u16), REGISTER_TIMEOUT);
108}
109
87static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, 110static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
88 const unsigned int offset, 111 const unsigned int offset,
89 void *value, const u16 length) 112 void *value, const u16 length)
@@ -100,7 +123,7 @@ static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
100 unsigned int i; 123 unsigned int i;
101 124
102 for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 125 for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
103 rt2500usb_register_read(rt2x00dev, PHY_CSR8, &reg); 126 rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg);
104 if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) 127 if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
105 break; 128 break;
106 udelay(REGISTER_BUSY_DELAY); 129 udelay(REGISTER_BUSY_DELAY);
@@ -114,12 +137,15 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
114{ 137{
115 u16 reg; 138 u16 reg;
116 139
140 mutex_lock(&rt2x00dev->usb_cache_mutex);
141
117 /* 142 /*
118 * Wait until the BBP becomes ready. 143 * Wait until the BBP becomes ready.
119 */ 144 */
120 reg = rt2500usb_bbp_check(rt2x00dev); 145 reg = rt2500usb_bbp_check(rt2x00dev);
121 if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { 146 if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
122 ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); 147 ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
148 mutex_unlock(&rt2x00dev->usb_cache_mutex);
123 return; 149 return;
124 } 150 }
125 151
@@ -131,7 +157,9 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
131 rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word); 157 rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
132 rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0); 158 rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
133 159
134 rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); 160 rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
161
162 mutex_unlock(&rt2x00dev->usb_cache_mutex);
135} 163}
136 164
137static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, 165static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -139,6 +167,8 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
139{ 167{
140 u16 reg; 168 u16 reg;
141 169
170 mutex_lock(&rt2x00dev->usb_cache_mutex);
171
142 /* 172 /*
143 * Wait until the BBP becomes ready. 173 * Wait until the BBP becomes ready.
144 */ 174 */
@@ -155,7 +185,7 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
155 rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word); 185 rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
156 rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1); 186 rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
157 187
158 rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); 188 rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
159 189
160 /* 190 /*
161 * Wait until the BBP becomes ready. 191 * Wait until the BBP becomes ready.
@@ -164,11 +194,14 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
164 if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { 194 if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
165 ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); 195 ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
166 *value = 0xff; 196 *value = 0xff;
197 mutex_unlock(&rt2x00dev->usb_cache_mutex);
167 return; 198 return;
168 } 199 }
169 200
170 rt2500usb_register_read(rt2x00dev, PHY_CSR7, &reg); 201 rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
171 *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); 202 *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
203
204 mutex_unlock(&rt2x00dev->usb_cache_mutex);
172} 205}
173 206
174static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, 207static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -180,20 +213,23 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
180 if (!word) 213 if (!word)
181 return; 214 return;
182 215
216 mutex_lock(&rt2x00dev->usb_cache_mutex);
217
183 for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 218 for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
184 rt2500usb_register_read(rt2x00dev, PHY_CSR10, &reg); 219 rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
185 if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) 220 if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
186 goto rf_write; 221 goto rf_write;
187 udelay(REGISTER_BUSY_DELAY); 222 udelay(REGISTER_BUSY_DELAY);
188 } 223 }
189 224
225 mutex_unlock(&rt2x00dev->usb_cache_mutex);
190 ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); 226 ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
191 return; 227 return;
192 228
193rf_write: 229rf_write:
194 reg = 0; 230 reg = 0;
195 rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value); 231 rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
196 rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg); 232 rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
197 233
198 reg = 0; 234 reg = 0;
199 rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16); 235 rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
@@ -201,8 +237,10 @@ rf_write:
201 rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0); 237 rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
202 rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1); 238 rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
203 239
204 rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg); 240 rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
205 rt2x00_rf_write(rt2x00dev, word, value); 241 rt2x00_rf_write(rt2x00dev, word, value);
242
243 mutex_unlock(&rt2x00dev->usb_cache_mutex);
206} 244}
207 245
208#ifdef CONFIG_RT2X00_LIB_DEBUGFS 246#ifdef CONFIG_RT2X00_LIB_DEBUGFS