From: George Beshers <gbeshers@redhat.com> Date: Thu, 31 Jul 2008 15:34:10 -0400 Subject: [IA64] Fix large MCA bootmem allocation Message-id: 20080731192815.4411.29311.sendpatchset@dhcp-100-2-194.bos.redhat.com O-Subject: [RHEL5.3 PATCH 18/19] [IA64] Fix large MCA bootmem allocation Bugzilla: 455308 RH-Acked-by: Prarit Bhargava <prarit@redhat.com> [patch] Fix large MCA bootmem allocation BZ#455308 Upstream: http://git.kernel.org/?p=linux/kernel/git/aegl/linux-2.6.git;a=commitdiff;h=785285fc8bc7f846ab68a063a8bf5a009d67725d The MCA code allocates bootmem memory for NR_CPUS, regardless of how many cpus the system actually has. This change allocates memory only for cpus that actually exist. On my test system with NR_CPUS = 1024, reserved memory was reduced by 130944k. Before: Memory: 27886976k/28111168k available (8282k code, 242304k reserved, 5928k data, 1792k init) After: Memory: 28017920k/28111168k available (8282k code, 111360k reserved, 5928k data, 1792k init) Signed-off-by: Russ Anderson <rja@sgi.com> Note: Patch cleaned up slightly because Prarit rejected another patch, the results is close to what is upstream. diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index c666582..39ed501 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -18,7 +18,7 @@ * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) * - * Copyright (C) 1999, 2004 Silicon Graphics, Inc. + * Copyright (C) 1999, 2004-2008 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * * 03/04/15 D. Mosberger Added INIT backtrace support. @@ -1757,43 +1757,46 @@ format_mca_init_stack(void *mca_data, unsigned long offset, strncpy(p->comm, type, sizeof(p->comm)-1); } +/* Caller prevents this from being called after init */ +static void * __cpuinit mca_bootmem(void) +{ + return __alloc_bootmem(sizeof(struct ia64_mca_cpu), + KERNEL_STACK_SIZE, 0); +} + /* Do per-CPU MCA-related initialization. */ void __cpuinit ia64_mca_cpu_init(void *cpu_data) { void *pal_vaddr; + void *data; + long sz = sizeof(struct ia64_mca_cpu); + int cpu = smp_processor_id(); static int first_time = 1; - if (first_time) { - void *mca_data; - int cpu; - - first_time = 0; - mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) - * NR_CPUS + KERNEL_STACK_SIZE); - mca_data = (void *)(((unsigned long)mca_data + - KERNEL_STACK_SIZE - 1) & - (-KERNEL_STACK_SIZE)); - for (cpu = 0; cpu < NR_CPUS; cpu++) { - format_mca_init_stack(mca_data, - offsetof(struct ia64_mca_cpu, mca_stack), - "MCA", cpu); - format_mca_init_stack(mca_data, - offsetof(struct ia64_mca_cpu, init_stack), - "INIT", cpu); - __per_cpu_mca[cpu] = __pa(mca_data); - mca_data += sizeof(struct ia64_mca_cpu); - } - } - /* - * The MCA info structure was allocated earlier and its - * physical address saved in __per_cpu_mca[cpu]. Copy that - * address * to ia64_mca_data so we can access it as a per-CPU - * variable. + * Structure will already be allocated if cpu has been online, + * then offlined. */ - __get_cpu_var(ia64_mca_data) = __per_cpu_mca[smp_processor_id()]; + if (__per_cpu_mca[cpu]) { + data = __va(__per_cpu_mca[cpu]); + } else { + if (first_time) { + data = mca_bootmem(); + first_time = 0; + } else + data = page_address(alloc_pages_node(numa_node_id(), + GFP_KERNEL, get_order(sz))); + if (!data) + panic("Could not allocate MCA memory for cpu %d\n", + cpu); + } + format_mca_init_stack(data, offsetof(struct ia64_mca_cpu, mca_stack), + "MCA", cpu); + format_mca_init_stack(data, offsetof(struct ia64_mca_cpu, init_stack), + "INIT", cpu); + __get_cpu_var(ia64_mca_data) = __per_cpu_mca[cpu] = __pa(data); /* * Stash away a copy of the PTE needed to map the per-CPU page.