nvme: fix Kconfig description for BLK_DEV_NVME_SCSI
[linux-2.6-block.git] / mm / sparse-vmemmap.c
index 4cba9c2783a147077150505dcf6114cf4592843a..b60802b3e5ead91c346ffd1b47d90b77155bdf79 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/mmzone.h>
 #include <linux/bootmem.h>
+#include <linux/memremap.h>
 #include <linux/highmem.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -70,7 +71,7 @@ void * __meminit vmemmap_alloc_block(unsigned long size, int node)
 }
 
 /* need to make sure size is all the same during early stage */
-void * __meminit vmemmap_alloc_block_buf(unsigned long size, int node)
+static void * __meminit alloc_block_buf(unsigned long size, int node)
 {
        void *ptr;
 
@@ -87,6 +88,77 @@ void * __meminit vmemmap_alloc_block_buf(unsigned long size, int node)
        return ptr;
 }
 
+static unsigned long __meminit vmem_altmap_next_pfn(struct vmem_altmap *altmap)
+{
+       return altmap->base_pfn + altmap->reserve + altmap->alloc
+               + altmap->align;
+}
+
+static unsigned long __meminit vmem_altmap_nr_free(struct vmem_altmap *altmap)
+{
+       unsigned long allocated = altmap->alloc + altmap->align;
+
+       if (altmap->free > allocated)
+               return altmap->free - allocated;
+       return 0;
+}
+
+/**
+ * vmem_altmap_alloc - allocate pages from the vmem_altmap reservation
+ * @altmap - reserved page pool for the allocation
+ * @nr_pfns - size (in pages) of the allocation
+ *
+ * Allocations are aligned to the size of the request
+ */
+static unsigned long __meminit vmem_altmap_alloc(struct vmem_altmap *altmap,
+               unsigned long nr_pfns)
+{
+       unsigned long pfn = vmem_altmap_next_pfn(altmap);
+       unsigned long nr_align;
+
+       nr_align = 1UL << find_first_bit(&nr_pfns, BITS_PER_LONG);
+       nr_align = ALIGN(pfn, nr_align) - pfn;
+
+       if (nr_pfns + nr_align > vmem_altmap_nr_free(altmap))
+               return ULONG_MAX;
+       altmap->alloc += nr_pfns;
+       altmap->align += nr_align;
+       return pfn + nr_align;
+}
+
+static void * __meminit altmap_alloc_block_buf(unsigned long size,
+               struct vmem_altmap *altmap)
+{
+       unsigned long pfn, nr_pfns;
+       void *ptr;
+
+       if (size & ~PAGE_MASK) {
+               pr_warn_once("%s: allocations must be multiple of PAGE_SIZE (%ld)\n",
+                               __func__, size);
+               return NULL;
+       }
+
+       nr_pfns = size >> PAGE_SHIFT;
+       pfn = vmem_altmap_alloc(altmap, nr_pfns);
+       if (pfn < ULONG_MAX)
+               ptr = __va(__pfn_to_phys(pfn));
+       else
+               ptr = NULL;
+       pr_debug("%s: pfn: %#lx alloc: %ld align: %ld nr: %#lx\n",
+                       __func__, pfn, altmap->alloc, altmap->align, nr_pfns);
+
+       return ptr;
+}
+
+/* need to make sure size is all the same during early stage */
+void * __meminit __vmemmap_alloc_block_buf(unsigned long size, int node,
+               struct vmem_altmap *altmap)
+{
+       if (altmap)
+               return altmap_alloc_block_buf(size, altmap);
+       return alloc_block_buf(size, node);
+}
+
 void __meminit vmemmap_verify(pte_t *pte, int node,
                                unsigned long start, unsigned long end)
 {
@@ -103,7 +175,7 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node)
        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 = alloc_block_buf(PAGE_SIZE, node);
                if (!p)
                        return NULL;
                entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL);