x86: add sysfs call to get NR_CPUS, nr_cpu_ids, disabled_cpus Provide a means to discover the following values in the kernel via /sys/devices/system/cpu/... nr_cpus: NR_CPUS - maximum number of cpus configured nr_cpu_ids: nr_cpu_ids - max index of possible cpus + 1 nr_disabled: disabled_cpus - number of disabled cpus (may be > NR_CPUS) This can be used by distros to select a kernel based on the cpus actually in the system. Also puts back in deleted kernel parameter "additional_cpus=NUM". Signed-off-by: Mike Travis --- arch/x86/kernel/apic.c | 4 +++- arch/x86/kernel/setup_percpu.c | 1 - arch/x86/kernel/smpboot.c | 19 +++++++++++++++++-- drivers/base/cpu.c | 26 ++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c @@ -1846,7 +1846,9 @@ void __cpuinit generic_processor_info(in if (num_processors >= NR_CPUS) { printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." - " Processor ignored.\n", NR_CPUS); + " Processor %d ignored.\n", NR_CPUS, + num_processors + disabled_cpus); + disabled_cpus++; return; } diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -17,7 +17,6 @@ #ifdef CONFIG_X86_LOCAL_APIC unsigned int num_processors; -unsigned disabled_cpus __cpuinitdata; /* Processor that is doing the boot up */ unsigned int boot_cpu_physical_apicid = -1U; unsigned int max_physical_apicid; diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1259,6 +1259,14 @@ void __init native_smp_cpus_done(unsigne check_nmi_watchdog(); } +static int additional_cpus __initdata = -1; + +static __init int setup_additional_cpus(char *s) +{ + return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL; +} +early_param("additional_cpus", setup_additional_cpus); + /* * cpu_possible_map should be static, it cannot change as cpu's * are onlined, or offlined. The reason is per-cpu data-structures @@ -1284,9 +1292,16 @@ __init void prefill_possible_map(void) if (!num_processors) num_processors = 1; + if (additional_cpus != -1 && disabled_cpus < additional_cpus) + disabled_cpus = additional_cpus; + possible = num_processors + disabled_cpus; - if (possible > NR_CPUS) - possible = NR_CPUS; + if (possible > NR_CPUS) { + printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." + " Processors %d-%d ignored.\n", CONFIG_NR_CPUS, + CONFIG_NR_CPUS, possible); + possible = CONFIG_NR_CPUS; + } printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n", possible, max_t(int, possible - num_processors, 0)); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -128,10 +128,36 @@ print_cpus_func(possible); print_cpus_func(possible); print_cpus_func(present); +/* + * Print nr_cpu_ids, NR_CPUS, disabled_cpus + */ +static ssize_t print_cpus_int(struct sysdev_class *class, char *buf, int value) +{ + int n = snprintf(buf, PAGE_SIZE-2, "%d\n", value); + return n; +} + +#define print_cpus_val(name, value) \ +static ssize_t print_cpus_##name(struct sysdev_class *class, char *buf) \ +{ \ + return print_cpus_int(class, buf, value); \ +} \ +static struct sysdev_class_attribute attr_##name = \ + _SYSDEV_CLASS_ATTR(name, 0444, print_cpus_##name, NULL) + +unsigned int disabled_cpus; + +print_cpus_val(nr_cpu_ids, nr_cpu_ids); +print_cpus_val(nr_cpus, CONFIG_NR_CPUS); +print_cpus_val(nr_disabled, disabled_cpus); + static struct sysdev_class_attribute *cpu_state_attr[] = { &attr_online_map, &attr_possible_map, &attr_present_map, + &attr_nr_cpu_ids, + &attr_nr_cpus, + &attr_nr_disabled, }; static int cpu_states_init(void)