mac80211: rt2x00: add support for the RT3662/RT3883 SoCs
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch
diff --git a/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch b/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch
new file mode 100644 (file)
index 0000000..879b4cc
--- /dev/null
@@ -0,0 +1,531 @@
+From 250a1b520cd7fdc0df4fc3fedea9066913f49ecf Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Sat, 17 Aug 2013 19:31:42 +0200
+Subject: [PATCH] rt2x00: rt2800: serialize shared memory access
+
+The shared memory of the rt2800 devices is accessible
+through the register offset range between 0x4000 and
+0x8000. The size of this range is 16KB only and on
+devices which have more than 16KB of shared memory either
+the low or the high part of the memory is accessible at a
+time.
+
+Serialize all accesses to the shared memory by a mutex,
+in order to avoid concurrent use of that.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+Changes since v1: ---
+---
+ drivers/net/wireless/rt2x00/rt2800lib.c  |   55 +++++++++++++++++++++++++++++-
+ drivers/net/wireless/rt2x00/rt2800lib.h  |   32 +++++++++++++++++
+ drivers/net/wireless/rt2x00/rt2800mmio.c |   26 ++++++++++++++
+ drivers/net/wireless/rt2x00/rt2800mmio.h |    4 +++
+ drivers/net/wireless/rt2x00/rt2800pci.c  |   14 ++++++++
+ drivers/net/wireless/rt2x00/rt2800soc.c  |    3 ++
+ drivers/net/wireless/rt2x00/rt2800usb.c  |   31 +++++++++++++++++
+ 7 files changed, 164 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -451,11 +451,13 @@ void rt2800_mcu_request(struct rt2x00_de
+               rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+               rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+               rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg);
+               reg = 0;
+               rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+               rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg);
++              rt2800_shared_mem_unlock(rt2x00dev);
+       }
+       mutex_unlock(&rt2x00dev->csr_mutex);
+@@ -674,7 +676,9 @@ int rt2800_load_firmware(struct rt2x00_d
+        * Wait for device to stabilize.
+        */
+       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
++              rt2800_shared_mem_unlock(rt2x00dev);
+               if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
+                       break;
+               msleep(1);
+@@ -694,10 +698,16 @@ int rt2800_load_firmware(struct rt2x00_d
+       /*
+        * Initialize firmware.
+        */
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+       rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
++      rt2800_shared_mem_unlock(rt2x00dev);
++
+       if (rt2x00_is_usb(rt2x00dev)) {
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
++              rt2800_shared_mem_unlock(rt2x00dev);
++
+               rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+       }
+       msleep(1);
+@@ -1001,8 +1011,10 @@ void rt2800_write_beacon(struct queue_en
+       beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx);
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+                                  entry->skb->len + padding_len);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       /*
+        * Enable beaconing again.
+@@ -1027,6 +1039,8 @@ static inline void rt2800_clear_beacon_r
+       beacon_base = rt2800_hw_beacon_base(rt2x00dev, index);
++      rt2800_shared_mem_lock(rt2x00dev);
++
+       /*
+        * For the Beacon base registers we only need to clear
+        * the whole TXWI which (when set to 0) will invalidate
+@@ -1034,6 +1048,8 @@ static inline void rt2800_clear_beacon_r
+        */
+       for (i = 0; i < txwi_desc_size; i += sizeof(__le32))
+               rt2800_register_write(rt2x00dev, beacon_base + i, 0);
++
++      rt2800_shared_mem_unlock(rt2x00dev);
+ }
+ void rt2800_clear_beacon(struct queue_entry *entry)
+@@ -1217,7 +1233,9 @@ static void rt2800_delete_wcid_attr(stru
+ {
+       u32 offset;
+       offset = MAC_WCID_ATTR_ENTRY(wcid);
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_write(rt2x00dev, offset, 0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+ }
+ static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev,
+@@ -1230,11 +1248,13 @@ static void rt2800_config_wcid_attr_bssi
+        * The BSS Idx numbers is split in a main value of 3 bits,
+        * and a extended field for adding one additional bit to the value.
+        */
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_read(rt2x00dev, offset, &reg);
+       rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7));
+       rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
+                          (bssidx & 0x8) >> 3);
+       rt2800_register_write(rt2x00dev, offset, reg);
++      rt2800_shared_mem_unlock(rt2x00dev);
+ }
+ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
+@@ -1247,6 +1267,7 @@ static void rt2800_config_wcid_attr_ciph
+       offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);
++      rt2800_shared_mem_lock(rt2x00dev);
+       if (crypto->cmd == SET_KEY) {
+               rt2800_register_read(rt2x00dev, offset, &reg);
+               rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
+@@ -1271,6 +1292,7 @@ static void rt2800_config_wcid_attr_ciph
+               rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0);
+               rt2800_register_write(rt2x00dev, offset, reg);
+       }
++      rt2800_shared_mem_unlock(rt2x00dev);
+       offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
+@@ -1280,8 +1302,11 @@ static void rt2800_config_wcid_attr_ciph
+           (crypto->cipher == CIPHER_AES))
+               iveiv_entry.iv[3] |= 0x20;
+       iveiv_entry.iv[3] |= key->keyidx << 6;
++
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_multiwrite(rt2x00dev, offset,
+                                     &iveiv_entry, sizeof(iveiv_entry));
++      rt2800_shared_mem_unlock(rt2x00dev);
+ }
+ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
+@@ -1304,8 +1329,11 @@ int rt2800_config_shared_key(struct rt2x
+                      sizeof(key_entry.rx_mic));
+               offset = SHARED_KEY_ENTRY(key->hw_key_idx);
++
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2800_register_multiwrite(rt2x00dev, offset,
+                                             &key_entry, sizeof(key_entry));
++              rt2800_shared_mem_unlock(rt2x00dev);
+       }
+       /*
+@@ -1320,10 +1348,12 @@ int rt2800_config_shared_key(struct rt2x
+       offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8);
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_read(rt2x00dev, offset, &reg);
+       rt2x00_set_field32(&reg, field,
+                          (crypto->cmd == SET_KEY) * crypto->cipher);
+       rt2800_register_write(rt2x00dev, offset, reg);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       /*
+        * Update WCID information
+@@ -1393,8 +1423,11 @@ int rt2800_config_pairwise_key(struct rt
+                      sizeof(key_entry.rx_mic));
+               offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
++
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2800_register_multiwrite(rt2x00dev, offset,
+                                             &key_entry, sizeof(key_entry));
++              rt2800_shared_mem_unlock(rt2x00dev);
+       }
+       /*
+@@ -4876,14 +4909,19 @@ static int rt2800_init_registers(struct
+       /*
+        * ASIC will keep garbage value after boot, clear encryption keys.
+        */
++      rt2800_shared_mem_lock(rt2x00dev);
+       for (i = 0; i < 4; i++)
+               rt2800_register_write(rt2x00dev,
+                                        SHARED_KEY_MODE_ENTRY(i), 0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       for (i = 0; i < 256; i++) {
+               rt2800_config_wcid(rt2x00dev, NULL, i);
+               rt2800_delete_wcid_attr(rt2x00dev, i);
++
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
++              rt2800_shared_mem_unlock(rt2x00dev);
+       }
+       /*
+@@ -5009,8 +5047,10 @@ static int rt2800_wait_bbp_ready(struct
+        * BBP was enabled after firmware was loaded,
+        * but we need to reactivate it now.
+        */
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+       rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       msleep(1);
+       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+@@ -6706,11 +6746,19 @@ int rt2800_enable_radio(struct rt2x00_de
+       /*
+        * Send signal during boot time to initialize firmware.
+        */
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+       rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+-      if (rt2x00_is_usb(rt2x00dev))
++      rt2800_shared_mem_unlock(rt2x00dev);
++
++      if (rt2x00_is_usb(rt2x00dev)) {
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
++              rt2800_shared_mem_unlock(rt2x00dev);
++      }
++
+       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
++
+       msleep(1);
+       /*
+@@ -7716,6 +7764,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+       int retval;
+       u32 reg;
++      rt2800_shared_mem_init_lock(rt2x00dev);
++
+       retval = rt2800_probe_rt(rt2x00dev);
+       if (retval)
+               return retval;
+@@ -7795,8 +7845,11 @@ void rt2800_get_tkip_seq(struct ieee8021
+       u32 offset;
+       offset = MAC_IVEIV_ENTRY(hw_key_idx);
++
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2800_register_multiread(rt2x00dev, offset,
+                                     &iveiv_entry, sizeof(iveiv_entry));
++      rt2800_shared_mem_unlock(rt2x00dev);
+       memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
+       memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
+--- a/drivers/net/wireless/rt2x00/rt2800lib.h
++++ b/drivers/net/wireless/rt2x00/rt2800lib.h
+@@ -35,6 +35,11 @@ struct rt2800_drv_data {
+       unsigned int tbtt_tick;
+       unsigned long rt2800_flags;
++
++      union {
++              spinlock_t spin;
++              struct mutex mutex;
++      } shmem_lock;
+ };
+ struct rt2800_ops {
+@@ -65,6 +70,10 @@ struct rt2800_ops {
+                                 const u8 *data, const size_t len);
+       int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
+       __le32 *(*drv_get_txwi)(struct queue_entry *entry);
++
++      void (*shmem_init_lock)(struct rt2x00_dev *rt2x00dev);
++      void (*shmem_lock)(struct rt2x00_dev *rt2x00dev);
++      void (*shmem_unlock)(struct rt2x00_dev *rt2x00dev);
+ };
+ static inline bool rt2800_has_high_shared_mem(struct rt2x00_dev *rt2x00dev)
+@@ -74,6 +83,29 @@ static inline bool rt2800_has_high_share
+       return test_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags);
+ }
++static inline void rt2800_shared_mem_init_lock(struct rt2x00_dev *rt2x00dev)
++{
++      const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
++
++      rt2800ops->shmem_init_lock(rt2x00dev);
++}
++
++static inline void rt2800_shared_mem_lock(struct rt2x00_dev *rt2x00dev)
++{
++      const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
++
++      if (rt2800_has_high_shared_mem(rt2x00dev))
++              rt2800ops->shmem_lock(rt2x00dev);
++}
++
++static inline void rt2800_shared_mem_unlock(struct rt2x00_dev *rt2x00dev)
++{
++      const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
++
++      if (rt2800_has_high_shared_mem(rt2x00dev))
++              rt2800ops->shmem_unlock(rt2x00dev);
++}
++
+ static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
+                                       const unsigned int offset,
+                                       u32 *value)
+--- a/drivers/net/wireless/rt2x00/rt2800mmio.c
++++ b/drivers/net/wireless/rt2x00/rt2800mmio.c
+@@ -820,8 +820,10 @@ int rt2800mmio_init_registers(struct rt2
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+       rt2x00mmio_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+       rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       if (rt2x00_is_pcie(rt2x00dev) &&
+           (rt2x00_rt(rt2x00dev, RT3090) ||
+@@ -865,6 +867,30 @@ int rt2800mmio_enable_radio(struct rt2x0
+ }
+ EXPORT_SYMBOL_GPL(rt2800mmio_enable_radio);
++void rt2800mmio_shmem_init_lock(struct rt2x00_dev *rt2x00dev)
++{
++      struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
++
++      spin_lock_init(&drv_data->shmem_lock.spin);
++}
++EXPORT_SYMBOL_GPL(rt2800mmio_shmem_init_lock);
++
++void rt2800mmio_shmem_lock(struct rt2x00_dev *rt2x00dev)
++{
++      struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
++
++      spin_lock_bh(&drv_data->shmem_lock.spin);
++}
++EXPORT_SYMBOL_GPL(rt2800mmio_shmem_lock);
++
++void rt2800mmio_shmem_unlock(struct rt2x00_dev *rt2x00dev)
++{
++      struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
++
++      spin_unlock_bh(&drv_data->shmem_lock.spin);
++}
++EXPORT_SYMBOL_GPL(rt2800mmio_shmem_unlock);
++
+ MODULE_AUTHOR(DRV_PROJECT);
+ MODULE_VERSION(DRV_VERSION);
+ MODULE_DESCRIPTION("rt2800 MMIO library");
+--- a/drivers/net/wireless/rt2x00/rt2800mmio.h
++++ b/drivers/net/wireless/rt2x00/rt2800mmio.h
+@@ -160,4 +160,8 @@ int rt2800mmio_init_registers(struct rt2
+ /* Device state switch handlers. */
+ int rt2800mmio_enable_radio(struct rt2x00_dev *rt2x00dev);
++void rt2800mmio_shmem_init_lock(struct rt2x00_dev *rt2x00dev);
++void rt2800mmio_shmem_lock(struct rt2x00_dev *rt2x00dev);
++void rt2800mmio_shmem_unlock(struct rt2x00_dev *rt2x00dev);
++
+ #endif /* RT2800MMIO_H */
+--- a/drivers/net/wireless/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/rt2x00/rt2800pci.c
+@@ -69,7 +69,9 @@ static void rt2800pci_mcu_status(struct
+               return;
+       for (i = 0; i < 200; i++) {
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
++              rt2800_shared_mem_unlock(rt2x00dev);
+               if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) ||
+                   (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) ||
+@@ -83,8 +85,10 @@ static void rt2800pci_mcu_status(struct
+       if (i == 200)
+               rt2x00_err(rt2x00dev, "MCU request failed, no response from hardware\n");
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+       rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+ }
+ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+@@ -184,6 +188,8 @@ static int rt2800pci_write_firmware(stru
+        */
+       reg = 0;
+       rt2x00_set_field32(&reg, PBF_SYS_CTRL_HOST_RAM_WRITE, 1);
++
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
+       /*
+@@ -197,6 +203,7 @@ static int rt2800pci_write_firmware(stru
+       rt2x00mmio_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+       rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       return 0;
+ }
+@@ -213,8 +220,10 @@ static int rt2800pci_enable_radio(struct
+               return retval;
+       /* After resume MCU_BOOT_SIGNAL will trash these. */
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+       rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, 0xff, 0x02);
+       rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF);
+@@ -233,10 +242,12 @@ static int rt2800pci_set_state(struct rt
+                                  0, 0x02);
+               rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
+       } else if (state == STATE_SLEEP) {
++              rt2800_shared_mem_lock(rt2x00dev);
+               rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
+                                         0xffffffff);
+               rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID,
+                                         0xffffffff);
++              rt2800_shared_mem_unlock(rt2x00dev);
+               rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP,
+                                  0xff, 0x01);
+       }
+@@ -337,6 +348,9 @@ static const struct rt2800_ops rt2800pci
+       .drv_write_firmware     = rt2800pci_write_firmware,
+       .drv_init_registers     = rt2800mmio_init_registers,
+       .drv_get_txwi           = rt2800mmio_get_txwi,
++      .shmem_init_lock        = rt2800mmio_shmem_init_lock,
++      .shmem_lock             = rt2800mmio_shmem_lock,
++      .shmem_unlock           = rt2800mmio_shmem_unlock,
+ };
+ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
+--- a/drivers/net/wireless/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/rt2x00/rt2800soc.c
+@@ -176,6 +176,9 @@ static const struct rt2800_ops rt2800soc
+       .drv_write_firmware     = rt2800soc_write_firmware,
+       .drv_init_registers     = rt2800mmio_init_registers,
+       .drv_get_txwi           = rt2800mmio_get_txwi,
++      .shmem_init_lock        = rt2800mmio_shmem_init_lock,
++      .shmem_lock             = rt2800mmio_shmem_lock,
++      .shmem_unlock           = rt2800mmio_shmem_unlock,
+ };
+ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
+--- a/drivers/net/wireless/rt2x00/rt2800usb.c
++++ b/drivers/net/wireless/rt2x00/rt2800usb.c
+@@ -51,6 +51,27 @@ static bool rt2800usb_hwcrypt_disabled(s
+       return modparam_nohwcrypt;
+ }
++static void rt2800usb_shmem_init_lock(struct rt2x00_dev *rt2x00dev)
++{
++      struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
++
++      mutex_init(&drv_data->shmem_lock.mutex);
++}
++
++static void rt2800usb_shmem_lock(struct rt2x00_dev *rt2x00dev)
++{
++      struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
++
++      mutex_lock(&drv_data->shmem_lock.mutex);
++}
++
++static void rt2800usb_shmem_unlock(struct rt2x00_dev *rt2x00dev)
++{
++      struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
++
++      mutex_unlock(&drv_data->shmem_lock.mutex);
++}
++
+ /*
+  * Queue handlers.
+  */
+@@ -260,8 +281,10 @@ static int rt2800usb_write_firmware(stru
+       rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+                                     data + offset, length);
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+       rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       /*
+        * Send firmware request to device to load firmware,
+@@ -276,7 +299,10 @@ static int rt2800usb_write_firmware(stru
+       }
+       msleep(10);
++
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       return 0;
+ }
+@@ -294,8 +320,10 @@ static int rt2800usb_init_registers(stru
+       if (rt2800_wait_csr_ready(rt2x00dev))
+               return -EBUSY;
++      rt2800_shared_mem_lock(rt2x00dev);
+       rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+       rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
++      rt2800_shared_mem_unlock(rt2x00dev);
+       reg = 0;
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+@@ -810,6 +838,9 @@ static const struct rt2800_ops rt2800usb
+       .drv_write_firmware     = rt2800usb_write_firmware,
+       .drv_init_registers     = rt2800usb_init_registers,
+       .drv_get_txwi           = rt2800usb_get_txwi,
++      .shmem_init_lock        = rt2800usb_shmem_init_lock,
++      .shmem_lock             = rt2800usb_shmem_lock,
++      .shmem_unlock           = rt2800usb_shmem_unlock,
+ };
+ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {