From 3f1731310f2625bad45b67b7c7026a9ff2a4f1e1 Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 27 Apr 2017 10:23:19 +0000 Subject: [PATCH] Add code to identify the CPUs on arm64 systems. The primary CPU is attached and identified early on. For the secondary CPUs this happens late, such that the drivers we need to spin up CPUs, such as psci(4), will be available. This also fixes some code in simplebus(4) where the return value of OF_getprop() was not properly checked. Heavily based on an earlier diff from drahn@. ok drahn@, jsg@ --- sys/arch/arm64/arm64/cpu.c | 147 ++++++++++++++++++++++++++++++++ sys/arch/arm64/conf/GENERIC | 3 +- sys/arch/arm64/conf/RAMDISK | 3 +- sys/arch/arm64/conf/files.arm64 | 6 +- sys/arch/arm64/dev/mainbus.c | 113 ++++++++++++++++-------- sys/arch/arm64/dev/mainbus.h | 4 +- sys/arch/arm64/dev/simplebus.c | 12 +-- sys/arch/arm64/include/armreg.h | 9 +- 8 files changed, 250 insertions(+), 47 deletions(-) create mode 100644 sys/arch/arm64/arm64/cpu.c diff --git a/sys/arch/arm64/arm64/cpu.c b/sys/arch/arm64/arm64/cpu.c new file mode 100644 index 00000000000..a9ee4608283 --- /dev/null +++ b/sys/arch/arm64/arm64/cpu.c @@ -0,0 +1,147 @@ +/* $OpenBSD: cpu.c,v 1.1 2017/04/27 10:23:19 kettenis Exp $ */ + +/* + * Copyright (c) 2016 Dale Rahn + * Copyright (c) 2017 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include + +/* CPU Identification */ +#define CPU_IMPL_ARM 0x41 + +#define CPU_PART_CORTEX_A53 0xd03 +#define CPU_PART_CORTEX_A35 0xd04 +#define CPU_PART_CORTEX_A57 0xd07 +#define CPU_PART_CORTEX_A72 0xd08 +#define CPU_PART_CORTEX_A73 0xd09 + +#define CPU_IMPL(midr) (((midr) >> 24) & 0xff) +#define CPU_PART(midr) (((midr) >> 4) & 0xfff) +#define CPU_VAR(midr) (((midr) >> 20) & 0xf) +#define CPU_REV(midr) (((midr) >> 0) & 0xf) + +struct cpu_cores { + int id; + char *name; +}; + +struct cpu_cores cpu_cores_none[] = { + { 0x0, "Unknown" }, +}; + +struct cpu_cores cpu_cores_arm[] = { + { CPU_PART_CORTEX_A35, "Cortex-A35" }, + { CPU_PART_CORTEX_A53, "Cortex-A53" }, + { CPU_PART_CORTEX_A57, "Cortex-A57" }, + { CPU_PART_CORTEX_A72, "Cortex-A72" }, + { CPU_PART_CORTEX_A73, "Cortex-A73" }, + { 0x0, "Unknown" }, +}; + +/* arm cores makers */ +const struct implementers { + int id; + char *name; + struct cpu_cores *corelist; +} cpu_implementers[] = { + { CPU_IMPL_ARM, "ARM", cpu_cores_arm }, + { 0, "", NULL }, +}; + +int cpu_match(struct device *, void *, void *); +void cpu_attach(struct device *, struct device *, void *); + +struct cfattach cpu_ca = { + sizeof(struct device), cpu_match, cpu_attach +}; + +struct cfdriver cpu_cd = { + NULL, "cpu", DV_DULL +}; + +void +cpu_identify(struct cpu_info *ci) +{ + uint64_t midr, impl, part; + char *impl_name = "Unknown"; + char *part_name = "Unknown"; + struct cpu_cores *coreselecter = cpu_cores_none; + int i; + + midr = READ_SPECIALREG(midr_el1); + impl = CPU_IMPL(midr); + part = CPU_PART(midr); + + for (i = 0; cpu_implementers[i].id != 0; i++) { + if (impl == cpu_implementers[i].id) { + impl_name = cpu_implementers[i].name; + coreselecter = cpu_implementers[i].corelist; + break; + } + } + + for (i = 0; coreselecter[i].id != 0; i++) { + if (part == coreselecter[i].id) { + part_name = coreselecter[i].name; + break; + } + } + + printf(" %s %s r%dp%d", impl_name, part_name, CPU_VAR(midr), + CPU_REV(midr)); +} + +int +cpu_match(struct device *parent, void *cfdata, void *aux) +{ + struct fdt_attach_args *faa = aux; + char buf[32]; + + if (OF_getprop(faa->fa_node, "device_type", buf, sizeof(buf)) > 0 && + strcmp(buf, "cpu") == 0) + return 1; + + return 0; +} + +void +cpu_attach(struct device *parent, struct device *dev, void *aux) +{ + struct fdt_attach_args *faa = aux; + struct cpu_info *ci; + uint64_t mpidr = READ_SPECIALREG(mpidr_el1); + + KASSERT(faa->fa_nreg > 0); + + if (faa->fa_reg[0].addr == (mpidr & MPIDR_AFF)) { + ci = &cpu_info_primary; + ci->ci_cpuid = dev->dv_unit; + ci->ci_dev = dev; + + printf(":"); + cpu_identify(ci); + } else { + printf(": not configured"); + } + + printf("\n"); +} diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC index 44ab4f3e39f..2f591071a80 100644 --- a/sys/arch/arm64/conf/GENERIC +++ b/sys/arch/arm64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.22 2017/03/10 03:27:50 jsg Exp $ +# $OpenBSD: GENERIC,v 1.23 2017/04/27 10:23:19 kettenis Exp $ # # GENERIC machine description file # @@ -35,6 +35,7 @@ config bsd swap generic # The main bus device mainbus0 at root +cpu0 at mainbus? simplebus* at fdt? scsibus* at scsi? diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK index d8ec65e41d1..506d1691824 100644 --- a/sys/arch/arm64/conf/RAMDISK +++ b/sys/arch/arm64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.19 2017/03/10 03:27:50 jsg Exp $ +# $OpenBSD: RAMDISK,v 1.20 2017/04/27 10:23:19 kettenis Exp $ # # GENERIC machine description file # @@ -45,6 +45,7 @@ config bsd root on rd0a swap on rd0b # The main bus device mainbus0 at root +cpu0 at mainbus? simplebus* at fdt? scsibus* at scsi? diff --git a/sys/arch/arm64/conf/files.arm64 b/sys/arch/arm64/conf/files.arm64 index e2370431497..29849085a9d 100644 --- a/sys/arch/arm64/conf/files.arm64 +++ b/sys/arch/arm64/conf/files.arm64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.arm64,v 1.11 2017/02/25 17:04:19 patrick Exp $ +# $OpenBSD: files.arm64,v 1.12 2017/04/27 10:23:19 kettenis Exp $ maxpartitions 16 maxusers 2 8 64 @@ -23,6 +23,7 @@ file arch/arm64/arm64/sig_machdep.c file arch/arm64/arm64/syscall.c file arch/arm64/arm64/sys_machdep.c +file arch/arm64/arm64/cpu.c file arch/arm64/arm64/intr.c file arch/arm64/arm64/softintr.c file arch/arm64/arm64/vfp.c @@ -75,6 +76,9 @@ include "dev/wscons/files.wscons" include "dev/rasops/files.rasops" include "dev/wsfont/files.wsfont" +device cpu {} +attach cpu at mainbus + # # Machine-independent HID support # diff --git a/sys/arch/arm64/dev/mainbus.c b/sys/arch/arm64/dev/mainbus.c index e638d63185f..1d8c8bbc274 100644 --- a/sys/arch/arm64/dev/mainbus.c +++ b/sys/arch/arm64/dev/mainbus.c @@ -1,6 +1,7 @@ -/* $OpenBSD: mainbus.c,v 1.3 2017/02/22 22:55:27 patrick Exp $ */ +/* $OpenBSD: mainbus.c,v 1.4 2017/04/27 10:23:19 kettenis Exp $ */ /* * Copyright (c) 2016 Patrick Wildt + * Copyright (c) 2017 Mark Kettenis * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -31,7 +32,11 @@ int mainbus_match(struct device *, void *, void *); void mainbus_attach(struct device *, struct device *, void *); -void mainbus_attach_node(struct device *, int); +void mainbus_attach_node(struct device *, int, cfmatch_t); +int mainbus_match_status(struct device *, void *, void *); +void mainbus_attach_cpus(struct device *, cfmatch_t); +int mainbus_match_primary(struct device *, void *, void *); +int mainbus_match_secondary(struct device *, void *, void *); struct mainbus_softc { struct device sc_dev; @@ -88,7 +93,7 @@ void mainbus_attach(struct device *parent, struct device *self, void *aux) { struct mainbus_softc *sc = (struct mainbus_softc *)self; - char buffer[128]; + char model[128]; int node, len; if ((node = OF_peer(0)) == 0) @@ -102,18 +107,16 @@ mainbus_attach(struct device *parent, struct device *self, void *aux) sc->sc_acells = OF_getpropint(OF_peer(0), "#address-cells", 1); sc->sc_scells = OF_getpropint(OF_peer(0), "#size-cells", 1); - if ((len = OF_getprop(node, "model", buffer, sizeof(buffer))) > 0) { - printf(": %s\n", buffer); + if ((len = OF_getprop(node, "model", model, sizeof(model))) > 0) { + printf(": %s\n", model); hw_prod = malloc(len, M_DEVBUF, M_NOWAIT); if (hw_prod) - strlcpy(hw_prod, buffer, len); + strlcpy(hw_prod, model, len); } else printf(": unknown model\n"); - /* Attach CPU first. */ - mainbus_legacy_found(self, "cpu"); - - /* TODO: Scan for interrupt controllers and attach them first? */ + /* Attach primary CPU first. */ + mainbus_attach_cpus(self, mainbus_match_primary); sc->sc_rangeslen = OF_getproplen(OF_peer(0), "ranges"); if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) { @@ -123,33 +126,27 @@ mainbus_attach(struct device *parent, struct device *self, void *aux) } /* Scan the whole tree. */ - for (node = OF_child(node); - node != 0; - node = OF_peer(node)) - { - mainbus_attach_node(self, node); - } + for (node = OF_child(node); node != 0; node = OF_peer(node)) + mainbus_attach_node(self, node, NULL); + + /* Attach secondary CPUs. */ + mainbus_attach_cpus(self, mainbus_match_secondary); } /* * Look for a driver that wants to be attached to this node. */ void -mainbus_attach_node(struct device *self, int node) +mainbus_attach_node(struct device *self, int node, cfmatch_t submatch) { struct mainbus_softc *sc = (struct mainbus_softc *)self; struct fdt_attach_args fa; - char buffer[128]; int i, len, line; uint32_t *cell, *reg; - if (!OF_getprop(node, "compatible", buffer, sizeof(buffer))) + if (OF_getproplen(node, "compatible") <= 0) return; - if (OF_getprop(node, "status", buffer, sizeof(buffer))) - if (!strcmp(buffer, "disabled")) - return; - memset(&fa, 0, sizeof(fa)); fa.fa_name = ""; fa.fa_node = node; @@ -196,24 +193,72 @@ mainbus_attach_node(struct device *self, int node) OF_getpropintarray(node, "interrupts", fa.fa_intr, len); } - /* TODO: attach the device's clocks first? */ - - config_found(self, &fa, NULL); + if (submatch == NULL) + submatch = mainbus_match_status; + config_found_sm(self, &fa, NULL, submatch); free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg)); free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t)); } -/* - * Legacy support for SoCs that do not use FDT. - */ +int +mainbus_match_status(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *fa = aux; + struct cfdata *cf = match; + char buf[32]; + + if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 && + strcmp(buf, "disabled") == 0) + return 0; + + return (*cf->cf_attach->ca_match)(parent, match, aux); +} + void -mainbus_legacy_found(struct device *self, char *name) +mainbus_attach_cpus(struct device *self, cfmatch_t match) +{ + struct mainbus_softc *sc = (struct mainbus_softc *)self; + int node = OF_finddevice("/cpus"); + int acells, scells; + + if (node == 0) + return; + + acells = sc->sc_acells; + scells = sc->sc_scells; + sc->sc_acells = OF_getpropint(node, "#address-cells", 2); + sc->sc_scells = OF_getpropint(node, "#size-cells", 0); + + for (node = OF_child(node); node != 0; node = OF_peer(node)) + mainbus_attach_node(self, node, match); + + sc->sc_acells = acells; + sc->sc_scells = scells; +} + +int +mainbus_match_primary(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *fa = aux; + struct cfdata *cf = match; + uint64_t mpidr = READ_SPECIALREG(mpidr_el1); + + if (fa->fa_nreg < 1 || fa->fa_reg[0].addr != (mpidr & MPIDR_AFF)) + return 0; + + return (*cf->cf_attach->ca_match)(parent, match, aux); +} + +int +mainbus_match_secondary(struct device *parent, void *match, void *aux) { - union mainbus_attach_args ma; + struct fdt_attach_args *fa = aux; + struct cfdata *cf = match; + uint64_t mpidr = READ_SPECIALREG(mpidr_el1); - memset(&ma, 0, sizeof(ma)); - ma.ma_name = name; + if (fa->fa_nreg < 1 || fa->fa_reg[0].addr == (mpidr & MPIDR_AFF)) + return 0; - config_found(self, &ma, NULL); + return (*cf->cf_attach->ca_match)(parent, match, aux); } diff --git a/sys/arch/arm64/dev/mainbus.h b/sys/arch/arm64/dev/mainbus.h index 9bafb71e4f7..5f63d0ec459 100644 --- a/sys/arch/arm64/dev/mainbus.h +++ b/sys/arch/arm64/dev/mainbus.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */ +/* $OpenBSD: mainbus.h,v 1.2 2017/04/27 10:23:19 kettenis Exp $ */ /* * Copyright (c) 2016 Patrick Wildt * @@ -24,6 +24,4 @@ union mainbus_attach_args { struct fdt_attach_args ma_faa; }; -void mainbus_legacy_found(struct device *, char *); - #endif /* __MAINBUS_H__ */ diff --git a/sys/arch/arm64/dev/simplebus.c b/sys/arch/arm64/dev/simplebus.c index f7eac42a36d..fccf11b5fbf 100644 --- a/sys/arch/arm64/dev/simplebus.c +++ b/sys/arch/arm64/dev/simplebus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: simplebus.c,v 1.6 2017/02/22 22:55:27 patrick Exp $ */ +/* $OpenBSD: simplebus.c,v 1.7 2017/04/27 10:23:19 kettenis Exp $ */ /* * Copyright (c) 2016 Patrick Wildt * @@ -157,16 +157,16 @@ simplebus_attach_node(struct device *self, int node) { struct simplebus_softc *sc = (struct simplebus_softc *)self; struct fdt_attach_args fa; - char buffer[128]; + char buf[32]; int i, len, line; uint32_t *cell, *reg; - if (!OF_getprop(node, "compatible", buffer, sizeof(buffer))) + if (OF_getproplen(node, "compatible") <= 0) return; - if (OF_getprop(node, "status", buffer, sizeof(buffer))) - if (!strcmp(buffer, "disabled")) - return; + if (OF_getprop(node, "status", buf, sizeof(buf)) > 0 && + strcmp(buf, "disabled") == 0) + return; memset(&fa, 0, sizeof(fa)); fa.fa_name = ""; diff --git a/sys/arch/arm64/include/armreg.h b/sys/arch/arm64/include/armreg.h index 1a1802b1dbb..74bd27e983d 100644 --- a/sys/arch/arm64/include/armreg.h +++ b/sys/arch/arm64/include/armreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: armreg.h,v 1.3 2017/02/06 19:23:45 patrick Exp $ */ +/* $OpenBSD: armreg.h,v 1.4 2017/04/27 10:23:19 kettenis Exp $ */ /*- * Copyright (c) 2013, 2014 Andrew Turner * Copyright (c) 2015 The FreeBSD Foundation @@ -67,6 +67,13 @@ #define CTR_ILINE_MASK (0xf << CTR_ILINE_SHIFT) #define CTR_ILINE_SIZE(reg) (((reg) & CTR_ILINE_MASK) >> CTR_ILINE_SHIFT) +/* MPIDR_EL1 - Multiprocessor Affinity Register */ +#define MPIDR_AFF3 (0xFFULL << 32) +#define MPIDR_AFF2 (0xFFULL << 16) +#define MPIDR_AFF1 (0xFFULL << 8) +#define MPIDR_AFF0 (0xFFULL << 0) +#define MPIDR_AFF (MPIDR_AFF3|MPIDR_AFF2|MPIDR_AFF1|MPIDR_AFF0) + /* DCZID_EL0 - Data Cache Zero ID register */ #define DCZID_DZP (1 << 4) /* DC ZVA prohibited if non-0 */ #define DCZID_BS_SHIFT 0 -- 2.20.1