diff options
Diffstat (limited to 'arch/x86')
27 files changed, 609 insertions, 395 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index fa555148823d..864affc9a7b0 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
| @@ -34,13 +34,9 @@ config DEBUG_STACK_USAGE | |||
| 34 | 34 | ||
| 35 | This option will slow down process creation somewhat. | 35 | This option will slow down process creation somewhat. |
| 36 | 36 | ||
| 37 | comment "Page alloc debug is incompatible with Software Suspend on i386" | ||
| 38 | depends on DEBUG_KERNEL && HIBERNATION | ||
| 39 | depends on X86_32 | ||
| 40 | |||
| 41 | config DEBUG_PAGEALLOC | 37 | config DEBUG_PAGEALLOC |
| 42 | bool "Debug page memory allocations" | 38 | bool "Debug page memory allocations" |
| 43 | depends on DEBUG_KERNEL && X86_32 | 39 | depends on DEBUG_KERNEL |
| 44 | help | 40 | help |
| 45 | Unmap pages from the kernel linear mapping after free_pages(). | 41 | Unmap pages from the kernel linear mapping after free_pages(). |
| 46 | This results in a large slowdown, but helps to find certain types | 42 | This results in a large slowdown, but helps to find certain types |
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 364865b1b08d..204af43535c5 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile | |||
| @@ -191,8 +191,10 @@ drivers-$(CONFIG_PCI) += arch/x86/pci/ | |||
| 191 | # must be linked after kernel/ | 191 | # must be linked after kernel/ |
| 192 | drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ | 192 | drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ |
| 193 | 193 | ||
| 194 | ifeq ($(CONFIG_X86_32),y) | 194 | # suspend and hibernation support |
| 195 | drivers-$(CONFIG_PM) += arch/x86/power/ | 195 | drivers-$(CONFIG_PM) += arch/x86/power/ |
| 196 | |||
| 197 | ifeq ($(CONFIG_X86_32),y) | ||
| 196 | drivers-$(CONFIG_FB) += arch/x86/video/ | 198 | drivers-$(CONFIG_FB) += arch/x86/video/ |
| 197 | endif | 199 | endif |
| 198 | 200 | ||
diff --git a/arch/x86/boot/printf.c b/arch/x86/boot/printf.c index 1a09f9309d3c..7e7e890699be 100644 --- a/arch/x86/boot/printf.c +++ b/arch/x86/boot/printf.c | |||
| @@ -33,8 +33,8 @@ static int skip_atoi(const char **s) | |||
| 33 | #define PLUS 4 /* show plus */ | 33 | #define PLUS 4 /* show plus */ |
| 34 | #define SPACE 8 /* space if plus */ | 34 | #define SPACE 8 /* space if plus */ |
| 35 | #define LEFT 16 /* left justified */ | 35 | #define LEFT 16 /* left justified */ |
| 36 | #define SPECIAL 32 /* 0x */ | 36 | #define SMALL 32 /* Must be 32 == 0x20 */ |
| 37 | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ | 37 | #define SPECIAL 64 /* 0x */ |
| 38 | 38 | ||
| 39 | #define do_div(n,base) ({ \ | 39 | #define do_div(n,base) ({ \ |
| 40 | int __res; \ | 40 | int __res; \ |
| @@ -45,12 +45,16 @@ __res; }) | |||
| 45 | static char *number(char *str, long num, int base, int size, int precision, | 45 | static char *number(char *str, long num, int base, int size, int precision, |
| 46 | int type) | 46 | int type) |
| 47 | { | 47 | { |
| 48 | char c, sign, tmp[66]; | 48 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
| 49 | const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; | 49 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ |
| 50 | |||
| 51 | char tmp[66]; | ||
| 52 | char c, sign, locase; | ||
| 50 | int i; | 53 | int i; |
| 51 | 54 | ||
| 52 | if (type & LARGE) | 55 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' |
| 53 | digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | 56 | * produces same digits or (maybe lowercased) letters */ |
| 57 | locase = (type & SMALL); | ||
| 54 | if (type & LEFT) | 58 | if (type & LEFT) |
| 55 | type &= ~ZEROPAD; | 59 | type &= ~ZEROPAD; |
| 56 | if (base < 2 || base > 36) | 60 | if (base < 2 || base > 36) |
| @@ -81,7 +85,7 @@ static char *number(char *str, long num, int base, int size, int precision, | |||
| 81 | tmp[i++] = '0'; | 85 | tmp[i++] = '0'; |
| 82 | else | 86 | else |
| 83 | while (num != 0) | 87 | while (num != 0) |
| 84 | tmp[i++] = digits[do_div(num, base)]; | 88 | tmp[i++] = (digits[do_div(num, base)] | locase); |
| 85 | if (i > precision) | 89 | if (i > precision) |
| 86 | precision = i; | 90 | precision = i; |
| 87 | size -= precision; | 91 | size -= precision; |
| @@ -95,7 +99,7 @@ static char *number(char *str, long num, int base, int size, int precision, | |||
| 95 | *str++ = '0'; | 99 | *str++ = '0'; |
| 96 | else if (base == 16) { | 100 | else if (base == 16) { |
| 97 | *str++ = '0'; | 101 | *str++ = '0'; |
| 98 | *str++ = digits[33]; | 102 | *str++ = ('X' | locase); |
| 99 | } | 103 | } |
| 100 | } | 104 | } |
| 101 | if (!(type & LEFT)) | 105 | if (!(type & LEFT)) |
| @@ -244,9 +248,9 @@ int vsprintf(char *buf, const char *fmt, va_list args) | |||
| 244 | base = 8; | 248 | base = 8; |
| 245 | break; | 249 | break; |
| 246 | 250 | ||
| 247 | case 'X': | ||
| 248 | flags |= LARGE; | ||
| 249 | case 'x': | 251 | case 'x': |
| 252 | flags |= SMALL; | ||
| 253 | case 'X': | ||
| 250 | base = 16; | 254 | base = 16; |
| 251 | break; | 255 | break; |
| 252 | 256 | ||
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 77562e7cdab6..3df340b54e57 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig | |||
| @@ -1421,7 +1421,6 @@ CONFIG_DEBUG_BUGVERBOSE=y | |||
| 1421 | # CONFIG_DEBUG_VM is not set | 1421 | # CONFIG_DEBUG_VM is not set |
| 1422 | # CONFIG_DEBUG_LIST is not set | 1422 | # CONFIG_DEBUG_LIST is not set |
| 1423 | # CONFIG_FRAME_POINTER is not set | 1423 | # CONFIG_FRAME_POINTER is not set |
| 1424 | # CONFIG_FORCED_INLINING is not set | ||
| 1425 | # CONFIG_RCU_TORTURE_TEST is not set | 1424 | # CONFIG_RCU_TORTURE_TEST is not set |
| 1426 | # CONFIG_LKDTM is not set | 1425 | # CONFIG_LKDTM is not set |
| 1427 | # CONFIG_FAULT_INJECTION is not set | 1426 | # CONFIG_FAULT_INJECTION is not set |
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index 9e2b0ef851de..eef98cb00c62 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig | |||
| @@ -1346,7 +1346,6 @@ CONFIG_DEBUG_BUGVERBOSE=y | |||
| 1346 | # CONFIG_DEBUG_VM is not set | 1346 | # CONFIG_DEBUG_VM is not set |
| 1347 | # CONFIG_DEBUG_LIST is not set | 1347 | # CONFIG_DEBUG_LIST is not set |
| 1348 | # CONFIG_FRAME_POINTER is not set | 1348 | # CONFIG_FRAME_POINTER is not set |
| 1349 | # CONFIG_FORCED_INLINING is not set | ||
| 1350 | # CONFIG_RCU_TORTURE_TEST is not set | 1349 | # CONFIG_RCU_TORTURE_TEST is not set |
| 1351 | # CONFIG_LKDTM is not set | 1350 | # CONFIG_LKDTM is not set |
| 1352 | # CONFIG_FAULT_INJECTION is not set | 1351 | # CONFIG_FAULT_INJECTION is not set |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 21dc1a061bf1..76ec0f8f138a 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
| @@ -84,8 +84,6 @@ ifeq ($(CONFIG_X86_64),y) | |||
| 84 | obj-y += genapic_64.o genapic_flat_64.o | 84 | obj-y += genapic_64.o genapic_flat_64.o |
| 85 | obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o | 85 | obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o |
| 86 | obj-$(CONFIG_AUDIT) += audit_64.o | 86 | obj-$(CONFIG_AUDIT) += audit_64.o |
| 87 | obj-$(CONFIG_PM) += suspend_64.o | ||
| 88 | obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o | ||
| 89 | 87 | ||
| 90 | obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o | 88 | obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o |
| 91 | obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o | 89 | obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o |
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 24885be5c48c..9b7e01daa1ca 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c | |||
| @@ -118,7 +118,7 @@ static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) | |||
| 118 | 118 | ||
| 119 | static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) | 119 | static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) |
| 120 | { | 120 | { |
| 121 | return sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group); | 121 | sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | /* Mutex protecting device creation against CPU hotplug */ | 124 | /* Mutex protecting device creation against CPU hotplug */ |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index be5c31d04884..824e21b80aad 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
| @@ -409,7 +409,8 @@ restore_nocheck_notrace: | |||
| 409 | RESTORE_REGS | 409 | RESTORE_REGS |
| 410 | addl $4, %esp # skip orig_eax/error_code | 410 | addl $4, %esp # skip orig_eax/error_code |
| 411 | CFI_ADJUST_CFA_OFFSET -4 | 411 | CFI_ADJUST_CFA_OFFSET -4 |
| 412 | 1: INTERRUPT_RETURN | 412 | ENTRY(irq_return) |
| 413 | INTERRUPT_RETURN | ||
| 413 | .section .fixup,"ax" | 414 | .section .fixup,"ax" |
| 414 | iret_exc: | 415 | iret_exc: |
| 415 | pushl $0 # no error code | 416 | pushl $0 # no error code |
| @@ -418,7 +419,7 @@ iret_exc: | |||
| 418 | .previous | 419 | .previous |
| 419 | .section __ex_table,"a" | 420 | .section __ex_table,"a" |
| 420 | .align 4 | 421 | .align 4 |
| 421 | .long 1b,iret_exc | 422 | .long irq_return,iret_exc |
| 422 | .previous | 423 | .previous |
| 423 | 424 | ||
| 424 | CFI_RESTORE_STATE | 425 | CFI_RESTORE_STATE |
| @@ -865,20 +866,16 @@ nmi_espfix_stack: | |||
| 865 | RESTORE_REGS | 866 | RESTORE_REGS |
| 866 | lss 12+4(%esp), %esp # back to espfix stack | 867 | lss 12+4(%esp), %esp # back to espfix stack |
| 867 | CFI_ADJUST_CFA_OFFSET -24 | 868 | CFI_ADJUST_CFA_OFFSET -24 |
| 868 | 1: INTERRUPT_RETURN | 869 | jmp irq_return |
| 869 | CFI_ENDPROC | 870 | CFI_ENDPROC |
| 870 | .section __ex_table,"a" | ||
| 871 | .align 4 | ||
| 872 | .long 1b,iret_exc | ||
| 873 | .previous | ||
| 874 | KPROBE_END(nmi) | 871 | KPROBE_END(nmi) |
| 875 | 872 | ||
| 876 | #ifdef CONFIG_PARAVIRT | 873 | #ifdef CONFIG_PARAVIRT |
| 877 | ENTRY(native_iret) | 874 | ENTRY(native_iret) |
| 878 | 1: iret | 875 | iret |
| 879 | .section __ex_table,"a" | 876 | .section __ex_table,"a" |
| 880 | .align 4 | 877 | .align 4 |
| 881 | .long 1b,iret_exc | 878 | .long native_iret, iret_exc |
| 882 | .previous | 879 | .previous |
| 883 | END(native_iret) | 880 | END(native_iret) |
| 884 | 881 | ||
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index c7341e81941c..6be39a387c5a 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -581,16 +581,24 @@ retint_restore_args: /* return to kernel space */ | |||
| 581 | */ | 581 | */ |
| 582 | TRACE_IRQS_IRETQ | 582 | TRACE_IRQS_IRETQ |
| 583 | restore_args: | 583 | restore_args: |
| 584 | RESTORE_ARGS 0,8,0 | 584 | RESTORE_ARGS 0,8,0 |
| 585 | #ifdef CONFIG_PARAVIRT | 585 | |
| 586 | ENTRY(irq_return) | ||
| 586 | INTERRUPT_RETURN | 587 | INTERRUPT_RETURN |
| 587 | #endif | 588 | |
| 589 | .section __ex_table, "a" | ||
| 590 | .quad irq_return, bad_iret | ||
| 591 | .previous | ||
| 592 | |||
| 593 | #ifdef CONFIG_PARAVIRT | ||
| 588 | ENTRY(native_iret) | 594 | ENTRY(native_iret) |
| 589 | iretq | 595 | iretq |
| 590 | 596 | ||
| 591 | .section __ex_table,"a" | 597 | .section __ex_table,"a" |
| 592 | .quad native_iret, bad_iret | 598 | .quad native_iret, bad_iret |
| 593 | .previous | 599 | .previous |
| 600 | #endif | ||
| 601 | |||
| 594 | .section .fixup,"ax" | 602 | .section .fixup,"ax" |
| 595 | bad_iret: | 603 | bad_iret: |
| 596 | /* | 604 | /* |
| @@ -804,7 +812,7 @@ paranoid_swapgs\trace: | |||
| 804 | SWAPGS_UNSAFE_STACK | 812 | SWAPGS_UNSAFE_STACK |
| 805 | paranoid_restore\trace: | 813 | paranoid_restore\trace: |
| 806 | RESTORE_ALL 8 | 814 | RESTORE_ALL 8 |
| 807 | INTERRUPT_RETURN | 815 | jmp irq_return |
| 808 | paranoid_userspace\trace: | 816 | paranoid_userspace\trace: |
| 809 | GET_THREAD_INFO(%rcx) | 817 | GET_THREAD_INFO(%rcx) |
| 810 | movl threadinfo_flags(%rcx),%ebx | 818 | movl threadinfo_flags(%rcx),%ebx |
| @@ -919,7 +927,7 @@ error_kernelspace: | |||
| 919 | iret run with kernel gs again, so don't set the user space flag. | 927 | iret run with kernel gs again, so don't set the user space flag. |
| 920 | B stepping K8s sometimes report an truncated RIP for IRET | 928 | B stepping K8s sometimes report an truncated RIP for IRET |
| 921 | exceptions returning to compat mode. Check for these here too. */ | 929 | exceptions returning to compat mode. Check for these here too. */ |
| 922 | leaq native_iret(%rip),%rbp | 930 | leaq irq_return(%rip),%rbp |
| 923 | cmpq %rbp,RIP(%rsp) | 931 | cmpq %rbp,RIP(%rsp) |
| 924 | je error_swapgs | 932 | je error_swapgs |
| 925 | movl %ebp,%ebp /* zero extend */ | 933 | movl %ebp,%ebp /* zero extend */ |
diff --git a/arch/x86/kernel/geode_32.c b/arch/x86/kernel/geode_32.c index 9c7f7d395968..9dad6ca6cd70 100644 --- a/arch/x86/kernel/geode_32.c +++ b/arch/x86/kernel/geode_32.c | |||
| @@ -163,14 +163,11 @@ EXPORT_SYMBOL_GPL(geode_gpio_setup_event); | |||
| 163 | 163 | ||
| 164 | static int __init geode_southbridge_init(void) | 164 | static int __init geode_southbridge_init(void) |
| 165 | { | 165 | { |
| 166 | int timers; | ||
| 167 | |||
| 168 | if (!is_geode()) | 166 | if (!is_geode()) |
| 169 | return -ENODEV; | 167 | return -ENODEV; |
| 170 | 168 | ||
| 171 | init_lbars(); | 169 | init_lbars(); |
| 172 | timers = geode_mfgpt_detect(); | 170 | (void) mfgpt_timer_setup(); |
| 173 | printk(KERN_INFO "geode: %d MFGPT timers available.\n", timers); | ||
| 174 | return 0; | 171 | return 0; |
| 175 | } | 172 | } |
| 176 | 173 | ||
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 5d8c5730686b..74ef4a41f224 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S | |||
| @@ -19,6 +19,10 @@ | |||
| 19 | #include <asm/thread_info.h> | 19 | #include <asm/thread_info.h> |
| 20 | #include <asm/asm-offsets.h> | 20 | #include <asm/asm-offsets.h> |
| 21 | #include <asm/setup.h> | 21 | #include <asm/setup.h> |
| 22 | #include <asm/processor-flags.h> | ||
| 23 | |||
| 24 | /* Physical address */ | ||
| 25 | #define pa(X) ((X) - __PAGE_OFFSET) | ||
| 22 | 26 | ||
| 23 | /* | 27 | /* |
| 24 | * References to members of the new_cpu_data structure. | 28 | * References to members of the new_cpu_data structure. |
| @@ -80,10 +84,6 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_ | |||
| 80 | */ | 84 | */ |
| 81 | .section .text.head,"ax",@progbits | 85 | .section .text.head,"ax",@progbits |
| 82 | ENTRY(startup_32) | 86 | ENTRY(startup_32) |
| 83 | /* check to see if KEEP_SEGMENTS flag is meaningful */ | ||
| 84 | cmpw $0x207, BP_version(%esi) | ||
| 85 | jb 1f | ||
| 86 | |||
| 87 | /* test KEEP_SEGMENTS flag to see if the bootloader is asking | 87 | /* test KEEP_SEGMENTS flag to see if the bootloader is asking |
| 88 | us to not reload segments */ | 88 | us to not reload segments */ |
| 89 | testb $(1<<6), BP_loadflags(%esi) | 89 | testb $(1<<6), BP_loadflags(%esi) |
| @@ -92,7 +92,7 @@ ENTRY(startup_32) | |||
| 92 | /* | 92 | /* |
| 93 | * Set segments to known values. | 93 | * Set segments to known values. |
| 94 | */ | 94 | */ |
| 95 | 1: lgdt boot_gdt_descr - __PAGE_OFFSET | 95 | lgdt pa(boot_gdt_descr) |
| 96 | movl $(__BOOT_DS),%eax | 96 | movl $(__BOOT_DS),%eax |
| 97 | movl %eax,%ds | 97 | movl %eax,%ds |
| 98 | movl %eax,%es | 98 | movl %eax,%es |
| @@ -105,8 +105,8 @@ ENTRY(startup_32) | |||
| 105 | */ | 105 | */ |
| 106 | cld | 106 | cld |
| 107 | xorl %eax,%eax | 107 | xorl %eax,%eax |
| 108 | movl $__bss_start - __PAGE_OFFSET,%edi | 108 | movl $pa(__bss_start),%edi |
| 109 | movl $__bss_stop - __PAGE_OFFSET,%ecx | 109 | movl $pa(__bss_stop),%ecx |
| 110 | subl %edi,%ecx | 110 | subl %edi,%ecx |
| 111 | shrl $2,%ecx | 111 | shrl $2,%ecx |
| 112 | rep ; stosl | 112 | rep ; stosl |
| @@ -118,31 +118,32 @@ ENTRY(startup_32) | |||
| 118 | * (kexec on panic case). Hence copy out the parameters before initializing | 118 | * (kexec on panic case). Hence copy out the parameters before initializing |
| 119 | * page tables. | 119 | * page tables. |
| 120 | */ | 120 | */ |
| 121 | movl $(boot_params - __PAGE_OFFSET),%edi | 121 | movl $pa(boot_params),%edi |
| 122 | movl $(PARAM_SIZE/4),%ecx | 122 | movl $(PARAM_SIZE/4),%ecx |
| 123 | cld | 123 | cld |
| 124 | rep | 124 | rep |
| 125 | movsl | 125 | movsl |
| 126 | movl boot_params - __PAGE_OFFSET + NEW_CL_POINTER,%esi | 126 | movl pa(boot_params) + NEW_CL_POINTER,%esi |
| 127 | andl %esi,%esi | 127 | andl %esi,%esi |
| 128 | jz 1f # No comand line | 128 | jz 1f # No comand line |
| 129 | movl $(boot_command_line - __PAGE_OFFSET),%edi | 129 | movl $pa(boot_command_line),%edi |
| 130 | movl $(COMMAND_LINE_SIZE/4),%ecx | 130 | movl $(COMMAND_LINE_SIZE/4),%ecx |
| 131 | rep | 131 | rep |
| 132 | movsl | 132 | movsl |
| 133 | 1: | 133 | 1: |
| 134 | 134 | ||
| 135 | #ifdef CONFIG_PARAVIRT | 135 | #ifdef CONFIG_PARAVIRT |
| 136 | cmpw $0x207, (boot_params + BP_version - __PAGE_OFFSET) | 136 | /* This is can only trip for a broken bootloader... */ |
| 137 | cmpw $0x207, pa(boot_params + BP_version) | ||
| 137 | jb default_entry | 138 | jb default_entry |
| 138 | 139 | ||
| 139 | /* Paravirt-compatible boot parameters. Look to see what architecture | 140 | /* Paravirt-compatible boot parameters. Look to see what architecture |
| 140 | we're booting under. */ | 141 | we're booting under. */ |
| 141 | movl (boot_params + BP_hardware_subarch - __PAGE_OFFSET), %eax | 142 | movl pa(boot_params + BP_hardware_subarch), %eax |
| 142 | cmpl $num_subarch_entries, %eax | 143 | cmpl $num_subarch_entries, %eax |
| 143 | jae bad_subarch | 144 | jae bad_subarch |
| 144 | 145 | ||
| 145 | movl subarch_entries - __PAGE_OFFSET(,%eax,4), %eax | 146 | movl pa(subarch_entries)(,%eax,4), %eax |
| 146 | subl $__PAGE_OFFSET, %eax | 147 | subl $__PAGE_OFFSET, %eax |
| 147 | jmp *%eax | 148 | jmp *%eax |
| 148 | 149 | ||
| @@ -170,17 +171,68 @@ num_subarch_entries = (. - subarch_entries) / 4 | |||
| 170 | * Mappings are created both at virtual address 0 (identity mapping) | 171 | * Mappings are created both at virtual address 0 (identity mapping) |
| 171 | * and PAGE_OFFSET for up to _end+sizeof(page tables)+INIT_MAP_BEYOND_END. | 172 | * and PAGE_OFFSET for up to _end+sizeof(page tables)+INIT_MAP_BEYOND_END. |
| 172 | * | 173 | * |
| 173 | * Warning: don't use %esi or the stack in this code. However, %esp | 174 | * Note that the stack is not yet set up! |
| 174 | * can be used as a GPR if you really need it... | ||
| 175 | */ | 175 | */ |
| 176 | page_pde_offset = (__PAGE_OFFSET >> 20); | 176 | #define PTE_ATTR 0x007 /* PRESENT+RW+USER */ |
| 177 | #define PDE_ATTR 0x067 /* PRESENT+RW+USER+DIRTY+ACCESSED */ | ||
| 178 | #define PGD_ATTR 0x001 /* PRESENT (no other attributes) */ | ||
| 177 | 179 | ||
| 178 | default_entry: | 180 | default_entry: |
| 179 | movl $(pg0 - __PAGE_OFFSET), %edi | 181 | #ifdef CONFIG_X86_PAE |
| 180 | movl $(swapper_pg_dir - __PAGE_OFFSET), %edx | 182 | |
| 181 | movl $0x007, %eax /* 0x007 = PRESENT+RW+USER */ | 183 | /* |
| 184 | * In PAE mode swapper_pg_dir is statically defined to contain enough | ||
| 185 | * entries to cover the VMSPLIT option (that is the top 1, 2 or 3 | ||
| 186 | * entries). The identity mapping is handled by pointing two PGD | ||
| 187 | * entries to the first kernel PMD. | ||
| 188 | * | ||
| 189 | * Note the upper half of each PMD or PTE are always zero at | ||
| 190 | * this stage. | ||
| 191 | */ | ||
| 192 | |||
| 193 | #define KPMDS ((0x100000000-__PAGE_OFFSET) >> 30) /* Number of kernel PMDs */ | ||
| 194 | |||
| 195 | xorl %ebx,%ebx /* %ebx is kept at zero */ | ||
| 196 | |||
| 197 | movl $pa(pg0), %edi | ||
| 198 | movl $pa(swapper_pg_pmd), %edx | ||
| 199 | movl $PTE_ATTR, %eax | ||
| 200 | 10: | ||
| 201 | leal PDE_ATTR(%edi),%ecx /* Create PMD entry */ | ||
| 202 | movl %ecx,(%edx) /* Store PMD entry */ | ||
| 203 | /* Upper half already zero */ | ||
| 204 | addl $8,%edx | ||
| 205 | movl $512,%ecx | ||
| 206 | 11: | ||
| 207 | stosl | ||
| 208 | xchgl %eax,%ebx | ||
| 209 | stosl | ||
| 210 | xchgl %eax,%ebx | ||
| 211 | addl $0x1000,%eax | ||
| 212 | loop 11b | ||
| 213 | |||
| 214 | /* | ||
| 215 | * End condition: we must map up to and including INIT_MAP_BEYOND_END | ||
| 216 | * bytes beyond the end of our own page tables. | ||
| 217 | */ | ||
| 218 | leal (INIT_MAP_BEYOND_END+PTE_ATTR)(%edi),%ebp | ||
| 219 | cmpl %ebp,%eax | ||
| 220 | jb 10b | ||
| 221 | 1: | ||
| 222 | movl %edi,pa(init_pg_tables_end) | ||
| 223 | |||
| 224 | /* Do early initialization of the fixmap area */ | ||
| 225 | movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax | ||
| 226 | movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8) | ||
| 227 | #else /* Not PAE */ | ||
| 228 | |||
| 229 | page_pde_offset = (__PAGE_OFFSET >> 20); | ||
| 230 | |||
| 231 | movl $pa(pg0), %edi | ||
| 232 | movl $pa(swapper_pg_dir), %edx | ||
| 233 | movl $PTE_ATTR, %eax | ||
| 182 | 10: | 234 | 10: |
| 183 | leal 0x007(%edi),%ecx /* Create PDE entry */ | 235 | leal PDE_ATTR(%edi),%ecx /* Create PDE entry */ |
| 184 | movl %ecx,(%edx) /* Store identity PDE entry */ | 236 | movl %ecx,(%edx) /* Store identity PDE entry */ |
| 185 | movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */ | 237 | movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */ |
| 186 | addl $4,%edx | 238 | addl $4,%edx |
| @@ -189,19 +241,20 @@ default_entry: | |||
| 189 | stosl | 241 | stosl |
| 190 | addl $0x1000,%eax | 242 | addl $0x1000,%eax |
| 191 | loop 11b | 243 | loop 11b |
| 192 | /* End condition: we must map up to and including INIT_MAP_BEYOND_END */ | 244 | /* |
| 193 | /* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */ | 245 | * End condition: we must map up to and including INIT_MAP_BEYOND_END |
| 194 | leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp | 246 | * bytes beyond the end of our own page tables; the +0x007 is |
| 247 | * the attribute bits | ||
| 248 | */ | ||
| 249 | leal (INIT_MAP_BEYOND_END+PTE_ATTR)(%edi),%ebp | ||
| 195 | cmpl %ebp,%eax | 250 | cmpl %ebp,%eax |
| 196 | jb 10b | 251 | jb 10b |
| 197 | movl %edi,(init_pg_tables_end - __PAGE_OFFSET) | 252 | movl %edi,pa(init_pg_tables_end) |
| 198 | |||
| 199 | /* Do an early initialization of the fixmap area */ | ||
| 200 | movl $(swapper_pg_dir - __PAGE_OFFSET), %edx | ||
| 201 | movl $(swapper_pg_pmd - __PAGE_OFFSET), %eax | ||
| 202 | addl $0x67, %eax /* 0x67 == _PAGE_TABLE */ | ||
| 203 | movl %eax, 4092(%edx) | ||
| 204 | 253 | ||
| 254 | /* Do early initialization of the fixmap area */ | ||
| 255 | movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax | ||
| 256 | movl %eax,pa(swapper_pg_dir+0xffc) | ||
| 257 | #endif | ||
| 205 | jmp 3f | 258 | jmp 3f |
| 206 | /* | 259 | /* |
| 207 | * Non-boot CPU entry point; entered from trampoline.S | 260 | * Non-boot CPU entry point; entered from trampoline.S |
| @@ -241,7 +294,7 @@ ENTRY(startup_32_smp) | |||
| 241 | * NOTE! We have to correct for the fact that we're | 294 | * NOTE! We have to correct for the fact that we're |
| 242 | * not yet offset PAGE_OFFSET.. | 295 | * not yet offset PAGE_OFFSET.. |
| 243 | */ | 296 | */ |
| 244 | #define cr4_bits mmu_cr4_features-__PAGE_OFFSET | 297 | #define cr4_bits pa(mmu_cr4_features) |
| 245 | movl cr4_bits,%edx | 298 | movl cr4_bits,%edx |
| 246 | andl %edx,%edx | 299 | andl %edx,%edx |
| 247 | jz 6f | 300 | jz 6f |
| @@ -276,10 +329,10 @@ ENTRY(startup_32_smp) | |||
| 276 | /* | 329 | /* |
| 277 | * Enable paging | 330 | * Enable paging |
| 278 | */ | 331 | */ |
| 279 | movl $swapper_pg_dir-__PAGE_OFFSET,%eax | 332 | movl $pa(swapper_pg_dir),%eax |
| 280 | movl %eax,%cr3 /* set the page table pointer.. */ | 333 | movl %eax,%cr3 /* set the page table pointer.. */ |
| 281 | movl %cr0,%eax | 334 | movl %cr0,%eax |
| 282 | orl $0x80000000,%eax | 335 | orl $X86_CR0_PG,%eax |
| 283 | movl %eax,%cr0 /* ..and set paging (PG) bit */ | 336 | movl %eax,%cr0 /* ..and set paging (PG) bit */ |
| 284 | ljmp $__BOOT_CS,$1f /* Clear prefetch and normalize %eip */ | 337 | ljmp $__BOOT_CS,$1f /* Clear prefetch and normalize %eip */ |
| 285 | 1: | 338 | 1: |
| @@ -552,16 +605,44 @@ ENTRY(_stext) | |||
| 552 | */ | 605 | */ |
| 553 | .section ".bss.page_aligned","wa" | 606 | .section ".bss.page_aligned","wa" |
| 554 | .align PAGE_SIZE_asm | 607 | .align PAGE_SIZE_asm |
| 608 | #ifdef CONFIG_X86_PAE | ||
| 609 | ENTRY(swapper_pg_pmd) | ||
| 610 | .fill 1024*KPMDS,4,0 | ||
| 611 | #else | ||
| 555 | ENTRY(swapper_pg_dir) | 612 | ENTRY(swapper_pg_dir) |
| 556 | .fill 1024,4,0 | 613 | .fill 1024,4,0 |
| 557 | ENTRY(swapper_pg_pmd) | 614 | #endif |
| 615 | ENTRY(swapper_pg_fixmap) | ||
| 558 | .fill 1024,4,0 | 616 | .fill 1024,4,0 |
| 559 | ENTRY(empty_zero_page) | 617 | ENTRY(empty_zero_page) |
| 560 | .fill 4096,1,0 | 618 | .fill 4096,1,0 |
| 561 | |||
| 562 | /* | 619 | /* |
| 563 | * This starts the data section. | 620 | * This starts the data section. |
| 564 | */ | 621 | */ |
| 622 | #ifdef CONFIG_X86_PAE | ||
| 623 | .section ".data.page_aligned","wa" | ||
| 624 | /* Page-aligned for the benefit of paravirt? */ | ||
| 625 | .align PAGE_SIZE_asm | ||
| 626 | ENTRY(swapper_pg_dir) | ||
| 627 | .long pa(swapper_pg_pmd+PGD_ATTR),0 /* low identity map */ | ||
| 628 | # if KPMDS == 3 | ||
| 629 | .long pa(swapper_pg_pmd+PGD_ATTR),0 | ||
| 630 | .long pa(swapper_pg_pmd+PGD_ATTR+0x1000),0 | ||
| 631 | .long pa(swapper_pg_pmd+PGD_ATTR+0x2000),0 | ||
| 632 | # elif KPMDS == 2 | ||
| 633 | .long 0,0 | ||
| 634 | .long pa(swapper_pg_pmd+PGD_ATTR),0 | ||
| 635 | .long pa(swapper_pg_pmd+PGD_ATTR+0x1000),0 | ||
| 636 | # elif KPMDS == 1 | ||
| 637 | .long 0,0 | ||
| 638 | .long 0,0 | ||
| 639 | .long pa(swapper_pg_pmd+PGD_ATTR),0 | ||
| 640 | # else | ||
| 641 | # error "Kernel PMDs should be 1, 2 or 3" | ||
| 642 | # endif | ||
| 643 | .align PAGE_SIZE_asm /* needs to be page-sized too */ | ||
| 644 | #endif | ||
| 645 | |||
| 565 | .data | 646 | .data |
| 566 | ENTRY(stack_start) | 647 | ENTRY(stack_start) |
| 567 | .long init_thread_union+THREAD_SIZE | 648 | .long init_thread_union+THREAD_SIZE |
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c index 219f86eb6123..027fc067b399 100644 --- a/arch/x86/kernel/mfgpt_32.c +++ b/arch/x86/kernel/mfgpt_32.c | |||
| @@ -12,48 +12,37 @@ | |||
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | /* | 14 | /* |
| 15 | * We are using the 32Khz input clock - its the only one that has the | 15 | * We are using the 32.768kHz input clock - it's the only one that has the |
| 16 | * ranges we find desirable. The following table lists the suitable | 16 | * ranges we find desirable. The following table lists the suitable |
| 17 | * divisors and the associated hz, minimum interval | 17 | * divisors and the associated Hz, minimum interval and the maximum interval: |
| 18 | * and the maximum interval: | ||
| 19 | * | 18 | * |
| 20 | * Divisor Hz Min Delta (S) Max Delta (S) | 19 | * Divisor Hz Min Delta (s) Max Delta (s) |
| 21 | * 1 32000 .0005 2.048 | 20 | * 1 32768 .00048828125 2.000 |
| 22 | * 2 16000 .001 4.096 | 21 | * 2 16384 .0009765625 4.000 |
| 23 | * 4 8000 .002 8.192 | 22 | * 4 8192 .001953125 8.000 |
| 24 | * 8 4000 .004 16.384 | 23 | * 8 4096 .00390625 16.000 |
| 25 | * 16 2000 .008 32.768 | 24 | * 16 2048 .0078125 32.000 |
| 26 | * 32 1000 .016 65.536 | 25 | * 32 1024 .015625 64.000 |
| 27 | * 64 500 .032 131.072 | 26 | * 64 512 .03125 128.000 |
| 28 | * 128 250 .064 262.144 | 27 | * 128 256 .0625 256.000 |
| 29 | * 256 125 .128 524.288 | 28 | * 256 128 .125 512.000 |
| 30 | */ | 29 | */ |
| 31 | 30 | ||
| 32 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
| 33 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
| 34 | #include <linux/module.h> | ||
| 35 | #include <asm/geode.h> | 33 | #include <asm/geode.h> |
| 36 | 34 | ||
| 37 | #define F_AVAIL 0x01 | ||
| 38 | |||
| 39 | static struct mfgpt_timer_t { | 35 | static struct mfgpt_timer_t { |
| 40 | int flags; | 36 | unsigned int avail:1; |
| 41 | struct module *owner; | ||
| 42 | } mfgpt_timers[MFGPT_MAX_TIMERS]; | 37 | } mfgpt_timers[MFGPT_MAX_TIMERS]; |
| 43 | 38 | ||
| 44 | /* Selected from the table above */ | 39 | /* Selected from the table above */ |
| 45 | 40 | ||
| 46 | #define MFGPT_DIVISOR 16 | 41 | #define MFGPT_DIVISOR 16 |
| 47 | #define MFGPT_SCALE 4 /* divisor = 2^(scale) */ | 42 | #define MFGPT_SCALE 4 /* divisor = 2^(scale) */ |
| 48 | #define MFGPT_HZ (32000 / MFGPT_DIVISOR) | 43 | #define MFGPT_HZ (32768 / MFGPT_DIVISOR) |
| 49 | #define MFGPT_PERIODIC (MFGPT_HZ / HZ) | 44 | #define MFGPT_PERIODIC (MFGPT_HZ / HZ) |
| 50 | 45 | ||
| 51 | #ifdef CONFIG_GEODE_MFGPT_TIMER | ||
| 52 | static int __init mfgpt_timer_setup(void); | ||
| 53 | #else | ||
| 54 | #define mfgpt_timer_setup() (0) | ||
| 55 | #endif | ||
| 56 | |||
| 57 | /* Allow for disabling of MFGPTs */ | 46 | /* Allow for disabling of MFGPTs */ |
| 58 | static int disable; | 47 | static int disable; |
| 59 | static int __init mfgpt_disable(char *s) | 48 | static int __init mfgpt_disable(char *s) |
| @@ -85,28 +74,37 @@ __setup("mfgptfix", mfgpt_fix); | |||
| 85 | * In other cases (such as with VSAless OpenFirmware), the system firmware | 74 | * In other cases (such as with VSAless OpenFirmware), the system firmware |
| 86 | * leaves timers available for us to use. | 75 | * leaves timers available for us to use. |
| 87 | */ | 76 | */ |
| 88 | int __init geode_mfgpt_detect(void) | 77 | |
| 78 | |||
| 79 | static int timers = -1; | ||
| 80 | |||
| 81 | static void geode_mfgpt_detect(void) | ||
| 89 | { | 82 | { |
| 90 | int count = 0, i; | 83 | int i; |
| 91 | u16 val; | 84 | u16 val; |
| 92 | 85 | ||
| 86 | timers = 0; | ||
| 87 | |||
| 93 | if (disable) { | 88 | if (disable) { |
| 94 | printk(KERN_INFO "geode-mfgpt: Skipping MFGPT setup\n"); | 89 | printk(KERN_INFO "geode-mfgpt: MFGPT support is disabled\n"); |
| 95 | return 0; | 90 | goto done; |
| 91 | } | ||
| 92 | |||
| 93 | if (!geode_get_dev_base(GEODE_DEV_MFGPT)) { | ||
| 94 | printk(KERN_INFO "geode-mfgpt: MFGPT LBAR is not set up\n"); | ||
| 95 | goto done; | ||
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { | 98 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { |
| 99 | val = geode_mfgpt_read(i, MFGPT_REG_SETUP); | 99 | val = geode_mfgpt_read(i, MFGPT_REG_SETUP); |
| 100 | if (!(val & MFGPT_SETUP_SETUP)) { | 100 | if (!(val & MFGPT_SETUP_SETUP)) { |
| 101 | mfgpt_timers[i].flags = F_AVAIL; | 101 | mfgpt_timers[i].avail = 1; |
| 102 | count++; | 102 | timers++; |
| 103 | } | 103 | } |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | /* set up clock event device, if desired */ | 106 | done: |
| 107 | i = mfgpt_timer_setup(); | 107 | printk(KERN_INFO "geode-mfgpt: %d MFGPT timers available.\n", timers); |
| 108 | |||
| 109 | return count; | ||
| 110 | } | 108 | } |
| 111 | 109 | ||
| 112 | int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) | 110 | int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) |
| @@ -183,36 +181,41 @@ int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable) | |||
| 183 | return 0; | 181 | return 0; |
| 184 | } | 182 | } |
| 185 | 183 | ||
| 186 | static int mfgpt_get(int timer, struct module *owner) | 184 | static int mfgpt_get(int timer) |
| 187 | { | 185 | { |
| 188 | mfgpt_timers[timer].flags &= ~F_AVAIL; | 186 | mfgpt_timers[timer].avail = 0; |
| 189 | mfgpt_timers[timer].owner = owner; | ||
| 190 | printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer); | 187 | printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer); |
| 191 | return timer; | 188 | return timer; |
| 192 | } | 189 | } |
| 193 | 190 | ||
| 194 | int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner) | 191 | int geode_mfgpt_alloc_timer(int timer, int domain) |
| 195 | { | 192 | { |
| 196 | int i; | 193 | int i; |
| 197 | 194 | ||
| 198 | if (!geode_get_dev_base(GEODE_DEV_MFGPT)) | 195 | if (timers == -1) { |
| 199 | return -ENODEV; | 196 | /* timers haven't been detected yet */ |
| 197 | geode_mfgpt_detect(); | ||
| 198 | } | ||
| 199 | |||
| 200 | if (!timers) | ||
| 201 | return -1; | ||
| 202 | |||
| 200 | if (timer >= MFGPT_MAX_TIMERS) | 203 | if (timer >= MFGPT_MAX_TIMERS) |
| 201 | return -EIO; | 204 | return -1; |
| 202 | 205 | ||
| 203 | if (timer < 0) { | 206 | if (timer < 0) { |
| 204 | /* Try to find an available timer */ | 207 | /* Try to find an available timer */ |
| 205 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { | 208 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { |
| 206 | if (mfgpt_timers[i].flags & F_AVAIL) | 209 | if (mfgpt_timers[i].avail) |
| 207 | return mfgpt_get(i, owner); | 210 | return mfgpt_get(i); |
| 208 | 211 | ||
| 209 | if (i == 5 && domain == MFGPT_DOMAIN_WORKING) | 212 | if (i == 5 && domain == MFGPT_DOMAIN_WORKING) |
| 210 | break; | 213 | break; |
| 211 | } | 214 | } |
| 212 | } else { | 215 | } else { |
| 213 | /* If they requested a specific timer, try to honor that */ | 216 | /* If they requested a specific timer, try to honor that */ |
| 214 | if (mfgpt_timers[timer].flags & F_AVAIL) | 217 | if (mfgpt_timers[timer].avail) |
| 215 | return mfgpt_get(timer, owner); | 218 | return mfgpt_get(timer); |
| 216 | } | 219 | } |
| 217 | 220 | ||
| 218 | /* No timers available - too bad */ | 221 | /* No timers available - too bad */ |
| @@ -244,10 +247,11 @@ static int __init mfgpt_setup(char *str) | |||
| 244 | } | 247 | } |
| 245 | __setup("mfgpt_irq=", mfgpt_setup); | 248 | __setup("mfgpt_irq=", mfgpt_setup); |
| 246 | 249 | ||
| 247 | static inline void mfgpt_disable_timer(u16 clock) | 250 | static void mfgpt_disable_timer(u16 clock) |
| 248 | { | 251 | { |
| 249 | u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP); | 252 | /* avoid races by clearing CMP1 and CMP2 unconditionally */ |
| 250 | geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN); | 253 | geode_mfgpt_write(clock, MFGPT_REG_SETUP, (u16) ~MFGPT_SETUP_CNTEN | |
| 254 | MFGPT_SETUP_CMP1 | MFGPT_SETUP_CMP2); | ||
| 251 | } | 255 | } |
| 252 | 256 | ||
| 253 | static int mfgpt_next_event(unsigned long, struct clock_event_device *); | 257 | static int mfgpt_next_event(unsigned long, struct clock_event_device *); |
| @@ -263,7 +267,7 @@ static struct clock_event_device mfgpt_clockevent = { | |||
| 263 | .shift = 32 | 267 | .shift = 32 |
| 264 | }; | 268 | }; |
| 265 | 269 | ||
| 266 | static inline void mfgpt_start_timer(u16 clock, u16 delta) | 270 | static void mfgpt_start_timer(u16 delta) |
| 267 | { | 271 | { |
| 268 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta); | 272 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta); |
| 269 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); | 273 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); |
| @@ -278,21 +282,25 @@ static void mfgpt_set_mode(enum clock_event_mode mode, | |||
| 278 | mfgpt_disable_timer(mfgpt_event_clock); | 282 | mfgpt_disable_timer(mfgpt_event_clock); |
| 279 | 283 | ||
| 280 | if (mode == CLOCK_EVT_MODE_PERIODIC) | 284 | if (mode == CLOCK_EVT_MODE_PERIODIC) |
| 281 | mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC); | 285 | mfgpt_start_timer(MFGPT_PERIODIC); |
| 282 | 286 | ||
| 283 | mfgpt_tick_mode = mode; | 287 | mfgpt_tick_mode = mode; |
| 284 | } | 288 | } |
| 285 | 289 | ||
| 286 | static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) | 290 | static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) |
| 287 | { | 291 | { |
| 288 | mfgpt_start_timer(mfgpt_event_clock, delta); | 292 | mfgpt_start_timer(delta); |
| 289 | return 0; | 293 | return 0; |
| 290 | } | 294 | } |
| 291 | 295 | ||
| 292 | /* Assume (foolishly?), that this interrupt was due to our tick */ | ||
| 293 | |||
| 294 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) | 296 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) |
| 295 | { | 297 | { |
| 298 | u16 val = geode_mfgpt_read(mfgpt_event_clock, MFGPT_REG_SETUP); | ||
| 299 | |||
| 300 | /* See if the interrupt was for us */ | ||
| 301 | if (!(val & (MFGPT_SETUP_SETUP | MFGPT_SETUP_CMP2 | MFGPT_SETUP_CMP1))) | ||
| 302 | return IRQ_NONE; | ||
| 303 | |||
| 296 | /* Turn off the clock (and clear the event) */ | 304 | /* Turn off the clock (and clear the event) */ |
| 297 | mfgpt_disable_timer(mfgpt_event_clock); | 305 | mfgpt_disable_timer(mfgpt_event_clock); |
| 298 | 306 | ||
| @@ -320,13 +328,12 @@ static struct irqaction mfgptirq = { | |||
| 320 | .name = "mfgpt-timer" | 328 | .name = "mfgpt-timer" |
| 321 | }; | 329 | }; |
| 322 | 330 | ||
| 323 | static int __init mfgpt_timer_setup(void) | 331 | int __init mfgpt_timer_setup(void) |
| 324 | { | 332 | { |
| 325 | int timer, ret; | 333 | int timer, ret; |
| 326 | u16 val; | 334 | u16 val; |
| 327 | 335 | ||
| 328 | timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING, | 336 | timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING); |
| 329 | THIS_MODULE); | ||
| 330 | if (timer < 0) { | 337 | if (timer < 0) { |
| 331 | printk(KERN_ERR | 338 | printk(KERN_ERR |
| 332 | "mfgpt-timer: Could not allocate a MFPGT timer\n"); | 339 | "mfgpt-timer: Could not allocate a MFPGT timer\n"); |
| @@ -363,7 +370,7 @@ static int __init mfgpt_timer_setup(void) | |||
| 363 | &mfgpt_clockevent); | 370 | &mfgpt_clockevent); |
| 364 | 371 | ||
| 365 | printk(KERN_INFO | 372 | printk(KERN_INFO |
| 366 | "mfgpt-timer: registering the MFGT timer as a clock event.\n"); | 373 | "mfgpt-timer: registering the MFGPT timer as a clock event.\n"); |
| 367 | clockevents_register_device(&mfgpt_clockevent); | 374 | clockevents_register_device(&mfgpt_clockevent); |
| 368 | 375 | ||
| 369 | return 0; | 376 | return 0; |
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index d1d8c347cc0b..691ab4cb167b 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c | |||
| @@ -154,7 +154,11 @@ struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; | |||
| 154 | struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; | 154 | struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; |
| 155 | EXPORT_SYMBOL(boot_cpu_data); | 155 | EXPORT_SYMBOL(boot_cpu_data); |
| 156 | 156 | ||
| 157 | #ifndef CONFIG_X86_PAE | ||
| 157 | unsigned long mmu_cr4_features; | 158 | unsigned long mmu_cr4_features; |
| 159 | #else | ||
| 160 | unsigned long mmu_cr4_features = X86_CR4_PAE; | ||
| 161 | #endif | ||
| 158 | 162 | ||
| 159 | /* for MCA, but anyone else can use it if they want */ | 163 | /* for MCA, but anyone else can use it if they want */ |
| 160 | unsigned int machine_id; | 164 | unsigned int machine_id; |
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index e6757aaa202b..a40051b71d9b 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c | |||
| @@ -53,7 +53,7 @@ EXPORT_SYMBOL(arch_register_cpu); | |||
| 53 | 53 | ||
| 54 | void arch_unregister_cpu(int num) | 54 | void arch_unregister_cpu(int num) |
| 55 | { | 55 | { |
| 56 | return unregister_cpu(&per_cpu(cpu_devices, num).cpu); | 56 | unregister_cpu(&per_cpu(cpu_devices, num).cpu); |
| 57 | } | 57 | } |
| 58 | EXPORT_SYMBOL(arch_unregister_cpu); | 58 | EXPORT_SYMBOL(arch_unregister_cpu); |
| 59 | #else | 59 | #else |
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index d1bc04006d16..8106bba41ecb 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include <asm/pgalloc.h> | 46 | #include <asm/pgalloc.h> |
| 47 | #include <asm/sections.h> | 47 | #include <asm/sections.h> |
| 48 | #include <asm/paravirt.h> | 48 | #include <asm/paravirt.h> |
| 49 | #include <asm/setup.h> | ||
| 49 | 50 | ||
| 50 | unsigned int __VMALLOC_RESERVE = 128 << 20; | 51 | unsigned int __VMALLOC_RESERVE = 128 << 20; |
| 51 | 52 | ||
| @@ -328,44 +329,38 @@ pteval_t __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC; | |||
| 328 | 329 | ||
| 329 | void __init native_pagetable_setup_start(pgd_t *base) | 330 | void __init native_pagetable_setup_start(pgd_t *base) |
| 330 | { | 331 | { |
| 331 | #ifdef CONFIG_X86_PAE | 332 | unsigned long pfn, va; |
| 332 | int i; | 333 | pgd_t *pgd; |
| 334 | pud_t *pud; | ||
| 335 | pmd_t *pmd; | ||
| 336 | pte_t *pte; | ||
| 333 | 337 | ||
| 334 | /* | 338 | /* |
| 335 | * Init entries of the first-level page table to the | 339 | * Remove any mappings which extend past the end of physical |
| 336 | * zero page, if they haven't already been set up. | 340 | * memory from the boot time page table: |
| 337 | * | ||
| 338 | * In a normal native boot, we'll be running on a | ||
| 339 | * pagetable rooted in swapper_pg_dir, but not in PAE | ||
| 340 | * mode, so this will end up clobbering the mappings | ||
| 341 | * for the lower 24Mbytes of the address space, | ||
| 342 | * without affecting the kernel address space. | ||
| 343 | */ | 341 | */ |
| 344 | for (i = 0; i < USER_PTRS_PER_PGD; i++) | 342 | for (pfn = max_low_pfn + 1; pfn < 1<<(32-PAGE_SHIFT); pfn++) { |
| 345 | set_pgd(&base[i], | 343 | va = PAGE_OFFSET + (pfn<<PAGE_SHIFT); |
| 346 | __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); | 344 | pgd = base + pgd_index(va); |
| 347 | 345 | if (!pgd_present(*pgd)) | |
| 348 | /* Make sure kernel address space is empty so that a pagetable | 346 | break; |
| 349 | will be allocated for it. */ | 347 | |
| 350 | memset(&base[USER_PTRS_PER_PGD], 0, | 348 | pud = pud_offset(pgd, va); |
| 351 | KERNEL_PGD_PTRS * sizeof(pgd_t)); | 349 | pmd = pmd_offset(pud, va); |
| 352 | #else | 350 | if (!pmd_present(*pmd)) |
| 351 | break; | ||
| 352 | |||
| 353 | pte = pte_offset_kernel(pmd, va); | ||
| 354 | if (!pte_present(*pte)) | ||
| 355 | break; | ||
| 356 | |||
| 357 | pte_clear(NULL, va, pte); | ||
| 358 | } | ||
| 353 | paravirt_alloc_pd(&init_mm, __pa(base) >> PAGE_SHIFT); | 359 | paravirt_alloc_pd(&init_mm, __pa(base) >> PAGE_SHIFT); |
| 354 | #endif | ||
| 355 | } | 360 | } |
| 356 | 361 | ||
| 357 | void __init native_pagetable_setup_done(pgd_t *base) | 362 | void __init native_pagetable_setup_done(pgd_t *base) |
| 358 | { | 363 | { |
| 359 | #ifdef CONFIG_X86_PAE | ||
| 360 | /* | ||
| 361 | * Add low memory identity-mappings - SMP needs it when | ||
| 362 | * starting up on an AP from real-mode. In the non-PAE | ||
| 363 | * case we already have these mappings through head.S. | ||
| 364 | * All user-space mappings are explicitly cleared after | ||
| 365 | * SMP startup. | ||
| 366 | */ | ||
| 367 | set_pgd(&base[0], base[USER_PTRS_PER_PGD]); | ||
| 368 | #endif | ||
| 369 | } | 364 | } |
| 370 | 365 | ||
| 371 | /* | 366 | /* |
| @@ -374,9 +369,8 @@ void __init native_pagetable_setup_done(pgd_t *base) | |||
| 374 | * the boot process. | 369 | * the boot process. |
| 375 | * | 370 | * |
| 376 | * If we're booting on native hardware, this will be a pagetable | 371 | * If we're booting on native hardware, this will be a pagetable |
| 377 | * constructed in arch/i386/kernel/head.S, and not running in PAE mode | 372 | * constructed in arch/x86/kernel/head_32.S. The root of the |
| 378 | * (even if we'll end up running in PAE). The root of the pagetable | 373 | * pagetable will be swapper_pg_dir. |
| 379 | * will be swapper_pg_dir. | ||
| 380 | * | 374 | * |
| 381 | * If we're booting paravirtualized under a hypervisor, then there are | 375 | * If we're booting paravirtualized under a hypervisor, then there are |
| 382 | * more options: we may already be running PAE, and the pagetable may | 376 | * more options: we may already be running PAE, and the pagetable may |
| @@ -537,14 +531,6 @@ void __init paging_init(void) | |||
| 537 | 531 | ||
| 538 | load_cr3(swapper_pg_dir); | 532 | load_cr3(swapper_pg_dir); |
| 539 | 533 | ||
| 540 | #ifdef CONFIG_X86_PAE | ||
| 541 | /* | ||
| 542 | * We will bail out later - printk doesn't work right now so | ||
| 543 | * the user would just see a hanging kernel. | ||
| 544 | */ | ||
| 545 | if (cpu_has_pae) | ||
| 546 | set_in_cr4(X86_CR4_PAE); | ||
| 547 | #endif | ||
| 548 | __flush_tlb_all(); | 534 | __flush_tlb_all(); |
| 549 | 535 | ||
| 550 | kmap_init(); | 536 | kmap_init(); |
| @@ -675,13 +661,11 @@ void __init mem_init(void) | |||
| 675 | BUG_ON((unsigned long)high_memory > VMALLOC_START); | 661 | BUG_ON((unsigned long)high_memory > VMALLOC_START); |
| 676 | #endif /* double-sanity-check paranoia */ | 662 | #endif /* double-sanity-check paranoia */ |
| 677 | 663 | ||
| 678 | #ifdef CONFIG_X86_PAE | ||
| 679 | if (!cpu_has_pae) | ||
| 680 | panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); | ||
| 681 | #endif | ||
| 682 | if (boot_cpu_data.wp_works_ok < 0) | 664 | if (boot_cpu_data.wp_works_ok < 0) |
| 683 | test_wp_bit(); | 665 | test_wp_bit(); |
| 684 | 666 | ||
| 667 | cpa_init(); | ||
| 668 | |||
| 685 | /* | 669 | /* |
| 686 | * Subtle. SMP is doing it's boot stuff late (because it has to | 670 | * Subtle. SMP is doing it's boot stuff late (because it has to |
| 687 | * fork idle threads) - but it also needs low mappings for the | 671 | * fork idle threads) - but it also needs low mappings for the |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 5fe880fc305d..b59fc238151f 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
| @@ -528,13 +528,15 @@ void __init mem_init(void) | |||
| 528 | reservedpages << (PAGE_SHIFT-10), | 528 | reservedpages << (PAGE_SHIFT-10), |
| 529 | datasize >> 10, | 529 | datasize >> 10, |
| 530 | initsize >> 10); | 530 | initsize >> 10); |
| 531 | |||
| 532 | cpa_init(); | ||
| 531 | } | 533 | } |
| 532 | 534 | ||
| 533 | void free_init_pages(char *what, unsigned long begin, unsigned long end) | 535 | void free_init_pages(char *what, unsigned long begin, unsigned long end) |
| 534 | { | 536 | { |
| 535 | unsigned long addr; | 537 | unsigned long addr = begin; |
| 536 | 538 | ||
| 537 | if (begin >= end) | 539 | if (addr >= end) |
| 538 | return; | 540 | return; |
| 539 | 541 | ||
| 540 | /* | 542 | /* |
| @@ -549,7 +551,7 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) | |||
| 549 | #else | 551 | #else |
| 550 | printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); | 552 | printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); |
| 551 | 553 | ||
| 552 | for (addr = begin; addr < end; addr += PAGE_SIZE) { | 554 | for (; addr < end; addr += PAGE_SIZE) { |
| 553 | ClearPageReserved(virt_to_page(addr)); | 555 | ClearPageReserved(virt_to_page(addr)); |
| 554 | init_page_count(virt_to_page(addr)); | 556 | init_page_count(virt_to_page(addr)); |
| 555 | memset((void *)(addr & ~(PAGE_SIZE-1)), | 557 | memset((void *)(addr & ~(PAGE_SIZE-1)), |
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index ee6648fe6b15..a4897a85268a 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
| @@ -260,41 +260,46 @@ static int __init early_ioremap_debug_setup(char *str) | |||
| 260 | early_param("early_ioremap_debug", early_ioremap_debug_setup); | 260 | early_param("early_ioremap_debug", early_ioremap_debug_setup); |
| 261 | 261 | ||
| 262 | static __initdata int after_paging_init; | 262 | static __initdata int after_paging_init; |
| 263 | static __initdata unsigned long bm_pte[1024] | 263 | static __initdata pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)] |
| 264 | __attribute__((aligned(PAGE_SIZE))); | 264 | __attribute__((aligned(PAGE_SIZE))); |
| 265 | 265 | ||
| 266 | static inline unsigned long * __init early_ioremap_pgd(unsigned long addr) | 266 | static inline pmd_t * __init early_ioremap_pmd(unsigned long addr) |
| 267 | { | 267 | { |
| 268 | return (unsigned long *)swapper_pg_dir + ((addr >> 22) & 1023); | 268 | pgd_t *pgd = &swapper_pg_dir[pgd_index(addr)]; |
| 269 | pud_t *pud = pud_offset(pgd, addr); | ||
| 270 | pmd_t *pmd = pmd_offset(pud, addr); | ||
| 271 | |||
| 272 | return pmd; | ||
| 269 | } | 273 | } |
| 270 | 274 | ||
| 271 | static inline unsigned long * __init early_ioremap_pte(unsigned long addr) | 275 | static inline pte_t * __init early_ioremap_pte(unsigned long addr) |
| 272 | { | 276 | { |
| 273 | return bm_pte + ((addr >> PAGE_SHIFT) & 1023); | 277 | return &bm_pte[pte_index(addr)]; |
| 274 | } | 278 | } |
| 275 | 279 | ||
| 276 | void __init early_ioremap_init(void) | 280 | void __init early_ioremap_init(void) |
| 277 | { | 281 | { |
| 278 | unsigned long *pgd; | 282 | pmd_t *pmd; |
| 279 | 283 | ||
| 280 | if (early_ioremap_debug) | 284 | if (early_ioremap_debug) |
| 281 | printk(KERN_INFO "early_ioremap_init()\n"); | 285 | printk(KERN_INFO "early_ioremap_init()\n"); |
| 282 | 286 | ||
| 283 | pgd = early_ioremap_pgd(fix_to_virt(FIX_BTMAP_BEGIN)); | 287 | pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); |
| 284 | *pgd = __pa(bm_pte) | _PAGE_TABLE; | ||
| 285 | memset(bm_pte, 0, sizeof(bm_pte)); | 288 | memset(bm_pte, 0, sizeof(bm_pte)); |
| 289 | pmd_populate_kernel(&init_mm, pmd, bm_pte); | ||
| 290 | |||
| 286 | /* | 291 | /* |
| 287 | * The boot-ioremap range spans multiple pgds, for which | 292 | * The boot-ioremap range spans multiple pmds, for which |
| 288 | * we are not prepared: | 293 | * we are not prepared: |
| 289 | */ | 294 | */ |
| 290 | if (pgd != early_ioremap_pgd(fix_to_virt(FIX_BTMAP_END))) { | 295 | if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) { |
| 291 | WARN_ON(1); | 296 | WARN_ON(1); |
| 292 | printk(KERN_WARNING "pgd %p != %p\n", | 297 | printk(KERN_WARNING "pmd %p != %p\n", |
| 293 | pgd, early_ioremap_pgd(fix_to_virt(FIX_BTMAP_END))); | 298 | pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))); |
| 294 | printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n", | 299 | printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n", |
| 295 | fix_to_virt(FIX_BTMAP_BEGIN)); | 300 | fix_to_virt(FIX_BTMAP_BEGIN)); |
| 296 | printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_END): %08lx\n", | 301 | printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_END): %08lx\n", |
| 297 | fix_to_virt(FIX_BTMAP_END)); | 302 | fix_to_virt(FIX_BTMAP_END)); |
| 298 | 303 | ||
| 299 | printk(KERN_WARNING "FIX_BTMAP_END: %d\n", FIX_BTMAP_END); | 304 | printk(KERN_WARNING "FIX_BTMAP_END: %d\n", FIX_BTMAP_END); |
| 300 | printk(KERN_WARNING "FIX_BTMAP_BEGIN: %d\n", | 305 | printk(KERN_WARNING "FIX_BTMAP_BEGIN: %d\n", |
| @@ -304,28 +309,29 @@ void __init early_ioremap_init(void) | |||
| 304 | 309 | ||
| 305 | void __init early_ioremap_clear(void) | 310 | void __init early_ioremap_clear(void) |
| 306 | { | 311 | { |
| 307 | unsigned long *pgd; | 312 | pmd_t *pmd; |
| 308 | 313 | ||
| 309 | if (early_ioremap_debug) | 314 | if (early_ioremap_debug) |
| 310 | printk(KERN_INFO "early_ioremap_clear()\n"); | 315 | printk(KERN_INFO "early_ioremap_clear()\n"); |
| 311 | 316 | ||
| 312 | pgd = early_ioremap_pgd(fix_to_virt(FIX_BTMAP_BEGIN)); | 317 | pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); |
| 313 | *pgd = 0; | 318 | pmd_clear(pmd); |
| 314 | paravirt_release_pt(__pa(pgd) >> PAGE_SHIFT); | 319 | paravirt_release_pt(__pa(bm_pte) >> PAGE_SHIFT); |
| 315 | __flush_tlb_all(); | 320 | __flush_tlb_all(); |
| 316 | } | 321 | } |
| 317 | 322 | ||
| 318 | void __init early_ioremap_reset(void) | 323 | void __init early_ioremap_reset(void) |
| 319 | { | 324 | { |
| 320 | enum fixed_addresses idx; | 325 | enum fixed_addresses idx; |
| 321 | unsigned long *pte, phys, addr; | 326 | unsigned long addr, phys; |
| 327 | pte_t *pte; | ||
| 322 | 328 | ||
| 323 | after_paging_init = 1; | 329 | after_paging_init = 1; |
| 324 | for (idx = FIX_BTMAP_BEGIN; idx >= FIX_BTMAP_END; idx--) { | 330 | for (idx = FIX_BTMAP_BEGIN; idx >= FIX_BTMAP_END; idx--) { |
| 325 | addr = fix_to_virt(idx); | 331 | addr = fix_to_virt(idx); |
| 326 | pte = early_ioremap_pte(addr); | 332 | pte = early_ioremap_pte(addr); |
| 327 | if (*pte & _PAGE_PRESENT) { | 333 | if (pte_present(*pte)) { |
| 328 | phys = *pte & PAGE_MASK; | 334 | phys = pte_val(*pte) & PAGE_MASK; |
| 329 | set_fixmap(idx, phys); | 335 | set_fixmap(idx, phys); |
| 330 | } | 336 | } |
| 331 | } | 337 | } |
| @@ -334,7 +340,8 @@ void __init early_ioremap_reset(void) | |||
| 334 | static void __init __early_set_fixmap(enum fixed_addresses idx, | 340 | static void __init __early_set_fixmap(enum fixed_addresses idx, |
| 335 | unsigned long phys, pgprot_t flags) | 341 | unsigned long phys, pgprot_t flags) |
| 336 | { | 342 | { |
| 337 | unsigned long *pte, addr = __fix_to_virt(idx); | 343 | unsigned long addr = __fix_to_virt(idx); |
| 344 | pte_t *pte; | ||
| 338 | 345 | ||
| 339 | if (idx >= __end_of_fixed_addresses) { | 346 | if (idx >= __end_of_fixed_addresses) { |
| 340 | BUG(); | 347 | BUG(); |
| @@ -342,9 +349,9 @@ static void __init __early_set_fixmap(enum fixed_addresses idx, | |||
| 342 | } | 349 | } |
| 343 | pte = early_ioremap_pte(addr); | 350 | pte = early_ioremap_pte(addr); |
| 344 | if (pgprot_val(flags)) | 351 | if (pgprot_val(flags)) |
| 345 | *pte = (phys & PAGE_MASK) | pgprot_val(flags); | 352 | set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); |
| 346 | else | 353 | else |
| 347 | *pte = 0; | 354 | pte_clear(NULL, addr, pte); |
| 348 | __flush_tlb_one(addr); | 355 | __flush_tlb_one(addr); |
| 349 | } | 356 | } |
| 350 | 357 | ||
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 8493c855582b..440210a2277d 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
| 9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
| 10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
| 11 | #include <linux/interrupt.h> | ||
| 11 | 12 | ||
| 12 | #include <asm/e820.h> | 13 | #include <asm/e820.h> |
| 13 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
| @@ -191,7 +192,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) | |||
| 191 | * or when the present bit is not set. Otherwise we would return a | 192 | * or when the present bit is not set. Otherwise we would return a |
| 192 | * pointer to a nonexisting mapping. | 193 | * pointer to a nonexisting mapping. |
| 193 | */ | 194 | */ |
| 194 | pte_t *lookup_address(unsigned long address, int *level) | 195 | pte_t *lookup_address(unsigned long address, unsigned int *level) |
| 195 | { | 196 | { |
| 196 | pgd_t *pgd = pgd_offset_k(address); | 197 | pgd_t *pgd = pgd_offset_k(address); |
| 197 | pud_t *pud; | 198 | pud_t *pud; |
| @@ -252,10 +253,11 @@ static int | |||
| 252 | try_preserve_large_page(pte_t *kpte, unsigned long address, | 253 | try_preserve_large_page(pte_t *kpte, unsigned long address, |
| 253 | struct cpa_data *cpa) | 254 | struct cpa_data *cpa) |
| 254 | { | 255 | { |
| 255 | unsigned long nextpage_addr, numpages, pmask, psize, flags; | 256 | unsigned long nextpage_addr, numpages, pmask, psize, flags, addr; |
| 256 | pte_t new_pte, old_pte, *tmp; | 257 | pte_t new_pte, old_pte, *tmp; |
| 257 | pgprot_t old_prot, new_prot; | 258 | pgprot_t old_prot, new_prot; |
| 258 | int level, do_split = 1; | 259 | int i, do_split = 1; |
| 260 | unsigned int level; | ||
| 259 | 261 | ||
| 260 | spin_lock_irqsave(&pgd_lock, flags); | 262 | spin_lock_irqsave(&pgd_lock, flags); |
| 261 | /* | 263 | /* |
| @@ -302,6 +304,19 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 302 | new_prot = static_protections(new_prot, address); | 304 | new_prot = static_protections(new_prot, address); |
| 303 | 305 | ||
| 304 | /* | 306 | /* |
| 307 | * We need to check the full range, whether | ||
| 308 | * static_protection() requires a different pgprot for one of | ||
| 309 | * the pages in the range we try to preserve: | ||
| 310 | */ | ||
| 311 | addr = address + PAGE_SIZE; | ||
| 312 | for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE) { | ||
| 313 | pgprot_t chk_prot = static_protections(new_prot, addr); | ||
| 314 | |||
| 315 | if (pgprot_val(chk_prot) != pgprot_val(new_prot)) | ||
| 316 | goto out_unlock; | ||
| 317 | } | ||
| 318 | |||
| 319 | /* | ||
| 305 | * If there are no changes, return. maxpages has been updated | 320 | * If there are no changes, return. maxpages has been updated |
| 306 | * above: | 321 | * above: |
| 307 | */ | 322 | */ |
| @@ -335,23 +350,103 @@ out_unlock: | |||
| 335 | return do_split; | 350 | return do_split; |
| 336 | } | 351 | } |
| 337 | 352 | ||
| 353 | static LIST_HEAD(page_pool); | ||
| 354 | static unsigned long pool_size, pool_pages, pool_low; | ||
| 355 | static unsigned long pool_used, pool_failed, pool_refill; | ||
| 356 | |||
| 357 | static void cpa_fill_pool(void) | ||
| 358 | { | ||
| 359 | struct page *p; | ||
| 360 | gfp_t gfp = GFP_KERNEL; | ||
| 361 | |||
| 362 | /* Do not allocate from interrupt context */ | ||
| 363 | if (in_irq() || irqs_disabled()) | ||
| 364 | return; | ||
| 365 | /* | ||
| 366 | * Check unlocked. I does not matter when we have one more | ||
| 367 | * page in the pool. The bit lock avoids recursive pool | ||
| 368 | * allocations: | ||
| 369 | */ | ||
| 370 | if (pool_pages >= pool_size || test_and_set_bit_lock(0, &pool_refill)) | ||
| 371 | return; | ||
| 372 | |||
| 373 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 374 | /* | ||
| 375 | * We could do: | ||
| 376 | * gfp = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; | ||
| 377 | * but this fails on !PREEMPT kernels | ||
| 378 | */ | ||
| 379 | gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN; | ||
| 380 | #endif | ||
| 381 | |||
| 382 | while (pool_pages < pool_size) { | ||
| 383 | p = alloc_pages(gfp, 0); | ||
| 384 | if (!p) { | ||
| 385 | pool_failed++; | ||
| 386 | break; | ||
| 387 | } | ||
| 388 | spin_lock_irq(&pgd_lock); | ||
| 389 | list_add(&p->lru, &page_pool); | ||
| 390 | pool_pages++; | ||
| 391 | spin_unlock_irq(&pgd_lock); | ||
| 392 | } | ||
| 393 | clear_bit_unlock(0, &pool_refill); | ||
| 394 | } | ||
| 395 | |||
| 396 | #define SHIFT_MB (20 - PAGE_SHIFT) | ||
| 397 | #define ROUND_MB_GB ((1 << 10) - 1) | ||
| 398 | #define SHIFT_MB_GB 10 | ||
| 399 | #define POOL_PAGES_PER_GB 16 | ||
| 400 | |||
| 401 | void __init cpa_init(void) | ||
| 402 | { | ||
| 403 | struct sysinfo si; | ||
| 404 | unsigned long gb; | ||
| 405 | |||
| 406 | si_meminfo(&si); | ||
| 407 | /* | ||
| 408 | * Calculate the number of pool pages: | ||
| 409 | * | ||
| 410 | * Convert totalram (nr of pages) to MiB and round to the next | ||
| 411 | * GiB. Shift MiB to Gib and multiply the result by | ||
| 412 | * POOL_PAGES_PER_GB: | ||
| 413 | */ | ||
| 414 | gb = ((si.totalram >> SHIFT_MB) + ROUND_MB_GB) >> SHIFT_MB_GB; | ||
| 415 | pool_size = POOL_PAGES_PER_GB * gb; | ||
| 416 | pool_low = pool_size; | ||
| 417 | |||
| 418 | cpa_fill_pool(); | ||
| 419 | printk(KERN_DEBUG | ||
| 420 | "CPA: page pool initialized %lu of %lu pages preallocated\n", | ||
| 421 | pool_pages, pool_size); | ||
| 422 | } | ||
| 423 | |||
| 338 | static int split_large_page(pte_t *kpte, unsigned long address) | 424 | static int split_large_page(pte_t *kpte, unsigned long address) |
| 339 | { | 425 | { |
| 340 | unsigned long flags, pfn, pfninc = 1; | 426 | unsigned long flags, pfn, pfninc = 1; |
| 341 | gfp_t gfp_flags = GFP_KERNEL; | ||
| 342 | unsigned int i, level; | 427 | unsigned int i, level; |
| 343 | pte_t *pbase, *tmp; | 428 | pte_t *pbase, *tmp; |
| 344 | pgprot_t ref_prot; | 429 | pgprot_t ref_prot; |
| 345 | struct page *base; | 430 | struct page *base; |
| 346 | 431 | ||
| 347 | #ifdef CONFIG_DEBUG_PAGEALLOC | 432 | /* |
| 348 | gfp_flags = GFP_ATOMIC | __GFP_NOWARN; | 433 | * Get a page from the pool. The pool list is protected by the |
| 349 | #endif | 434 | * pgd_lock, which we have to take anyway for the split |
| 350 | base = alloc_pages(gfp_flags, 0); | 435 | * operation: |
| 351 | if (!base) | 436 | */ |
| 437 | spin_lock_irqsave(&pgd_lock, flags); | ||
| 438 | if (list_empty(&page_pool)) { | ||
| 439 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
| 352 | return -ENOMEM; | 440 | return -ENOMEM; |
| 441 | } | ||
| 442 | |||
| 443 | base = list_first_entry(&page_pool, struct page, lru); | ||
| 444 | list_del(&base->lru); | ||
| 445 | pool_pages--; | ||
| 446 | |||
| 447 | if (pool_pages < pool_low) | ||
| 448 | pool_low = pool_pages; | ||
| 353 | 449 | ||
| 354 | spin_lock_irqsave(&pgd_lock, flags); | ||
| 355 | /* | 450 | /* |
| 356 | * Check for races, another CPU might have split this page | 451 | * Check for races, another CPU might have split this page |
| 357 | * up for us already: | 452 | * up for us already: |
| @@ -396,17 +491,24 @@ static int split_large_page(pte_t *kpte, unsigned long address) | |||
| 396 | base = NULL; | 491 | base = NULL; |
| 397 | 492 | ||
| 398 | out_unlock: | 493 | out_unlock: |
| 494 | /* | ||
| 495 | * If we dropped out via the lookup_address check under | ||
| 496 | * pgd_lock then stick the page back into the pool: | ||
| 497 | */ | ||
| 498 | if (base) { | ||
| 499 | list_add(&base->lru, &page_pool); | ||
| 500 | pool_pages++; | ||
| 501 | } else | ||
| 502 | pool_used++; | ||
| 399 | spin_unlock_irqrestore(&pgd_lock, flags); | 503 | spin_unlock_irqrestore(&pgd_lock, flags); |
| 400 | 504 | ||
| 401 | if (base) | ||
| 402 | __free_pages(base, 0); | ||
| 403 | |||
| 404 | return 0; | 505 | return 0; |
| 405 | } | 506 | } |
| 406 | 507 | ||
| 407 | static int __change_page_attr(unsigned long address, struct cpa_data *cpa) | 508 | static int __change_page_attr(unsigned long address, struct cpa_data *cpa) |
| 408 | { | 509 | { |
| 409 | int level, do_split, err; | 510 | int do_split, err; |
| 511 | unsigned int level; | ||
| 410 | struct page *kpte_page; | 512 | struct page *kpte_page; |
| 411 | pte_t *kpte; | 513 | pte_t *kpte; |
| 412 | 514 | ||
| @@ -598,7 +700,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, | |||
| 598 | * Check whether we really changed something: | 700 | * Check whether we really changed something: |
| 599 | */ | 701 | */ |
| 600 | if (!cpa.flushtlb) | 702 | if (!cpa.flushtlb) |
| 601 | return ret; | 703 | goto out; |
| 602 | 704 | ||
| 603 | /* | 705 | /* |
| 604 | * No need to flush, when we did not set any of the caching | 706 | * No need to flush, when we did not set any of the caching |
| @@ -617,6 +719,8 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, | |||
| 617 | else | 719 | else |
| 618 | cpa_flush_all(cache); | 720 | cpa_flush_all(cache); |
| 619 | 721 | ||
| 722 | out: | ||
| 723 | cpa_fill_pool(); | ||
| 620 | return ret; | 724 | return ret; |
| 621 | } | 725 | } |
| 622 | 726 | ||
| @@ -770,6 +874,12 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
| 770 | * but that can deadlock->flush only current cpu: | 874 | * but that can deadlock->flush only current cpu: |
| 771 | */ | 875 | */ |
| 772 | __flush_tlb_all(); | 876 | __flush_tlb_all(); |
| 877 | |||
| 878 | /* | ||
| 879 | * Try to refill the page pool here. We can do this only after | ||
| 880 | * the tlb flush. | ||
| 881 | */ | ||
| 882 | cpa_fill_pool(); | ||
| 773 | } | 883 | } |
| 774 | #endif | 884 | #endif |
| 775 | 885 | ||
diff --git a/arch/x86/power/Makefile b/arch/x86/power/Makefile index d764ec950065..9ff4d5b55ad1 100644 --- a/arch/x86/power/Makefile +++ b/arch/x86/power/Makefile | |||
| @@ -1,2 +1,2 @@ | |||
| 1 | obj-$(CONFIG_PM) += cpu.o | 1 | obj-$(CONFIG_PM_SLEEP) += cpu_$(BITS).o |
| 2 | obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o | 2 | obj-$(CONFIG_HIBERNATION) += hibernate_$(BITS).o hibernate_asm_$(BITS).o |
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu_32.c index efcf620d1439..7f9c6da04a4c 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu_32.c | |||
| @@ -40,7 +40,7 @@ static void __save_processor_state(struct saved_context *ctxt) | |||
| 40 | savesegment(ss, ctxt->ss); | 40 | savesegment(ss, ctxt->ss); |
| 41 | 41 | ||
| 42 | /* | 42 | /* |
| 43 | * control registers | 43 | * control registers |
| 44 | */ | 44 | */ |
| 45 | ctxt->cr0 = read_cr0(); | 45 | ctxt->cr0 = read_cr0(); |
| 46 | ctxt->cr2 = read_cr2(); | 46 | ctxt->cr2 = read_cr2(); |
diff --git a/arch/x86/kernel/suspend_64.c b/arch/x86/power/cpu_64.c index 7ac7130022f1..66bdfb591fd8 100644 --- a/arch/x86/kernel/suspend_64.c +++ b/arch/x86/power/cpu_64.c | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Suspend support specific for i386. | 2 | * Suspend and hibernation support for x86-64 |
| 3 | * | 3 | * |
| 4 | * Distribute under GPLv2 | 4 | * Distribute under GPLv2 |
| 5 | * | 5 | * |
| 6 | * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl> | ||
| 6 | * Copyright (c) 2002 Pavel Machek <pavel@suse.cz> | 7 | * Copyright (c) 2002 Pavel Machek <pavel@suse.cz> |
| 7 | * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org> | 8 | * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org> |
| 8 | */ | 9 | */ |
| @@ -14,9 +15,6 @@ | |||
| 14 | #include <asm/pgtable.h> | 15 | #include <asm/pgtable.h> |
| 15 | #include <asm/mtrr.h> | 16 | #include <asm/mtrr.h> |
| 16 | 17 | ||
| 17 | /* References to section boundaries */ | ||
| 18 | extern const void __nosave_begin, __nosave_end; | ||
| 19 | |||
| 20 | static void fix_processor_context(void); | 18 | static void fix_processor_context(void); |
| 21 | 19 | ||
| 22 | struct saved_context saved_context; | 20 | struct saved_context saved_context; |
| @@ -63,7 +61,7 @@ static void __save_processor_state(struct saved_context *ctxt) | |||
| 63 | mtrr_save_fixed_ranges(NULL); | 61 | mtrr_save_fixed_ranges(NULL); |
| 64 | 62 | ||
| 65 | /* | 63 | /* |
| 66 | * control registers | 64 | * control registers |
| 67 | */ | 65 | */ |
| 68 | rdmsrl(MSR_EFER, ctxt->efer); | 66 | rdmsrl(MSR_EFER, ctxt->efer); |
| 69 | ctxt->cr0 = read_cr0(); | 67 | ctxt->cr0 = read_cr0(); |
| @@ -166,155 +164,3 @@ static void fix_processor_context(void) | |||
| 166 | loaddebug(¤t->thread, 7); | 164 | loaddebug(¤t->thread, 7); |
| 167 | } | 165 | } |
| 168 | } | 166 | } |
| 169 | |||
| 170 | #ifdef CONFIG_HIBERNATION | ||
| 171 | /* Defined in arch/x86_64/kernel/suspend_asm.S */ | ||
| 172 | extern int restore_image(void); | ||
| 173 | |||
| 174 | /* | ||
| 175 | * Address to jump to in the last phase of restore in order to get to the image | ||
| 176 | * kernel's text (this value is passed in the image header). | ||
| 177 | */ | ||
| 178 | unsigned long restore_jump_address; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Value of the cr3 register from before the hibernation (this value is passed | ||
| 182 | * in the image header). | ||
| 183 | */ | ||
| 184 | unsigned long restore_cr3; | ||
| 185 | |||
| 186 | pgd_t *temp_level4_pgt; | ||
| 187 | |||
| 188 | void *relocated_restore_code; | ||
| 189 | |||
| 190 | static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) | ||
| 191 | { | ||
| 192 | long i, j; | ||
| 193 | |||
| 194 | i = pud_index(address); | ||
| 195 | pud = pud + i; | ||
| 196 | for (; i < PTRS_PER_PUD; pud++, i++) { | ||
| 197 | unsigned long paddr; | ||
| 198 | pmd_t *pmd; | ||
| 199 | |||
| 200 | paddr = address + i*PUD_SIZE; | ||
| 201 | if (paddr >= end) | ||
| 202 | break; | ||
| 203 | |||
| 204 | pmd = (pmd_t *)get_safe_page(GFP_ATOMIC); | ||
| 205 | if (!pmd) | ||
| 206 | return -ENOMEM; | ||
| 207 | set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); | ||
| 208 | for (j = 0; j < PTRS_PER_PMD; pmd++, j++, paddr += PMD_SIZE) { | ||
| 209 | unsigned long pe; | ||
| 210 | |||
| 211 | if (paddr >= end) | ||
| 212 | break; | ||
| 213 | pe = __PAGE_KERNEL_LARGE_EXEC | paddr; | ||
| 214 | pe &= __supported_pte_mask; | ||
| 215 | set_pmd(pmd, __pmd(pe)); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static int set_up_temporary_mappings(void) | ||
| 222 | { | ||
| 223 | unsigned long start, end, next; | ||
| 224 | int error; | ||
| 225 | |||
| 226 | temp_level4_pgt = (pgd_t *)get_safe_page(GFP_ATOMIC); | ||
| 227 | if (!temp_level4_pgt) | ||
| 228 | return -ENOMEM; | ||
| 229 | |||
| 230 | /* It is safe to reuse the original kernel mapping */ | ||
| 231 | set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map), | ||
| 232 | init_level4_pgt[pgd_index(__START_KERNEL_map)]); | ||
| 233 | |||
| 234 | /* Set up the direct mapping from scratch */ | ||
| 235 | start = (unsigned long)pfn_to_kaddr(0); | ||
| 236 | end = (unsigned long)pfn_to_kaddr(end_pfn); | ||
| 237 | |||
| 238 | for (; start < end; start = next) { | ||
| 239 | pud_t *pud = (pud_t *)get_safe_page(GFP_ATOMIC); | ||
| 240 | if (!pud) | ||
| 241 | return -ENOMEM; | ||
| 242 | next = start + PGDIR_SIZE; | ||
| 243 | if (next > end) | ||
| 244 | next = end; | ||
| 245 | if ((error = res_phys_pud_init(pud, __pa(start), __pa(next)))) | ||
| 246 | return error; | ||
| 247 | set_pgd(temp_level4_pgt + pgd_index(start), | ||
| 248 | mk_kernel_pgd(__pa(pud))); | ||
| 249 | } | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | int swsusp_arch_resume(void) | ||
| 254 | { | ||
| 255 | int error; | ||
| 256 | |||
| 257 | /* We have got enough memory and from now on we cannot recover */ | ||
| 258 | if ((error = set_up_temporary_mappings())) | ||
| 259 | return error; | ||
| 260 | |||
| 261 | relocated_restore_code = (void *)get_safe_page(GFP_ATOMIC); | ||
| 262 | if (!relocated_restore_code) | ||
| 263 | return -ENOMEM; | ||
| 264 | memcpy(relocated_restore_code, &core_restore_code, | ||
| 265 | &restore_registers - &core_restore_code); | ||
| 266 | |||
| 267 | restore_image(); | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* | ||
| 272 | * pfn_is_nosave - check if given pfn is in the 'nosave' section | ||
| 273 | */ | ||
| 274 | |||
| 275 | int pfn_is_nosave(unsigned long pfn) | ||
| 276 | { | ||
| 277 | unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT; | ||
| 278 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT; | ||
| 279 | return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); | ||
| 280 | } | ||
| 281 | |||
| 282 | struct restore_data_record { | ||
| 283 | unsigned long jump_address; | ||
| 284 | unsigned long cr3; | ||
| 285 | unsigned long magic; | ||
| 286 | }; | ||
| 287 | |||
| 288 | #define RESTORE_MAGIC 0x0123456789ABCDEFUL | ||
| 289 | |||
| 290 | /** | ||
| 291 | * arch_hibernation_header_save - populate the architecture specific part | ||
| 292 | * of a hibernation image header | ||
| 293 | * @addr: address to save the data at | ||
| 294 | */ | ||
| 295 | int arch_hibernation_header_save(void *addr, unsigned int max_size) | ||
| 296 | { | ||
| 297 | struct restore_data_record *rdr = addr; | ||
| 298 | |||
| 299 | if (max_size < sizeof(struct restore_data_record)) | ||
| 300 | return -EOVERFLOW; | ||
| 301 | rdr->jump_address = restore_jump_address; | ||
| 302 | rdr->cr3 = restore_cr3; | ||
| 303 | rdr->magic = RESTORE_MAGIC; | ||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | /** | ||
| 308 | * arch_hibernation_header_restore - read the architecture specific data | ||
| 309 | * from the hibernation image header | ||
| 310 | * @addr: address to read the data from | ||
| 311 | */ | ||
| 312 | int arch_hibernation_header_restore(void *addr) | ||
| 313 | { | ||
| 314 | struct restore_data_record *rdr = addr; | ||
| 315 | |||
| 316 | restore_jump_address = rdr->jump_address; | ||
| 317 | restore_cr3 = rdr->cr3; | ||
| 318 | return (rdr->magic == RESTORE_MAGIC) ? 0 : -EINVAL; | ||
| 319 | } | ||
| 320 | #endif /* CONFIG_HIBERNATION */ | ||
diff --git a/arch/x86/power/suspend.c b/arch/x86/power/hibernate_32.c index a0020b913f31..f2b6e3f11bfc 100644 --- a/arch/x86/power/suspend.c +++ b/arch/x86/power/hibernate_32.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Suspend support specific for i386 - temporary page tables | 2 | * Hibernation support specific for i386 - temporary page tables |
| 3 | * | 3 | * |
| 4 | * Distribute under GPLv2 | 4 | * Distribute under GPLv2 |
| 5 | * | 5 | * |
| @@ -13,7 +13,7 @@ | |||
| 13 | #include <asm/page.h> | 13 | #include <asm/page.h> |
| 14 | #include <asm/pgtable.h> | 14 | #include <asm/pgtable.h> |
| 15 | 15 | ||
| 16 | /* Defined in arch/i386/power/swsusp.S */ | 16 | /* Defined in hibernate_asm_32.S */ |
| 17 | extern int restore_image(void); | 17 | extern int restore_image(void); |
| 18 | 18 | ||
| 19 | /* References to section boundaries */ | 19 | /* References to section boundaries */ |
| @@ -23,7 +23,7 @@ extern const void __nosave_begin, __nosave_end; | |||
| 23 | pgd_t *resume_pg_dir; | 23 | pgd_t *resume_pg_dir; |
| 24 | 24 | ||
| 25 | /* The following three functions are based on the analogous code in | 25 | /* The following three functions are based on the analogous code in |
| 26 | * arch/i386/mm/init.c | 26 | * arch/x86/mm/init_32.c |
| 27 | */ | 27 | */ |
| 28 | 28 | ||
| 29 | /* | 29 | /* |
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c new file mode 100644 index 000000000000..b542355e0e34 --- /dev/null +++ b/arch/x86/power/hibernate_64.c | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * Hibernation support for x86-64 | ||
| 3 | * | ||
| 4 | * Distribute under GPLv2 | ||
| 5 | * | ||
| 6 | * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl> | ||
| 7 | * Copyright (c) 2002 Pavel Machek <pavel@suse.cz> | ||
| 8 | * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/smp.h> | ||
| 12 | #include <linux/suspend.h> | ||
| 13 | #include <asm/proto.h> | ||
| 14 | #include <asm/page.h> | ||
| 15 | #include <asm/pgtable.h> | ||
| 16 | #include <asm/mtrr.h> | ||
| 17 | |||
| 18 | /* References to section boundaries */ | ||
| 19 | extern const void __nosave_begin, __nosave_end; | ||
| 20 | |||
| 21 | /* Defined in hibernate_asm_64.S */ | ||
| 22 | extern int restore_image(void); | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Address to jump to in the last phase of restore in order to get to the image | ||
| 26 | * kernel's text (this value is passed in the image header). | ||
| 27 | */ | ||
| 28 | unsigned long restore_jump_address; | ||
| 29 | |||
| 30 | /* | ||
| 31 | * Value of the cr3 register from before the hibernation (this value is passed | ||
| 32 | * in the image header). | ||
| 33 | */ | ||
| 34 | unsigned long restore_cr3; | ||
| 35 | |||
| 36 | pgd_t *temp_level4_pgt; | ||
| 37 | |||
| 38 | void *relocated_restore_code; | ||
| 39 | |||
| 40 | static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) | ||
| 41 | { | ||
| 42 | long i, j; | ||
| 43 | |||
| 44 | i = pud_index(address); | ||
| 45 | pud = pud + i; | ||
| 46 | for (; i < PTRS_PER_PUD; pud++, i++) { | ||
| 47 | unsigned long paddr; | ||
| 48 | pmd_t *pmd; | ||
| 49 | |||
| 50 | paddr = address + i*PUD_SIZE; | ||
| 51 | if (paddr >= end) | ||
| 52 | break; | ||
| 53 | |||
| 54 | pmd = (pmd_t *)get_safe_page(GFP_ATOMIC); | ||
| 55 | if (!pmd) | ||
| 56 | return -ENOMEM; | ||
| 57 | set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); | ||
| 58 | for (j = 0; j < PTRS_PER_PMD; pmd++, j++, paddr += PMD_SIZE) { | ||
| 59 | unsigned long pe; | ||
| 60 | |||
| 61 | if (paddr >= end) | ||
| 62 | break; | ||
| 63 | pe = __PAGE_KERNEL_LARGE_EXEC | paddr; | ||
| 64 | pe &= __supported_pte_mask; | ||
| 65 | set_pmd(pmd, __pmd(pe)); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int set_up_temporary_mappings(void) | ||
| 72 | { | ||
| 73 | unsigned long start, end, next; | ||
| 74 | int error; | ||
| 75 | |||
| 76 | temp_level4_pgt = (pgd_t *)get_safe_page(GFP_ATOMIC); | ||
| 77 | if (!temp_level4_pgt) | ||
| 78 | return -ENOMEM; | ||
| 79 | |||
| 80 | /* It is safe to reuse the original kernel mapping */ | ||
| 81 | set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map), | ||
| 82 | init_level4_pgt[pgd_index(__START_KERNEL_map)]); | ||
| 83 | |||
| 84 | /* Set up the direct mapping from scratch */ | ||
| 85 | start = (unsigned long)pfn_to_kaddr(0); | ||
| 86 | end = (unsigned long)pfn_to_kaddr(end_pfn); | ||
| 87 | |||
| 88 | for (; start < end; start = next) { | ||
| 89 | pud_t *pud = (pud_t *)get_safe_page(GFP_ATOMIC); | ||
| 90 | if (!pud) | ||
| 91 | return -ENOMEM; | ||
| 92 | next = start + PGDIR_SIZE; | ||
| 93 | if (next > end) | ||
| 94 | next = end; | ||
| 95 | if ((error = res_phys_pud_init(pud, __pa(start), __pa(next)))) | ||
| 96 | return error; | ||
| 97 | set_pgd(temp_level4_pgt + pgd_index(start), | ||
| 98 | mk_kernel_pgd(__pa(pud))); | ||
| 99 | } | ||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | int swsusp_arch_resume(void) | ||
| 104 | { | ||
| 105 | int error; | ||
| 106 | |||
| 107 | /* We have got enough memory and from now on we cannot recover */ | ||
| 108 | if ((error = set_up_temporary_mappings())) | ||
| 109 | return error; | ||
| 110 | |||
| 111 | relocated_restore_code = (void *)get_safe_page(GFP_ATOMIC); | ||
| 112 | if (!relocated_restore_code) | ||
| 113 | return -ENOMEM; | ||
| 114 | memcpy(relocated_restore_code, &core_restore_code, | ||
| 115 | &restore_registers - &core_restore_code); | ||
| 116 | |||
| 117 | restore_image(); | ||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | /* | ||
| 122 | * pfn_is_nosave - check if given pfn is in the 'nosave' section | ||
| 123 | */ | ||
| 124 | |||
| 125 | int pfn_is_nosave(unsigned long pfn) | ||
| 126 | { | ||
| 127 | unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT; | ||
| 128 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT; | ||
| 129 | return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); | ||
| 130 | } | ||
| 131 | |||
| 132 | struct restore_data_record { | ||
| 133 | unsigned long jump_address; | ||
| 134 | unsigned long cr3; | ||
| 135 | unsigned long magic; | ||
| 136 | }; | ||
| 137 | |||
| 138 | #define RESTORE_MAGIC 0x0123456789ABCDEFUL | ||
| 139 | |||
| 140 | /** | ||
| 141 | * arch_hibernation_header_save - populate the architecture specific part | ||
| 142 | * of a hibernation image header | ||
| 143 | * @addr: address to save the data at | ||
| 144 | */ | ||
| 145 | int arch_hibernation_header_save(void *addr, unsigned int max_size) | ||
| 146 | { | ||
| 147 | struct restore_data_record *rdr = addr; | ||
| 148 | |||
| 149 | if (max_size < sizeof(struct restore_data_record)) | ||
| 150 | return -EOVERFLOW; | ||
| 151 | rdr->jump_address = restore_jump_address; | ||
| 152 | rdr->cr3 = restore_cr3; | ||
| 153 | rdr->magic = RESTORE_MAGIC; | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 158 | * arch_hibernation_header_restore - read the architecture specific data | ||
| 159 | * from the hibernation image header | ||
| 160 | * @addr: address to read the data from | ||
| 161 | */ | ||
| 162 | int arch_hibernation_header_restore(void *addr) | ||
| 163 | { | ||
| 164 | struct restore_data_record *rdr = addr; | ||
| 165 | |||
| 166 | restore_jump_address = rdr->jump_address; | ||
| 167 | restore_cr3 = rdr->cr3; | ||
| 168 | return (rdr->magic == RESTORE_MAGIC) ? 0 : -EINVAL; | ||
| 169 | } | ||
diff --git a/arch/x86/power/swsusp.S b/arch/x86/power/hibernate_asm_32.S index 53662e05b393..b95aa6cfe3cb 100644 --- a/arch/x86/power/swsusp.S +++ b/arch/x86/power/hibernate_asm_32.S | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | .text | 1 | .text |
| 2 | 2 | ||
| 3 | /* Originally gcc generated, modified by hand | 3 | /* |
| 4 | * | ||
| 5 | * This may not use any stack, nor any variable that is not "NoSave": | 4 | * This may not use any stack, nor any variable that is not "NoSave": |
| 6 | * | 5 | * |
| 7 | * Its rewriting one kernel image with another. What is stack in "old" | 6 | * Its rewriting one kernel image with another. What is stack in "old" |
diff --git a/arch/x86/kernel/suspend_asm_64.S b/arch/x86/power/hibernate_asm_64.S index aeb9a4d7681e..1deb3244b99b 100644 --- a/arch/x86/kernel/suspend_asm_64.S +++ b/arch/x86/power/hibernate_asm_64.S | |||
| @@ -1,7 +1,12 @@ | |||
| 1 | /* Copyright 2004,2005 Pavel Machek <pavel@suse.cz>, Andi Kleen <ak@suse.de>, Rafael J. Wysocki <rjw@sisk.pl> | 1 | /* |
| 2 | * Hibernation support for x86-64 | ||
| 2 | * | 3 | * |
| 3 | * Distribute under GPLv2. | 4 | * Distribute under GPLv2. |
| 4 | * | 5 | * |
| 6 | * Copyright 2007 Rafael J. Wysocki <rjw@sisk.pl> | ||
| 7 | * Copyright 2005 Andi Kleen <ak@suse.de> | ||
| 8 | * Copyright 2004 Pavel Machek <pavel@suse.cz> | ||
| 9 | * | ||
| 5 | * swsusp_arch_resume must not use any stack or any nonlocal variables while | 10 | * swsusp_arch_resume must not use any stack or any nonlocal variables while |
| 6 | * copying pages: | 11 | * copying pages: |
| 7 | * | 12 | * |
| @@ -9,7 +14,7 @@ | |||
| 9 | * image could very well be data page in "new" image, and overwriting | 14 | * image could very well be data page in "new" image, and overwriting |
| 10 | * your own stack under you is bad idea. | 15 | * your own stack under you is bad idea. |
| 11 | */ | 16 | */ |
| 12 | 17 | ||
| 13 | .text | 18 | .text |
| 14 | #include <linux/linkage.h> | 19 | #include <linux/linkage.h> |
| 15 | #include <asm/segment.h> | 20 | #include <asm/segment.h> |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 45aa771e73a9..0144395448ae 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
| @@ -58,7 +58,7 @@ | |||
| 58 | 58 | ||
| 59 | xmaddr_t arbitrary_virt_to_machine(unsigned long address) | 59 | xmaddr_t arbitrary_virt_to_machine(unsigned long address) |
| 60 | { | 60 | { |
| 61 | int level; | 61 | unsigned int level; |
| 62 | pte_t *pte = lookup_address(address, &level); | 62 | pte_t *pte = lookup_address(address, &level); |
| 63 | unsigned offset = address & PAGE_MASK; | 63 | unsigned offset = address & PAGE_MASK; |
| 64 | 64 | ||
| @@ -71,7 +71,7 @@ void make_lowmem_page_readonly(void *vaddr) | |||
| 71 | { | 71 | { |
| 72 | pte_t *pte, ptev; | 72 | pte_t *pte, ptev; |
| 73 | unsigned long address = (unsigned long)vaddr; | 73 | unsigned long address = (unsigned long)vaddr; |
| 74 | int level; | 74 | unsigned int level; |
| 75 | 75 | ||
| 76 | pte = lookup_address(address, &level); | 76 | pte = lookup_address(address, &level); |
| 77 | BUG_ON(pte == NULL); | 77 | BUG_ON(pte == NULL); |
| @@ -86,7 +86,7 @@ void make_lowmem_page_readwrite(void *vaddr) | |||
| 86 | { | 86 | { |
| 87 | pte_t *pte, ptev; | 87 | pte_t *pte, ptev; |
| 88 | unsigned long address = (unsigned long)vaddr; | 88 | unsigned long address = (unsigned long)vaddr; |
| 89 | int level; | 89 | unsigned int level; |
| 90 | 90 | ||
| 91 | pte = lookup_address(address, &level); | 91 | pte = lookup_address(address, &level); |
| 92 | BUG_ON(pte == NULL); | 92 | BUG_ON(pte == NULL); |
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index b3721fd6877b..c39e1a5aa241 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c | |||
| @@ -217,17 +217,17 @@ unsigned long long xen_sched_clock(void) | |||
| 217 | /* Get the CPU speed from Xen */ | 217 | /* Get the CPU speed from Xen */ |
| 218 | unsigned long xen_cpu_khz(void) | 218 | unsigned long xen_cpu_khz(void) |
| 219 | { | 219 | { |
| 220 | u64 cpu_khz = 1000000ULL << 32; | 220 | u64 xen_khz = 1000000ULL << 32; |
| 221 | const struct vcpu_time_info *info = | 221 | const struct vcpu_time_info *info = |
| 222 | &HYPERVISOR_shared_info->vcpu_info[0].time; | 222 | &HYPERVISOR_shared_info->vcpu_info[0].time; |
| 223 | 223 | ||
| 224 | do_div(cpu_khz, info->tsc_to_system_mul); | 224 | do_div(xen_khz, info->tsc_to_system_mul); |
| 225 | if (info->tsc_shift < 0) | 225 | if (info->tsc_shift < 0) |
| 226 | cpu_khz <<= -info->tsc_shift; | 226 | xen_khz <<= -info->tsc_shift; |
| 227 | else | 227 | else |
| 228 | cpu_khz >>= info->tsc_shift; | 228 | xen_khz >>= info->tsc_shift; |
| 229 | 229 | ||
| 230 | return cpu_khz; | 230 | return xen_khz; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | /* | 233 | /* |
