Use boot_cpu_alloc to allocate a cpu area chunk that is needed to store the statically declared per cpu data and then point the per_cpu_offset pointers to the cpu area. The per cpu area is moved to a ZERO offset using some linker scripting. All per cpu variable addresses become true offsets into a cpu area to their respective variable. The addresses of per cpu variables can be treated like the offsets that are returned by CPU_ALLOC. Signed-off-by: Christoph Lameter --- arch/x86/kernel/setup64.c | 29 ++++++++++++----------------- arch/x86/kernel/vmlinux_64.lds.S | 3 ++- include/asm-generic/sections.h | 1 + include/asm-generic/vmlinux.lds.h | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 18 deletions(-) Index: linux-2.6/arch/x86/kernel/setup64.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/setup64.c 2007-11-18 22:39:24.706247819 -0800 +++ linux-2.6/arch/x86/kernel/setup64.c 2007-11-19 10:31:49.088824106 -0800 @@ -87,35 +87,30 @@ __setup("noexec32=", nonx32_setup); void __init setup_per_cpu_areas(void) { int i; - unsigned long size; + char *base; #ifdef CONFIG_HOTPLUG_CPU prefill_possible_map(); #endif /* Copy section for each CPU (we discard the original) */ - size = PERCPU_ENOUGH_ROOM; + base = boot_cpu_alloc(PERCPU_ENOUGH_ROOM); + if (base) + panic("Cannot allocate per cpu data at 0\n"); - printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n", size); + printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n", + PERCPU_ENOUGH_ROOM); for_each_cpu_mask (i, cpu_possible_map) { - char *ptr; + cpu_pda(i)->data_offset = cpu_offset(i); - if (!NODE_DATA(cpu_to_node(i))) { - printk("cpu with no node %d, num_online_nodes %d\n", - i, num_online_nodes()); - ptr = alloc_bootmem_pages(size); - } else { - ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size); - } - if (!ptr) - panic("Cannot allocate cpu data for CPU %d\n", i); - cpu_pda(i)->data_offset = ptr - __per_cpu_start; - memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); + memcpy(CPU_PTR(base, i), __load_per_cpu_start, + __per_cpu_end - __per_cpu_start); } -} + count_vm_events(CPU_BYTES, PERCPU_ENOUGH_ROOM); +} void pda_init(int cpu) -{ +{ struct x8664_pda *pda = cpu_pda(cpu); /* Setup up data that may be needed in __get_free_pages early */ Index: linux-2.6/include/asm-generic/vmlinux.lds.h =================================================================== --- linux-2.6.orig/include/asm-generic/vmlinux.lds.h 2007-11-18 22:39:23.370497641 -0800 +++ linux-2.6/include/asm-generic/vmlinux.lds.h 2007-11-19 10:30:20.095586336 -0800 @@ -258,8 +258,25 @@ #define PERCPU(align) \ . = ALIGN(align); \ __per_cpu_start = .; \ + __load_per_cpu_start = .; \ .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \ *(.data.percpu) \ *(.data.percpu.shared_aligned) \ } \ + __load_per_cpu_end = .; \ __per_cpu_end = .; + +#define ZERO_BASED_PERCPU \ + percpu : { } :percpu \ + __load_per_cpu_start = .; \ + .data.percpu 0 : AT(__load_per_cpu_start - LOAD_OFFSET) { \ + __per_cpu_start = .; \ + *(.data.percpu) \ + *(.data.percpu.shared_aligned) \ + __per_cpu_end = .; \ + } \ + . = __load_per_cpu_start + __per_cpu_end - __per_cpu_start; \ + __load_per_cpu_end = .; \ + data : { } :data + + Index: linux-2.6/arch/x86/kernel/vmlinux_64.lds.S =================================================================== --- linux-2.6.orig/arch/x86/kernel/vmlinux_64.lds.S 2007-11-18 22:41:39.261997209 -0800 +++ linux-2.6/arch/x86/kernel/vmlinux_64.lds.S 2007-11-18 22:42:33.119247430 -0800 @@ -19,6 +19,7 @@ cpu_area = CPU_AREA_BASE; PHDRS { text PT_LOAD FLAGS(5); /* R_E */ + percpu PT_LOAD FLAGS(4); /* R__ */ data PT_LOAD FLAGS(7); /* RWE */ user PT_LOAD FLAGS(7); /* RWE */ data.init PT_LOAD FLAGS(7); /* RWE */ @@ -206,7 +207,7 @@ SECTIONS __initramfs_end = .; #endif - PERCPU(4096) + ZERO_BASED_PERCPU . = ALIGN(4096); __init_end = .; Index: linux-2.6/include/asm-generic/sections.h =================================================================== --- linux-2.6.orig/include/asm-generic/sections.h 2007-11-18 22:39:23.374497627 -0800 +++ linux-2.6/include/asm-generic/sections.h 2007-11-18 22:45:33.073997351 -0800 @@ -12,6 +12,7 @@ extern char _sextratext[] __attribute__( extern char _eextratext[] __attribute__((weak)); extern char _end[]; extern char __per_cpu_start[], __per_cpu_end[]; +extern char __load_per_cpu_start[], __load_per_cpu_end[]; extern char __kprobes_text_start[], __kprobes_text_end[]; extern char __initdata_begin[], __initdata_end[]; extern char __start_rodata[], __end_rodata[]; -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/