Use register_t instead of uint32_t in smc/hmc calls such that arguments
authorkettenis <kettenis@openbsd.org>
Fri, 29 Dec 2017 14:45:15 +0000 (14:45 +0000)
committerkettenis <kettenis@openbsd.org>
Fri, 29 Dec 2017 14:45:15 +0000 (14:45 +0000)
to SMC64 functions don't get truncated.  Implement support for the CPU_ON
call.

sys/arch/arm/arm/cpu.c
sys/arch/arm64/arm64/cpu.c
sys/dev/fdt/psci.c

index 6ca9668..d51f20e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cpu.c,v 1.42 2017/12/24 19:43:51 kettenis Exp $       */
+/*     $OpenBSD: cpu.c,v 1.43 2017/12/29 14:45:15 kettenis Exp $       */
 /*     $NetBSD: cpu.c,v 1.56 2004/04/14 04:01:49 bsh Exp $     */
 
 
@@ -339,4 +339,4 @@ intr_barrier(void *ih)
        sched_barrier(NULL);
 }
 
-/* End of cpu.c */
+int    (*cpu_on_fn)(register_t, register_t);
index 169a21f..73ec87d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cpu.c,v 1.8 2017/12/24 19:42:51 kettenis Exp $        */
+/*     $OpenBSD: cpu.c,v 1.9 2017/12/29 14:45:15 kettenis Exp $        */
 
 /*
  * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
@@ -196,3 +196,5 @@ cpu_clockspeed(int *freq)
        *freq = clock_get_frequency(cpu_node, NULL) / 1000000;
        return 0;
 }
+
+int    (*cpu_on_fn)(register_t, register_t);
index b24613a..e5761a8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: psci.c,v 1.2 2017/02/27 08:39:25 patrick Exp $        */
+/*     $OpenBSD: psci.c,v 1.3 2017/12/29 14:45:15 kettenis Exp $       */
 
 /*
  * Copyright (c) 2016 Jonathan Gray <jsg@openbsd.org>
 
 extern void (*cpuresetfn)(void);
 extern void (*powerdownfn)(void);
+extern int (*cpu_on_fn)(register_t, register_t);
 
 #define SYSTEM_OFF     0x84000008
 #define SYSTEM_RESET   0x84000009
+#ifdef __LP64__
+#define CPU_ON         0xc4000003
+#else
+#define CPU_ON         0x84000003
+#endif
 
 struct psci_softc {
-       struct device            sc_dev;
-       void                     (*callfn)(uint32_t, uint32_t, uint32_t, uint32_t);
-       int                      sc_system_off;
-       int                      sc_system_reset;
+       struct device    sc_dev;
+       register_t       (*sc_callfn)(register_t, register_t, register_t,
+                            register_t);
+       int              sc_system_off;
+       int              sc_system_reset;
+       int              sc_cpu_on;
 };
 
 struct psci_softc *psci_sc;
@@ -45,9 +53,10 @@ int  psci_match(struct device *, void *, void *);
 void   psci_attach(struct device *, struct device *, void *);
 void   psci_reset(void);
 void   psci_powerdown(void);
+int    psci_cpu_on(register_t, register_t);
 
-extern void hvc_call(uint32_t, uint32_t, uint32_t, uint32_t);
-extern void smc_call(uint32_t, uint32_t, uint32_t, uint32_t);
+extern register_t hvc_call(register_t, register_t, register_t, register_t);
+extern register_t smc_call(register_t, register_t, register_t, register_t);
 
 struct cfattach psci_ca = {
        sizeof(struct psci_softc), psci_match, psci_attach
@@ -70,15 +79,15 @@ psci_match(struct device *parent, void *match, void *aux)
 void
 psci_attach(struct device *parent, struct device *self, void *aux)
 {
-       struct psci_softc               *sc = (struct psci_softc *) self;
-       struct fdt_attach_args          *faa = aux;
-       char                             method[128];
+       struct psci_softc *sc = (struct psci_softc *)self;
+       struct fdt_attach_args *faa = aux;
+       char method[128];
 
        if (OF_getprop(faa->fa_node, "method", method, sizeof(method))) {
                if (strcmp(method, "hvc") == 0)
-                       sc->callfn = hvc_call;
+                       sc->sc_callfn = hvc_call;
                else if (strcmp(method, "smc") == 0)
-                       sc->callfn = smc_call;
+                       sc->sc_callfn = smc_call;
        }
 
        /*
@@ -90,11 +99,13 @@ psci_attach(struct device *parent, struct device *self, void *aux)
            OF_is_compatible(faa->fa_node, "arm,psci-1.0")) {
                sc->sc_system_off = SYSTEM_OFF;
                sc->sc_system_reset = SYSTEM_RESET;
+               sc->sc_cpu_on = CPU_ON;
        } else if (OF_is_compatible(faa->fa_node, "arm,psci")) {
                sc->sc_system_off = OF_getpropint(faa->fa_node,
                    "system_off", 0);
                sc->sc_system_reset = OF_getpropint(faa->fa_node,
                    "system_reset", 0);
+               sc->sc_cpu_on = OF_getpropint(faa->fa_node, "cpu_on", 0);
        }
 
        printf("\n");
@@ -104,20 +115,31 @@ psci_attach(struct device *parent, struct device *self, void *aux)
                powerdownfn = psci_powerdown;
        if (sc->sc_system_reset != 0)
                cpuresetfn = psci_reset;
+       if (sc->sc_cpu_on != 0)
+               cpu_on_fn = psci_cpu_on;
 }
 
 void
 psci_reset(void)
 {
        struct psci_softc *sc = psci_sc;
-       if (sc->callfn)
-               (*sc->callfn)(sc->sc_system_reset, 0, 0, 0);
+       if (sc->sc_callfn)
+               (*sc->sc_callfn)(sc->sc_system_reset, 0, 0, 0);
 }
 
 void
 psci_powerdown(void)
 {
        struct psci_softc *sc = psci_sc;
-       if (sc->callfn)
-               (*sc->callfn)(sc->sc_system_off, 0, 0, 0);
+       if (sc->sc_callfn)
+               (*sc->sc_callfn)(sc->sc_system_off, 0, 0, 0);
+}
+
+int
+psci_cpu_on(register_t mpidr, register_t pc)
+{
+       struct psci_softc *sc = psci_sc;
+       if (sc->sc_callfn)
+               return (*sc->sc_callfn)(sc->sc_cpu_on, mpidr, pc, 0);
+       return -1;
 }