diff options
author | Tejun Heo <tj@kernel.org> | 2009-06-24 02:13:52 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2009-06-24 02:13:52 -0400 |
commit | 9b7dbc7dc0365a943af2d73b1376a6f0aac5dc0d (patch) | |
tree | 324bef0a494e20f415b8fb892fe9240fba638156 /arch/alpha | |
parent | 6088464cf1ae9fb3d2ccc0ec5feb3f5b971098d8 (diff) |
alpha: switch to dynamic percpu allocator
Alpha implements custom SHIFT_PERCPU_PTR for modules because percpu
area can be located far away from the 4G area where the module text is
located. The custom SHIFT_PERCPU_PTR forces GOT usage using ldq
instruction with literal relocation; however, the relocation can't be
used with dynamically allocated percpu variables. Fortunately,
similar result can be achieved by using weak percpu variable
definitions.
This patch makes alpha use weak definitions and switch to dynamic
percpu allocator.
asm/tlbflush.h was getting linux/sched.h via asm/percpu.h which no
longer needs it. Include linux/sched.h directly in asm/tlbflush.h.
Compile tested. Generation of litereal relocation verified.
This patch is based on Ivan Kokshaysky's alpha percpu patch.
[ Impact: use dynamic percpu allocator ]
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'arch/alpha')
-rw-r--r-- | arch/alpha/Kconfig | 3 | ||||
-rw-r--r-- | arch/alpha/include/asm/percpu.h | 95 | ||||
-rw-r--r-- | arch/alpha/include/asm/tlbflush.h | 1 |
3 files changed, 9 insertions, 90 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 05d86407188c..9fb8aae5c391 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig | |||
@@ -70,9 +70,6 @@ config AUTO_IRQ_AFFINITY | |||
70 | depends on SMP | 70 | depends on SMP |
71 | default y | 71 | default y |
72 | 72 | ||
73 | config HAVE_LEGACY_PER_CPU_AREA | ||
74 | def_bool y | ||
75 | |||
76 | source "init/Kconfig" | 73 | source "init/Kconfig" |
77 | source "kernel/Kconfig.freezer" | 74 | source "kernel/Kconfig.freezer" |
78 | 75 | ||
diff --git a/arch/alpha/include/asm/percpu.h b/arch/alpha/include/asm/percpu.h index 7f0a9c4f2fd0..2c12378e3aa9 100644 --- a/arch/alpha/include/asm/percpu.h +++ b/arch/alpha/include/asm/percpu.h | |||
@@ -1,97 +1,18 @@ | |||
1 | #ifndef __ALPHA_PERCPU_H | 1 | #ifndef __ALPHA_PERCPU_H |
2 | #define __ALPHA_PERCPU_H | 2 | #define __ALPHA_PERCPU_H |
3 | 3 | ||
4 | #include <linux/compiler.h> | ||
5 | #include <linux/threads.h> | ||
6 | #include <linux/percpu-defs.h> | ||
7 | |||
8 | /* | 4 | /* |
9 | * Determine the real variable name from the name visible in the | 5 | * To calculate addresses of locally defined variables, GCC uses |
10 | * kernel sources. | 6 | * 32-bit displacement from the GP. Which doesn't work for per cpu |
11 | */ | 7 | * variables in modules, as an offset to the kernel per cpu area is |
12 | #define per_cpu_var(var) per_cpu__##var | 8 | * way above 4G. |
13 | |||
14 | #ifdef CONFIG_SMP | ||
15 | |||
16 | /* | ||
17 | * per_cpu_offset() is the offset that has to be added to a | ||
18 | * percpu variable to get to the instance for a certain processor. | ||
19 | */ | ||
20 | extern unsigned long __per_cpu_offset[NR_CPUS]; | ||
21 | |||
22 | #define per_cpu_offset(x) (__per_cpu_offset[x]) | ||
23 | |||
24 | #define __my_cpu_offset per_cpu_offset(raw_smp_processor_id()) | ||
25 | #ifdef CONFIG_DEBUG_PREEMPT | ||
26 | #define my_cpu_offset per_cpu_offset(smp_processor_id()) | ||
27 | #else | ||
28 | #define my_cpu_offset __my_cpu_offset | ||
29 | #endif | ||
30 | |||
31 | #ifndef MODULE | ||
32 | #define SHIFT_PERCPU_PTR(var, offset) RELOC_HIDE(&per_cpu_var(var), (offset)) | ||
33 | #else | ||
34 | /* | ||
35 | * To calculate addresses of locally defined variables, GCC uses 32-bit | ||
36 | * displacement from the GP. Which doesn't work for per cpu variables in | ||
37 | * modules, as an offset to the kernel per cpu area is way above 4G. | ||
38 | * | 9 | * |
39 | * This forces allocation of a GOT entry for per cpu variable using | 10 | * Always use weak definitions for percpu variables in modules. |
40 | * ldq instruction with a 'literal' relocation. | ||
41 | */ | ||
42 | #define SHIFT_PERCPU_PTR(var, offset) ({ \ | ||
43 | extern int simple_identifier_##var(void); \ | ||
44 | unsigned long __ptr, tmp_gp; \ | ||
45 | asm ( "br %1, 1f \n\ | ||
46 | 1: ldgp %1, 0(%1) \n\ | ||
47 | ldq %0, per_cpu__" #var"(%1)\t!literal" \ | ||
48 | : "=&r"(__ptr), "=&r"(tmp_gp)); \ | ||
49 | (typeof(&per_cpu_var(var)))(__ptr + (offset)); }) | ||
50 | |||
51 | #endif /* MODULE */ | ||
52 | |||
53 | /* | ||
54 | * A percpu variable may point to a discarded regions. The following are | ||
55 | * established ways to produce a usable pointer from the percpu variable | ||
56 | * offset. | ||
57 | */ | 11 | */ |
58 | #define per_cpu(var, cpu) \ | 12 | #if defined(MODULE) && defined(CONFIG_SMP) |
59 | (*SHIFT_PERCPU_PTR(var, per_cpu_offset(cpu))) | 13 | #define ARCH_NEEDS_WEAK_PER_CPU |
60 | #define __get_cpu_var(var) \ | ||
61 | (*SHIFT_PERCPU_PTR(var, my_cpu_offset)) | ||
62 | #define __raw_get_cpu_var(var) \ | ||
63 | (*SHIFT_PERCPU_PTR(var, __my_cpu_offset)) | ||
64 | |||
65 | #else /* ! SMP */ | ||
66 | |||
67 | #define per_cpu(var, cpu) (*((void)(cpu), &per_cpu_var(var))) | ||
68 | #define __get_cpu_var(var) per_cpu_var(var) | ||
69 | #define __raw_get_cpu_var(var) per_cpu_var(var) | ||
70 | |||
71 | #endif /* SMP */ | ||
72 | |||
73 | #ifdef CONFIG_SMP | ||
74 | #define PER_CPU_BASE_SECTION ".data.percpu" | ||
75 | #else | ||
76 | #define PER_CPU_BASE_SECTION ".data" | ||
77 | #endif | ||
78 | |||
79 | #ifdef CONFIG_SMP | ||
80 | |||
81 | #ifdef MODULE | ||
82 | #define PER_CPU_SHARED_ALIGNED_SECTION "" | ||
83 | #else | ||
84 | #define PER_CPU_SHARED_ALIGNED_SECTION ".shared_aligned" | ||
85 | #endif | ||
86 | #define PER_CPU_FIRST_SECTION ".first" | ||
87 | |||
88 | #else | ||
89 | |||
90 | #define PER_CPU_SHARED_ALIGNED_SECTION "" | ||
91 | #define PER_CPU_FIRST_SECTION "" | ||
92 | |||
93 | #endif | 14 | #endif |
94 | 15 | ||
95 | #define PER_CPU_ATTRIBUTES | 16 | #include <asm-generic/percpu.h> |
96 | 17 | ||
97 | #endif /* __ALPHA_PERCPU_H */ | 18 | #endif /* __ALPHA_PERCPU_H */ |
diff --git a/arch/alpha/include/asm/tlbflush.h b/arch/alpha/include/asm/tlbflush.h index 9d87aaa08c0d..e89e0c2e15b1 100644 --- a/arch/alpha/include/asm/tlbflush.h +++ b/arch/alpha/include/asm/tlbflush.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _ALPHA_TLBFLUSH_H | 2 | #define _ALPHA_TLBFLUSH_H |
3 | 3 | ||
4 | #include <linux/mm.h> | 4 | #include <linux/mm.h> |
5 | #include <linux/sched.h> | ||
5 | #include <asm/compiler.h> | 6 | #include <asm/compiler.h> |
6 | #include <asm/pgalloc.h> | 7 | #include <asm/pgalloc.h> |
7 | 8 | ||