[coreboot-gerrit] Patch set updated for coreboot: 487a2f3 arm64: add psci support to secmon

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Mar 27 14:27:41 CET 2015


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

-gerrit

commit 487a2f3d49f71ced8425a514853960ebd7c577ad
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Fri Sep 19 15:52:31 2014 -0500

    arm64: add psci support to secmon
    
    The PSCI functionality initially includes CPU_ON and CPU_OFF
    functions. Upon entering secmon the if the parameters are non-NULL
    then a PSCI CPU_ON action is done for the current CPU.
    
    BUG=chrome-os-partner:32112
    BRANCH=None
    TEST=Booted kernel with PSCI support. Brought up all CPUS in kernel
         using PSCI. Turned CPUs on and off.
    
    Change-Id: I256fa45a1c9889ff9d7990eb1898df1ec241c117
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 689ba03e313e7e52e9b74aa774897b55cbd52748
    Original-Change-Id: I943826b7dbcc8e3f6c8c4b66344af8fac12ba94e
    Original-Signed-off-by: Aaron Durbin <adurbin at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/218923
    Original-Reviewed-by: Furquan Shaikh <furquan at chromium.org>
---
 src/arch/arm64/armv8/secmon/Makefile.inc  |   1 +
 src/arch/arm64/armv8/secmon/psci.c        | 208 ++++++++++++++++++++++++++++++
 src/arch/arm64/armv8/secmon/secmon_init.c |  20 +--
 src/arch/arm64/include/arch/psci.h        | 115 +++++++++++++++++
 4 files changed, 329 insertions(+), 15 deletions(-)

diff --git a/src/arch/arm64/armv8/secmon/Makefile.inc b/src/arch/arm64/armv8/secmon/Makefile.inc
index 03b93ed..1c7a696 100644
--- a/src/arch/arm64/armv8/secmon/Makefile.inc
+++ b/src/arch/arm64/armv8/secmon/Makefile.inc
@@ -32,6 +32,7 @@ secmon-c-ccopts += -I$(src)/arch/arm64/include/armv8/ -include $(src)/include/kc
 secmon-S-ccopts += -I$(src)/arch/arm64/include/armv8/ -include $(src)/include/kconfig.h -D__SECMON__
 
 secmon-y += secmon_init.c
+secmon-y += psci.c
 secmon-y += smc.c
 secmon-y += trampoline.S
 secmon-y += ../exception.c
diff --git a/src/arch/arm64/armv8/secmon/psci.c b/src/arch/arm64/armv8/secmon/psci.c
new file mode 100644
index 0000000..9764cac
--- /dev/null
+++ b/src/arch/arm64/armv8/secmon/psci.c
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <smp/spinlock.h>
+#include <arch/cpu.h>
+#include <arch/psci.h>
+#include <arch/smc.h>
+#include <arch/transition.h>
+#include <arch/lib_helpers.h>
+#include <console/console.h>
+#include "secmon.h"
+
+enum {
+	PSCI_CPU_STATE_OFF = 0,
+	PSCI_CPU_STATE_ON_PENDING,
+	PSCI_CPU_STATE_ON,
+};
+
+struct psci_cpu_state {
+	uint64_t mpidr;
+	void *entry;
+	void *arg;
+	int state;
+};
+
+DECLARE_SPIN_LOCK(psci_spinlock);
+
+static struct psci_cpu_state psci_state[CONFIG_MAX_CPUS];
+
+
+static inline void psci_lock(void)
+{
+	spin_lock(&psci_spinlock);
+}
+
+static inline void psci_unlock(void)
+{
+	spin_unlock(&psci_spinlock);
+}
+
+static inline int psci_cpu_state_locked(int i)
+{
+	return psci_state[i].state;
+}
+
+static inline void psci_cpu_set_state_locked(int i, int s)
+{
+	psci_state[i].state = s;
+}
+
+static struct cpu_info *mpidr_to_cpu_info(uint64_t mpidr)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(psci_state); i++) {
+		if (mpidr == psci_state[i].mpidr)
+			return cpu_info_for_cpu(i);
+	}
+
+	return NULL;
+}
+
+static void psci_cpu_on_callback(void *arg)
+{
+	struct psci_cpu_state *s = arg;
+
+	psci_turn_on_self(s->entry, s->arg);
+}
+
+static void psci_cpu_on(struct psci_func *pf)
+{
+	uint64_t entry;
+	uint64_t target_mpidr;
+	uint64_t context_id;
+	struct cpu_info *ci;
+	int cpu_state;
+	struct cpu_action action;
+
+	target_mpidr = psci64_arg(pf, PSCI_PARAM_0);
+	entry = psci64_arg(pf, PSCI_PARAM_1);
+	context_id = psci64_arg(pf, PSCI_PARAM_2);
+
+	ci = mpidr_to_cpu_info(target_mpidr);
+
+	if (ci == NULL) {
+		psci32_return(pf, PSCI_RET_INVALID_PARAMETERS);
+		return;
+	}
+
+	psci_lock();
+	cpu_state = psci_cpu_state_locked(ci->id);
+
+	if (cpu_state == PSCI_CPU_STATE_ON_PENDING) {
+		psci32_return(pf, PSCI_RET_ON_PENDING);
+		psci_unlock();
+		return;
+	} else if (cpu_state == PSCI_CPU_STATE_ON) {
+		psci32_return(pf, PSCI_RET_ALREADY_ON);
+		psci_unlock();
+		return;
+	}
+
+	psci_cpu_set_state_locked(ci->id, PSCI_CPU_STATE_ON_PENDING);
+	/* Set the parameters and initialize the action. */
+	psci_state[ci->id].entry = (void *)(uintptr_t)entry;
+	psci_state[ci->id].arg = (void *)(uintptr_t)context_id;
+	action.run = &psci_cpu_on_callback;
+	action.arg = &psci_state[ci->id];
+
+	if (arch_run_on_cpu_async(ci->id, &action)) {
+		psci32_return(pf, PSCI_RET_INTERNAL_FAILURE);
+		psci_unlock();
+		return;
+	}
+
+	psci_unlock();
+
+	psci32_return(pf, PSCI_RET_SUCCESS);
+}
+
+static void psci_cpu_off(struct psci_func *pf)
+{
+	psci_lock();
+	psci_cpu_set_state_locked(cpu_info()->id, PSCI_CPU_STATE_OFF);
+	psci_unlock();
+
+	/* TODO(adurbin): writeback cache and actually turn off CPU. */
+	secmon_trampoline(&secmon_wait_for_action, NULL);
+}
+
+static int psci_handler(struct smc_call *smc)
+{
+	struct psci_func pf_storage;
+	struct psci_func *pf = &pf_storage;
+
+	psci_func_init(pf, smc);
+
+	switch (pf->id) {
+	case PSCI_CPU_ON64:
+		psci_cpu_on(pf);
+		break;
+	case PSCI_CPU_OFF64:
+		psci_cpu_off(pf);
+		break;
+	default:
+		psci32_return(pf, PSCI_RET_NOT_SUPPORTED);
+		break;
+	}
+
+	return 0;
+}
+
+void psci_init(void)
+{
+	struct cpu_info *ci;
+	uint64_t mpidr;
+
+	/* Set this CPUs MPIDR clearing the bits that are not per-cpu. */
+	ci = cpu_info();
+	mpidr = raw_read_mpidr_el1();
+	mpidr &= ~(1ULL << 31); /* RES1 */
+	mpidr &= ~(1ULL << 30); /* U */
+	mpidr &= ~(1ULL << 24); /* MT */
+	psci_state[ci->id].mpidr = mpidr;
+
+	if (!cpu_is_bsp())
+		return;
+
+	/* Register PSCI handlers. */
+	if (smc_register_range(PSCI_CPU_OFF64, PSCI_CPU_ON64, &psci_handler))
+		printk(BIOS_ERR, "Couldn't register PSCI handler.\n");
+}
+
+void psci_turn_on_self(void *entry, void *arg)
+{
+	struct exc_state state;
+	int target_el;
+	struct cpu_info *ci = cpu_info();
+
+	psci_lock();
+	psci_cpu_set_state_locked(ci->id, PSCI_CPU_STATE_ON);
+	psci_unlock();
+
+	/* Target EL is determined if HVC is enabled or not. */
+	target_el = (raw_read_scr_el3() & SCR_HVC_ENABLE) ? EL2 : EL1;
+
+	memset(&state, 0, sizeof(state));
+	state.elx.spsr = get_eret_el(target_el, SPSR_USE_H);
+	transition_with_entry(entry, arg, &state);
+}
diff --git a/src/arch/arm64/armv8/secmon/secmon_init.c b/src/arch/arm64/armv8/secmon/secmon_init.c
index 6172505..bfb5d46 100644
--- a/src/arch/arm64/armv8/secmon/secmon_init.c
+++ b/src/arch/arm64/armv8/secmon/secmon_init.c
@@ -23,11 +23,10 @@
 #include <arch/io.h>
 #include <arch/exception.h>
 #include <arch/lib_helpers.h>
+#include <arch/psci.h>
 #include <arch/secmon.h>
 #include <arch/smc.h>
-#include <arch/transition.h>
 #include <console/console.h>
-#include <rmodule.h>
 #include <stddef.h>
 #include "secmon.h"
 
@@ -44,25 +43,16 @@ static void cpu_init(int bsp)
 
 static void secmon_init(struct secmon_params *params, int bsp)
 {
-	struct exc_state exc_state;
-
 	exception_hwinit();
 	cpu_init(bsp);
 
 	smc_init();
+	psci_init();
 
-	/*
-	 * Check if the arg is non-NULL
-	 * 1) If yes, we make an EL2 transition to that entry point
-	 * 2) If no, we just wait
-	 */
-	if (params != NULL) {
-		memset(&exc_state, 0, sizeof(exc_state));
-		exc_state.elx.spsr =
-			get_eret_el(params->elx_el, params->elx_mode);
+	/* If turn on CPU if params are not NULL. */
+	if (params != NULL)
+		psci_turn_on_self(params->entry, params->arg);
 
-		transition_with_entry(params->entry, params->arg, &exc_state);
-	}
 	secmon_wait_for_action();
 }
 
diff --git a/src/arch/arm64/include/arch/psci.h b/src/arch/arm64/include/arch/psci.h
new file mode 100644
index 0000000..c39f13a
--- /dev/null
+++ b/src/arch/arm64/include/arch/psci.h
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#ifndef __ARCH_PSCI_H__
+#define __ARCH_PSCI_H__
+
+#include <arch/smc.h>
+
+/* Return Values */
+enum {
+	PSCI_RET_SUCCESS = 0,
+	PSCI_RET_NOT_SUPPORTED = -1,
+	PSCI_RET_INVALID_PARAMETERS = -2,
+	PSCI_RET_DENIED = -3,
+	PSCI_RET_ALREADY_ON = -4,
+	PSCI_RET_ON_PENDING = -5,
+	PSCI_RET_INTERNAL_FAILURE = -6,
+	PSCI_RET_NOT_PRESENT = -7,
+	PSCI_RET_DISABLED = -8,
+};
+
+/* PSCI Functions. */
+enum {
+	/* 32-bit System level functions. */
+	PSCI_VERSION = SMC_FUNC_FAST32(0x4, 0x0),
+	PSCI_SYSTEM_OFF = SMC_FUNC_FAST32(0x4, 0x8),
+	PSCI_SYSTEM_RESET = SMC_FUNC_FAST32(0x4, 0x9),
+
+	/* 32-bit CPU support functions. */
+	PSCI_CPU_SUSPEND32 = SMC_FUNC_FAST32(0x4, 0x1),
+	PSCI_CPU_OFF32 = SMC_FUNC_FAST32(0x4, 0x2),
+	PSCI_CPU_ON32 = SMC_FUNC_FAST32(0x4, 0x3),
+
+	/* 64-bit CPU support functions. */
+	PSCI_CPU_SUSPEND64 = SMC_FUNC_FAST64(0x4, 0x1),
+	PSCI_CPU_OFF64 = SMC_FUNC_FAST64(0x4, 0x2),
+	PSCI_CPU_ON64 = SMC_FUNC_FAST64(0x4, 0x3),
+};
+
+/* Parameter arguments. */
+enum {
+	PSCI_PARAM_0 = 1,
+	PSCI_PARAM_1,
+	PSCI_PARAM_2,
+	PSCI_PARAM_3,
+	PSCI_RETURN_0 = 1,
+	PSCI_RETURN_1,
+	PSCI_RETURN_2,
+	PSCI_RETURN_3,
+};
+
+struct psci_func {
+	uint32_t id;
+	struct smc_call *smc;
+};
+
+static inline void psci_func_init(struct psci_func *pf, struct smc_call *smc)
+{
+	pf->id = smc_function_id(smc);
+	pf->smc = smc;
+}
+
+static inline uint64_t psci64_arg(struct psci_func *pf, unsigned i)
+{
+	return smc64_arg(pf->smc, i);
+}
+
+static inline uint32_t psci32_arg(struct psci_func *pf, unsigned i)
+{
+	return psci64_arg(pf, i);
+}
+
+static inline void psci64_result(struct psci_func *pf, unsigned i, uint64_t v)
+{
+	smc64_result(pf->smc, i, v);
+}
+
+static inline void psci32_result(struct psci_func *pf, unsigned i, uint32_t v)
+{
+	uint64_t v64 = v;
+	psci64_result(pf, i, v64);
+}
+
+static inline void psci32_return(struct psci_func *pf, int32_t val)
+{
+	psci32_result(pf, 0, val);
+}
+
+static inline void psci64_return(struct psci_func *pf, int64_t val)
+{
+	psci64_result(pf, 0, val);
+}
+
+void psci_init(void);
+
+/* Turn on the current CPU within the PSCI subsystem. */
+void psci_turn_on_self(void *entry, void *arg);
+
+#endif /* __ARCH_PSCI_H__ */



More information about the coreboot-gerrit mailing list