From owner-svn-src-all@freebsd.org Wed Dec 7 14:24:54 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A581BC6A9D4; Wed, 7 Dec 2016 14:24:54 +0000 (UTC) (envelope-from andrew@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 75368C25; Wed, 7 Dec 2016 14:24:54 +0000 (UTC) (envelope-from andrew@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uB7EOrPa003993; Wed, 7 Dec 2016 14:24:53 GMT (envelope-from andrew@FreeBSD.org) Received: (from andrew@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uB7EOrJk003991; Wed, 7 Dec 2016 14:24:53 GMT (envelope-from andrew@FreeBSD.org) Message-Id: <201612071424.uB7EOrJk003991@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: andrew set sender to andrew@FreeBSD.org using -f From: Andrew Turner Date: Wed, 7 Dec 2016 14:24:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r309674 - in head/sys: conf dev/psci X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 07 Dec 2016 14:24:54 -0000 Author: andrew Date: Wed Dec 7 14:24:53 2016 New Revision: 309674 URL: https://svnweb.freebsd.org/changeset/base/309674 Log: Add ACPI support to the PSCI driver. This checks the Fixed ACPI Description Table to find if the hardware supports PSCI, and if so what method the kernel should use to interact with it. Obtained from: ABT Systems Ltd Sponsored by: The FreeBSD Foundation Modified: head/sys/conf/files.arm64 head/sys/dev/psci/psci.c Modified: head/sys/conf/files.arm64 ============================================================================== --- head/sys/conf/files.arm64 Wed Dec 7 13:19:19 2016 (r309673) +++ head/sys/conf/files.arm64 Wed Dec 7 14:24:53 2016 (r309674) @@ -156,7 +156,7 @@ dev/ofw/ofw_cpu.c optional fdt dev/ofw/ofwpci.c optional fdt pci dev/pci/pci_host_generic.c optional pci dev/pci/pci_host_generic_fdt.c optional pci fdt -dev/psci/psci.c optional psci fdt +dev/psci/psci.c optional psci dev/psci/psci_arm64.S optional psci dev/uart/uart_cpu_arm64.c optional uart dev/uart/uart_dev_pl011.c optional uart pl011 Modified: head/sys/dev/psci/psci.c ============================================================================== --- head/sys/dev/psci/psci.c Wed Dec 7 13:19:19 2016 (r309673) +++ head/sys/dev/psci/psci.c Wed Dec 7 14:24:53 2016 (r309674) @@ -43,6 +43,9 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_acpi.h" +#include "opt_platform.h" + #include #include #include @@ -52,11 +55,19 @@ __FBSDID("$FreeBSD$"); #include #include +#include + +#ifdef DEV_ACPI +#include +#include +#endif +#ifdef FDT #include #include #include #include +#endif #include @@ -67,43 +78,60 @@ struct psci_softc { uint32_t psci_fnids[PSCI_FN_MAX]; }; +#ifdef FDT static int psci_v0_1_init(device_t dev); +#endif static int psci_v0_2_init(device_t dev); struct psci_softc *psci_softc = NULL; +#ifdef __arm__ +#define USE_ACPI 0 +#define USE_FDT 1 +#elif defined(__aarch64__) +#define USE_ACPI (arm64_bus_method == ARM64_BUS_ACPI) +#define USE_FDT (arm64_bus_method == ARM64_BUS_FDT) +#else +#error Unknown architecture +#endif + +#ifdef FDT 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} }; +#endif -static int psci_probe(device_t dev); -static int psci_attach(device_t dev); +static int psci_attach(device_t, psci_initfn_t); static void psci_shutdown(void *, int); -static device_method_t psci_methods[] = { - DEVMETHOD(device_probe, psci_probe), - DEVMETHOD(device_attach, psci_attach), +#ifdef FDT +static int psci_fdt_probe(device_t dev); +static int psci_fdt_attach(device_t dev); + +static device_method_t psci_fdt_methods[] = { + DEVMETHOD(device_probe, psci_fdt_probe), + DEVMETHOD(device_attach, psci_fdt_attach), DEVMETHOD_END }; -static driver_t psci_driver = { +static driver_t psci_fdt_driver = { "psci", - psci_methods, + psci_fdt_methods, sizeof(struct psci_softc), }; -static devclass_t psci_devclass; +static devclass_t psci_fdt_devclass; -EARLY_DRIVER_MODULE(psci, simplebus, psci_driver, psci_devclass, 0, 0, +EARLY_DRIVER_MODULE(psci, simplebus, psci_fdt_driver, psci_fdt_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); -EARLY_DRIVER_MODULE(psci, ofwbus, psci_driver, psci_devclass, 0, 0, +EARLY_DRIVER_MODULE(psci, ofwbus, psci_fdt_driver, psci_fdt_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); static psci_callfn_t -psci_get_callfn(phandle_t node) +psci_fdt_get_callfn(phandle_t node) { char method[16]; @@ -121,7 +149,7 @@ psci_get_callfn(phandle_t node) } static int -psci_probe(device_t dev) +psci_fdt_probe(device_t dev) { const struct ofw_compat_data *ocd; @@ -138,25 +166,144 @@ psci_probe(device_t dev) } static int -psci_attach(device_t dev) +psci_fdt_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); + sc->psci_call = psci_fdt_get_callfn(node); + + return (psci_attach(dev, psci_init)); +} +#endif + +#ifdef DEV_ACPI +static void psci_acpi_identify(driver_t *, device_t); +static int psci_acpi_probe(device_t); +static int psci_acpi_attach(device_t); + +static device_method_t psci_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, psci_acpi_identify), + DEVMETHOD(device_probe, psci_acpi_probe), + DEVMETHOD(device_attach, psci_acpi_attach), + + DEVMETHOD_END +}; + +static driver_t psci_acpi_driver = { + "psci", + psci_acpi_methods, + sizeof(struct psci_softc), +}; + +static devclass_t psci_acpi_devclass; + +EARLY_DRIVER_MODULE(psci, acpi, psci_acpi_driver, psci_acpi_devclass, 0, 0, + BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); + +static int +psci_acpi_bootflags(void) +{ + ACPI_TABLE_FADT *fadt; + vm_paddr_t physaddr; + int flags; + + physaddr = acpi_find_table(ACPI_SIG_FADT); + if (physaddr == 0) + return (0); + + fadt = acpi_map_table(physaddr, ACPI_SIG_FADT); + if (fadt == NULL) { + printf("psci: Unable to map the FADT\n"); + return (0); + } + + flags = fadt->ArmBootFlags; + + acpi_unmap_table(fadt); + return (flags); +} + +static psci_callfn_t +psci_acpi_get_callfn(int flags) +{ + + if ((flags & ACPI_FADT_PSCI_COMPLIANT) != 0) { + if ((flags & ACPI_FADT_PSCI_USE_HVC) != 0) + return (psci_hvc_despatch); + else + return (psci_smc_despatch); + } else { + printf("psci: PSCI conduit not supplied in the device tree\n"); + } + + return (NULL); +} + +static void +psci_acpi_identify(driver_t *driver, device_t parent) +{ + device_t dev; + int flags; + + flags = psci_acpi_bootflags(); + if ((flags & ACPI_FADT_PSCI_COMPLIANT) != 0) { + dev = BUS_ADD_CHILD(parent, + BUS_PASS_CPU + BUS_PASS_ORDER_FIRST, "psci", -1); + + if (dev != NULL) + acpi_set_private(dev, (void *)(uintptr_t)flags); + } +} + +static int +psci_acpi_probe(device_t dev) +{ + uintptr_t flags; + + flags = (uintptr_t)acpi_get_private(dev); + if ((flags & ACPI_FADT_PSCI_COMPLIANT) == 0) + return (ENXIO); + + device_set_desc(dev, "ARM Power State Co-ordination Interface Driver"); + return (BUS_PROBE_SPECIFIC); +} + +static int +psci_acpi_attach(device_t dev) +{ + struct psci_softc *sc = device_get_softc(dev); + uintptr_t flags; + + flags = (uintptr_t)acpi_get_private(dev); + if ((flags & ACPI_FADT_PSCI_USE_HVC) != 0) + sc->psci_call = psci_hvc_despatch; + else + sc->psci_call = psci_smc_despatch; + + return (psci_attach(dev, psci_v0_2_init)); +} +#endif + +static int +psci_attach(device_t dev, psci_initfn_t psci_init) +{ + struct psci_softc *sc = device_get_softc(dev); + + if (psci_softc != NULL) + return (ENXIO); + if (sc->psci_call == NULL) return (ENXIO); + KASSERT(psci_init != NULL, ("PSCI init function cannot be NULL")); if (psci_init(dev)) return (ENXIO); @@ -178,21 +325,62 @@ psci_get_version(struct psci_softc *sc) return (PSCI_RETVAL_NOT_SUPPORTED); } +#ifdef FDT +static int +psci_fdt_callfn(psci_callfn_t *callfn) +{ + phandle_t node; + + node = ofw_bus_find_compatible(OF_peer(0), "arm,psci-0.2"); + if (node == 0) + /* TODO: Handle psci 0.1 */ + return (PSCI_MISSING); + + *callfn = psci_fdt_get_callfn(node); + return (0); +} +#endif + +#ifdef DEV_ACPI +static int +psci_acpi_callfn(psci_callfn_t *callfn) +{ + int flags; + + flags = psci_acpi_bootflags(); + if ((flags & ACPI_FADT_PSCI_COMPLIANT) == 0) + return (PSCI_MISSING); + + *callfn = psci_acpi_get_callfn(flags); + return (0); +} +#endif + int psci_cpu_on(unsigned long cpu, unsigned long entry, unsigned long context_id) { psci_callfn_t callfn; - phandle_t node; uint32_t fnid; + int error; 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_MISSING); - fnid = PSCI_FNID_CPU_ON; - callfn = psci_get_callfn(node); + callfn = NULL; +#ifdef FDT + if (USE_FDT) { + error = psci_fdt_callfn(&callfn); + if (error != 0) + return (error); + } +#endif +#ifdef DEV_ACPI + if (callfn == NULL && USE_ACPI) { + error = psci_acpi_callfn(&callfn); + if (error != 0) + return (error); + } +#endif + if (callfn == NULL) return (PSCI_MISSING); } else { @@ -209,6 +397,9 @@ psci_shutdown(void *xsc, int howto) { uint32_t fn = 0; + if (psci_softc == NULL) + return; + /* 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]; @@ -221,6 +412,8 @@ psci_shutdown(void *xsc, int howto) /* System reset and off do not return. */ } +#ifdef FDT +/* Only support PSCI 0.1 on FDT */ static int psci_v0_1_init(device_t dev) { @@ -264,6 +457,7 @@ psci_v0_1_init(device_t dev) return(0); } +#endif static int psci_v0_2_init(device_t dev)