All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: u-boot@lists.denx.de
Subject: [PATCH 10/22] x86: mp: Support APs waiting for instructions
Date: Thu, 21 May 2020 20:23:14 -0600	[thread overview]
Message-ID: <20200521202309.10.I5cdb6d2b53a528eaebda2227b8cdfe26c4c73ceb@changeid> (raw)
In-Reply-To: <20200522022326.238388-1-sjg@chromium.org>

At present the APs (non-boot CPUs) are inited once and then parked ready
for the OS to use them. However in some cases we want to send new requests
through, such as to change MTRRs and keep them consistent across CPUs.

Change the last state of the flight plan to go into a wait loop, accepting
instructions from the main CPU.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/x86/cpu/mp_init.c    | 99 ++++++++++++++++++++++++++++++++++++---
 arch/x86/include/asm/mp.h | 11 +++++
 2 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index ccb68b8b89b..c424f283807 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -43,14 +43,36 @@ struct mp_flight_plan {
 	struct mp_flight_record *records;
 };
 
-static struct mp_flight_plan mp_info;
-
 struct cpu_map {
 	struct udevice *dev;
 	int apic_id;
 	int err_code;
 };
 
+struct mp_callback {
+	/**
+	 * func() - Function to call on the AP
+	 *
+	 * @arg: Argument to pass
+	 */
+	void (*func)(void *arg);
+	void *arg;
+	int logical_cpu_number;
+};
+
+static struct mp_flight_plan mp_info;
+
+/*
+ * ap_callbacks - Callback mailbox array
+ *
+ * Array of callback, one entry for each available CPU, indexed by the CPU
+ * number, which is dev->req_seq. The entry for the main CPU is never used.
+ * When this is NULL, there is no pending work for the CPU to run. When
+ * non-NULL it points to the mp_callback structure. This is shared between all
+ * CPUs, so should only be written by the main CPU.
+ */
+static struct mp_callback **ap_callbacks;
+
 static inline void barrier_wait(atomic_t *b)
 {
 	while (atomic_read(b) == 0)
@@ -147,11 +169,9 @@ static void ap_init(unsigned int cpu_index)
 	debug("AP: slot %d apic_id %x, dev %s\n", cpu_index, apic_id,
 	      dev ? dev->name : "(apic_id not found)");
 
-	/* Walk the flight plan */
+	/* Walk the flight plan, which never returns */
 	ap_do_flight_plan(dev);
-
-	/* Park the AP */
-	debug("parking\n");
+	debug("Unexpected return\n");
 done:
 	stop_this_cpu();
 }
@@ -442,6 +462,68 @@ static int get_bsp(struct udevice **devp, int *cpu_countp)
 	return dev->req_seq;
 }
 
+static struct mp_callback *read_callback(struct mp_callback **slot)
+{
+	struct mp_callback *ret;
+
+	asm volatile ("mov	%1, %0\n"
+		: "=r" (ret)
+		: "m" (*slot)
+		: "memory"
+	);
+	return ret;
+}
+
+static void store_callback(struct mp_callback **slot, struct mp_callback *val)
+{
+	asm volatile ("mov	%1, %0\n"
+		: "=m" (*slot)
+		: "r" (val)
+		: "memory"
+	);
+}
+
+/**
+ * ap_wait_for_instruction() - Wait for and process requests from the main CPU
+ *
+ * This is called by APs (here, everything other than the main boot CPU) to
+ * await instructions. They arrive in the form of a function call and argument,
+ * which is then called. This uses a simple mailbox with atomic read/set
+ *
+ * @cpu: CPU that is waiting
+ * @unused: Optional argument provided by struct mp_flight_record, not used here
+ * @return Does not return
+ */
+static int ap_wait_for_instruction(struct udevice *cpu, void *unused)
+{
+	struct mp_callback lcb;
+	struct mp_callback **per_cpu_slot;
+
+	per_cpu_slot = &ap_callbacks[cpu->req_seq];
+
+	while (1) {
+		struct mp_callback *cb = read_callback(per_cpu_slot);
+
+		if (!cb) {
+			asm ("pause");
+			continue;
+		}
+
+		/* Copy to local variable before using the value */
+		memcpy(&lcb, cb, sizeof(lcb));
+		mfence();
+		if (lcb.logical_cpu_number == MP_SELECT_ALL ||
+		    lcb.logical_cpu_number == MP_SELECT_APS ||
+		    cpu->req_seq == lcb.logical_cpu_number)
+			lcb.func(lcb.arg);
+
+		/* Indicate we are finished */
+		store_callback(per_cpu_slot, NULL);
+	}
+
+	return 0;
+}
+
 static int mp_init_cpu(struct udevice *cpu, void *unused)
 {
 	struct cpu_platdata *plat = dev_get_parent_platdata(cpu);
@@ -454,6 +536,7 @@ static int mp_init_cpu(struct udevice *cpu, void *unused)
 
 static struct mp_flight_record mp_steps[] = {
 	MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
+	MP_FR_BLOCK_APS(ap_wait_for_instruction, NULL, NULL, NULL),
 };
 
 int mp_init(void)
@@ -491,6 +574,10 @@ int mp_init(void)
 	if (ret)
 		log_warning("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n");
 
+	ap_callbacks = calloc(num_cpus, sizeof(struct mp_callback *));
+	if (!ap_callbacks)
+		return -ENOMEM;
+
 	/* Copy needed parameters so that APs have a reference to the plan */
 	mp_info.num_records = ARRAY_SIZE(mp_steps);
 	mp_info.records = mp_steps;
diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h
index 94af819ad9a..41b1575f4be 100644
--- a/arch/x86/include/asm/mp.h
+++ b/arch/x86/include/asm/mp.h
@@ -11,6 +11,17 @@
 #include <asm/atomic.h>
 #include <asm/cache.h>
 
+enum {
+	/* Indicates that the function should run on all CPUs */
+	MP_SELECT_ALL	= -1,
+
+	/* Run on boot CPUs */
+	MP_SELECT_BSP	= -2,
+
+	/* Run on non-boot CPUs */
+	MP_SELECT_APS	= -3,
+};
+
 typedef int (*mp_callback_t)(struct udevice *cpu, void *arg);
 
 /*
-- 
2.27.0.rc0.183.gde8f92d652-goog

  parent reply	other threads:[~2020-05-22  2:23 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-22  2:23 [PATCH 00/22] x86: Enhance MTRR functionality to support multiple CPUs Simon Glass
2020-05-22  2:23 ` [PATCH 01/22] x86: mp_init: Switch to livetree Simon Glass
2020-06-10 13:25   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 02/22] x86: Move MP code into mp_init Simon Glass
2020-06-10 13:25   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 03/22] x86: mp_init: Avoid declarations in header files Simon Glass
2020-06-10 13:25   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 04/22] x86: mp_init: Switch parameter names in start_aps() Simon Glass
2020-06-10 13:25   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 05/22] x86: mp_init: Drop the num_cpus static variable Simon Glass
2020-06-10 13:25   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 06/22] x86: mtrr: Fix 'ensable' typo Simon Glass
2020-06-10 13:26   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 07/22] x86: mp_init: Set up the CPU numbers at the start Simon Glass
2020-06-10 13:26   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 08/22] x86: mp_init: Adjust bsp_init() to return more information Simon Glass
2020-06-10 13:26   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 09/22] x86: cpu: Remove unnecessary #ifdefs Simon Glass
2020-06-10 13:26   ` Wolfgang Wallner
2020-05-22  2:23 ` Simon Glass [this message]
2020-06-10 13:27   ` [PATCH 10/22] x86: mp: Support APs waiting for instructions Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 11/22] global_data: Add a generic global_data flag for SMP state Simon Glass
2020-06-10 13:27   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 12/22] x86: Set the SMP flag when MP init is complete Simon Glass
2020-06-10 13:27   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 13/22] x86: mp: Allow running functions on multiple CPUs Simon Glass
2020-06-10 13:27   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 14/22] x86: mp: Park CPUs before running the OS Simon Glass
2020-06-10 13:27   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 15/22] x86: mp: Add iterators for CPUs Simon Glass
2020-06-10 13:27   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 16/22] x86: mtrr: Use MP calls to list the MTRRs Simon Glass
2020-06-10 13:28   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 17/22] x86: mtrr: Update MTRRs on all CPUs Simon Glass
2020-06-10 13:28   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 18/22] x86: mtrr: Add support for writing to MTRRs on any CPU Simon Glass
2020-06-10 13:28   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 19/22] x86: mtrr: Update the command to use the new mtrr calls Simon Glass
2020-06-10 13:28   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 20/22] x86: mtrr: Restructure so command execution is in one place Simon Glass
2020-06-10 13:28   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 21/22] x86: mtrr: Update 'mtrr' to allow setting MTRRs on any CPU Simon Glass
2020-06-10 13:29   ` Wolfgang Wallner
2020-05-22  2:23 ` [PATCH 22/22] x86: mtrr: Enhance 'mtrr' command to list " Simon Glass
2020-06-10 13:29   ` Wolfgang Wallner
2020-05-22 10:54 ` [PATCH 00/22] x86: Enhance MTRR functionality to support multiple CPUs Andy Shevchenko
2020-05-22 13:42   ` Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200521202309.10.I5cdb6d2b53a528eaebda2227b8cdfe26c4c73ceb@changeid \
    --to=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.