[coreboot-gerrit] Patch set updated for coreboot: ec28a97 arm64: Implement PSCI command support

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Apr 10 08:44:27 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9423

-gerrit

commit ec28a97401dfc339ed6e5f7bbe8568462e76f079
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Thu Oct 30 13:13:50 2014 -0500

    arm64: Implement PSCI command support
    
    Provide support for SoCs to participate in PSCI commands.
    There are 2 steps to a command:
    1. prepare() - look at request and adjust state accordingly
    2. commit() - take action on the command
    
    The prepare() function is called with psci locks held while
    the commit() function is called with the locks dropped.
    No SoC implements the appropriate logic yet.
    
    BUG=chrome-os-partner:32136
    BRANCH=None
    TEST=Booted PSCI kernel -- no SMP because cmd_prepare()
         knowingly fails. Spintable kernel still brings up both
         CPUs.
    
    Change-Id: I2ae4d1c3f3eac4d1060c1b41472909933815d078
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 698d38b53bbc2bc043548792cea7219542b5fe6b
    Original-Change-Id: I0821dc2ee8dc6bd1e8bc1c10f8b98b10e24fc97e
    Original-Signed-off-by: Aaron Durbin <adurbin at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/226485
    Original-Reviewed-by: Furquan Shaikh <furquan at chromium.org>
---
 src/arch/arm64/armv8/secmon/psci.c | 76 +++++++++++++++++++++++++++++++++-----
 src/arch/arm64/include/arch/psci.h | 35 ++++++++++++++++++
 src/soc/nvidia/tegra132/psci.c     | 12 ++++++
 3 files changed, 113 insertions(+), 10 deletions(-)

diff --git a/src/arch/arm64/armv8/secmon/psci.c b/src/arch/arm64/armv8/secmon/psci.c
index 93c5bdd..3ba7e73 100644
--- a/src/arch/arm64/armv8/secmon/psci.c
+++ b/src/arch/arm64/armv8/secmon/psci.c
@@ -174,15 +174,18 @@ static void psci_cpu_on_callback(void *arg)
 				e->cpu_state.startup.arg, &state);
 }
 
-static void psci_cpu_on_prepare(struct psci_node *e, const struct cpu_action *a)
+static void psci_cpu_on_prepare(struct psci_cmd *cmd,
+				const struct cpu_action *a)
 {
 	struct psci_node *ancestor;
+	struct psci_node *e;
 	int state = PSCI_STATE_ON_PENDING;
 
+	e = cmd->target;
 	e->cpu_state.startup = *a;
 	ancestor = psci_find_ancestor(e, PSCI_AFFINITY_LEVEL_HIGHEST, state);
 	e->cpu_state.ancestor = ancestor;
-	psci_set_hierarchy_state(e, ancestor, state);
+	cmd->ancestor = ancestor;
 }
 
 static int psci_schedule_cpu_on(struct psci_node *e)
@@ -206,6 +209,9 @@ static int psci_schedule_cpu_on(struct psci_node *e)
 void psci_turn_on_self(const struct cpu_action *action)
 {
 	struct psci_node *e = node_self();
+	struct psci_cmd cmd = {
+		.type = PSCI_CMD_ON,
+	};
 
 	if (e == NULL) {
 		printk(BIOS_ERR, "Couldn't turn on self: mpidr %llx\n",
@@ -213,8 +219,11 @@ void psci_turn_on_self(const struct cpu_action *action)
 		return;
 	}
 
+	cmd.target = e;
+
 	psci_lock();
-	psci_cpu_on_prepare(e, action);
+	psci_cpu_on_prepare(&cmd, action);
+	psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_ON_PENDING);
 	psci_unlock();
 
 	psci_schedule_cpu_on(e);
@@ -235,8 +244,12 @@ static void psci_cpu_on(struct psci_func *pf)
 	uint64_t target_mpidr;
 	uint64_t context_id;
 	int cpu_state;
+	int ret;
 	struct psci_node *e;
 	struct cpu_action action;
+	struct psci_cmd cmd = {
+		.type = PSCI_CMD_ON,
+	};
 
 	target_mpidr = psci64_arg(pf, PSCI_PARAM_0);
 	entry = psci64_arg(pf, PSCI_PARAM_1);
@@ -262,28 +275,71 @@ static void psci_cpu_on(struct psci_func *pf)
 		return;
 	}
 
+	cmd.target = e;
 	action.run = (void *)entry;
 	action.arg = (void *)context_id;
-	psci_cpu_on_prepare(e, &action);
+	psci_cpu_on_prepare(&cmd, &action);
+
+	ret = soc_psci_ops.cmd_prepare(&cmd);
+
+	if (ret == PSCI_RET_SUCCESS)
+		psci_set_hierarchy_state(e, cmd.ancestor,
+					PSCI_STATE_ON_PENDING);
+
 	psci_unlock();
 
+	if (ret != PSCI_RET_SUCCESS)
+		return psci32_return(pf, ret);
+
+	ret = soc_psci_ops.cmd_commit(&cmd);
+
+	if (ret != PSCI_RET_SUCCESS) {
+		psci_lock();
+		psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_OFF);
+		psci_unlock();
+		return psci32_return(pf, ret);
+	}
+
 	psci32_return(pf, psci_schedule_cpu_on(e));
 }
 
 static int psci_turn_off_node(struct psci_node *e, int level,
 					int state_id)
 {
-	struct psci_node *ancestor;
+	int ret;
+	struct psci_cmd cmd = {
+		.type = PSCI_CMD_OFF,
+		.state_id = state_id,
+		.target = e,
+	};
 
 	psci_lock();
-	ancestor = psci_find_ancestor(e, level, PSCI_STATE_OFF);
-	psci_set_hierarchy_state(e, ancestor, PSCI_STATE_OFF);
+
+	cmd.ancestor = psci_find_ancestor(e, level, PSCI_STATE_OFF);
+
+	ret = soc_psci_ops.cmd_prepare(&cmd);
+
+	if (ret == PSCI_RET_SUCCESS)
+		psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_OFF);
+
 	psci_unlock();
 
-	/* TODO(adurbin): writeback cache and actually turn off CPU. */
-	secmon_trampoline(&secmon_wait_for_action, NULL);
+	if (ret != PSCI_RET_SUCCESS)
+		return ret;
 
-	return PSCI_RET_SUCCESS;
+	/* Should never return. */
+	ret = soc_psci_ops.cmd_commit(&cmd);
+
+	/* Adjust ret to be an error. */
+	if (ret == PSCI_RET_SUCCESS)
+		ret = PSCI_RET_INTERNAL_FAILURE;
+
+	/* Turn things back on. */
+	psci_lock();
+	psci_set_hierarchy_state(e, cmd.ancestor, PSCI_STATE_ON);
+	psci_unlock();
+
+	return ret;
 }
 
 int psci_turn_off_self(void)
diff --git a/src/arch/arm64/include/arch/psci.h b/src/arch/arm64/include/arch/psci.h
index 555333a..b408f3d 100644
--- a/src/arch/arm64/include/arch/psci.h
+++ b/src/arch/arm64/include/arch/psci.h
@@ -104,12 +104,47 @@ static inline int psci_root_node(const struct psci_node *n)
 	return psci_node_parent(n) == NULL;
 }
 
+enum {
+	PSCI_CMD_ON,
+	PSCI_CMD_OFF,
+	PSCI_CMD_STANDBY,
+};
+
+/*
+ * PSCI actions are serialized into a command for the SoC to process. There are
+ * 2 phases of a command being processed: prepare and commit. The prepare() is
+ * called with the PSCI locks held for the state of the PSCI nodes. If
+ * successful, the appropriate locks will be dropped and commit() will be
+ * called with the same structure. It is permissible for the SoC support code
+ * to modify the struture passed in (e.g. to update the requested state_id to
+ * reflect dynamic constraints on how deep of a state to enter).
+ */
+struct psci_cmd {
+	/* Command type. */
+	int type;
+	/*
+	 * PSCI state id for PSCI_CMD_OFF and PSCI_CMD_STANDBY commands.
+	 * A value of -1 indicates a CPU_OFF request.
+	 */
+	int state_id;
+	/*
+	 * target is the command's target, but it can affect up to the
+	 * ancestor entity. If target == ancestor then it only affects
+	 * target, otherwise all entites up the hierarchy including ancestor.
+	 */
+	struct psci_node *target;
+	struct psci_node *ancestor;
+};
+
 struct psci_soc_ops {
 	/*
 	 * Return number of entities one level below given parent affinitly
 	 * level and mpidr.
 	 */
 	size_t (*children_at_level)(int parent_level, uint64_t mpidr);
+
+	int (*cmd_prepare)(struct psci_cmd *cmd);
+	int (*cmd_commit)(struct psci_cmd *cmd);
 };
 
 /* Each SoC needs to provide the functions in the psci_soc_ops structure. */
diff --git a/src/soc/nvidia/tegra132/psci.c b/src/soc/nvidia/tegra132/psci.c
index 6ba39e0..0b5d793 100644
--- a/src/soc/nvidia/tegra132/psci.c
+++ b/src/soc/nvidia/tegra132/psci.c
@@ -45,6 +45,18 @@ static size_t children_at_level(int parent_level, uint64_t mpidr)
 	}
 }
 
+static int cmd_prepare(struct psci_cmd *cmd)
+{
+	return PSCI_RET_NOT_SUPPORTED;
+}
+
+static int cmd_commit(struct psci_cmd *cmd)
+{
+	return PSCI_RET_NOT_SUPPORTED;
+}
+
 struct psci_soc_ops soc_psci_ops = {
 	.children_at_level = &children_at_level,
+	.cmd_prepare = &cmd_prepare,
+	.cmd_commit = &cmd_commit,
 };



More information about the coreboot-gerrit mailing list