diff options
Diffstat (limited to 'arch/x86/kernel/cpu/common.c')
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 145 |
1 files changed, 67 insertions, 78 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 83492b1f93b..0f73ea42308 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -21,14 +21,16 @@ | |||
21 | #include <asm/asm.h> | 21 | #include <asm/asm.h> |
22 | #include <asm/numa.h> | 22 | #include <asm/numa.h> |
23 | #include <asm/smp.h> | 23 | #include <asm/smp.h> |
24 | #include <asm/cpu.h> | ||
25 | #include <asm/cpumask.h> | ||
24 | #ifdef CONFIG_X86_LOCAL_APIC | 26 | #ifdef CONFIG_X86_LOCAL_APIC |
25 | #include <asm/mpspec.h> | 27 | #include <asm/mpspec.h> |
26 | #include <asm/apic.h> | 28 | #include <asm/apic.h> |
27 | #include <mach_apic.h> | 29 | #include <mach_apic.h> |
28 | #include <asm/genapic.h> | 30 | #include <asm/genapic.h> |
31 | #include <asm/uv/uv.h> | ||
29 | #endif | 32 | #endif |
30 | 33 | ||
31 | #include <asm/pda.h> | ||
32 | #include <asm/pgtable.h> | 34 | #include <asm/pgtable.h> |
33 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
34 | #include <asm/desc.h> | 36 | #include <asm/desc.h> |
@@ -50,6 +52,15 @@ cpumask_var_t cpu_initialized_mask; | |||
50 | /* representing cpus for which sibling maps can be computed */ | 52 | /* representing cpus for which sibling maps can be computed */ |
51 | cpumask_var_t cpu_sibling_setup_mask; | 53 | cpumask_var_t cpu_sibling_setup_mask; |
52 | 54 | ||
55 | /* correctly size the local cpu masks */ | ||
56 | void __init setup_cpu_local_masks(void) | ||
57 | { | ||
58 | alloc_bootmem_cpumask_var(&cpu_initialized_mask); | ||
59 | alloc_bootmem_cpumask_var(&cpu_callin_mask); | ||
60 | alloc_bootmem_cpumask_var(&cpu_callout_mask); | ||
61 | alloc_bootmem_cpumask_var(&cpu_sibling_setup_mask); | ||
62 | } | ||
63 | |||
53 | #else /* CONFIG_X86_32 */ | 64 | #else /* CONFIG_X86_32 */ |
54 | 65 | ||
55 | cpumask_t cpu_callin_map; | 66 | cpumask_t cpu_callin_map; |
@@ -62,23 +73,23 @@ cpumask_t cpu_sibling_setup_map; | |||
62 | 73 | ||
63 | static struct cpu_dev *this_cpu __cpuinitdata; | 74 | static struct cpu_dev *this_cpu __cpuinitdata; |
64 | 75 | ||
76 | DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { | ||
65 | #ifdef CONFIG_X86_64 | 77 | #ifdef CONFIG_X86_64 |
66 | /* We need valid kernel segments for data and code in long mode too | 78 | /* |
67 | * IRET will check the segment types kkeil 2000/10/28 | 79 | * We need valid kernel segments for data and code in long mode too |
68 | * Also sysret mandates a special GDT layout | 80 | * IRET will check the segment types kkeil 2000/10/28 |
69 | */ | 81 | * Also sysret mandates a special GDT layout |
70 | /* The TLS descriptors are currently at a different place compared to i386. | 82 | * |
71 | Hopefully nobody expects them at a fixed place (Wine?) */ | 83 | * The TLS descriptors are currently at a different place compared to i386. |
72 | DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { | 84 | * Hopefully nobody expects them at a fixed place (Wine?) |
85 | */ | ||
73 | [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } }, | 86 | [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } }, |
74 | [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } }, | 87 | [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } }, |
75 | [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } }, | 88 | [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } }, |
76 | [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } }, | 89 | [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } }, |
77 | [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } }, | 90 | [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } }, |
78 | [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } }, | 91 | [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } }, |
79 | } }; | ||
80 | #else | 92 | #else |
81 | DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { | ||
82 | [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } }, | 93 | [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } }, |
83 | [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } }, | 94 | [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } }, |
84 | [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } }, | 95 | [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } }, |
@@ -110,9 +121,9 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { | |||
110 | [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } }, | 121 | [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } }, |
111 | 122 | ||
112 | [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } }, | 123 | [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } }, |
113 | [GDT_ENTRY_PERCPU] = { { { 0x00000000, 0x00000000 } } }, | 124 | [GDT_ENTRY_PERCPU] = { { { 0x0000ffff, 0x00cf9200 } } }, |
114 | } }; | ||
115 | #endif | 125 | #endif |
126 | } }; | ||
116 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); | 127 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); |
117 | 128 | ||
118 | #ifdef CONFIG_X86_32 | 129 | #ifdef CONFIG_X86_32 |
@@ -242,18 +253,28 @@ static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c) | |||
242 | 253 | ||
243 | __u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata; | 254 | __u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata; |
244 | 255 | ||
256 | void load_percpu_segment(int cpu) | ||
257 | { | ||
258 | #ifdef CONFIG_X86_32 | ||
259 | loadsegment(fs, __KERNEL_PERCPU); | ||
260 | #else | ||
261 | loadsegment(gs, 0); | ||
262 | wrmsrl(MSR_GS_BASE, (unsigned long)per_cpu(irq_stack_union.gs_base, cpu)); | ||
263 | #endif | ||
264 | } | ||
265 | |||
245 | /* Current gdt points %fs at the "master" per-cpu area: after this, | 266 | /* Current gdt points %fs at the "master" per-cpu area: after this, |
246 | * it's on the real one. */ | 267 | * it's on the real one. */ |
247 | void switch_to_new_gdt(void) | 268 | void switch_to_new_gdt(int cpu) |
248 | { | 269 | { |
249 | struct desc_ptr gdt_descr; | 270 | struct desc_ptr gdt_descr; |
250 | 271 | ||
251 | gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id()); | 272 | gdt_descr.address = (long)get_cpu_gdt_table(cpu); |
252 | gdt_descr.size = GDT_SIZE - 1; | 273 | gdt_descr.size = GDT_SIZE - 1; |
253 | load_gdt(&gdt_descr); | 274 | load_gdt(&gdt_descr); |
254 | #ifdef CONFIG_X86_32 | 275 | /* Reload the per-cpu base */ |
255 | asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory"); | 276 | |
256 | #endif | 277 | load_percpu_segment(cpu); |
257 | } | 278 | } |
258 | 279 | ||
259 | static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {}; | 280 | static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {}; |
@@ -877,54 +898,26 @@ static __init int setup_disablecpuid(char *arg) | |||
877 | __setup("clearcpuid=", setup_disablecpuid); | 898 | __setup("clearcpuid=", setup_disablecpuid); |
878 | 899 | ||
879 | #ifdef CONFIG_X86_64 | 900 | #ifdef CONFIG_X86_64 |
880 | struct x8664_pda **_cpu_pda __read_mostly; | ||
881 | EXPORT_SYMBOL(_cpu_pda); | ||
882 | |||
883 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; | 901 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; |
884 | 902 | ||
885 | static char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; | 903 | DEFINE_PER_CPU_FIRST(union irq_stack_union, |
904 | irq_stack_union) __aligned(PAGE_SIZE); | ||
905 | #ifdef CONFIG_SMP | ||
906 | DEFINE_PER_CPU(char *, irq_stack_ptr); /* will be set during per cpu init */ | ||
907 | #else | ||
908 | DEFINE_PER_CPU(char *, irq_stack_ptr) = | ||
909 | per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64; | ||
910 | #endif | ||
886 | 911 | ||
887 | void __cpuinit pda_init(int cpu) | 912 | DEFINE_PER_CPU(unsigned long, kernel_stack) = |
888 | { | 913 | (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE; |
889 | struct x8664_pda *pda = cpu_pda(cpu); | 914 | EXPORT_PER_CPU_SYMBOL(kernel_stack); |
890 | 915 | ||
891 | /* Setup up data that may be needed in __get_free_pages early */ | 916 | DEFINE_PER_CPU(unsigned int, irq_count) = -1; |
892 | loadsegment(fs, 0); | ||
893 | loadsegment(gs, 0); | ||
894 | /* Memory clobbers used to order PDA accessed */ | ||
895 | mb(); | ||
896 | wrmsrl(MSR_GS_BASE, pda); | ||
897 | mb(); | ||
898 | |||
899 | pda->cpunumber = cpu; | ||
900 | pda->irqcount = -1; | ||
901 | pda->kernelstack = (unsigned long)stack_thread_info() - | ||
902 | PDA_STACKOFFSET + THREAD_SIZE; | ||
903 | pda->active_mm = &init_mm; | ||
904 | pda->mmu_state = 0; | ||
905 | |||
906 | if (cpu == 0) { | ||
907 | /* others are initialized in smpboot.c */ | ||
908 | pda->pcurrent = &init_task; | ||
909 | pda->irqstackptr = boot_cpu_stack; | ||
910 | pda->irqstackptr += IRQSTACKSIZE - 64; | ||
911 | } else { | ||
912 | if (!pda->irqstackptr) { | ||
913 | pda->irqstackptr = (char *) | ||
914 | __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER); | ||
915 | if (!pda->irqstackptr) | ||
916 | panic("cannot allocate irqstack for cpu %d", | ||
917 | cpu); | ||
918 | pda->irqstackptr += IRQSTACKSIZE - 64; | ||
919 | } | ||
920 | 917 | ||
921 | if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE) | 918 | static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks |
922 | pda->nodenumber = cpu_to_node(cpu); | 919 | [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]) |
923 | } | 920 | __aligned(PAGE_SIZE); |
924 | } | ||
925 | |||
926 | static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + | ||
927 | DEBUG_STKSZ] __page_aligned_bss; | ||
928 | 921 | ||
929 | extern asmlinkage void ignore_sysret(void); | 922 | extern asmlinkage void ignore_sysret(void); |
930 | 923 | ||
@@ -982,15 +975,14 @@ void __cpuinit cpu_init(void) | |||
982 | struct tss_struct *t = &per_cpu(init_tss, cpu); | 975 | struct tss_struct *t = &per_cpu(init_tss, cpu); |
983 | struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu); | 976 | struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu); |
984 | unsigned long v; | 977 | unsigned long v; |
985 | char *estacks = NULL; | ||
986 | struct task_struct *me; | 978 | struct task_struct *me; |
987 | int i; | 979 | int i; |
988 | 980 | ||
989 | /* CPU 0 is initialised in head64.c */ | 981 | #ifdef CONFIG_NUMA |
990 | if (cpu != 0) | 982 | if (cpu != 0 && percpu_read(node_number) == 0 && |
991 | pda_init(cpu); | 983 | cpu_to_node(cpu) != NUMA_NO_NODE) |
992 | else | 984 | percpu_write(node_number, cpu_to_node(cpu)); |
993 | estacks = boot_exception_stacks; | 985 | #endif |
994 | 986 | ||
995 | me = current; | 987 | me = current; |
996 | 988 | ||
@@ -1006,7 +998,9 @@ void __cpuinit cpu_init(void) | |||
1006 | * and set up the GDT descriptor: | 998 | * and set up the GDT descriptor: |
1007 | */ | 999 | */ |
1008 | 1000 | ||
1009 | switch_to_new_gdt(); | 1001 | switch_to_new_gdt(cpu); |
1002 | loadsegment(fs, 0); | ||
1003 | |||
1010 | load_idt((const struct desc_ptr *)&idt_descr); | 1004 | load_idt((const struct desc_ptr *)&idt_descr); |
1011 | 1005 | ||
1012 | memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8); | 1006 | memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8); |
@@ -1024,18 +1018,13 @@ void __cpuinit cpu_init(void) | |||
1024 | * set up and load the per-CPU TSS | 1018 | * set up and load the per-CPU TSS |
1025 | */ | 1019 | */ |
1026 | if (!orig_ist->ist[0]) { | 1020 | if (!orig_ist->ist[0]) { |
1027 | static const unsigned int order[N_EXCEPTION_STACKS] = { | 1021 | static const unsigned int sizes[N_EXCEPTION_STACKS] = { |
1028 | [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, | 1022 | [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ, |
1029 | [DEBUG_STACK - 1] = DEBUG_STACK_ORDER | 1023 | [DEBUG_STACK - 1] = DEBUG_STKSZ |
1030 | }; | 1024 | }; |
1025 | char *estacks = per_cpu(exception_stacks, cpu); | ||
1031 | for (v = 0; v < N_EXCEPTION_STACKS; v++) { | 1026 | for (v = 0; v < N_EXCEPTION_STACKS; v++) { |
1032 | if (cpu) { | 1027 | estacks += sizes[v]; |
1033 | estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); | ||
1034 | if (!estacks) | ||
1035 | panic("Cannot allocate exception " | ||
1036 | "stack %ld %d\n", v, cpu); | ||
1037 | } | ||
1038 | estacks += PAGE_SIZE << order[v]; | ||
1039 | orig_ist->ist[v] = t->x86_tss.ist[v] = | 1028 | orig_ist->ist[v] = t->x86_tss.ist[v] = |
1040 | (unsigned long)estacks; | 1029 | (unsigned long)estacks; |
1041 | } | 1030 | } |
@@ -1114,7 +1103,7 @@ void __cpuinit cpu_init(void) | |||
1114 | clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); | 1103 | clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); |
1115 | 1104 | ||
1116 | load_idt(&idt_descr); | 1105 | load_idt(&idt_descr); |
1117 | switch_to_new_gdt(); | 1106 | switch_to_new_gdt(cpu); |
1118 | 1107 | ||
1119 | /* | 1108 | /* |
1120 | * Set up and load the per-CPU TSS and LDT | 1109 | * Set up and load the per-CPU TSS and LDT |