Add code to identify the CPUs on arm64 systems. The primary CPU is attached
authorkettenis <kettenis@openbsd.org>
Thu, 27 Apr 2017 10:23:19 +0000 (10:23 +0000)
committerkettenis <kettenis@openbsd.org>
Thu, 27 Apr 2017 10:23:19 +0000 (10:23 +0000)
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 [new file with mode: 0644]
sys/arch/arm64/conf/GENERIC
sys/arch/arm64/conf/RAMDISK
sys/arch/arm64/conf/files.arm64
sys/arch/arm64/dev/mainbus.c
sys/arch/arm64/dev/mainbus.h
sys/arch/arm64/dev/simplebus.c
sys/arch/arm64/include/armreg.h

diff --git a/sys/arch/arm64/arm64/cpu.c b/sys/arch/arm64/arm64/cpu.c
new file mode 100644 (file)
index 0000000..a9ee460
--- /dev/null
@@ -0,0 +1,147 @@
+/*     $OpenBSD: cpu.c,v 1.1 2017/04/27 10:23:19 kettenis Exp $        */
+
+/*
+ * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
+ * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+/* 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");
+}
index 44ab4f3..2f59107 100644 (file)
@@ -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?
index d8ec65e..506d169 100644 (file)
@@ -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?
index e237043..2984908 100644 (file)
@@ -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
 #
index e638d63..1d8c8bb 100644 (file)
@@ -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 <patrick@blueri.se>
+ * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 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);
 }
index 9bafb71..5f63d0e 100644 (file)
@@ -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 <patrick@blueri.se>
  *
@@ -24,6 +24,4 @@ union mainbus_attach_args {
        struct fdt_attach_args   ma_faa;
 };
 
-void mainbus_legacy_found(struct device *, char *);
-
 #endif /* __MAINBUS_H__ */
index f7eac42..fccf11b 100644 (file)
@@ -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 <patrick@blueri.se>
  *
@@ -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 = "";
index 1a1802b..74bd27e 100644 (file)
@@ -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
 #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