x86: trim mtrr don't close gap for resource allocation.
authorYinghai Lu <yhlu.kernel.send@gmail.com>
Tue, 18 Mar 2008 23:44:19 +0000 (16:44 -0700)
committerIngo Molnar <mingo@elte.hu>
Fri, 21 Mar 2008 16:06:15 +0000 (17:06 +0100)
fix the bug reported here:

http://bugzilla.kernel.org/show_bug.cgi?id=10232

use update_memory_range() instead of add_memory_range() directly
to avoid closing the gap.

( the new code only affects and runs on systems where the MTRR
  workaround triggers. )

Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/e820_32.c
arch/x86/kernel/e820_64.c
include/asm-x86/e820_32.h
include/asm-x86/e820_64.h

index be83336fddba9c6c3629bbe1748aa42480a6e707..a6450b3ae759f2ce994bd40deedea2dbfceb4db8 100644 (file)
@@ -711,7 +711,8 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
                trim_size = end_pfn;
                trim_size <<= PAGE_SHIFT;
                trim_size -= trim_start;
-               add_memory_region(trim_start, trim_size, E820_RESERVED);
+               update_memory_range(trim_start, trim_size, E820_RAM,
+                                       E820_RESERVED);
                update_e820();
                return 1;
        }
index 4e16ef4a2659f38f18d613289527f415d9ad92f1..80444c5c9b148d67f34c49f59efc4574133f4b5e 100644 (file)
@@ -749,6 +749,32 @@ static int __init parse_memmap(char *arg)
        return 0;
 }
 early_param("memmap", parse_memmap);
+void __init update_memory_range(u64 start, u64 size, unsigned old_type,
+                               unsigned new_type)
+{
+       int i;
+
+       BUG_ON(old_type == new_type);
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               u64 final_start, final_end;
+               if (ei->type != old_type)
+                       continue;
+               /* totally covered? */
+               if (ei->addr >= start && ei->size <= size) {
+                       ei->type = new_type;
+                       continue;
+               }
+               /* partially covered */
+               final_start = max(start, ei->addr);
+               final_end = min(start + size, ei->addr + ei->size);
+               if (final_start >= final_end)
+                       continue;
+               add_memory_region(final_start, final_end - final_start,
+                                        new_type);
+       }
+}
 void __init update_e820(void)
 {
        u8 nr_map;
index 9f65b4cc323c49cf39d61242f62394865c94decb..9be697126013278dbcb5da6f0b04a40893239981 100644 (file)
@@ -744,6 +744,33 @@ void __init finish_e820_parsing(void)
        }
 }
 
+void __init update_memory_range(u64 start, u64 size, unsigned old_type,
+                               unsigned new_type)
+{
+       int i;
+
+       BUG_ON(old_type == new_type);
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               u64 final_start, final_end;
+               if (ei->type != old_type)
+                       continue;
+               /* totally covered? */
+               if (ei->addr >= start && ei->size <= size) {
+                       ei->type = new_type;
+                       continue;
+               }
+               /* partially covered */
+               final_start = max(start, ei->addr);
+               final_end = min(start + size, ei->addr + ei->size);
+               if (final_start >= final_end)
+                       continue;
+               add_memory_region(final_start, final_end - final_start,
+                                        new_type);
+       }
+}
+
 void __init update_e820(void)
 {
        u8 nr_map;
index f1da7ebd19051dd040ce24f77db73ef02eee8ff3..e7207a6de3e0915be4be38a29150797d6eadcaa4 100644 (file)
@@ -28,6 +28,8 @@ extern void find_max_pfn(void);
 extern void register_bootmem_low_pages(unsigned long max_low_pfn);
 extern void add_memory_region(unsigned long long start,
                              unsigned long long size, int type);
+extern void update_memory_range(u64 start, u64 size, unsigned old_type,
+                               unsigned new_type);
 extern void e820_register_memory(void);
 extern void limit_regions(unsigned long long size);
 extern void print_memory_map(char *who);
index a560c4f5d500f658901fb4d44bade9dd1acdcaec..22ede73ae724997a5a3fbb1b7355a4cd296c57cd 100644 (file)
@@ -18,6 +18,8 @@ extern unsigned long find_e820_area(unsigned long start, unsigned long end,
                                    unsigned size, unsigned long align);
 extern void add_memory_region(unsigned long start, unsigned long size, 
                              int type);
+extern void update_memory_range(u64 start, u64 size, unsigned old_type,
+                               unsigned new_type);
 extern void setup_memory_region(void);
 extern void contig_e820_setup(void); 
 extern unsigned long e820_end_of_ram(void);