[coreboot-gerrit] Change in coreboot[master]: cpu/x86: Create mp_init_by_apic_id() function to perform single AP init

Subrata Banik (Code Review) gerrit at coreboot.org
Wed Apr 11 15:23:16 CEST 2018


Subrata Banik has uploaded this change for review. ( https://review.coreboot.org/25621


Change subject: cpu/x86: Create mp_init_by_apic_id() function to perform single AP init
......................................................................

cpu/x86: Create mp_init_by_apic_id() function to perform single AP init

This function provides an option to perform initialization of single
AP based on APIC id.

Modify associated mp init APIs to accept APIC ID as input. If APIC
ID is 0 then enable all associated APs else just enable the specific AP
which is marked by APIC ID.

BRANCH=none
BUG=b:74436746
TEST=Able to perform single AP init based on given APIC ID.

Change-Id: I1bc19a19ef442214d784905806b6172558d1e5ca
Signed-off-by: Subrata Banik <subrata.banik at intel.com>
---
M src/cpu/x86/mp_init.c
M src/include/cpu/x86/mp.h
2 files changed, 113 insertions(+), 11 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/25621/1

diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c
index 6d1ae26..52feca9 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -391,11 +391,11 @@
 	return ap_count;
 }
 
-static int allocate_cpu_devices(struct bus *cpu_bus, struct mp_params *p)
+static int allocate_cpu_devices(struct bus *cpu_bus, struct mp_params *p,
+		uint8_t apic_id)
 {
 	int i;
 	int max_cpus;
-	struct cpu_info *info;
 
 	max_cpus = p->num_cpus;
 	if (max_cpus > CONFIG_MAX_CPUS) {
@@ -404,7 +404,6 @@
 		max_cpus = CONFIG_MAX_CPUS;
 	}
 
-	info = cpu_info();
 	for (i = 1; i < max_cpus; i++) {
 		struct device_path cpu_path;
 		struct device *new;
@@ -414,7 +413,7 @@
 
 		/* Assuming linear APIC space allocation. AP will set its own
 		   APIC id in the ap_init() path above. */
-		cpu_path.apic.apic_id = info->cpu->path.apic.apic_id + i;
+		cpu_path.apic.apic_id = apic_id + i;
 
 		/* Allocate the new CPU device structure */
 		new = alloc_find_dev(cpu_bus, &cpu_path);
@@ -446,7 +445,8 @@
 	return timeout;
 }
 
-static int start_aps(struct bus *cpu_bus, int ap_count, atomic_t *num_aps)
+static int start_aps(struct bus *cpu_bus, int ap_count, atomic_t *num_aps,
+		uint8_t apic_id)
 {
 	int sipi_vector;
 	/* Max location is 4KiB below 1MiB */
@@ -464,7 +464,10 @@
 		return -1;
 	}
 
-	printk(BIOS_DEBUG, "Attempting to start %d APs\n", ap_count);
+	if (!apic_id)
+		printk(BIOS_DEBUG, "Attempting to start %d APs\n", ap_count);
+	else
+		printk(BIOS_DEBUG, "Attempting to start 1 APs with APIC ID = %d \n", apic_id);
 
 	if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) {
 		printk(BIOS_DEBUG, "Waiting for ICR not to be busy...");
@@ -476,7 +479,7 @@
 	}
 
 	/* Send INIT IPI to all but self. */
-	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
+	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apic_id));
 	lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
 			   LAPIC_DM_INIT);
 	printk(BIOS_DEBUG, "Waiting for 10ms after sending INIT.\n");
@@ -492,7 +495,7 @@
 		printk(BIOS_DEBUG, "done.\n");
 	}
 
-	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
+	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apic_id));
 	lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
 			   LAPIC_DM_STARTUP | sipi_vector);
 	printk(BIOS_DEBUG, "Waiting for 1st SIPI to complete...");
@@ -515,7 +518,7 @@
 		printk(BIOS_DEBUG, "done.\n");
 	}
 
-	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
+	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apic_id));
 	lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
 			   LAPIC_DM_STARTUP | sipi_vector);
 	printk(BIOS_DEBUG, "Waiting for 2nd SIPI to complete...");
@@ -626,6 +629,8 @@
 {
 	int num_cpus;
 	atomic_t *ap_count;
+	struct cpu_info *info;
+	uint8_t apic_id;
 
 	init_bsp(cpu_bus);
 
@@ -634,8 +639,10 @@
 		return -1;
 	}
 
+	info = cpu_info();
+	apic_id = info->cpu->path.apic.apic_id;
 	/* Default to currently running CPU. */
-	num_cpus = allocate_cpu_devices(cpu_bus, p);
+	num_cpus = allocate_cpu_devices(cpu_bus, p, apic_id);
 
 	if (num_cpus < p->num_cpus) {
 		printk(BIOS_CRIT,
@@ -659,7 +666,8 @@
 
 	/* Start the APs providing number of APs and the cpus_entered field. */
 	global_num_aps = p->num_cpus - 1;
-	if (start_aps(cpu_bus, global_num_aps, ap_count) < 0) {
+
+	if (start_aps(cpu_bus, global_num_aps, ap_count, apic_id) < 0) {
 		mdelay(1000);
 		printk(BIOS_DEBUG, "%d/%d eventually checked in?\n",
 		       atomic_read(ap_count), global_num_aps);
@@ -670,6 +678,58 @@
 	return bsp_do_flight_plan(p);
 }
 
+/*
+ * init_this_ap() will set up the SIPI vector and bring up the APs according to
+ * mp_params. Each flight record will be executed according to the plan.
+ *
+ * The MP initialization has the following properties:
+ * 1. AP is brought up from reset.
+ * 2. Init AP is done based on APIC ID, which has been set earlier.
+ *
+ * init_this_ap() returns < 0 on error, 0 on success.
+ */
+static int init_this_ap(struct bus *cpu_bus, struct mp_params *p, int apicid)
+{
+	int num_cpus;
+	atomic_t *ap_count;
+
+	if (p == NULL || p->flight_plan == NULL || p->num_records < 1) {
+		printk(BIOS_CRIT, "Invalid MP parameters\n");
+		return -1;
+	}
+	/* Default to currently running CPU. */
+	num_cpus = allocate_cpu_devices(cpu_bus, p, apicid - 1);
+
+	if (num_cpus < p->num_cpus) {
+		printk(BIOS_CRIT,
+		       "ERROR: More cpus requested (%d) than supported (%d).\n",
+		       p->num_cpus, num_cpus);
+		return -1;
+	}
+
+	/* Copy needed parameters so that APs have a reference to the plan. */
+	mp_info.num_records = p->num_records;
+	mp_info.records = p->flight_plan;
+
+	/* Load the SIPI vector. */
+	ap_count = load_sipi_vector(p);
+	if (ap_count == NULL)
+		return -1;
+
+	/* Make sure SIPI data hits RAM so the APs that come up will see
+	 * the startup code even if the caches are disabled.  */
+	wbinvd();
+
+	if (start_aps(cpu_bus, global_num_aps, ap_count, apicid) < 0) {
+		mdelay(1000);
+		printk(BIOS_DEBUG, "%d/%d eventually checked in?\n",
+		       atomic_read(ap_count), global_num_aps);
+		return -1;
+	}
+
+	return 0;
+}
+
 /* Calls cpu_initialize(info->index) which calls the coreboot CPU drivers. */
 static void mp_initialize_cpu(void)
 {
@@ -1064,3 +1124,31 @@
 
 	return ret;
 }
+
+int mp_init_by_apic_id(struct bus *cpu_bus, const struct mp_ops *mp_ops, int apicid)
+{
+	int ret;
+	struct mp_params mp_params;
+
+	memset(&mp_params, 0, sizeof(mp_params));
+
+	if (apicid <= 0) {
+		printk(BIOS_ERR, "Invalid APIC ID: %d\n", apicid);
+		return -1;
+	}
+
+	mp_params.num_cpus = 1;
+	/* Gather microcode information. */
+	if (mp_ops->get_microcode_info != NULL)
+		mp_ops->get_microcode_info(&mp_params.microcode_pointer,
+			&mp_params.parallel_microcode_load);
+	mp_params.flight_plan = &mp_steps[0];
+	mp_params.num_records = ARRAY_SIZE(mp_steps);
+
+	/* Start the APs providing number of APs and the cpus_entered field. */
+	global_num_aps = mp_ops->get_cpu_count() - 1;
+
+	ret = init_this_ap(cpu_bus, &mp_params, apicid);
+
+	return ret;
+}
diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h
index bc9cf05..04fba6a 100644
--- a/src/include/cpu/x86/mp.h
+++ b/src/include/cpu/x86/mp.h
@@ -116,6 +116,20 @@
  */
 int mp_init_with_smm(struct bus *cpu_bus, const struct mp_ops *mp_ops);
 
+/*
+ * mp_init_by_apic_id() returns < 0 on failure and 0 on success. The mp_ops
+ * argument is used to drive the multiprocess initialization.
+ * The sequence of operations
+ * is the following:
+ * 1. get_cpu_count()
+ * 2. get_microcode_info()
+ * 3. mp_initialize_cpu() for each cpu
+ *
+ * This function to bring back AP into Enable state marked by APIC ID,
+ * if this AP is in disable/halt state before.
+ */
+int mp_init_by_apic_id(struct bus *cpu_bus, const struct mp_ops *mp_ops,
+		int apicid);
 
 /*
  * After APs are up and PARALLEL_MP_AP_WORK is enabled one can issue work

-- 
To view, visit https://review.coreboot.org/25621
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1bc19a19ef442214d784905806b6172558d1e5ca
Gerrit-Change-Number: 25621
Gerrit-PatchSet: 1
Gerrit-Owner: Subrata Banik <subrata.banik at intel.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20180411/007a6cf1/attachment-0001.html>


More information about the coreboot-gerrit mailing list