* @target_node: effective numa node if dev_dax memory range is onlined
  * @dev - device core
  * @pgmap - pgmap for memmap setup / lifetime (driver owned)
+ * @dax_mem_res: physical address range of hotadded DAX memory
  */
 struct dev_dax {
        struct dax_region *region;
        int target_node;
        struct device dev;
        struct dev_pagemap pgmap;
+       struct resource *dax_kmem_res;
 };
 
 static inline struct dev_dax *to_dev_dax(struct device *dev)
 
                kfree(new_res);
                return rc;
        }
+       dev_dax->dax_kmem_res = new_res;
 
        return 0;
 }
 
+#ifdef CONFIG_MEMORY_HOTREMOVE
+static int dev_dax_kmem_remove(struct device *dev)
+{
+       struct dev_dax *dev_dax = to_dev_dax(dev);
+       struct resource *res = dev_dax->dax_kmem_res;
+       resource_size_t kmem_start = res->start;
+       resource_size_t kmem_size = resource_size(res);
+       int rc;
+
+       /*
+        * We have one shot for removing memory, if some memory blocks were not
+        * offline prior to calling this function remove_memory() will fail, and
+        * there is no way to hotremove this memory until reboot because device
+        * unbind will succeed even if we return failure.
+        */
+       rc = remove_memory(dev_dax->target_node, kmem_start, kmem_size);
+       if (rc) {
+               dev_err(dev,
+                       "DAX region %pR cannot be hotremoved until the next reboot\n",
+                       res);
+               return rc;
+       }
+
+       /* Release and free dax resources */
+       release_resource(res);
+       kfree(res);
+       dev_dax->dax_kmem_res = NULL;
+
+       return 0;
+}
+#else
 static int dev_dax_kmem_remove(struct device *dev)
 {
        /*
-        * Purposely leak the request_mem_region() for the device-dax
-        * range and return '0' to ->remove() attempts. The removal of
-        * the device from the driver always succeeds, but the region
-        * is permanently pinned as reserved by the unreleased
+        * Without hotremove purposely leak the request_mem_region() for the
+        * device-dax range and return '0' to ->remove() attempts. The removal
+        * of the device from the driver always succeeds, but the region is
+        * permanently pinned as reserved by the unreleased
         * request_mem_region().
         */
        return 0;
 }
+#endif /* CONFIG_MEMORY_HOTREMOVE */
 
 static struct dax_device_driver device_dax_kmem_driver = {
        .drv = {