diff options
author | Tejun Heo <tj@kernel.org> | 2009-01-13 06:41:35 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-16 08:20:03 -0500 |
commit | b12d8db8fbfaed1e8222a15333a3645599636854 (patch) | |
tree | 4ae6ce55232885d0707eb464c5b43a54bdfe3ce4 | |
parent | 9939ddaff52787b2a7c1adf1b2afc95421aa0884 (diff) |
x86: make pda a percpu variable
[ Based on original patch from Christoph Lameter and Mike Travis. ]
As pda is now allocated in percpu area, it can easily be made a proper
percpu variable. Make it so by defining per cpu symbol from linker
script and declaring it in C code for SMP and simply defining it for
UP. This change cleans up code and brings SMP and UP closer a bit.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/include/asm/pda.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/head64.c | 10 | ||||
-rw-r--r-- | arch/x86/kernel/head_64.S | 5 | ||||
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 16 | ||||
-rw-r--r-- | arch/x86/kernel/vmlinux_64.lds.S | 4 |
6 files changed, 23 insertions, 20 deletions
diff --git a/arch/x86/include/asm/pda.h b/arch/x86/include/asm/pda.h index e91558e37850..66ae1043393d 100644 --- a/arch/x86/include/asm/pda.h +++ b/arch/x86/include/asm/pda.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/cache.h> | 7 | #include <linux/cache.h> |
8 | #include <linux/threads.h> | 8 | #include <linux/threads.h> |
9 | #include <asm/page.h> | 9 | #include <asm/page.h> |
10 | #include <asm/percpu.h> | ||
10 | 11 | ||
11 | /* Per processor datastructure. %gs points to it while the kernel runs */ | 12 | /* Per processor datastructure. %gs points to it while the kernel runs */ |
12 | struct x8664_pda { | 13 | struct x8664_pda { |
@@ -39,10 +40,10 @@ struct x8664_pda { | |||
39 | unsigned irq_spurious_count; | 40 | unsigned irq_spurious_count; |
40 | } ____cacheline_aligned_in_smp; | 41 | } ____cacheline_aligned_in_smp; |
41 | 42 | ||
42 | extern struct x8664_pda *_cpu_pda[NR_CPUS]; | 43 | DECLARE_PER_CPU(struct x8664_pda, __pda); |
43 | extern void pda_init(int); | 44 | extern void pda_init(int); |
44 | 45 | ||
45 | #define cpu_pda(i) (_cpu_pda[i]) | 46 | #define cpu_pda(cpu) (&per_cpu(__pda, cpu)) |
46 | 47 | ||
47 | /* | 48 | /* |
48 | * There is no fast way to get the base address of the PDA, all the accesses | 49 | * There is no fast way to get the base address of the PDA, all the accesses |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 7041acdf5579..c49498d40830 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -879,9 +879,6 @@ static __init int setup_disablecpuid(char *arg) | |||
879 | __setup("clearcpuid=", setup_disablecpuid); | 879 | __setup("clearcpuid=", setup_disablecpuid); |
880 | 880 | ||
881 | #ifdef CONFIG_X86_64 | 881 | #ifdef CONFIG_X86_64 |
882 | struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly; | ||
883 | EXPORT_SYMBOL(_cpu_pda); | ||
884 | |||
885 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; | 882 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; |
886 | 883 | ||
887 | static char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; | 884 | static char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; |
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index e99b661a97f4..71b6f6ec96a2 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c | |||
@@ -26,18 +26,8 @@ | |||
26 | #include <asm/bios_ebda.h> | 26 | #include <asm/bios_ebda.h> |
27 | #include <asm/trampoline.h> | 27 | #include <asm/trampoline.h> |
28 | 28 | ||
29 | #ifndef CONFIG_SMP | ||
30 | /* boot cpu pda, referenced by head_64.S to initialize %gs on UP */ | ||
31 | struct x8664_pda _boot_cpu_pda; | ||
32 | #endif | ||
33 | |||
34 | void __init x86_64_init_pda(void) | 29 | void __init x86_64_init_pda(void) |
35 | { | 30 | { |
36 | #ifdef CONFIG_SMP | ||
37 | cpu_pda(0) = (void *)__per_cpu_load; | ||
38 | #else | ||
39 | cpu_pda(0) = &_boot_cpu_pda; | ||
40 | #endif | ||
41 | pda_init(0); | 31 | pda_init(0); |
42 | } | 32 | } |
43 | 33 | ||
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 7a995d0e9f78..c8ace880661b 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/msr.h> | 19 | #include <asm/msr.h> |
20 | #include <asm/cache.h> | 20 | #include <asm/cache.h> |
21 | #include <asm/processor-flags.h> | 21 | #include <asm/processor-flags.h> |
22 | #include <asm/percpu.h> | ||
22 | 23 | ||
23 | #ifdef CONFIG_PARAVIRT | 24 | #ifdef CONFIG_PARAVIRT |
24 | #include <asm/asm-offsets.h> | 25 | #include <asm/asm-offsets.h> |
@@ -250,7 +251,7 @@ ENTRY(secondary_startup_64) | |||
250 | * secondary CPU,initial_gs should be set to its pda address | 251 | * secondary CPU,initial_gs should be set to its pda address |
251 | * before the CPU runs this code. | 252 | * before the CPU runs this code. |
252 | * | 253 | * |
253 | * On UP, initial_gs points to _boot_cpu_pda and doesn't | 254 | * On UP, initial_gs points to PER_CPU_VAR(__pda) and doesn't |
254 | * change. | 255 | * change. |
255 | */ | 256 | */ |
256 | movl $MSR_GS_BASE,%ecx | 257 | movl $MSR_GS_BASE,%ecx |
@@ -284,7 +285,7 @@ ENTRY(secondary_startup_64) | |||
284 | #ifdef CONFIG_SMP | 285 | #ifdef CONFIG_SMP |
285 | .quad __per_cpu_load | 286 | .quad __per_cpu_load |
286 | #else | 287 | #else |
287 | .quad _boot_cpu_pda | 288 | .quad PER_CPU_VAR(__pda) |
288 | #endif | 289 | #endif |
289 | __FINITDATA | 290 | __FINITDATA |
290 | 291 | ||
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index be1ff34db112..daeedf82c15f 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -66,6 +66,16 @@ static void __init setup_node_to_cpumask_map(void); | |||
66 | static inline void setup_node_to_cpumask_map(void) { } | 66 | static inline void setup_node_to_cpumask_map(void) { } |
67 | #endif | 67 | #endif |
68 | 68 | ||
69 | /* | ||
70 | * Define load_pda_offset() and per-cpu __pda for x86_64. | ||
71 | * load_pda_offset() is responsible for loading the offset of pda into | ||
72 | * %gs. | ||
73 | * | ||
74 | * On SMP, pda offset also duals as percpu base address and thus it | ||
75 | * should be at the start of per-cpu area. To achieve this, it's | ||
76 | * preallocated in vmlinux_64.lds.S directly instead of using | ||
77 | * DEFINE_PER_CPU(). | ||
78 | */ | ||
69 | #ifdef CONFIG_X86_64 | 79 | #ifdef CONFIG_X86_64 |
70 | void __cpuinit load_pda_offset(int cpu) | 80 | void __cpuinit load_pda_offset(int cpu) |
71 | { | 81 | { |
@@ -74,6 +84,10 @@ void __cpuinit load_pda_offset(int cpu) | |||
74 | wrmsrl(MSR_GS_BASE, cpu_pda(cpu)); | 84 | wrmsrl(MSR_GS_BASE, cpu_pda(cpu)); |
75 | mb(); | 85 | mb(); |
76 | } | 86 | } |
87 | #ifndef CONFIG_SMP | ||
88 | DEFINE_PER_CPU(struct x8664_pda, __pda); | ||
89 | EXPORT_PER_CPU_SYMBOL(__pda); | ||
90 | #endif | ||
77 | 91 | ||
78 | #endif /* CONFIG_SMP && CONFIG_X86_64 */ | 92 | #endif /* CONFIG_SMP && CONFIG_X86_64 */ |
79 | 93 | ||
@@ -180,8 +194,6 @@ void __init setup_per_cpu_areas(void) | |||
180 | memcpy(ptr, __per_cpu_load, __per_cpu_end - __per_cpu_start); | 194 | memcpy(ptr, __per_cpu_load, __per_cpu_end - __per_cpu_start); |
181 | per_cpu_offset(cpu) = ptr - __per_cpu_start; | 195 | per_cpu_offset(cpu) = ptr - __per_cpu_start; |
182 | #ifdef CONFIG_X86_64 | 196 | #ifdef CONFIG_X86_64 |
183 | cpu_pda(cpu) = (void *)ptr; | ||
184 | |||
185 | /* | 197 | /* |
186 | * CPU0 modified pda in the init data area, reload pda | 198 | * CPU0 modified pda in the init data area, reload pda |
187 | * offset for CPU0 and clear the area for others. | 199 | * offset for CPU0 and clear the area for others. |
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S index 962f21f1d4d7..d2a0baa87d1b 100644 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ b/arch/x86/kernel/vmlinux_64.lds.S | |||
@@ -217,10 +217,12 @@ SECTIONS | |||
217 | * percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the | 217 | * percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the |
218 | * output PHDR, so the next output section - __data_nosave - should | 218 | * output PHDR, so the next output section - __data_nosave - should |
219 | * switch it back to data.init. Also, pda should be at the head of | 219 | * switch it back to data.init. Also, pda should be at the head of |
220 | * percpu area. Preallocate it. | 220 | * percpu area. Preallocate it and define the percpu offset symbol |
221 | * so that it can be accessed as a percpu variable. | ||
221 | */ | 222 | */ |
222 | . = ALIGN(PAGE_SIZE); | 223 | . = ALIGN(PAGE_SIZE); |
223 | PERCPU_VADDR_PREALLOC(0, :percpu, pda_size) | 224 | PERCPU_VADDR_PREALLOC(0, :percpu, pda_size) |
225 | per_cpu____pda = __per_cpu_start; | ||
224 | #else | 226 | #else |
225 | PERCPU(PAGE_SIZE) | 227 | PERCPU(PAGE_SIZE) |
226 | #endif | 228 | #endif |