Index: stable/11/sys/arm64/arm64/vm_machdep.c =================================================================== --- stable/11/sys/arm64/arm64/vm_machdep.c (revision 319206) +++ stable/11/sys/arm64/arm64/vm_machdep.c (revision 319207) @@ -1,263 +1,273 @@ /*- * Copyright (c) 2014 Andrew Turner * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ +#include "opt_platform.h" + #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef VFP #include #endif +#ifdef DEV_PSCI +#include +#endif + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child * ready to run and return to user mode. */ void cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) { struct pcb *pcb2; struct trapframe *tf; if ((flags & RFPROC) == 0) return; if (td1 == curthread) { /* * Save the tpidr_el0 and the vfp state, these normally happen * in cpu_switch, but if userland changes these then forks * this may not have happened. */ td1->td_pcb->pcb_tpidr_el0 = READ_SPECIALREG(tpidr_el0); #ifdef VFP if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0) vfp_save_state(td1, td1->td_pcb); #endif } pcb2 = (struct pcb *)(td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1; td2->td_pcb = pcb2; bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); td2->td_pcb->pcb_l0addr = vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l0); tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1); bcopy(td1->td_frame, tf, sizeof(*tf)); tf->tf_x[0] = 0; tf->tf_x[1] = 0; tf->tf_spsr = 0; td2->td_frame = tf; /* Set the return value registers for fork() */ td2->td_pcb->pcb_x[8] = (uintptr_t)fork_return; td2->td_pcb->pcb_x[9] = (uintptr_t)td2; td2->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame; td2->td_pcb->pcb_vfpcpu = UINT_MAX; /* Setup to release spin count in fork_exit(). */ td2->td_md.md_spinlock_count = 1; td2->td_md.md_saved_daif = 0; } void cpu_reset(void) { - printf("cpu_reset"); +#ifdef DEV_PSCI + psci_reset(); +#endif + + printf("cpu_reset failed"); while(1) __asm volatile("wfi" ::: "memory"); } void cpu_thread_swapin(struct thread *td) { } void cpu_thread_swapout(struct thread *td) { } void cpu_set_syscall_retval(struct thread *td, int error) { struct trapframe *frame; frame = td->td_frame; switch (error) { case 0: frame->tf_x[0] = td->td_retval[0]; frame->tf_x[1] = td->td_retval[1]; frame->tf_spsr &= ~PSR_C; /* carry bit */ break; case ERESTART: frame->tf_elr -= 4; break; case EJUSTRETURN: break; default: frame->tf_spsr |= PSR_C; /* carry bit */ frame->tf_x[0] = error; break; } } /* * Initialize machine state, mostly pcb and trap frame for a new * thread, about to return to userspace. Put enough state in the new * thread's PCB to get it to go back to the fork_return(), which * finalizes the thread state and handles peculiarities of the first * return to userspace for the new thread. */ void cpu_copy_thread(struct thread *td, struct thread *td0) { bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb)); td->td_pcb->pcb_x[8] = (uintptr_t)fork_return; td->td_pcb->pcb_x[9] = (uintptr_t)td; td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; td->td_pcb->pcb_vfpcpu = UINT_MAX; /* Setup to release spin count in fork_exit(). */ td->td_md.md_spinlock_count = 1; td->td_md.md_saved_daif = 0; } /* * Set that machine state for performing an upcall that starts * the entry function with the given argument. */ void cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { struct trapframe *tf = td->td_frame; tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size); tf->tf_elr = (register_t)entry; tf->tf_x[0] = (register_t)arg; } int cpu_set_user_tls(struct thread *td, void *tls_base) { struct pcb *pcb; if ((uintptr_t)tls_base >= VM_MAXUSER_ADDRESS) return (EINVAL); pcb = td->td_pcb; pcb->pcb_tpidr_el0 = (register_t)tls_base; if (td == curthread) WRITE_SPECIALREG(tpidr_el0, tls_base); return (0); } void cpu_thread_exit(struct thread *td) { } void cpu_thread_alloc(struct thread *td) { td->td_pcb = (struct pcb *)(td->td_kstack + td->td_kstack_pages * PAGE_SIZE) - 1; td->td_frame = (struct trapframe *)STACKALIGN( td->td_pcb - 1); } void cpu_thread_free(struct thread *td) { } void cpu_thread_clean(struct thread *td) { } /* * Intercept the return address from a freshly forked process that has NOT * been scheduled yet. * * This is needed to make kernel threads stay in kernel mode. */ void cpu_fork_kthread_handler(struct thread *td, void (*func)(void *), void *arg) { td->td_pcb->pcb_x[8] = (uintptr_t)func; td->td_pcb->pcb_x[9] = (uintptr_t)arg; td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; td->td_pcb->pcb_vfpcpu = UINT_MAX; } void cpu_exit(struct thread *td) { } void swi_vm(void *v) { if (busdma_swi_pending != 0) busdma_swi(); } Index: stable/11/sys/conf/options.arm64 =================================================================== --- stable/11/sys/conf/options.arm64 (revision 319206) +++ stable/11/sys/conf/options.arm64 (revision 319207) @@ -1,12 +1,14 @@ # $FreeBSD$ ARM64 opt_global.h INTRNG opt_global.h SOCDEV_PA opt_global.h SOCDEV_VA opt_global.h THUNDERX_PASS_1_1_ERRATA opt_global.h VFP opt_global.h +DEV_PSCI opt_platform.h + # SoC Support SOC_CAVM_THUNDERX opt_soc.h SOC_HISI_HI6220 opt_soc.h Index: stable/11/sys/dev/psci/psci.c =================================================================== --- stable/11/sys/dev/psci/psci.c (revision 319206) +++ stable/11/sys/dev/psci/psci.c (revision 319207) @@ -1,308 +1,315 @@ /*- * Copyright (c) 2014 Robin Randhawa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * This implements support for ARM's Power State Co-ordination Interface * [PSCI]. The implementation adheres to version 0.2 of the PSCI specification * but also supports v0.1. PSCI standardizes operations such as system reset, CPU * on/off/suspend. PSCI requires a compliant firmware implementation. * * The PSCI specification used for this implementation is available at: * * . * * TODO: * - Add support for remaining PSCI calls [this implementation only * supports get_version, system_reset and cpu_on]. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include struct psci_softc { device_t dev; psci_callfn_t psci_call; uint32_t psci_fnids[PSCI_FN_MAX]; }; static int psci_v0_1_init(device_t dev); static int psci_v0_2_init(device_t dev); struct psci_softc *psci_softc = NULL; static struct ofw_compat_data compat_data[] = { {"arm,psci-0.2", (uintptr_t)psci_v0_2_init}, {"arm,psci", (uintptr_t)psci_v0_1_init}, {NULL, 0} }; static int psci_probe(device_t dev); static int psci_attach(device_t dev); static void psci_shutdown(void *, int); static device_method_t psci_methods[] = { DEVMETHOD(device_probe, psci_probe), DEVMETHOD(device_attach, psci_attach), DEVMETHOD_END }; static driver_t psci_driver = { "psci", psci_methods, sizeof(struct psci_softc), }; static devclass_t psci_devclass; EARLY_DRIVER_MODULE(psci, simplebus, psci_driver, psci_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); EARLY_DRIVER_MODULE(psci, ofwbus, psci_driver, psci_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); static psci_callfn_t psci_get_callfn(phandle_t node) { char method[16]; if ((OF_getprop(node, "method", method, sizeof(method))) > 0) { if (strcmp(method, "hvc") == 0) return (psci_hvc_despatch); else if (strcmp(method, "smc") == 0) return (psci_smc_despatch); else printf("psci: PSCI conduit \"%s\" invalid\n", method); } else printf("psci: PSCI conduit not supplied in the device tree\n"); return (NULL); } static int psci_probe(device_t dev) { const struct ofw_compat_data *ocd; if (!ofw_bus_status_okay(dev)) return (ENXIO); ocd = ofw_bus_search_compatible(dev, compat_data); if (ocd->ocd_str == NULL) return (ENXIO); device_set_desc(dev, "ARM Power State Co-ordination Interface Driver"); return (BUS_PROBE_SPECIFIC); } static int psci_attach(device_t dev) { struct psci_softc *sc = device_get_softc(dev); const struct ofw_compat_data *ocd; psci_initfn_t psci_init; phandle_t node; if (psci_softc != NULL) return (ENXIO); ocd = ofw_bus_search_compatible(dev, compat_data); psci_init = (psci_initfn_t)ocd->ocd_data; KASSERT(psci_init != NULL, ("PSCI init function cannot be NULL")); node = ofw_bus_get_node(dev); sc->psci_call = psci_get_callfn(node); if (sc->psci_call == NULL) return (ENXIO); if (psci_init(dev)) return (ENXIO); psci_softc = sc; return (0); } static int psci_get_version(struct psci_softc *sc) { uint32_t fnid; /* PSCI version wasn't supported in v0.1. */ fnid = sc->psci_fnids[PSCI_FN_VERSION]; if (fnid) return (sc->psci_call(fnid, 0, 0, 0)); return (PSCI_RETVAL_NOT_SUPPORTED); } int psci_cpu_on(unsigned long cpu, unsigned long entry, unsigned long context_id) { psci_callfn_t callfn; phandle_t node; uint32_t fnid; if (psci_softc == NULL) { node = ofw_bus_find_compatible(OF_peer(0), "arm,psci-0.2"); if (node == 0) /* TODO: Handle psci 0.1 */ return (PSCI_RETVAL_INTERNAL_FAILURE); fnid = PSCI_FNID_CPU_ON; callfn = psci_get_callfn(node); if (callfn == NULL) return (PSCI_RETVAL_INTERNAL_FAILURE); } else { callfn = psci_softc->psci_call; fnid = psci_softc->psci_fnids[PSCI_FN_CPU_ON]; } /* PSCI v0.1 and v0.2 both support cpu_on. */ return (callfn(fnid, cpu, entry, context_id)); } static void psci_shutdown(void *xsc, int howto) { uint32_t fn = 0; /* PSCI system_off and system_reset werent't supported in v0.1. */ if ((howto & RB_POWEROFF) != 0) fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_OFF]; else if ((howto & RB_HALT) == 0) fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_RESET]; if (fn) psci_softc->psci_call(fn, 0, 0, 0); /* System reset and off do not return. */ } +void +psci_reset(void) +{ + + psci_shutdown(NULL, 0); +} + static int psci_v0_1_init(device_t dev) { struct psci_softc *sc = device_get_softc(dev); int psci_fn; uint32_t psci_fnid; phandle_t node; int len; /* Zero out the function ID table - Is this needed ? */ for (psci_fn = PSCI_FN_VERSION, psci_fnid = PSCI_FNID_VERSION; psci_fn < PSCI_FN_MAX; psci_fn++, psci_fnid++) sc->psci_fnids[psci_fn] = 0; /* PSCI v0.1 doesn't specify function IDs. Get them from DT */ node = ofw_bus_get_node(dev); if ((len = OF_getproplen(node, "cpu_suspend")) > 0) { OF_getencprop(node, "cpu_suspend", &psci_fnid, len); sc->psci_fnids[PSCI_FN_CPU_SUSPEND] = psci_fnid; } if ((len = OF_getproplen(node, "cpu_on")) > 0) { OF_getencprop(node, "cpu_on", &psci_fnid, len); sc->psci_fnids[PSCI_FN_CPU_ON] = psci_fnid; } if ((len = OF_getproplen(node, "cpu_off")) > 0) { OF_getencprop(node, "cpu_off", &psci_fnid, len); sc->psci_fnids[PSCI_FN_CPU_OFF] = psci_fnid; } if ((len = OF_getproplen(node, "migrate")) > 0) { OF_getencprop(node, "migrate", &psci_fnid, len); sc->psci_fnids[PSCI_FN_MIGRATE] = psci_fnid; } if (bootverbose) device_printf(dev, "PSCI version 0.1 available\n"); return(0); } static int psci_v0_2_init(device_t dev) { struct psci_softc *sc = device_get_softc(dev); int version; /* PSCI v0.2 specifies explicit function IDs. */ sc->psci_fnids[PSCI_FN_VERSION] = PSCI_FNID_VERSION; sc->psci_fnids[PSCI_FN_CPU_SUSPEND] = PSCI_FNID_CPU_SUSPEND; sc->psci_fnids[PSCI_FN_CPU_OFF] = PSCI_FNID_CPU_OFF; sc->psci_fnids[PSCI_FN_CPU_ON] = PSCI_FNID_CPU_ON; sc->psci_fnids[PSCI_FN_AFFINITY_INFO] = PSCI_FNID_AFFINITY_INFO; sc->psci_fnids[PSCI_FN_MIGRATE] = PSCI_FNID_MIGRATE; sc->psci_fnids[PSCI_FN_MIGRATE_INFO_TYPE] = PSCI_FNID_MIGRATE_INFO_TYPE; sc->psci_fnids[PSCI_FN_MIGRATE_INFO_UP_CPU] = PSCI_FNID_MIGRATE_INFO_UP_CPU; sc->psci_fnids[PSCI_FN_SYSTEM_OFF] = PSCI_FNID_SYSTEM_OFF; sc->psci_fnids[PSCI_FN_SYSTEM_RESET] = PSCI_FNID_SYSTEM_RESET; version = psci_get_version(sc); if (version == PSCI_RETVAL_NOT_SUPPORTED) return (1); if ((PSCI_VER_MAJOR(version) == 0 && PSCI_VER_MINOR(version) == 2) || (PSCI_VER_MAJOR(version) == 1 && PSCI_VER_MINOR(version) == 0)) { if (bootverbose) device_printf(dev, "PSCI version 0.2 available\n"); /* * We only register this for v0.2 since v0.1 doesn't support * system_reset. */ EVENTHANDLER_REGISTER(shutdown_final, psci_shutdown, sc, SHUTDOWN_PRI_LAST); return (0); } device_printf(dev, "PSCI version number mismatched with DT\n"); return (1); } Index: stable/11/sys/dev/psci/psci.h =================================================================== --- stable/11/sys/dev/psci/psci.h (revision 319206) +++ stable/11/sys/dev/psci/psci.h (revision 319207) @@ -1,102 +1,102 @@ /*- * Copyright (c) 2013, 2014 Robin Randhawa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE_PSCI_H_ #define _MACHINE_PSCI_H_ #include typedef int (*psci_initfn_t)(device_t dev); typedef int (*psci_callfn_t)(register_t, register_t, register_t, register_t); extern int psci_present; -void psci_system_reset(void); +void psci_reset(void); int psci_cpu_on(unsigned long, unsigned long, unsigned long); int psci_hvc_despatch(register_t, register_t, register_t, register_t); int psci_smc_despatch(register_t, register_t, register_t, register_t); /* * PSCI return codes. */ #define PSCI_RETVAL_SUCCESS 0 #define PSCI_RETVAL_NOT_SUPPORTED -1 #define PSCI_RETVAL_INVALID_PARAMS -2 #define PSCI_RETVAL_DENIED -3 #define PSCI_RETVAL_ALREADY_ON -4 #define PSCI_RETVAL_ON_PENDING -5 #define PSCI_RETVAL_INTERNAL_FAILURE -6 #define PSCI_RETVAL_NOT_PRESENT -7 #define PSCI_RETVAL_DISABLED -8 /* * PSCI function codes (as per PSCI v0.2). */ #ifdef __aarch64__ #define PSCI_FNID_VERSION 0x84000000 #define PSCI_FNID_CPU_SUSPEND 0xc4000001 #define PSCI_FNID_CPU_OFF 0x84000002 #define PSCI_FNID_CPU_ON 0xc4000003 #define PSCI_FNID_AFFINITY_INFO 0xc4000004 #define PSCI_FNID_MIGRATE 0xc4000005 #define PSCI_FNID_MIGRATE_INFO_TYPE 0x84000006 #define PSCI_FNID_MIGRATE_INFO_UP_CPU 0xc4000007 #define PSCI_FNID_SYSTEM_OFF 0x84000008 #define PSCI_FNID_SYSTEM_RESET 0x84000009 #else #define PSCI_FNID_VERSION 0x84000000 #define PSCI_FNID_CPU_SUSPEND 0x84000001 #define PSCI_FNID_CPU_OFF 0x84000002 #define PSCI_FNID_CPU_ON 0x84000003 #define PSCI_FNID_AFFINITY_INFO 0x84000004 #define PSCI_FNID_MIGRATE 0x84000005 #define PSCI_FNID_MIGRATE_INFO_TYPE 0x84000006 #define PSCI_FNID_MIGRATE_INFO_UP_CPU 0x84000007 #define PSCI_FNID_SYSTEM_OFF 0x84000008 #define PSCI_FNID_SYSTEM_RESET 0x84000009 #endif #define PSCI_VER_MAJOR(v) (((v) >> 16) & 0xFF) #define PSCI_VER_MINOR(v) ((v) & 0xFF) enum psci_fn { PSCI_FN_VERSION, PSCI_FN_CPU_SUSPEND, PSCI_FN_CPU_OFF, PSCI_FN_CPU_ON, PSCI_FN_AFFINITY_INFO, PSCI_FN_MIGRATE, PSCI_FN_MIGRATE_INFO_TYPE, PSCI_FN_MIGRATE_INFO_UP_CPU, PSCI_FN_SYSTEM_OFF, PSCI_FN_SYSTEM_RESET, PSCI_FN_MAX }; #endif /* _MACHINE_PSCI_H_ */ Index: stable/11 =================================================================== --- stable/11 (revision 319206) +++ stable/11 (revision 319207) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r317361