From 0179fcfaab2fdbff0da00bf76be08e913d5a0f47 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Thu, 30 Oct 2014 13:13:50 -0500 Subject: 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 Original-Commit-Id: 698d38b53bbc2bc043548792cea7219542b5fe6b Original-Change-Id: I0821dc2ee8dc6bd1e8bc1c10f8b98b10e24fc97e Original-Signed-off-by: Aaron Durbin Original-Reviewed-on: https://chromium-review.googlesource.com/226485 Original-Reviewed-by: Furquan Shaikh Reviewed-on: http://review.coreboot.org/9423 Reviewed-by: Stefan Reinauer Tested-by: build bot (Jenkins) --- src/arch/arm64/armv8/secmon/psci.c | 76 +++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 10 deletions(-) (limited to 'src/arch/arm64/armv8') diff --git a/src/arch/arm64/armv8/secmon/psci.c b/src/arch/arm64/armv8/secmon/psci.c index 93c5bddcb9..3ba7e73e61 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) -- cgit v1.2.3