Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
[linux-3.10.git] / arch / x86 / kernel / e820.c
index 51c3b18..62d61e9 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/acpi.h>
 #include <linux/firmware-map.h>
 #include <linux/memblock.h>
+#include <linux/sort.h>
 
 #include <asm/e820.h>
 #include <asm/proto.h>
@@ -227,22 +228,38 @@ void __init e820_print_map(char *who)
  *        ____________________33__
  *        ______________________4_
  */
+struct change_member {
+       struct e820entry *pbios; /* pointer to original bios entry */
+       unsigned long long addr; /* address for this change point */
+};
+
+static int __init cpcompare(const void *a, const void *b)
+{
+       struct change_member * const *app = a, * const *bpp = b;
+       const struct change_member *ap = *app, *bp = *bpp;
+
+       /*
+        * Inputs are pointers to two elements of change_point[].  If their
+        * addresses are unequal, their difference dominates.  If the addresses
+        * are equal, then consider one that represents the end of its region
+        * to be greater than one that does not.
+        */
+       if (ap->addr != bp->addr)
+               return ap->addr > bp->addr ? 1 : -1;
+
+       return (ap->addr != ap->pbios->addr) - (bp->addr != bp->pbios->addr);
+}
 
 int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
                             u32 *pnr_map)
 {
-       struct change_member {
-               struct e820entry *pbios; /* pointer to original bios entry */
-               unsigned long long addr; /* address for this change point */
-       };
        static struct change_member change_point_list[2*E820_X_MAX] __initdata;
        static struct change_member *change_point[2*E820_X_MAX] __initdata;
        static struct e820entry *overlap_list[E820_X_MAX] __initdata;
        static struct e820entry new_bios[E820_X_MAX] __initdata;
-       struct change_member *change_tmp;
        unsigned long current_type, last_type;
        unsigned long long last_addr;
-       int chgidx, still_changing;
+       int chgidx;
        int overlap_entries;
        int new_bios_entry;
        int old_nr, new_nr, chg_nr;
@@ -279,35 +296,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
        chg_nr = chgidx;
 
        /* sort change-point list by memory addresses (low -> high) */
-       still_changing = 1;
-       while (still_changing)  {
-               still_changing = 0;
-               for (i = 1; i < chg_nr; i++)  {
-                       unsigned long long curaddr, lastaddr;
-                       unsigned long long curpbaddr, lastpbaddr;
-
-                       curaddr = change_point[i]->addr;
-                       lastaddr = change_point[i - 1]->addr;
-                       curpbaddr = change_point[i]->pbios->addr;
-                       lastpbaddr = change_point[i - 1]->pbios->addr;
-
-                       /*
-                        * swap entries, when:
-                        *
-                        * curaddr > lastaddr or
-                        * curaddr == lastaddr and curaddr == curpbaddr and
-                        * lastaddr != lastpbaddr
-                        */
-                       if (curaddr < lastaddr ||
-                           (curaddr == lastaddr && curaddr == curpbaddr &&
-                            lastaddr != lastpbaddr)) {
-                               change_tmp = change_point[i];
-                               change_point[i] = change_point[i-1];
-                               change_point[i-1] = change_tmp;
-                               still_changing = 1;
-                       }
-               }
-       }
+       sort(change_point, chg_nr, sizeof *change_point, cpcompare, NULL);
 
        /* create a new bios memory map, removing overlaps */
        overlap_entries = 0;     /* number of entries in the overlap table */
@@ -738,35 +727,17 @@ core_initcall(e820_mark_nvs_memory);
 /*
  * pre allocated 4k and reserved it in memblock and e820_saved
  */
-u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
+u64 __init early_reserve_e820(u64 size, u64 align)
 {
-       u64 size = 0;
        u64 addr;
-       u64 start;
 
-       for (start = startt; ; start += size) {
-               start = memblock_x86_find_in_range_size(start, &size, align);
-               if (start == MEMBLOCK_ERROR)
-                       return 0;
-               if (size >= sizet)
-                       break;
+       addr = __memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
+       if (addr) {
+               e820_update_range_saved(addr, size, E820_RAM, E820_RESERVED);
+               printk(KERN_INFO "update e820_saved for early_reserve_e820\n");
+               update_e820_saved();
        }
 
-#ifdef CONFIG_X86_32
-       if (start >= MAXMEM)
-               return 0;
-       if (start + size > MAXMEM)
-               size = MAXMEM - start;
-#endif
-
-       addr = round_down(start + size - sizet, align);
-       if (addr < start)
-               return 0;
-       memblock_x86_reserve_range(addr, addr + sizet, "new next");
-       e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
-       printk(KERN_INFO "update e820_saved for early_reserve_e820\n");
-       update_e820_saved();
-
        return addr;
 }
 
@@ -1090,7 +1061,7 @@ void __init memblock_x86_fill(void)
         * We are safe to enable resizing, beause memblock_x86_fill()
         * is rather later for x86
         */
-       memblock_can_resize = 1;
+       memblock_allow_resize();
 
        for (i = 0; i < e820.nr_map; i++) {
                struct e820entry *ei = &e820.map[i];
@@ -1105,22 +1076,36 @@ void __init memblock_x86_fill(void)
                memblock_add(ei->addr, ei->size);
        }
 
-       memblock_analyze();
        memblock_dump_all();
 }
 
 void __init memblock_find_dma_reserve(void)
 {
 #ifdef CONFIG_X86_64
-       u64 free_size_pfn;
-       u64 mem_size_pfn;
+       u64 nr_pages = 0, nr_free_pages = 0;
+       unsigned long start_pfn, end_pfn;
+       phys_addr_t start, end;
+       int i;
+       u64 u;
+
        /*
         * need to find out used area below MAX_DMA_PFN
         * need to use memblock to get free size in [0, MAX_DMA_PFN]
         * at first, and assume boot_mem will not take below MAX_DMA_PFN
         */
-       mem_size_pfn = memblock_x86_memory_in_range(0, MAX_DMA_PFN << PAGE_SHIFT) >> PAGE_SHIFT;
-       free_size_pfn = memblock_x86_free_memory_in_range(0, MAX_DMA_PFN << PAGE_SHIFT) >> PAGE_SHIFT;
-       set_dma_reserve(mem_size_pfn - free_size_pfn);
+       for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, NULL) {
+               start_pfn = min_t(unsigned long, start_pfn, MAX_DMA_PFN);
+               end_pfn = min_t(unsigned long, end_pfn, MAX_DMA_PFN);
+               nr_pages += end_pfn - start_pfn;
+       }
+
+       for_each_free_mem_range(u, MAX_NUMNODES, &start, &end, NULL) {
+               start_pfn = min_t(unsigned long, PFN_UP(start), MAX_DMA_PFN);
+               end_pfn = min_t(unsigned long, PFN_DOWN(end), MAX_DMA_PFN);
+               if (start_pfn < end_pfn)
+                       nr_free_pages += end_pfn - start_pfn;
+       }
+
+       set_dma_reserve(nr_pages - nr_free_pages);
 #endif
 }