x86: Remove move_cleanup_count from irq_cfg
[safe/jmp/linux-2.6] / arch / x86 / kernel / e820.c
index e858268..d17d482 100644 (file)
@@ -110,19 +110,50 @@ int __init e820_all_mapped(u64 start, u64 end, unsigned type)
 /*
  * Add a memory region to the kernel e820 map.
  */
-void __init e820_add_region(u64 start, u64 size, int type)
+static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size,
+                                        int type)
 {
-       int x = e820.nr_map;
+       int x = e820x->nr_map;
 
-       if (x == ARRAY_SIZE(e820.map)) {
+       if (x >= ARRAY_SIZE(e820x->map)) {
                printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
                return;
        }
 
-       e820.map[x].addr = start;
-       e820.map[x].size = size;
-       e820.map[x].type = type;
-       e820.nr_map++;
+       e820x->map[x].addr = start;
+       e820x->map[x].size = size;
+       e820x->map[x].type = type;
+       e820x->nr_map++;
+}
+
+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)
@@ -134,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");
        }
 }
 
@@ -221,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 */
@@ -417,11 +429,12 @@ static int __init append_e820_map(struct e820entry *biosmap, int nr_map)
        return __append_e820_map(biosmap, nr_map);
 }
 
-static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
+static u64 __init __e820_update_range(struct e820map *e820x, u64 start,
                                        u64 size, unsigned old_type,
                                        unsigned new_type)
 {
-       int i;
+       u64 end;
+       unsigned int i;
        u64 real_updated_size = 0;
 
        BUG_ON(old_type == new_type);
@@ -429,27 +442,55 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
        if (size > (ULLONG_MAX - start))
                size = ULLONG_MAX - start;
 
-       for (i = 0; i < e820.nr_map; i++) {
+       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;
-               e820_add_region(final_start, final_end - final_start,
-                                        new_type);
+
+               __e820_add_region(e820x, final_start, final_end - final_start,
+                                 new_type);
+
                real_updated_size += final_end - final_start;
 
+               /*
+                * left range could be head or tail, so need to update
+                * size at first.
+                */
                ei->size -= final_end - final_start;
                if (ei->addr < final_start)
                        continue;
@@ -461,13 +502,13 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
 u64 __init e820_update_range(u64 start, u64 size, unsigned old_type,
                             unsigned new_type)
 {
-       return e820_update_range_map(&e820, start, size, old_type, new_type);
+       return __e820_update_range(&e820, start, size, old_type, new_type);
 }
 
 static u64 __init e820_update_range_saved(u64 start, u64 size,
                                          unsigned old_type, unsigned new_type)
 {
-       return e820_update_range_map(&e820_saved, start, size, old_type,
+       return __e820_update_range(&e820_saved, start, size, old_type,
                                     new_type);
 }
 
@@ -511,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))
@@ -522,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))
@@ -576,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;
@@ -586,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",
@@ -858,6 +893,9 @@ void __init reserve_early_overlap_ok(u64 start, u64 end, char *name)
  */
 void __init reserve_early(u64 start, u64 end, char *name)
 {
+       if (start >= end)
+               return;
+
        drop_overlaps_that_are_ok(start, end);
        __reserve_early(start, end, name, 0);
 }
@@ -1017,8 +1055,8 @@ u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
                        continue;
                return addr;
        }
-       return -1UL;
 
+       return -1ULL;
 }
 
 /*
@@ -1030,14 +1068,24 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
        u64 addr;
        u64 start;
 
-       start = startt;
-       while (size < sizet)
+       for (start = startt; ; start += size) {
                start = find_e820_area_size(start, &size, align);
+               if (!(start + 1))
+                       return 0;
+               if (size >= sizet)
+                       break;
+       }
 
-       if (size < sizet)
+#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;
        e820_update_range(addr, sizet, E820_RAM, E820_RESERVED);
        e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
        printk(KERN_INFO "update e820 for early_reserve_e820\n");
@@ -1250,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");
@@ -1283,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;
@@ -1317,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;
@@ -1328,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.
         *
@@ -1368,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);