* between each attampt. When the busy bit is still set at that time,
  * the access attempt is considered to have failed,
  * and we will print an error.
+ * If the usb_cache_mutex is already held then the _lock variants must
+ * be used instead.
  */
 static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
                                           const unsigned int offset,
        *value = le16_to_cpu(reg);
 }
 
+static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+                                               const unsigned int offset,
+                                               u16 *value)
+{
+       __le16 reg;
+       rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+                                      USB_VENDOR_REQUEST_IN, offset,
+                                      ®, sizeof(u16), REGISTER_TIMEOUT);
+       *value = le16_to_cpu(reg);
+}
+
 static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev,
                                                const unsigned int offset,
                                                void *value, const u16 length)
                                      ®, sizeof(u16), REGISTER_TIMEOUT);
 }
 
+static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+                                                const unsigned int offset,
+                                                u16 value)
+{
+       __le16 reg = cpu_to_le16(value);
+       rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+                                      USB_VENDOR_REQUEST_OUT, offset,
+                                      ®, sizeof(u16), REGISTER_TIMEOUT);
+}
+
 static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
                                                 const unsigned int offset,
                                                 void *value, const u16 length)
        unsigned int i;
 
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2500usb_register_read(rt2x00dev, PHY_CSR8, ®);
+               rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, ®);
                if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
                        break;
                udelay(REGISTER_BUSY_DELAY);
 {
        u16 reg;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        /*
         * Wait until the BBP becomes ready.
         */
        reg = rt2500usb_bbp_check(rt2x00dev);
        if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
                ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+               mutex_unlock(&rt2x00dev->usb_cache_mutex);
                return;
        }
 
        rt2x00_set_field16(®, PHY_CSR7_REG_ID, word);
        rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0);
 
-       rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 {
        u16 reg;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        /*
         * Wait until the BBP becomes ready.
         */
        rt2x00_set_field16(®, PHY_CSR7_REG_ID, word);
        rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1);
 
-       rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
        /*
         * Wait until the BBP becomes ready.
        if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
                ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
                *value = 0xff;
+               mutex_unlock(&rt2x00dev->usb_cache_mutex);
                return;
        }
 
-       rt2500usb_register_read(rt2x00dev, PHY_CSR7, ®);
+       rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®);
        *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
        if (!word)
                return;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2500usb_register_read(rt2x00dev, PHY_CSR10, ®);
+               rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, ®);
                if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
                        goto rf_write;
                udelay(REGISTER_BUSY_DELAY);
        }
 
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
        ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
        return;
 
 rf_write:
        reg = 0;
        rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value);
-       rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
 
        reg = 0;
        rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16);
        rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0);
        rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1);
 
-       rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
        rt2x00_rf_write(rt2x00dev, word, value);
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <linux/firmware.h>
+#include <linux/mutex.h>
 
 #include <net/mac80211.h>
 
        void __iomem *csr_addr;
        void *csr_cache;
 
+       /*
+        * Mutex to protect register accesses on USB devices.
+        * There are 2 reasons this is needed, one is to ensure
+        * use of the csr_cache (for USB devices) by one thread
+        * isn't corrupted by another thread trying to access it.
+        * The other is that access to BBP and RF registers
+        * require multiple BUS transactions and if another thread
+        * attempted to access one of those registers at the same
+        * time one of the writes could silently fail.
+        */
+       struct mutex usb_cache_mutex;
+
        /*
         * Interface configuration.
         */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/bug.h>
 
 #include "rt2x00.h"
 #include "rt2x00usb.h"
            (requesttype == USB_VENDOR_REQUEST_IN) ?
            usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
 
+
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
                status = usb_control_msg(usb_dev, pipe, request, requesttype,
                                         value, offset, buffer, buffer_length,
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
 
-int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
-                                 const u8 request, const u8 requesttype,
-                                 const u16 offset, void *buffer,
-                                 const u16 buffer_length, const int timeout)
+int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
+                                  const u8 request, const u8 requesttype,
+                                  const u16 offset, void *buffer,
+                                  const u16 buffer_length, const int timeout)
 {
        int status;
 
+       BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex));
+
        /*
         * Check for Cache availability.
         */
 
        return status;
 }
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_req_buff_lock);
+
+int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
+                                 const u8 request, const u8 requesttype,
+                                 const u16 offset, void *buffer,
+                                 const u16 buffer_length, const int timeout)
+{
+       int status;
+
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
+       status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
+                                               requesttype, offset, buffer,
+                                               buffer_length, timeout);
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       return status;
+}
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
 
 /*
        rt2x00dev->dev = usb_intf;
        rt2x00dev->ops = ops;
        rt2x00dev->hw = hw;
+       mutex_init(&rt2x00dev->usb_cache_mutex);
 
        rt2x00dev->usb_maxpacket =
            usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
 
                                  const u16 offset, void *buffer,
                                  const u16 buffer_length, const int timeout);
 
+/*
+ * A version of rt2x00usb_vendor_request_buff which must be called
+ * if the usb_cache_mutex is already held. */
+int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
+                                  const u8 request, const u8 requesttype,
+                                  const u16 offset, void *buffer,
+                                  const u16 buffer_length, const int timeout);
+
 /*
  * Simple wrapper around rt2x00usb_vendor_request to write a single
  * command to the device. Since we don't use the buffer argument we
 
  * between each attampt. When the busy bit is still set at that time,
  * the access attempt is considered to have failed,
  * and we will print an error.
+ * The _lock versions must be used if you already hold the usb_cache_mutex
  */
 static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev,
                                         const unsigned int offset, u32 *value)
        *value = le32_to_cpu(reg);
 }
 
+static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+                                             const unsigned int offset, u32 *value)
+{
+       __le32 reg;
+       rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+                                      USB_VENDOR_REQUEST_IN, offset,
+                                      ®, sizeof(u32), REGISTER_TIMEOUT);
+       *value = le32_to_cpu(reg);
+}
+
 static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev,
                                              const unsigned int offset,
                                              void *value, const u32 length)
                                      ®, sizeof(u32), REGISTER_TIMEOUT);
 }
 
+static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+                                              const unsigned int offset, u32 value)
+{
+       __le32 reg = cpu_to_le32(value);
+       rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+                                      USB_VENDOR_REQUEST_OUT, offset,
+                                     ®, sizeof(u32), REGISTER_TIMEOUT);
+}
+
 static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
                                               const unsigned int offset,
                                               void *value, const u32 length)
        unsigned int i;
 
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt73usb_register_read(rt2x00dev, PHY_CSR3, ®);
+               rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, ®);
                if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
                        break;
                udelay(REGISTER_BUSY_DELAY);
 {
        u32 reg;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        /*
         * Wait until the BBP becomes ready.
         */
        reg = rt73usb_bbp_check(rt2x00dev);
        if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
                ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+               mutex_unlock(&rt2x00dev->usb_cache_mutex);
                return;
        }
 
        rt2x00_set_field32(®, PHY_CSR3_BUSY, 1);
        rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0);
 
-       rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+       rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        /*
         * Wait until the BBP becomes ready.
         */
        reg = rt73usb_bbp_check(rt2x00dev);
        if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
                ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+               mutex_unlock(&rt2x00dev->usb_cache_mutex);
                return;
        }
 
        rt2x00_set_field32(®, PHY_CSR3_BUSY, 1);
        rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1);
 
-       rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+       rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
 
        /*
         * Wait until the BBP becomes ready.
        }
 
        *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
        if (!word)
                return;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt73usb_register_read(rt2x00dev, PHY_CSR4, ®);
+               rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, ®);
                if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
                        goto rf_write;
                udelay(REGISTER_BUSY_DELAY);
        }
 
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
        ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
        return;
 
        rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0);
        rt2x00_set_field32(®, PHY_CSR4_BUSY, 1);
 
-       rt73usb_register_write(rt2x00dev, PHY_CSR4, reg);
+       rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
        rt2x00_rf_write(rt2x00dev, word, value);
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS