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 <travis@sgi.com>
---
 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)
