x86: Move MP initialization codes into a common place

Most of the MP initialization codes in arch/x86/cpu/baytrail/cpu.c is
common to all x86 processors, except detect_num_cpus() which varies
from cpu to cpu. Move these to arch/x86/cpu/cpu.c and implement the
new 'get_count' method for baytrail and cpu_x86 drivers. Now we call
cpu_get_count() in mp_init() to get the number of CPUs.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c
index 05156a5..a011730 100644
--- a/arch/x86/cpu/baytrail/cpu.c
+++ b/arch/x86/cpu/baytrail/cpu.c
@@ -12,78 +12,9 @@
 #include <asm/cpu.h>
 #include <asm/cpu_x86.h>
 #include <asm/lapic.h>
-#include <asm/mp.h>
 #include <asm/msr.h>
 #include <asm/turbo.h>
 
-#ifdef CONFIG_SMP
-static int enable_smis(struct udevice *cpu, void *unused)
-{
-	return 0;
-}
-
-static struct mp_flight_record mp_steps[] = {
-	MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
-	/* Wait for APs to finish initialization before proceeding. */
-	MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
-};
-
-static int detect_num_cpus(void)
-{
-	int ecx = 0;
-
-	/*
-	 * Use the algorithm described in Intel 64 and IA-32 Architectures
-	 * Software Developer's Manual Volume 3 (3A, 3B & 3C): System
-	 * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
-	 * of CPUID Extended Topology Leaf.
-	 */
-	while (1) {
-		struct cpuid_result leaf_b;
-
-		leaf_b = cpuid_ext(0xb, ecx);
-
-		/*
-		 * Bay Trail doesn't have hyperthreading so just determine the
-		 * number of cores by from level type (ecx[15:8] == * 2)
-		 */
-		if ((leaf_b.ecx & 0xff00) == 0x0200)
-			return leaf_b.ebx & 0xffff;
-		ecx++;
-	}
-}
-
-static int baytrail_init_cpus(void)
-{
-	struct mp_params mp_params;
-
-	lapic_setup();
-
-	mp_params.num_cpus = detect_num_cpus();
-	mp_params.parallel_microcode_load = 0,
-	mp_params.flight_plan = &mp_steps[0];
-	mp_params.num_records = ARRAY_SIZE(mp_steps);
-	mp_params.microcode_pointer = 0;
-
-	if (mp_init(&mp_params)) {
-		printf("Warning: MP init failure\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-#endif
-
-int x86_init_cpus(void)
-{
-#ifdef CONFIG_SMP
-	debug("Init additional CPUs\n");
-	baytrail_init_cpus();
-#endif
-
-	return 0;
-}
-
 static void set_max_freq(void)
 {
 	msr_t perf_ctl;
@@ -176,9 +107,38 @@
 	return 0;
 }
 
+static int baytrail_get_count(struct udevice *dev)
+{
+	int ecx = 0;
+
+	/*
+	 * Use the algorithm described in Intel 64 and IA-32 Architectures
+	 * Software Developer's Manual Volume 3 (3A, 3B & 3C): System
+	 * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
+	 * of CPUID Extended Topology Leaf.
+	 */
+	while (1) {
+		struct cpuid_result leaf_b;
+
+		leaf_b = cpuid_ext(0xb, ecx);
+
+		/*
+		 * Bay Trail doesn't have hyperthreading so just determine the
+		 * number of cores by from level type (ecx[15:8] == * 2)
+		 */
+		if ((leaf_b.ecx & 0xff00) == 0x0200)
+			return leaf_b.ebx & 0xffff;
+
+		ecx++;
+	}
+
+	return 0;
+}
+
 static const struct cpu_ops cpu_x86_baytrail_ops = {
 	.get_desc	= cpu_x86_get_desc,
 	.get_info	= baytrail_get_info,
+	.get_count	= baytrail_get_count,
 };
 
 static const struct udevice_id cpu_x86_baytrail_ids[] = {
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index 1dfd9e6..a6e88cf 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -21,10 +21,13 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <errno.h>
 #include <malloc.h>
 #include <asm/control_regs.h>
 #include <asm/cpu.h>
+#include <asm/lapic.h>
+#include <asm/mp.h>
 #include <asm/post.h>
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
@@ -621,8 +624,45 @@
 }
 #endif
 
+#ifdef CONFIG_SMP
+static int enable_smis(struct udevice *cpu, void *unused)
+{
+	return 0;
+}
+
+static struct mp_flight_record mp_steps[] = {
+	MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
+	/* Wait for APs to finish initialization before proceeding */
+	MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
+};
+
+static int x86_mp_init(void)
+{
+	struct mp_params mp_params;
+
+	lapic_setup();
+
+	mp_params.parallel_microcode_load = 0,
+	mp_params.flight_plan = &mp_steps[0];
+	mp_params.num_records = ARRAY_SIZE(mp_steps);
+	mp_params.microcode_pointer = 0;
+
+	if (mp_init(&mp_params)) {
+		printf("Warning: MP init failure\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+#endif
+
 __weak int x86_init_cpus(void)
 {
+#ifdef CONFIG_SMP
+	debug("Init additional CPUs\n");
+	x86_mp_init();
+#endif
+
 	return 0;
 }
 
diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c
index d32ba66..0941041 100644
--- a/arch/x86/cpu/cpu_x86.c
+++ b/arch/x86/cpu/cpu_x86.c
@@ -10,6 +10,8 @@
 #include <errno.h>
 #include <asm/cpu.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 int cpu_x86_bind(struct udevice *dev)
 {
 	struct cpu_platdata *plat = dev_get_parent_platdata(dev);
@@ -30,8 +32,34 @@
 	return 0;
 }
 
+static int cpu_x86_get_count(struct udevice *dev)
+{
+	int node, cpu;
+	int num = 0;
+
+	node = fdt_path_offset(gd->fdt_blob, "/cpus");
+	if (node < 0)
+		return -ENOENT;
+
+	for (cpu = fdt_first_subnode(gd->fdt_blob, node);
+	     cpu >= 0;
+	     cpu = fdt_next_subnode(gd->fdt_blob, cpu)) {
+		const char *device_type;
+
+		device_type = fdt_getprop(gd->fdt_blob, cpu,
+					  "device_type", NULL);
+		if (!device_type)
+			continue;
+		if (strcmp(device_type, "cpu") == 0)
+			num++;
+	}
+
+	return num;
+}
+
 static const struct cpu_ops cpu_x86_ops = {
 	.get_desc	= cpu_x86_get_desc,
+	.get_count	= cpu_x86_get_count,
 };
 
 static const struct udevice_id cpu_x86_ids[] = {
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index ac5753a..5564d84 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -22,6 +22,9 @@
 #include <dm/uclass-internal.h>
 #include <linux/linkage.h>
 
+/* Total CPUs include BSP */
+static int num_cpus;
+
 /* This also needs to match the sipi.S assembly code for saved MSR encoding */
 struct saved_msr {
 	uint32_t index;
@@ -383,7 +386,7 @@
 	int ret = 0;
 	const int timeout_us = 100000;
 	const int step_us = 100;
-	int num_aps = mp_params->num_cpus - 1;
+	int num_aps = num_cpus - 1;
 
 	for (i = 0; i < mp_params->num_records; i++) {
 		struct mp_flight_record *rec = &mp_params->flight_plan[i];
@@ -451,7 +454,16 @@
 		return -1;
 	}
 
+	num_cpus = cpu_get_count(cpu);
+	if (num_cpus < 0) {
+		debug("Cannot get number of CPUs: err=%d\n", num_cpus);
+		return num_cpus;
+	}
+
-	ret = check_cpu_devices(p->num_cpus);
+	if (num_cpus < 2)
+		debug("Warning: Only 1 CPU is detected\n");
+
+	ret = check_cpu_devices(num_cpus);
 	if (ret)
 		debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n");
 
@@ -471,7 +483,7 @@
 	wbinvd();
 
 	/* Start the APs providing number of APs and the cpus_entered field */
-	num_aps = p->num_cpus - 1;
+	num_aps = num_cpus - 1;
 	ret = start_aps(num_aps, ap_count);
 	if (ret) {
 		mdelay(1000);
diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h
index c0930fd..2e6c312 100644
--- a/arch/x86/include/asm/mp.h
+++ b/arch/x86/include/asm/mp.h
@@ -59,7 +59,6 @@
  * SMM support.
  */
 struct mp_params {
-	int num_cpus; /* Total cpus include BSP */
 	int parallel_microcode_load;
 	const void *microcode_pointer;
 	/* Flight plan  for APs and BSP */
diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c
index a2814a8..7660f99 100644
--- a/drivers/cpu/cpu-uclass.c
+++ b/drivers/cpu/cpu-uclass.c
@@ -12,6 +12,8 @@
 #include <dm/lists.h>
 #include <dm/root.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 int cpu_get_desc(struct udevice *dev, char *buf, int size)
 {
 	struct cpu_ops *ops = cpu_get_ops(dev);