Merge tag 'char-misc-5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / mm / sparse-vmemmap.c
index 0db7738..16183d8 100644 (file)
@@ -69,11 +69,19 @@ void * __meminit vmemmap_alloc_block(unsigned long size, int node)
                                __pa(MAX_DMA_ADDRESS));
 }
 
+static void * __meminit altmap_alloc_block_buf(unsigned long size,
+                                              struct vmem_altmap *altmap);
+
 /* need to make sure size is all the same during early stage */
-void * __meminit vmemmap_alloc_block_buf(unsigned long size, int node)
+void * __meminit vmemmap_alloc_block_buf(unsigned long size, int node,
+                                        struct vmem_altmap *altmap)
 {
-       void *ptr = sparse_buffer_alloc(size);
+       void *ptr;
+
+       if (altmap)
+               return altmap_alloc_block_buf(size, altmap);
 
+       ptr = sparse_buffer_alloc(size);
        if (!ptr)
                ptr = vmemmap_alloc_block(size, node);
        return ptr;
@@ -94,15 +102,8 @@ static unsigned long __meminit vmem_altmap_nr_free(struct vmem_altmap *altmap)
        return 0;
 }
 
-/**
- * altmap_alloc_block_buf - allocate pages from the device page map
- * @altmap:    device page map
- * @size:      size (in bytes) of the allocation
- *
- * Allocations are aligned to the size of the request.
- */
-void * __meminit altmap_alloc_block_buf(unsigned long size,
-               struct vmem_altmap *altmap)
+static void * __meminit altmap_alloc_block_buf(unsigned long size,
+                                              struct vmem_altmap *altmap)
 {
        unsigned long pfn, nr_pfns, nr_align;
 
@@ -139,12 +140,15 @@ void __meminit vmemmap_verify(pte_t *pte, int node,
                        start, end - 1);
 }
 
-pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node)
+pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node,
+                                      struct vmem_altmap *altmap)
 {
        pte_t *pte = pte_offset_kernel(pmd, addr);
        if (pte_none(*pte)) {
                pte_t entry;
-               void *p = vmemmap_alloc_block_buf(PAGE_SIZE, node);
+               void *p;
+
+               p = vmemmap_alloc_block_buf(PAGE_SIZE, node, altmap);
                if (!p)
                        return NULL;
                entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL);
@@ -212,8 +216,8 @@ pgd_t * __meminit vmemmap_pgd_populate(unsigned long addr, int node)
        return pgd;
 }
 
-int __meminit vmemmap_populate_basepages(unsigned long start,
-                                        unsigned long end, int node)
+int __meminit vmemmap_populate_basepages(unsigned long start, unsigned long end,
+                                        int node, struct vmem_altmap *altmap)
 {
        unsigned long addr = start;
        pgd_t *pgd;
@@ -235,7 +239,7 @@ int __meminit vmemmap_populate_basepages(unsigned long start,
                pmd = vmemmap_pmd_populate(pud, addr, node);
                if (!pmd)
                        return -ENOMEM;
-               pte = vmemmap_pte_populate(pmd, addr, node);
+               pte = vmemmap_pte_populate(pmd, addr, node, altmap);
                if (!pte)
                        return -ENOMEM;
                vmemmap_verify(pte, node, addr, addr + PAGE_SIZE);
@@ -247,20 +251,12 @@ int __meminit vmemmap_populate_basepages(unsigned long start,
 struct page * __meminit __populate_section_memmap(unsigned long pfn,
                unsigned long nr_pages, int nid, struct vmem_altmap *altmap)
 {
-       unsigned long start;
-       unsigned long end;
-
-       /*
-        * The minimum granularity of memmap extensions is
-        * PAGES_PER_SUBSECTION as allocations are tracked in the
-        * 'subsection_map' bitmap of the section.
-        */
-       end = ALIGN(pfn + nr_pages, PAGES_PER_SUBSECTION);
-       pfn &= PAGE_SUBSECTION_MASK;
-       nr_pages = end - pfn;
-
-       start = (unsigned long) pfn_to_page(pfn);
-       end = start + nr_pages * sizeof(struct page);
+       unsigned long start = (unsigned long) pfn_to_page(pfn);
+       unsigned long end = start + nr_pages * sizeof(struct page);
+
+       if (WARN_ON_ONCE(!IS_ALIGNED(pfn, PAGES_PER_SUBSECTION) ||
+               !IS_ALIGNED(nr_pages, PAGES_PER_SUBSECTION)))
+               return NULL;
 
        if (vmemmap_populate(start, end, nid, altmap))
                return NULL;