x86: Remove move_cleanup_count from irq_cfg
[safe/jmp/linux-2.6] / arch / x86 / kernel / e820.c
index 95b81c1..d17d482 100644 (file)
@@ -115,7 +115,7 @@ static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size,
 {
        int x = e820x->nr_map;
 
-       if (x == ARRAY_SIZE(e820x->map)) {
+       if (x >= ARRAY_SIZE(e820x->map)) {
                printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
                return;
        }
@@ -131,6 +131,31 @@ void __init e820_add_region(u64 start, u64 size, int type)
        __e820_add_region(&e820, start, size, type);
 }
 
+static void __init e820_print_type(u32 type)
+{
+       switch (type) {
+       case E820_RAM:
+       case E820_RESERVED_KERN:
+               printk(KERN_CONT "(usable)");
+               break;
+       case E820_RESERVED:
+               printk(KERN_CONT "(reserved)");
+               break;
+       case E820_ACPI:
+               printk(KERN_CONT "(ACPI data)");
+               break;
+       case E820_NVS:
+               printk(KERN_CONT "(ACPI NVS)");
+               break;
+       case E820_UNUSABLE:
+               printk(KERN_CONT "(unusable)");
+               break;
+       default:
+               printk(KERN_CONT "type %u", type);
+               break;
+       }
+}
+
 void __init e820_print_map(char *who)
 {
        int i;
@@ -140,27 +165,8 @@ void __init e820_print_map(char *who)
                       (unsigned long long) e820.map[i].addr,
                       (unsigned long long)
                       (e820.map[i].addr + e820.map[i].size));
-               switch (e820.map[i].type) {
-               case E820_RAM:
-               case E820_RESERVED_KERN:
-                       printk(KERN_CONT "(usable)\n");
-                       break;
-               case E820_RESERVED:
-                       printk(KERN_CONT "(reserved)\n");
-                       break;
-               case E820_ACPI:
-                       printk(KERN_CONT "(ACPI data)\n");
-                       break;
-               case E820_NVS:
-                       printk(KERN_CONT "(ACPI NVS)\n");
-                       break;
-               case E820_UNUSABLE:
-                       printk("(unusable)\n");
-                       break;
-               default:
-                       printk(KERN_CONT "type %u\n", e820.map[i].type);
-                       break;
-               }
+               e820_print_type(e820.map[i].type);
+               printk(KERN_CONT "\n");
        }
 }
 
@@ -227,7 +233,7 @@ void __init e820_print_map(char *who)
  */
 
 int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
-                               int *pnr_map)
+                            u32 *pnr_map)
 {
        struct change_member {
                struct e820entry *pbios; /* pointer to original bios entry */
@@ -427,6 +433,7 @@ static u64 __init __e820_update_range(struct e820map *e820x, u64 start,
                                        u64 size, unsigned old_type,
                                        unsigned new_type)
 {
+       u64 end;
        unsigned int i;
        u64 real_updated_size = 0;
 
@@ -435,21 +442,43 @@ static u64 __init __e820_update_range(struct e820map *e820x, u64 start,
        if (size > (ULLONG_MAX - start))
                size = ULLONG_MAX - start;
 
+       end = start + size;
+       printk(KERN_DEBUG "e820 update range: %016Lx - %016Lx ",
+                      (unsigned long long) start,
+                      (unsigned long long) end);
+       e820_print_type(old_type);
+       printk(KERN_CONT " ==> ");
+       e820_print_type(new_type);
+       printk(KERN_CONT "\n");
+
        for (i = 0; i < e820x->nr_map; i++) {
                struct e820entry *ei = &e820x->map[i];
                u64 final_start, final_end;
+               u64 ei_end;
+
                if (ei->type != old_type)
                        continue;
-               /* totally covered? */
-               if (ei->addr >= start &&
-                   (ei->addr + ei->size) <= (start + size)) {
+
+               ei_end = ei->addr + ei->size;
+               /* totally covered by new range? */
+               if (ei->addr >= start && ei_end <= end) {
                        ei->type = new_type;
                        real_updated_size += ei->size;
                        continue;
                }
+
+               /* new range is totally covered? */
+               if (ei->addr < start && ei_end > end) {
+                       __e820_add_region(e820x, start, size, new_type);
+                       __e820_add_region(e820x, end, ei_end - end, ei->type);
+                       ei->size = start - ei->addr;
+                       real_updated_size += size;
+                       continue;
+               }
+
                /* partially covered */
                final_start = max(start, ei->addr);
-               final_end = min(start + size, ei->addr + ei->size);
+               final_end = min(end, ei_end);
                if (final_start >= final_end)
                        continue;
 
@@ -523,7 +552,7 @@ u64 __init e820_remove_range(u64 start, u64 size, unsigned old_type,
 
 void __init update_e820(void)
 {
-       int nr_map;
+       u32 nr_map;
 
        nr_map = e820.nr_map;
        if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map))
@@ -534,7 +563,7 @@ void __init update_e820(void)
 }
 static void __init update_e820_saved(void)
 {
-       int nr_map;
+       u32 nr_map;
 
        nr_map = e820_saved.nr_map;
        if (sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map))
@@ -588,7 +617,7 @@ __init int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize,
  */
 __init void e820_setup_gap(void)
 {
-       unsigned long gapstart, gapsize, round;
+       unsigned long gapstart, gapsize;
        int found;
 
        gapstart = 0x10000000;
@@ -598,22 +627,16 @@ __init void e820_setup_gap(void)
 #ifdef CONFIG_X86_64
        if (!found) {
                gapstart = (max_pfn << PAGE_SHIFT) + 1024*1024;
-               printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit "
-                      "address range\n"
-                      KERN_ERR "PCI: Unassigned devices with 32bit resource "
-                      "registers may break!\n");
+               printk(KERN_ERR
+       "PCI: Warning: Cannot find a gap in the 32bit address range\n"
+       "PCI: Unassigned devices with 32bit resource registers may break!\n");
        }
 #endif
 
        /*
-        * See how much we want to round up: start off with
-        * rounding to the next 1MB area.
+        * e820_reserve_resources_late protect stolen RAM already
         */
-       round = 0x100000;
-       while ((gapsize >> 4) > round)
-               round += round;
-       /* Fun with two's complement */
-       pci_mem_start = (gapstart + round) & -round;
+       pci_mem_start = gapstart;
 
        printk(KERN_INFO
               "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
@@ -1045,12 +1068,13 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
        u64 addr;
        u64 start;
 
-       start = startt;
-       while (size < sizet && (start + 1))
+       for (start = startt; ; start += size) {
                start = find_e820_area_size(start, &size, align);
-
-       if (size < sizet)
-               return 0;
+               if (!(start + 1))
+                       return 0;
+               if (size >= sizet)
+                       break;
+       }
 
 #ifdef CONFIG_X86_32
        if (start >= MAXMEM)
@@ -1274,7 +1298,7 @@ early_param("memmap", parse_memmap_opt);
 void __init finish_e820_parsing(void)
 {
        if (userdef) {
-               int nr = e820.nr_map;
+               u32 nr = e820.nr_map;
 
                if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0)
                        early_panic("Invalid user supplied memory map");
@@ -1307,7 +1331,7 @@ void __init e820_reserve_resources(void)
        struct resource *res;
        u64 end;
 
-       res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
+       res = alloc_bootmem(sizeof(struct resource) * e820.nr_map);
        e820_res = res;
        for (i = 0; i < e820.nr_map; i++) {
                end = e820.map[i].addr + e820.map[i].size - 1;
@@ -1341,6 +1365,25 @@ void __init e820_reserve_resources(void)
        }
 }
 
+/* How much should we pad RAM ending depending on where it is? */
+static unsigned long ram_alignment(resource_size_t pos)
+{
+       unsigned long mb = pos >> 20;
+
+       /* To 64kB in the first megabyte */
+       if (!mb)
+               return 64*1024;
+
+       /* To 1MB in the first 16MB */
+       if (mb < 16)
+               return 1024*1024;
+
+       /* To 64MB for anything above that */
+       return 64*1024*1024;
+}
+
+#define MAX_RESOURCE_SIZE ((resource_size_t)-1)
+
 void __init e820_reserve_resources_late(void)
 {
        int i;
@@ -1352,12 +1395,32 @@ void __init e820_reserve_resources_late(void)
                        insert_resource_expand_to_fit(&iomem_resource, res);
                res++;
        }
+
+       /*
+        * Try to bump up RAM regions to reasonable boundaries to
+        * avoid stolen RAM:
+        */
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *entry = &e820.map[i];
+               u64 start, end;
+
+               if (entry->type != E820_RAM)
+                       continue;
+               start = entry->addr + entry->size;
+               end = round_up(start, ram_alignment(start)) - 1;
+               if (end > MAX_RESOURCE_SIZE)
+                       end = MAX_RESOURCE_SIZE;
+               if (start >= end)
+                       continue;
+               reserve_region_with_split(&iomem_resource, start, end,
+                                         "RAM buffer");
+       }
 }
 
 char *__init default_machine_specific_memory_setup(void)
 {
        char *who = "BIOS-e820";
-       int new_nr;
+       u32 new_nr;
        /*
         * Try to copy the BIOS-supplied E820-map.
         *
@@ -1392,28 +1455,11 @@ char *__init default_machine_specific_memory_setup(void)
        return who;
 }
 
-char *__init __attribute__((weak)) machine_specific_memory_setup(void)
-{
-       if (x86_quirks->arch_memory_setup) {
-               char *who = x86_quirks->arch_memory_setup();
-
-               if (who)
-                       return who;
-       }
-       return default_machine_specific_memory_setup();
-}
-
-/* Overridden in paravirt.c if CONFIG_PARAVIRT */
-char * __init __attribute__((weak)) memory_setup(void)
-{
-       return machine_specific_memory_setup();
-}
-
 void __init setup_memory_map(void)
 {
        char *who;
 
-       who = memory_setup();
+       who = x86_init.resources.memory_setup();
        memcpy(&e820_saved, &e820, sizeof(struct e820map));
        printk(KERN_INFO "BIOS-provided physical RAM map:\n");
        e820_print_map(who);