diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-07 14:02:23 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-07 14:02:23 -0400 |
| commit | fb1ae635772d679eb312fa447290fc02cd0e4cf1 (patch) | |
| tree | 45733f9820da1190cd58bfff080edbb02af961a8 | |
| parent | addb2d6c13993060ae75f5005815b19dd2abdd64 (diff) | |
| parent | 472a474c6630efd195d3738339fd1bdc8aa3b1aa (diff) | |
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-tip
* 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-tip:
x86: Fix double enable_IR_x2apic() call on SMP kernel on !SMP boards
x86: Increase CONFIG_NODES_SHIFT max to 10
ibft, x86: Change reserve_ibft_region() to find_ibft_region()
x86, hpet: Fix bug in RTC emulation
x86, hpet: Erratum workaround for read after write of HPET comparator
bootmem, x86: Fix 32bit numa system without RAM on node 0
nobootmem, x86: Fix 32bit numa system without RAM on node 0
x86: Handle overlapping mptables
x86: Make e820_remove_range to handle all covered case
x86-32, resume: do a global tlb flush in S4 resume
| -rw-r--r-- | arch/x86/Kconfig | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/apic/apic.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/e820.c | 24 | ||||
| -rw-r--r-- | arch/x86/kernel/hpet.c | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/mpparse.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/setup.c | 14 | ||||
| -rw-r--r-- | arch/x86/power/hibernate_asm_32.S | 15 | ||||
| -rw-r--r-- | drivers/firmware/iscsi_ibft_find.c | 11 | ||||
| -rw-r--r-- | include/linux/iscsi_ibft.h | 8 | ||||
| -rw-r--r-- | mm/bootmem.c | 17 |
10 files changed, 82 insertions, 26 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0eacb1ffb421..9458685902bd 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -1216,8 +1216,8 @@ config NUMA_EMU | |||
| 1216 | 1216 | ||
| 1217 | config NODES_SHIFT | 1217 | config NODES_SHIFT |
| 1218 | int "Maximum NUMA Nodes (as a power of 2)" if !MAXSMP | 1218 | int "Maximum NUMA Nodes (as a power of 2)" if !MAXSMP |
| 1219 | range 1 9 | 1219 | range 1 10 |
| 1220 | default "9" if MAXSMP | 1220 | default "10" if MAXSMP |
| 1221 | default "6" if X86_64 | 1221 | default "6" if X86_64 |
| 1222 | default "4" if X86_NUMAQ | 1222 | default "4" if X86_NUMAQ |
| 1223 | default "3" | 1223 | default "3" |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 00187f1fcfb7..e5a4a1e01618 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
| @@ -1640,8 +1640,10 @@ int __init APIC_init_uniprocessor(void) | |||
| 1640 | } | 1640 | } |
| 1641 | #endif | 1641 | #endif |
| 1642 | 1642 | ||
| 1643 | #ifndef CONFIG_SMP | ||
| 1643 | enable_IR_x2apic(); | 1644 | enable_IR_x2apic(); |
| 1644 | default_setup_apic_routing(); | 1645 | default_setup_apic_routing(); |
| 1646 | #endif | ||
| 1645 | 1647 | ||
| 1646 | verify_local_APIC(); | 1648 | verify_local_APIC(); |
| 1647 | connect_bsp_APIC(); | 1649 | connect_bsp_APIC(); |
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 740b440fbd73..7bca3c6a02fb 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c | |||
| @@ -519,29 +519,45 @@ u64 __init e820_remove_range(u64 start, u64 size, unsigned old_type, | |||
| 519 | printk(KERN_DEBUG "e820 remove range: %016Lx - %016Lx ", | 519 | printk(KERN_DEBUG "e820 remove range: %016Lx - %016Lx ", |
| 520 | (unsigned long long) start, | 520 | (unsigned long long) start, |
| 521 | (unsigned long long) end); | 521 | (unsigned long long) end); |
| 522 | e820_print_type(old_type); | 522 | if (checktype) |
| 523 | e820_print_type(old_type); | ||
| 523 | printk(KERN_CONT "\n"); | 524 | printk(KERN_CONT "\n"); |
| 524 | 525 | ||
| 525 | for (i = 0; i < e820.nr_map; i++) { | 526 | for (i = 0; i < e820.nr_map; i++) { |
| 526 | struct e820entry *ei = &e820.map[i]; | 527 | struct e820entry *ei = &e820.map[i]; |
| 527 | u64 final_start, final_end; | 528 | u64 final_start, final_end; |
| 529 | u64 ei_end; | ||
| 528 | 530 | ||
| 529 | if (checktype && ei->type != old_type) | 531 | if (checktype && ei->type != old_type) |
| 530 | continue; | 532 | continue; |
| 533 | |||
| 534 | ei_end = ei->addr + ei->size; | ||
| 531 | /* totally covered? */ | 535 | /* totally covered? */ |
| 532 | if (ei->addr >= start && | 536 | if (ei->addr >= start && ei_end <= end) { |
| 533 | (ei->addr + ei->size) <= (start + size)) { | ||
| 534 | real_removed_size += ei->size; | 537 | real_removed_size += ei->size; |
| 535 | memset(ei, 0, sizeof(struct e820entry)); | 538 | memset(ei, 0, sizeof(struct e820entry)); |
| 536 | continue; | 539 | continue; |
| 537 | } | 540 | } |
| 541 | |||
| 542 | /* new range is totally covered? */ | ||
| 543 | if (ei->addr < start && ei_end > end) { | ||
| 544 | e820_add_region(end, ei_end - end, ei->type); | ||
| 545 | ei->size = start - ei->addr; | ||
| 546 | real_removed_size += size; | ||
| 547 | continue; | ||
| 548 | } | ||
| 549 | |||
| 538 | /* partially covered */ | 550 | /* partially covered */ |
| 539 | final_start = max(start, ei->addr); | 551 | final_start = max(start, ei->addr); |
| 540 | final_end = min(start + size, ei->addr + ei->size); | 552 | final_end = min(end, ei_end); |
| 541 | if (final_start >= final_end) | 553 | if (final_start >= final_end) |
| 542 | continue; | 554 | continue; |
| 543 | real_removed_size += final_end - final_start; | 555 | real_removed_size += final_end - final_start; |
| 544 | 556 | ||
| 557 | /* | ||
| 558 | * left range could be head or tail, so need to update | ||
| 559 | * size at first. | ||
| 560 | */ | ||
| 545 | ei->size -= final_end - final_start; | 561 | ei->size -= final_end - final_start; |
| 546 | if (ei->addr < final_start) | 562 | if (ei->addr < final_start) |
| 547 | continue; | 563 | continue; |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index d10a7e7294f4..23b4ecdffa9b 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
| @@ -400,9 +400,15 @@ static int hpet_next_event(unsigned long delta, | |||
| 400 | * then we might have a real hardware problem. We can not do | 400 | * then we might have a real hardware problem. We can not do |
| 401 | * much about it here, but at least alert the user/admin with | 401 | * much about it here, but at least alert the user/admin with |
| 402 | * a prominent warning. | 402 | * a prominent warning. |
| 403 | * An erratum on some chipsets (ICH9,..), results in comparator read | ||
| 404 | * immediately following a write returning old value. Workaround | ||
| 405 | * for this is to read this value second time, when first | ||
| 406 | * read returns old value. | ||
| 403 | */ | 407 | */ |
| 404 | WARN_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt, | 408 | if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) { |
| 409 | WARN_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt, | ||
| 405 | KERN_WARNING "hpet: compare register read back failed.\n"); | 410 | KERN_WARNING "hpet: compare register read back failed.\n"); |
| 411 | } | ||
| 406 | 412 | ||
| 407 | return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; | 413 | return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; |
| 408 | } | 414 | } |
| @@ -1144,6 +1150,7 @@ int hpet_set_periodic_freq(unsigned long freq) | |||
| 1144 | do_div(clc, freq); | 1150 | do_div(clc, freq); |
| 1145 | clc >>= hpet_clockevent.shift; | 1151 | clc >>= hpet_clockevent.shift; |
| 1146 | hpet_pie_delta = clc; | 1152 | hpet_pie_delta = clc; |
| 1153 | hpet_pie_limit = 0; | ||
| 1147 | } | 1154 | } |
| 1148 | return 1; | 1155 | return 1; |
| 1149 | } | 1156 | } |
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index a2c1edd2d3ac..e81030f71a8f 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c | |||
| @@ -664,7 +664,7 @@ static void __init smp_reserve_memory(struct mpf_intel *mpf) | |||
| 664 | { | 664 | { |
| 665 | unsigned long size = get_mpc_size(mpf->physptr); | 665 | unsigned long size = get_mpc_size(mpf->physptr); |
| 666 | 666 | ||
| 667 | reserve_early(mpf->physptr, mpf->physptr+size, "MP-table mpc"); | 667 | reserve_early_overlap_ok(mpf->physptr, mpf->physptr+size, "MP-table mpc"); |
| 668 | } | 668 | } |
| 669 | 669 | ||
| 670 | static int __init smp_scan_config(unsigned long base, unsigned long length) | 670 | static int __init smp_scan_config(unsigned long base, unsigned long length) |
| @@ -693,7 +693,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) | |||
| 693 | mpf, (u64)virt_to_phys(mpf)); | 693 | mpf, (u64)virt_to_phys(mpf)); |
| 694 | 694 | ||
| 695 | mem = virt_to_phys(mpf); | 695 | mem = virt_to_phys(mpf); |
| 696 | reserve_early(mem, mem + sizeof(*mpf), "MP-table mpf"); | 696 | reserve_early_overlap_ok(mem, mem + sizeof(*mpf), "MP-table mpf"); |
| 697 | if (mpf->physptr) | 697 | if (mpf->physptr) |
| 698 | smp_reserve_memory(mpf); | 698 | smp_reserve_memory(mpf); |
| 699 | 699 | ||
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 9570541caf7c..c4851eff57b3 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
| @@ -607,6 +607,16 @@ static int __init setup_elfcorehdr(char *arg) | |||
| 607 | early_param("elfcorehdr", setup_elfcorehdr); | 607 | early_param("elfcorehdr", setup_elfcorehdr); |
| 608 | #endif | 608 | #endif |
| 609 | 609 | ||
| 610 | static __init void reserve_ibft_region(void) | ||
| 611 | { | ||
| 612 | unsigned long addr, size = 0; | ||
| 613 | |||
| 614 | addr = find_ibft_region(&size); | ||
| 615 | |||
| 616 | if (size) | ||
| 617 | reserve_early_overlap_ok(addr, addr + size, "ibft"); | ||
| 618 | } | ||
| 619 | |||
| 610 | #ifdef CONFIG_X86_RESERVE_LOW_64K | 620 | #ifdef CONFIG_X86_RESERVE_LOW_64K |
| 611 | static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) | 621 | static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) |
| 612 | { | 622 | { |
| @@ -909,6 +919,8 @@ void __init setup_arch(char **cmdline_p) | |||
| 909 | */ | 919 | */ |
| 910 | find_smp_config(); | 920 | find_smp_config(); |
| 911 | 921 | ||
| 922 | reserve_ibft_region(); | ||
| 923 | |||
| 912 | reserve_trampoline_memory(); | 924 | reserve_trampoline_memory(); |
| 913 | 925 | ||
| 914 | #ifdef CONFIG_ACPI_SLEEP | 926 | #ifdef CONFIG_ACPI_SLEEP |
| @@ -976,8 +988,6 @@ void __init setup_arch(char **cmdline_p) | |||
| 976 | 988 | ||
| 977 | dma32_reserve_bootmem(); | 989 | dma32_reserve_bootmem(); |
| 978 | 990 | ||
| 979 | reserve_ibft_region(); | ||
| 980 | |||
| 981 | #ifdef CONFIG_KVM_CLOCK | 991 | #ifdef CONFIG_KVM_CLOCK |
| 982 | kvmclock_init(); | 992 | kvmclock_init(); |
| 983 | #endif | 993 | #endif |
diff --git a/arch/x86/power/hibernate_asm_32.S b/arch/x86/power/hibernate_asm_32.S index b641388d8286..ad47daeafa4e 100644 --- a/arch/x86/power/hibernate_asm_32.S +++ b/arch/x86/power/hibernate_asm_32.S | |||
| @@ -27,10 +27,17 @@ ENTRY(swsusp_arch_suspend) | |||
| 27 | ret | 27 | ret |
| 28 | 28 | ||
| 29 | ENTRY(restore_image) | 29 | ENTRY(restore_image) |
| 30 | movl mmu_cr4_features, %ecx | ||
| 30 | movl resume_pg_dir, %eax | 31 | movl resume_pg_dir, %eax |
| 31 | subl $__PAGE_OFFSET, %eax | 32 | subl $__PAGE_OFFSET, %eax |
| 32 | movl %eax, %cr3 | 33 | movl %eax, %cr3 |
| 33 | 34 | ||
| 35 | jecxz 1f # cr4 Pentium and higher, skip if zero | ||
| 36 | andl $~(X86_CR4_PGE), %ecx | ||
| 37 | movl %ecx, %cr4; # turn off PGE | ||
| 38 | movl %cr3, %eax; # flush TLB | ||
| 39 | movl %eax, %cr3 | ||
| 40 | 1: | ||
| 34 | movl restore_pblist, %edx | 41 | movl restore_pblist, %edx |
| 35 | .p2align 4,,7 | 42 | .p2align 4,,7 |
| 36 | 43 | ||
| @@ -54,16 +61,8 @@ done: | |||
| 54 | movl $swapper_pg_dir, %eax | 61 | movl $swapper_pg_dir, %eax |
| 55 | subl $__PAGE_OFFSET, %eax | 62 | subl $__PAGE_OFFSET, %eax |
| 56 | movl %eax, %cr3 | 63 | movl %eax, %cr3 |
| 57 | /* Flush TLB, including "global" things (vmalloc) */ | ||
| 58 | movl mmu_cr4_features, %ecx | 64 | movl mmu_cr4_features, %ecx |
| 59 | jecxz 1f # cr4 Pentium and higher, skip if zero | 65 | jecxz 1f # cr4 Pentium and higher, skip if zero |
| 60 | movl %ecx, %edx | ||
| 61 | andl $~(X86_CR4_PGE), %edx | ||
| 62 | movl %edx, %cr4; # turn off PGE | ||
| 63 | 1: | ||
| 64 | movl %cr3, %eax; # flush TLB | ||
| 65 | movl %eax, %cr3 | ||
| 66 | jecxz 1f # cr4 Pentium and higher, skip if zero | ||
| 67 | movl %ecx, %cr4; # turn PGE back on | 66 | movl %ecx, %cr4; # turn PGE back on |
| 68 | 1: | 67 | 1: |
| 69 | 68 | ||
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 134dd7328397..d6470ef36e4a 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c | |||
| @@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(ibft_addr); | |||
| 51 | * Routine used to find the iSCSI Boot Format Table. The logical | 51 | * Routine used to find the iSCSI Boot Format Table. The logical |
| 52 | * kernel address is set in the ibft_addr global variable. | 52 | * kernel address is set in the ibft_addr global variable. |
| 53 | */ | 53 | */ |
| 54 | void __init reserve_ibft_region(void) | 54 | unsigned long __init find_ibft_region(unsigned long *sizep) |
| 55 | { | 55 | { |
| 56 | unsigned long pos; | 56 | unsigned long pos; |
| 57 | unsigned int len = 0; | 57 | unsigned int len = 0; |
| @@ -77,6 +77,11 @@ void __init reserve_ibft_region(void) | |||
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | if (ibft_addr) | 80 | if (ibft_addr) { |
| 81 | reserve_bootmem(pos, PAGE_ALIGN(len), BOOTMEM_DEFAULT); | 81 | *sizep = PAGE_ALIGN(len); |
| 82 | return pos; | ||
| 83 | } | ||
| 84 | |||
| 85 | *sizep = 0; | ||
| 86 | return 0; | ||
| 82 | } | 87 | } |
diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h index 6092487e2950..d2e4042f8f5e 100644 --- a/include/linux/iscsi_ibft.h +++ b/include/linux/iscsi_ibft.h | |||
| @@ -42,9 +42,13 @@ extern struct ibft_table_header *ibft_addr; | |||
| 42 | * mapped address is set in the ibft_addr variable. | 42 | * mapped address is set in the ibft_addr variable. |
| 43 | */ | 43 | */ |
| 44 | #ifdef CONFIG_ISCSI_IBFT_FIND | 44 | #ifdef CONFIG_ISCSI_IBFT_FIND |
| 45 | extern void __init reserve_ibft_region(void); | 45 | unsigned long find_ibft_region(unsigned long *sizep); |
| 46 | #else | 46 | #else |
| 47 | static inline void reserve_ibft_region(void) { } | 47 | static inline unsigned long find_ibft_region(unsigned long *sizep) |
| 48 | { | ||
| 49 | *sizep = 0; | ||
| 50 | return 0; | ||
| 51 | } | ||
| 48 | #endif | 52 | #endif |
| 49 | 53 | ||
| 50 | #endif /* ISCSI_IBFT_H */ | 54 | #endif /* ISCSI_IBFT_H */ |
diff --git a/mm/bootmem.c b/mm/bootmem.c index eff224220571..58c66cc5056a 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
| @@ -304,9 +304,22 @@ unsigned long __init free_all_bootmem_node(pg_data_t *pgdat) | |||
| 304 | unsigned long __init free_all_bootmem(void) | 304 | unsigned long __init free_all_bootmem(void) |
| 305 | { | 305 | { |
| 306 | #ifdef CONFIG_NO_BOOTMEM | 306 | #ifdef CONFIG_NO_BOOTMEM |
| 307 | return free_all_memory_core_early(NODE_DATA(0)->node_id); | 307 | /* |
| 308 | * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id | ||
| 309 | * because in some case like Node0 doesnt have RAM installed | ||
| 310 | * low ram will be on Node1 | ||
| 311 | * Use MAX_NUMNODES will make sure all ranges in early_node_map[] | ||
| 312 | * will be used instead of only Node0 related | ||
| 313 | */ | ||
| 314 | return free_all_memory_core_early(MAX_NUMNODES); | ||
| 308 | #else | 315 | #else |
| 309 | return free_all_bootmem_core(NODE_DATA(0)->bdata); | 316 | unsigned long total_pages = 0; |
| 317 | bootmem_data_t *bdata; | ||
| 318 | |||
| 319 | list_for_each_entry(bdata, &bdata_list, list) | ||
| 320 | total_pages += free_all_bootmem_core(bdata); | ||
| 321 | |||
| 322 | return total_pages; | ||
| 310 | #endif | 323 | #endif |
| 311 | } | 324 | } |
| 312 | 325 | ||
