]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - mm/memory_hotplug.c
Merge branch 'drm-rockchip-next-fixes-2016-01-22' of https://github.com/markyzq/kerne...
[karo-tx-linux.git] / mm / memory_hotplug.c
index 92f95952692b0f9aa20bec8afa3cd1725e573452..4af58a3a8ffa345c16fe190be76ba9f9e83113d4 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
 #include <linux/memory.h>
+#include <linux/memremap.h>
 #include <linux/memory_hotplug.h>
 #include <linux/highmem.h>
 #include <linux/vmalloc.h>
@@ -506,10 +507,25 @@ int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
        unsigned long i;
        int err = 0;
        int start_sec, end_sec;
+       struct vmem_altmap *altmap;
+
        /* during initialize mem_map, align hot-added range to section */
        start_sec = pfn_to_section_nr(phys_start_pfn);
        end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
 
+       altmap = to_vmem_altmap((unsigned long) pfn_to_page(phys_start_pfn));
+       if (altmap) {
+               /*
+                * Validate altmap is within bounds of the total request
+                */
+               if (altmap->base_pfn != phys_start_pfn
+                               || vmem_altmap_offset(altmap) > nr_pages) {
+                       pr_warn_once("memory add fail, invalid altmap\n");
+                       return -EINVAL;
+               }
+               altmap->alloc = 0;
+       }
+
        for (i = start_sec; i <= end_sec; i++) {
                err = __add_section(nid, zone, section_nr_to_pfn(i));
 
@@ -731,7 +747,8 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn)
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
 }
 
-static int __remove_section(struct zone *zone, struct mem_section *ms)
+static int __remove_section(struct zone *zone, struct mem_section *ms,
+               unsigned long map_offset)
 {
        unsigned long start_pfn;
        int scn_nr;
@@ -748,7 +765,7 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)
        start_pfn = section_nr_to_pfn(scn_nr);
        __remove_zone(zone, start_pfn);
 
-       sparse_remove_one_section(zone, ms);
+       sparse_remove_one_section(zone, ms, map_offset);
        return 0;
 }
 
@@ -767,9 +784,32 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
                 unsigned long nr_pages)
 {
        unsigned long i;
-       int sections_to_remove;
-       resource_size_t start, size;
-       int ret = 0;
+       unsigned long map_offset = 0;
+       int sections_to_remove, ret = 0;
+
+       /* In the ZONE_DEVICE case device driver owns the memory region */
+       if (is_dev_zone(zone)) {
+               struct page *page = pfn_to_page(phys_start_pfn);
+               struct vmem_altmap *altmap;
+
+               altmap = to_vmem_altmap((unsigned long) page);
+               if (altmap)
+                       map_offset = vmem_altmap_offset(altmap);
+       } else {
+               resource_size_t start, size;
+
+               start = phys_start_pfn << PAGE_SHIFT;
+               size = nr_pages * PAGE_SIZE;
+
+               ret = release_mem_region_adjustable(&iomem_resource, start,
+                                       size);
+               if (ret) {
+                       resource_size_t endres = start + size - 1;
+
+                       pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
+                                       &start, &endres, ret);
+               }
+       }
 
        /*
         * We can only remove entire sections
@@ -777,23 +817,12 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
        BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
        BUG_ON(nr_pages % PAGES_PER_SECTION);
 
-       start = phys_start_pfn << PAGE_SHIFT;
-       size = nr_pages * PAGE_SIZE;
-
-       /* in the ZONE_DEVICE case device driver owns the memory region */
-       if (!is_dev_zone(zone))
-               ret = release_mem_region_adjustable(&iomem_resource, start, size);
-       if (ret) {
-               resource_size_t endres = start + size - 1;
-
-               pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
-                               &start, &endres, ret);
-       }
-
        sections_to_remove = nr_pages / PAGES_PER_SECTION;
        for (i = 0; i < sections_to_remove; i++) {
                unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
-               ret = __remove_section(zone, __pfn_to_section(pfn));
+
+               ret = __remove_section(zone, __pfn_to_section(pfn), map_offset);
+               map_offset = 0;
                if (ret)
                        break;
        }