From owner-svn-src-head@freebsd.org Mon Dec 14 13:10:19 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CC2394B9741; Mon, 14 Dec 2020 13:10:19 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4CvhZg5Q7Fz4qt4; Mon, 14 Dec 2020 13:10:19 +0000 (UTC) (envelope-from mmel@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 mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id ACD2722225; Mon, 14 Dec 2020 13:10:19 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 0BEDAJeE013965; Mon, 14 Dec 2020 13:10:19 GMT (envelope-from mmel@FreeBSD.org) Received: (from mmel@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 0BEDAJ8c013964; Mon, 14 Dec 2020 13:10:19 GMT (envelope-from mmel@FreeBSD.org) Message-Id: <202012141310.0BEDAJ8c013964@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mmel set sender to mmel@FreeBSD.org using -f From: Michal Meloun Date: Mon, 14 Dec 2020 13:10:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r368634 - head/sys/arm/arm X-SVN-Group: head X-SVN-Commit-Author: mmel X-SVN-Commit-Paths: head/sys/arm/arm X-SVN-Commit-Revision: 368634 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Dec 2020 13:10:19 -0000 Author: mmel Date: Mon Dec 14 13:10:19 2020 New Revision: 368634 URL: https://svnweb.freebsd.org/changeset/base/368634 Log: Finish implementation of ARM PMU interrupts. The ARM PMU may use single per-core interrupt or may use multiple generic interrupts, one per core. In this case, special attention must be paid to the correct identification of the physical location of the core, its order in the external database (FDT) and the associated cpuid. Also keep in mind that a SoC can have multiple different PMUs (usually one per cluster) Modified: head/sys/arm/arm/pmu.c Modified: head/sys/arm/arm/pmu.c ============================================================================== --- head/sys/arm/arm/pmu.c Mon Dec 14 11:57:43 2020 (r368633) +++ head/sys/arm/arm/pmu.c Mon Dec 14 13:10:19 2020 (r368634) @@ -60,33 +60,19 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef notyet #define MAX_RLEN 8 -#else -#define MAX_RLEN 1 -#endif +struct pmu_intr { + struct resource *res; + void *ih; + int cpuid; +}; + struct pmu_softc { - struct resource *res[MAX_RLEN]; device_t dev; - void *ih[MAX_RLEN]; + struct pmu_intr irq[MAX_RLEN]; }; -static struct resource_spec pmu_spec[] = { - { SYS_RES_IRQ, 0, RF_ACTIVE }, - /* We don't currently handle pmu events, other than on cpu 0 */ -#ifdef notyet - { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 6, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 7, RF_ACTIVE | RF_OPTIONAL }, -#endif - { -1, 0 } -}; - /* CCNT */ #if __ARM_ARCH > 6 int pmu_attched = 0; @@ -131,34 +117,163 @@ pmu_intr(void *arg) } static int +pmu_parse_affinity(struct pmu_softc *sc, struct pmu_intr *irq, phandle_t xref, + uint32_t mpidr) +{ + struct pcpu *pcpu; + int i, err; + + + if (xref != 0) { + err = OF_getencprop(OF_node_from_xref(xref), "reg", &mpidr, + sizeof(mpidr)); + if (err < 0) { + device_printf(sc->dev, "missing 'reg' property\n"); + return (ENXIO); + } + } + + for (i = 0; i < MAXCPU; i++) { + pcpu = pcpu_find(i); + if (pcpu != NULL && pcpu->pc_mpidr == mpidr) { + irq->cpuid = i; + return (0); + } + } + + device_printf(sc->dev, "Cannot find CPU with MPIDR: 0x%08X\n", mpidr); + return (ENXIO); +} + +static int +pmu_parse_intr(struct pmu_softc *sc) +{ + bool has_affinity; + phandle_t node, *cpus; + int rid, err, ncpus, i; + + + node = ofw_bus_get_node(sc->dev); + has_affinity = OF_hasprop(node, "interrupt-affinity"); + + for (i = 0; i < MAX_RLEN; i++) + sc->irq[i].cpuid = -1; + + cpus = NULL; + if (has_affinity) { + ncpus = OF_getencprop_alloc_multi(node, "interrupt-affinity", + sizeof(*cpus), (void **)&cpus); + if (ncpus < 0) { + device_printf(sc->dev, + "Cannot read interrupt affinity property\n"); + return (ENXIO); + } + } + + /* Process first interrupt */ + rid = 0; + sc->irq[0].res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid, + RF_ACTIVE | RF_SHAREABLE); + + if (sc->irq[0].res == NULL) { + device_printf(sc->dev, "Cannot get interrupt\n"); + err = ENXIO; + goto done; + } + + /* Check if PMU have one per-CPU interrupt */ + if (intr_is_per_cpu(sc->irq[0].res)) { + if (has_affinity) { + device_printf(sc->dev, + "Per CPU interupt have declared affinity\n"); + err = ENXIO; + goto done; + } + return (0); + } + + /* + * PMU with set of generic interrupts (one per core) + * Each one must be binded to exact core. + */ + err = pmu_parse_affinity(sc, sc->irq + 0, has_affinity ? cpus[0]: 0, + 0); + if (err != 0) { + device_printf(sc->dev, "Cannot parse affinity for CPUid: 0\n"); + goto done; + } + + for (i = 1; i < MAX_RLEN; i++) { + rid = i; + sc->irq[i].res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, + &rid, RF_ACTIVE | RF_SHAREABLE); + if (sc->irq[i].res == NULL) + break; + + if (intr_is_per_cpu(sc->irq[i].res)) + { + device_printf(sc->dev, "Unexpected per CPU interupt\n"); + err = ENXIO; + goto done; + } + + if (has_affinity && i >= ncpus) { + device_printf(sc->dev, "Missing value in interrupt " + "affinity property\n"); + err = ENXIO; + goto done; + } + + err = pmu_parse_affinity(sc, sc->irq + i, + has_affinity ? cpus[i]: 0, i); + if (err != 0) { + device_printf(sc->dev, + "Cannot parse affinity for CPUid: %d.\n", i); + goto done; + } + } + err = 0; +done: + OF_prop_free(cpus); + return (err); +} + +static int pmu_attach(device_t dev) { struct pmu_softc *sc; #if defined(__arm__) && (__ARM_ARCH > 6) uint32_t iesr; #endif - int err; - int i; + int err, i; sc = device_get_softc(dev); sc->dev = dev; - if (bus_alloc_resources(dev, pmu_spec, sc->res)) { - device_printf(dev, "could not allocate resources\n"); - return (ENXIO); - } + err = pmu_parse_intr(sc); + if (err != 0) + return (err); - /* Setup interrupt handler */ for (i = 0; i < MAX_RLEN; i++) { - if (sc->res[i] == NULL) + if (sc->irq[i].res == NULL) break; - - err = bus_setup_intr(dev, sc->res[i], INTR_MPSAFE | INTR_TYPE_MISC, - pmu_intr, NULL, NULL, &sc->ih[i]); - if (err) { - device_printf(dev, "Unable to setup interrupt handler.\n"); - return (ENXIO); + err = bus_setup_intr(dev, sc->irq[i].res, + INTR_MPSAFE | INTR_TYPE_MISC, pmu_intr, NULL, NULL, + &sc->irq[i].ih); + if (err != 0) { + device_printf(dev, + "Unable to setup interrupt handler.\n"); + goto fail; } + if (sc->irq[i].cpuid != -1) { + err = bus_bind_intr(dev, sc->irq[i].res, + sc->irq[i].cpuid); + if (err != 0) { + device_printf(sc->dev, + "Unable to bind interrupt.\n"); + goto fail; + } + } } #if defined(__arm__) && (__ARM_ARCH > 6) @@ -176,11 +291,32 @@ pmu_attach(device_t dev) #endif return (0); + +fail: + for (i = 1; i < MAX_RLEN; i++) { + if (sc->irq[i].ih != NULL) + bus_teardown_intr(dev, sc->irq[i].res, sc->irq[i].ih); + if (sc->irq[i].res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, i, + sc->irq[i].res); + } + return(err); } #ifdef FDT static struct ofw_compat_data compat_data[] = { {"arm,armv8-pmuv3", 1}, + {"arm,cortex-a77-pmu", 1}, + {"arm,cortex-a76-pmu", 1}, + {"arm,cortex-a75-pmu", 1}, + {"arm,cortex-a73-pmu", 1}, + {"arm,cortex-a72-pmu", 1}, + {"arm,cortex-a65-pmu", 1}, + {"arm,cortex-a57-pmu", 1}, + {"arm,cortex-a55-pmu", 1}, + {"arm,cortex-a53-pmu", 1}, + {"arm,cortex-a34-pmu", 1}, + {"arm,cortex-a17-pmu", 1}, {"arm,cortex-a15-pmu", 1}, {"arm,cortex-a12-pmu", 1},