--- include/asm-generic/percpu.h | 9 +++++++-- include/asm-generic/sections.h | 9 +++++++++ include/asm-generic/vmlinux.lds.h | 15 +++++++++++++++ include/linux/percpu.h | 2 +- init/main.c | 17 +++++++++-------- 5 files changed, 41 insertions(+), 11 deletions(-) Index: linux-2.6/include/asm-generic/percpu.h =================================================================== --- linux-2.6.orig/include/asm-generic/percpu.h 2007-11-27 18:01:05.664463056 -0800 +++ linux-2.6/include/asm-generic/percpu.h 2007-11-27 18:53:32.833212865 -0800 @@ -42,8 +42,13 @@ extern unsigned long __per_cpu_offset[NR * Only S390 provides its own means of moving the pointer. */ #ifndef SHIFT_PTR +#ifdef CONFIG_PERCPU_ZERO_BASED +#define SHIFT_PTR(__p, __offset) \ + ((__typeof(__p))((void *)(__p) + (__offset))) +#else #define SHIFT_PTR(__p, __offset) RELOC_HIDE((__p), (__offset)) -#endif +#endif /* CONFIG_PER_CPU_ZERO_BASED */ +#endif /* SHIFT_PTR */ /* * A percpu variable may point to a discarded reghions. The following are Index: linux-2.6/include/asm-generic/sections.h =================================================================== --- linux-2.6.orig/include/asm-generic/sections.h 2007-11-27 17:59:27.640463082 -0800 +++ linux-2.6/include/asm-generic/sections.h 2007-11-27 18:46:28.520212656 -0800 @@ -11,7 +11,16 @@ extern char _sinittext[], _einittext[]; extern char _sextratext[] __attribute__((weak)); extern char _eextratext[] __attribute__((weak)); extern char _end[]; +#ifdef CONFIG_PERCPU_ZERO_BASED +extern char __per_cpu_load; +unsigned long __per_cpu_size; +#define __per_cpu_start ((char *)0) +#define __per_cpu_end ((char *)__per_cpu_size) +#else extern char __per_cpu_start[], __per_cpu_end[]; +#define __per_cpu_load __per_cpu_start +#define __per_cpu_size (__per_cpu_end - __per_cpu_start) +#endif extern char __kprobes_text_start[], __kprobes_text_end[]; extern char __initdata_begin[], __initdata_end[]; extern char __start_rodata[], __end_rodata[]; Index: linux-2.6/include/asm-generic/vmlinux.lds.h =================================================================== --- linux-2.6.orig/include/asm-generic/vmlinux.lds.h 2007-11-27 18:16:46.841463106 -0800 +++ linux-2.6/include/asm-generic/vmlinux.lds.h 2007-11-27 18:21:50.681212867 -0800 @@ -255,6 +255,20 @@ *(.initcall7.init) \ *(.initcall7s.init) +#ifdef CONFIG_PERCPU_ZERO_BASED +#define PERCPU(align) \ + . = ALIGN(align); \ + percpu : { } :percpu \ + __per_cpu_load = .; \ + .data.percpu 0 : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \ + *(.data.percpu.first) \ + *(.data.percpu) \ + *(.data.percpu.shared_aligned) \ + __per_cpu_size = .; \ + } \ + . = __per_cpu_load + __per_cpu_size; \ + data : { } :data +#else #define PERCPU(align) \ . = ALIGN(align); \ __per_cpu_start = .; \ @@ -264,3 +278,4 @@ *(.data.percpu.shared_aligned) \ } \ __per_cpu_end = .; +#endif Index: linux-2.6/init/main.c =================================================================== --- linux-2.6.orig/init/main.c 2007-11-27 18:46:32.812462970 -0800 +++ linux-2.6/init/main.c 2007-11-27 18:52:17.932326634 -0800 @@ -370,18 +370,19 @@ EXPORT_SYMBOL(__per_cpu_offset); static void __init setup_per_cpu_areas(void) { - unsigned long size, i; - char *ptr; - unsigned long nr_possible_cpus = num_possible_cpus(); + unsigned long size; + int cpu; /* Copy section for each CPU (we discard the original) */ size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE); - ptr = alloc_bootmem_pages(size * nr_possible_cpus); - for_each_possible_cpu(i) { - __per_cpu_offset[i] = ptr - __per_cpu_start; - memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); - ptr += size; + for_each_possible_cpu(cpu) { + char *ptr; + + ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(cpu)), + size); + __per_cpu_offset[cpu] = ptr - __per_cpu_start; + memcpy(ptr, __per_cpu_load, __per_cpu_size); } } #endif /* CONFIG_ARCH_SETS_UP_CPU_AREA */