wil_halp_vote(wil);
 
+       if (wil_mem_access_lock(wil)) {
+               wil_halp_unvote(wil);
+               return;
+       }
+
        wil_memcpy_fromio_32(&r, off, sizeof(r));
        wil_mbox_ring_le2cpus(&r);
        /*
        }
  out:
        seq_puts(s, "}\n");
+       wil_mem_access_unlock(wil);
        wil_halp_unvote(wil);
 }
 
        if (ret < 0)
                return ret;
 
+       ret = wil_mem_access_lock(wil);
+       if (ret) {
+               wil_pm_runtime_put(wil);
+               return ret;
+       }
+
        a = wmi_buffer(wil, cpu_to_le32(mem_addr));
 
        if (a)
        else
                seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
 
+       wil_mem_access_unlock(wil);
        wil_pm_runtime_put(wil);
 
        return 0;
        size_t unaligned_bytes, aligned_count, ret;
        int rc;
 
-       if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
-           test_bit(wil_status_suspended, wil_blob->wil->status))
-               return 0;
-
        if (pos < 0)
                return -EINVAL;
 
                return rc;
        }
 
+       rc = wil_mem_access_lock(wil);
+       if (rc) {
+               kfree(buf);
+               wil_pm_runtime_put(wil);
+               return rc;
+       }
+
        wil_memcpy_fromio_32(buf, (const void __iomem *)
                             wil_blob->blob.data + aligned_pos, aligned_count);
 
        ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
 
+       wil_mem_access_unlock(wil);
        wil_pm_runtime_put(wil);
 
        kfree(buf);
 
        }
 }
 
+/* Device memory access is prohibited while reset or suspend.
+ * wil_mem_access_lock protects accessing device memory in these cases
+ */
+int wil_mem_access_lock(struct wil6210_priv *wil)
+{
+       if (!down_read_trylock(&wil->mem_lock))
+               return -EBUSY;
+
+       if (test_bit(wil_status_suspending, wil->status) ||
+           test_bit(wil_status_suspended, wil->status)) {
+               up_read(&wil->mem_lock);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+void wil_mem_access_unlock(struct wil6210_priv *wil)
+{
+       up_read(&wil->mem_lock);
+}
+
 static void wil_ring_fini_tx(struct wil6210_priv *wil, int id)
 {
        struct wil_ring *ring = &wil->ring_tx[id];
        spin_lock_init(&wil->wmi_ev_lock);
        spin_lock_init(&wil->net_queue_lock);
        init_waitqueue_head(&wil->wq);
+       init_rwsem(&wil->mem_lock);
 
        wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
        if (!wil->wmi_wq)
        }
 
        set_bit(wil_status_resetting, wil->status);
-       if (test_bit(wil_status_collecting_dumps, wil->status)) {
-               /* Device collects crash dump, cancel the reset.
-                * following crash dump collection, reset would take place.
-                */
-               wil_dbg_misc(wil, "reject reset while collecting crash dump\n");
-               rc = -EBUSY;
-               goto out;
-       }
-
        mutex_lock(&wil->vif_mutex);
        wil_abort_scan_all_vifs(wil, false);
        mutex_unlock(&wil->vif_mutex);
 
        WARN_ON(!mutex_is_locked(&wil->mutex));
 
+       down_write(&wil->mem_lock);
        rc = wil_reset(wil, true);
+       up_write(&wil->mem_lock);
        if (rc)
                return rc;
 
 
 int __wil_down(struct wil6210_priv *wil)
 {
+       int rc;
        WARN_ON(!mutex_is_locked(&wil->mutex));
 
        set_bit(wil_status_resetting, wil->status);
        wil_abort_scan_all_vifs(wil, false);
        mutex_unlock(&wil->vif_mutex);
 
-       return wil_reset(wil, false);
+       down_write(&wil->mem_lock);
+       rc = wil_reset(wil, false);
+       up_write(&wil->mem_lock);
+
+       return rc;
 }
 
 int wil_down(struct wil6210_priv *wil)
 
 /*
  * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
        wil_dbg_pm(wil, "suspend keep radio on\n");
 
        /* Prevent handling of new tx and wmi commands */
-       set_bit(wil_status_suspending, wil->status);
-       if (test_bit(wil_status_collecting_dumps, wil->status)) {
-               /* Device collects crash dump, cancel the suspend */
-               wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
-               clear_bit(wil_status_suspending, wil->status);
+       rc = down_write_trylock(&wil->mem_lock);
+       if (!rc) {
+               wil_err(wil,
+                       "device is busy. down_write_trylock failed, returned (0x%x)\n",
+                       rc);
                wil->suspend_stats.rejected_by_host++;
                return -EBUSY;
        }
+
+       set_bit(wil_status_suspending, wil->status);
+       up_write(&wil->mem_lock);
+
        wil_pm_stop_all_net_queues(wil);
 
        if (!wil_is_tx_idle(wil)) {
 
        wil_dbg_pm(wil, "suspend radio off\n");
 
-       set_bit(wil_status_suspending, wil->status);
-       if (test_bit(wil_status_collecting_dumps, wil->status)) {
-               /* Device collects crash dump, cancel the suspend */
-               wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
-               clear_bit(wil_status_suspending, wil->status);
+       rc = down_write_trylock(&wil->mem_lock);
+       if (!rc) {
+               wil_err(wil,
+                       "device is busy. down_write_trylock failed, returned (0x%x)\n",
+                       rc);
                wil->suspend_stats.rejected_by_host++;
                return -EBUSY;
        }
 
+       set_bit(wil_status_suspending, wil->status);
+       up_write(&wil->mem_lock);
+
        /* if netif up, hardware is alive, shut it down */
        mutex_lock(&wil->vif_mutex);
        active_ifaces = wil_has_active_ifaces(wil, true, false);
 
        wil_status_suspending, /* suspend in progress */
        wil_status_suspended, /* suspend completed, device is suspended */
        wil_status_resuming, /* resume in progress */
-       wil_status_collecting_dumps, /* crashdump collection in progress */
        wil_status_last /* keep last */
 };
 
        struct wil_txrx_ops txrx_ops;
 
        struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
+       /* for synchronizing device memory access while reset or suspend */
+       struct rw_semaphore mem_lock;
        /* statistics */
        atomic_t isr_count_rx, isr_count_tx;
        /* debugfs */
                          size_t count);
 void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
                        size_t count);
+int wil_mem_access_lock(struct wil6210_priv *wil);
+void wil_mem_access_unlock(struct wil6210_priv *wil);
 
 struct wil6210_vif *
 wil_vif_alloc(struct wil6210_priv *wil, const char *name,
 
 /*
  * Copyright (c) 2015,2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 
 int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
 {
-       int i;
+       int i, rc;
        const struct fw_map *map;
        void *data;
        u32 host_min, dump_size, offset, len;
                return -EINVAL;
        }
 
-       set_bit(wil_status_collecting_dumps, wil->status);
-       if (test_bit(wil_status_suspending, wil->status) ||
-           test_bit(wil_status_suspended, wil->status) ||
-           test_bit(wil_status_resetting, wil->status)) {
-               wil_err(wil, "cannot collect fw dump during suspend/reset\n");
-               clear_bit(wil_status_collecting_dumps, wil->status);
-               return -EINVAL;
-       }
+       rc = wil_mem_access_lock(wil);
+       if (rc)
+               return rc;
 
        /* copy to crash dump area */
        for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
                wil_memcpy_fromio_32((void * __force)(dest + offset),
                                     (const void __iomem * __force)data, len);
        }
-
-       clear_bit(wil_status_collecting_dumps, wil->status);
+       wil_mem_access_unlock(wil);
 
        return 0;
 }