void __iomem *virt;
        acpi_physical_address phys;
        acpi_size size;
-       unsigned long refcount;
+       union {
+               unsigned long refcount;
+               struct rcu_work rwork;
+       } track;
 };
 
 static LIST_HEAD(acpi_ioremaps);
        map = acpi_map_lookup(phys, size);
        if (map) {
                virt = map->virt + (phys - map->phys);
-               map->refcount++;
+               map->track.refcount++;
        }
        mutex_unlock(&acpi_ioremap_lock);
        return virt;
        /* Check if there's a suitable mapping already. */
        map = acpi_map_lookup(phys, size);
        if (map) {
-               map->refcount++;
+               map->track.refcount++;
                goto out;
        }
 
        map->virt = virt;
        map->phys = pg_off;
        map->size = pg_sz;
-       map->refcount = 1;
+       map->track.refcount = 1;
 
        list_add_tail_rcu(&map->list, &acpi_ioremaps);
 
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
+static void acpi_os_map_remove(struct acpi_ioremap *map)
+{
+       acpi_unmap(map->phys, map->virt);
+       kfree(map);
+}
+
+static void acpi_os_map_cleanup_deferred(struct work_struct *work)
+{
+       acpi_os_map_remove(container_of(to_rcu_work(work), struct acpi_ioremap,
+                                       track.rwork));
+}
+
 /* Must be called with mutex_lock(&acpi_ioremap_lock) */
-static unsigned long acpi_os_drop_map_ref(struct acpi_ioremap *map)
+static bool acpi_os_drop_map_ref(struct acpi_ioremap *map, bool defer)
 {
-       unsigned long refcount = --map->refcount;
+       if (--map->track.refcount)
+               return true;
 
-       if (!refcount)
-               list_del_rcu(&map->list);
-       return refcount;
+       list_del_rcu(&map->list);
+
+       if (defer) {
+               INIT_RCU_WORK(&map->track.rwork, acpi_os_map_cleanup_deferred);
+               queue_rcu_work(system_wq, &map->track.rwork);
+       }
+       return defer;
 }
 
 static void acpi_os_map_cleanup(struct acpi_ioremap *map)
 {
+       if (!map)
+               return;
+
        synchronize_rcu_expedited();
-       acpi_unmap(map->phys, map->virt);
-       kfree(map);
+       acpi_os_map_remove(map);
 }
 
-/**
- * acpi_os_unmap_iomem - Drop a memory mapping reference.
- * @virt: Start of the address range to drop a reference to.
- * @size: Size of the address range to drop a reference to.
- *
- * Look up the given virtual address range in the list of existing ACPI memory
- * mappings, drop a reference to it and unmap it if there are no more active
- * references to it.
- *
- * During early init (when acpi_permanent_mmap has not been set yet) this
- * routine simply calls __acpi_unmap_table() to get the job done.  Since
- * __acpi_unmap_table() is an __init function, the __ref annotation is needed
- * here.
- */
-void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
+static void __ref __acpi_os_unmap_iomem(void __iomem *virt, acpi_size size,
+                                       bool defer)
 {
        struct acpi_ioremap *map;
-       unsigned long refcount;
 
        if (!acpi_permanent_mmap) {
                __acpi_unmap_table(virt, size);
        }
 
        mutex_lock(&acpi_ioremap_lock);
+
        map = acpi_map_lookup_virt(virt, size);
        if (!map) {
                mutex_unlock(&acpi_ioremap_lock);
                WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);
                return;
        }
-       refcount = acpi_os_drop_map_ref(map);
+       if (acpi_os_drop_map_ref(map, defer))
+               map = NULL;
+
        mutex_unlock(&acpi_ioremap_lock);
 
-       if (!refcount)
-               acpi_os_map_cleanup(map);
+       acpi_os_map_cleanup(map);
+}
+
+/**
+ * acpi_os_unmap_iomem - Drop a memory mapping reference.
+ * @virt: Start of the address range to drop a reference to.
+ * @size: Size of the address range to drop a reference to.
+ *
+ * Look up the given virtual address range in the list of existing ACPI memory
+ * mappings, drop a reference to it and unmap it if there are no more active
+ * references to it.
+ *
+ * During early init (when acpi_permanent_mmap has not been set yet) this
+ * routine simply calls __acpi_unmap_table() to get the job done.  Since
+ * __acpi_unmap_table() is an __init function, the __ref annotation is needed
+ * here.
+ */
+void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
+{
+       __acpi_os_unmap_iomem(virt, size, false);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem);
 
+/**
+ * acpi_os_unmap_memory - Drop a memory mapping reference.
+ * @virt: Start of the address range to drop a reference to.
+ * @size: Size of the address range to drop a reference to.
+ *
+ * Look up the given virtual address range in the list of existing ACPI memory
+ * mappings, drop a reference to it and if there are no more active references
+ * to it, queue it up for later removal.
+ *
+ * During early init (when acpi_permanent_mmap has not been set yet) this
+ * routine behaves like acpi_os_unmap_iomem().
+ */
 void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
 {
-       return acpi_os_unmap_iomem((void __iomem *)virt, size);
+       __acpi_os_unmap_iomem((void __iomem *)virt, size, true);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
 {
        u64 addr;
        struct acpi_ioremap *map;
-       unsigned long refcount;
 
        if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
                return;
                return;
 
        mutex_lock(&acpi_ioremap_lock);
+
        map = acpi_map_lookup(addr, gas->bit_width / 8);
        if (!map) {
                mutex_unlock(&acpi_ioremap_lock);
                return;
        }
-       refcount = acpi_os_drop_map_ref(map);
+       if (acpi_os_drop_map_ref(map, false))
+               map = NULL;
+
        mutex_unlock(&acpi_ioremap_lock);
 
-       if (!refcount)
-               acpi_os_map_cleanup(map);
+       acpi_os_map_cleanup(map);
 }
 EXPORT_SYMBOL(acpi_os_unmap_generic_address);