Commit 8ff48a8b authored by Ivo van Doorn's avatar Ivo van Doorn Committed by John W. Linville
Browse files

rt2x00: Fix race condition when using inderect registers



Indirect registers require multiple calls to the CSR
register in order to access the indirect registers.
This must be protected under a lock to prevent race
conditions which could cause invalid data to
be returned when reading from the indirect register or silent
failures when writing data to the indirect register.

USB drivers where already protected under a mutex,
so rename the mutex and make PCI drivers use the mutex
as well.
This now means that BBP and RF registers are no longer
accessible in interrupt context. That is not a bad
situation since the slow behavior of accessing
those registers means we don't _want_ to access them
in interrupt context either.
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent bad13639
...@@ -69,14 +69,14 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -69,14 +69,14 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; u32 reg;
mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt2400pci_bbp_check(rt2x00dev); reg = rt2400pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { if (rt2x00_get_field32(reg, BBPCSR_BUSY))
ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); goto exit_fail;
return;
}
/* /*
* Write the data into the BBP. * Write the data into the BBP.
...@@ -88,6 +88,15 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -88,6 +88,15 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1); rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
mutex_unlock(&rt2x00dev->csr_mutex);
return;
exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
} }
static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
...@@ -95,14 +104,14 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -95,14 +104,14 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; u32 reg;
mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt2400pci_bbp_check(rt2x00dev); reg = rt2400pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { if (rt2x00_get_field32(reg, BBPCSR_BUSY))
ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); goto exit_fail;
return;
}
/* /*
* Write the request into the BBP. * Write the request into the BBP.
...@@ -118,13 +127,20 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -118,13 +127,20 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt2400pci_bbp_check(rt2x00dev); reg = rt2400pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { if (rt2x00_get_field32(reg, BBPCSR_BUSY))
ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); goto exit_fail;
*value = 0xff;
return;
}
*value = rt2x00_get_field32(reg, BBPCSR_VALUE); *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex);
return;
exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
*value = 0xff;
} }
static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
...@@ -136,6 +152,8 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, ...@@ -136,6 +152,8 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->csr_mutex);
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2x00pci_register_read(rt2x00dev, RFCSR, &reg); rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
if (!rt2x00_get_field32(reg, RFCSR_BUSY)) if (!rt2x00_get_field32(reg, RFCSR_BUSY))
...@@ -143,6 +161,7 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, ...@@ -143,6 +161,7 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
udelay(REGISTER_BUSY_DELAY); udelay(REGISTER_BUSY_DELAY);
} }
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
return; return;
...@@ -155,6 +174,8 @@ rf_write: ...@@ -155,6 +174,8 @@ rf_write:
rt2x00pci_register_write(rt2x00dev, RFCSR, reg); rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
rt2x00_rf_write(rt2x00dev, word, value); rt2x00_rf_write(rt2x00dev, word, value);
mutex_unlock(&rt2x00dev->csr_mutex);
} }
static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
......
...@@ -69,14 +69,14 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -69,14 +69,14 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; u32 reg;
mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt2500pci_bbp_check(rt2x00dev); reg = rt2500pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { if (rt2x00_get_field32(reg, BBPCSR_BUSY))
ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); goto exit_fail;
return;
}
/* /*
* Write the data into the BBP. * Write the data into the BBP.
...@@ -88,6 +88,15 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -88,6 +88,15 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1); rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
mutex_unlock(&rt2x00dev->csr_mutex);
return;
exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
} }
static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
...@@ -95,14 +104,14 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -95,14 +104,14 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; u32 reg;
mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt2500pci_bbp_check(rt2x00dev); reg = rt2500pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { if (rt2x00_get_field32(reg, BBPCSR_BUSY))
ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); goto exit_fail;
return;
}
/* /*
* Write the request into the BBP. * Write the request into the BBP.
...@@ -118,13 +127,20 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -118,13 +127,20 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt2500pci_bbp_check(rt2x00dev); reg = rt2500pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { if (rt2x00_get_field32(reg, BBPCSR_BUSY))
ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); goto exit_fail;
*value = 0xff;
return;
}
*value = rt2x00_get_field32(reg, BBPCSR_VALUE); *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex);
return;
exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
*value = 0xff;
} }
static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
...@@ -136,6 +152,8 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, ...@@ -136,6 +152,8 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->csr_mutex);
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2x00pci_register_read(rt2x00dev, RFCSR, &reg); rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
if (!rt2x00_get_field32(reg, RFCSR_BUSY)) if (!rt2x00_get_field32(reg, RFCSR_BUSY))
...@@ -143,6 +161,7 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, ...@@ -143,6 +161,7 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
udelay(REGISTER_BUSY_DELAY); udelay(REGISTER_BUSY_DELAY);
} }
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
return; return;
...@@ -155,6 +174,8 @@ rf_write: ...@@ -155,6 +174,8 @@ rf_write:
rt2x00pci_register_write(rt2x00dev, RFCSR, reg); rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
rt2x00_rf_write(rt2x00dev, word, value); rt2x00_rf_write(rt2x00dev, word, value);
mutex_unlock(&rt2x00dev->csr_mutex);
} }
static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
* between each attampt. When the busy bit is still set at that time, * between each attampt. When the busy bit is still set at that time,
* the access attempt is considered to have failed, * the access attempt is considered to have failed,
* and we will print an error. * and we will print an error.
* If the usb_cache_mutex is already held then the _lock variants must * If the csr_mutex is already held then the _lock variants must
* be used instead. * be used instead.
*/ */
static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
...@@ -132,7 +132,7 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -132,7 +132,7 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
{ {
u16 reg; u16 reg;
mutex_lock(&rt2x00dev->usb_cache_mutex); mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
...@@ -151,12 +151,12 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -151,12 +151,12 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
return; return;
exit_fail: exit_fail:
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
} }
...@@ -166,7 +166,7 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -166,7 +166,7 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
{ {
u16 reg; u16 reg;
mutex_lock(&rt2x00dev->usb_cache_mutex); mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
...@@ -194,12 +194,12 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -194,12 +194,12 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg); rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
*value = rt2x00_get_field16(reg, PHY_CSR7_DATA); *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
return; return;
exit_fail: exit_fail:
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
*value = 0xff; *value = 0xff;
...@@ -214,7 +214,7 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, ...@@ -214,7 +214,7 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->usb_cache_mutex); mutex_lock(&rt2x00dev->csr_mutex);
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg); rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
...@@ -223,7 +223,7 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, ...@@ -223,7 +223,7 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
udelay(REGISTER_BUSY_DELAY); udelay(REGISTER_BUSY_DELAY);
} }
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
return; return;
...@@ -241,7 +241,7 @@ rf_write: ...@@ -241,7 +241,7 @@ rf_write:
rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
rt2x00_rf_write(rt2x00dev, word, value); rt2x00_rf_write(rt2x00dev, word, value);
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
} }
#ifdef CONFIG_RT2X00_LIB_DEBUGFS #ifdef CONFIG_RT2X00_LIB_DEBUGFS
......
...@@ -746,16 +746,15 @@ struct rt2x00_dev { ...@@ -746,16 +746,15 @@ struct rt2x00_dev {
} csr; } csr;
/* /*
* Mutex to protect register accesses on USB devices. * Mutex to protect register accesses.
* There are 2 reasons this is needed, one is to ensure * For PCI and USB devices it protects against concurrent indirect
* use of the csr_cache (for USB devices) by one thread * register access (BBP, RF, MCU) since accessing those
* isn't corrupted by another thread trying to access it. * registers require multiple calls to the CSR registers.
* The other is that access to BBP and RF registers * For USB devices it also protects the csr_cache since that
* require multiple BUS transactions and if another thread * field is used for normal CSR access and it cannot support
* attempted to access one of those registers at the same * multiple callers simultaneously.
* time one of the writes could silently fail. */
*/ struct mutex csr_mutex;
struct mutex usb_cache_mutex;
/* /*
* Current packet filter configuration for the device. * Current packet filter configuration for the device.
......
...@@ -1051,6 +1051,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) ...@@ -1051,6 +1051,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
{ {
int retval = -ENOMEM; int retval = -ENOMEM;
mutex_init(&rt2x00dev->csr_mutex);
/* /*
* Make room for rt2x00_intf inside the per-interface * Make room for rt2x00_intf inside the per-interface
* structure ieee80211_vif. * structure ieee80211_vif.
......
...@@ -79,7 +79,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, ...@@ -79,7 +79,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
{ {
int status; int status;
BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex)); BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex));
/* /*
* Check for Cache availability. * Check for Cache availability.
...@@ -110,13 +110,13 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, ...@@ -110,13 +110,13 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
{ {
int status; int status;
mutex_lock(&rt2x00dev->usb_cache_mutex); mutex_lock(&rt2x00dev->csr_mutex);
status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request, status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
requesttype, offset, buffer, requesttype, offset, buffer,
buffer_length, timeout); buffer_length, timeout);
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
return status; return status;
} }
...@@ -132,7 +132,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, ...@@ -132,7 +132,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
unsigned char *tb; unsigned char *tb;
u16 off, len, bsize; u16 off, len, bsize;
mutex_lock(&rt2x00dev->usb_cache_mutex); mutex_lock(&rt2x00dev->csr_mutex);
tb = (char *)buffer; tb = (char *)buffer;
off = offset; off = offset;
...@@ -148,7 +148,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, ...@@ -148,7 +148,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
off += bsize; off += bsize;
} }
mutex_unlock(&rt2x00dev->usb_cache_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
return status; return status;
} }
...@@ -531,7 +531,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, ...@@ -531,7 +531,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00dev->dev = &usb_intf->dev; rt2x00dev->dev = &usb_intf->dev;
rt2x00dev->ops = ops; rt2x00dev->ops = ops;
rt2x00dev->hw = hw; rt2x00dev->hw = hw;
mutex_init(&rt2x00dev->usb_cache_mutex);
rt2x00dev->usb_maxpacket = rt2x00dev->usb_maxpacket =
usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1); usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
......
...@@ -75,14 +75,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -75,14 +75,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; u32 reg;
mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt61pci_bbp_check(rt2x00dev); reg = rt61pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); goto exit_fail;
return;
}
/* /*
* Write the data into the BBP. * Write the data into the BBP.
...@@ -94,6 +94,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, ...@@ -94,6 +94,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0); rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
mutex_unlock(&rt2x00dev->csr_mutex);
return;
exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
} }
static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
...@@ -101,14 +109,14 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -101,14 +109,14 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; u32 reg;
mutex_lock(&rt2x00dev->csr_mutex);
/* /*
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt61pci_bbp_check(rt2x00dev); reg = rt61pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); goto exit_fail;
return;
}
/* /*
* Write the request into the BBP. * Write the request into the BBP.
...@@ -124,13 +132,19 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, ...@@ -124,13 +132,19 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready. * Wait until the BBP becomes ready.
*/ */
reg = rt61pci_bbp_check(rt2x00dev); reg = rt61pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); goto exit_fail;
*value = 0xff;
return;
}