]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - kernel/memremap.c
add devm_memremap_pages
[karo-tx-linux.git] / kernel / memremap.c
index 5c9b55eaf121a7f2fc891353cc3d70c06c78518d..72b0c66628b6b3db589ad0cd6ed6533edb68a9ea 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/io.h>
 #include <linux/mm.h>
+#include <linux/memory_hotplug.h>
 
 #ifndef ioremap_cache
 /* temporary while we convert existing ioremap_cache users to memremap */
@@ -135,3 +136,55 @@ void devm_memunmap(struct device *dev, void *addr)
        memunmap(addr);
 }
 EXPORT_SYMBOL(devm_memunmap);
+
+#ifdef CONFIG_ZONE_DEVICE
+struct page_map {
+       struct resource res;
+};
+
+static void devm_memremap_pages_release(struct device *dev, void *res)
+{
+       struct page_map *page_map = res;
+
+       /* pages are dead and unused, undo the arch mapping */
+       arch_remove_memory(page_map->res.start, resource_size(&page_map->res));
+}
+
+void *devm_memremap_pages(struct device *dev, struct resource *res)
+{
+       int is_ram = region_intersects(res->start, resource_size(res),
+                       "System RAM");
+       struct page_map *page_map;
+       int error, nid;
+
+       if (is_ram == REGION_MIXED) {
+               WARN_ONCE(1, "%s attempted on mixed region %pr\n",
+                               __func__, res);
+               return ERR_PTR(-ENXIO);
+       }
+
+       if (is_ram == REGION_INTERSECTS)
+               return __va(res->start);
+
+       page_map = devres_alloc(devm_memremap_pages_release,
+                       sizeof(*page_map), GFP_KERNEL);
+       if (!page_map)
+               return ERR_PTR(-ENOMEM);
+
+       memcpy(&page_map->res, res, sizeof(*res));
+
+       nid = dev_to_node(dev);
+       if (nid < 0)
+               nid = 0;
+
+       error = arch_add_memory(nid, res->start, resource_size(res), true);
+       if (error) {
+               devres_free(page_map);
+               return ERR_PTR(error);
+       }
+
+       devres_add(dev, page_map);
+       return __va(res->start);
+}
+EXPORT_SYMBOL(devm_memremap_pages);
+#endif /* CONFIG_ZONE_DEVICE */