18aaa1a77SRuslan Bukin /*-
28aaa1a77SRuslan Bukin * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
38aaa1a77SRuslan Bukin * All rights reserved.
48aaa1a77SRuslan Bukin *
58aaa1a77SRuslan Bukin * This software was developed by SRI International and the University of
68aaa1a77SRuslan Bukin * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
78aaa1a77SRuslan Bukin * ("CTSRD"), as part of the DARPA CRASH research programme.
88aaa1a77SRuslan Bukin *
98aaa1a77SRuslan Bukin * Redistribution and use in source and binary forms, with or without
108aaa1a77SRuslan Bukin * modification, are permitted provided that the following conditions
118aaa1a77SRuslan Bukin * are met:
128aaa1a77SRuslan Bukin * 1. Redistributions of source code must retain the above copyright
138aaa1a77SRuslan Bukin * notice, this list of conditions and the following disclaimer.
148aaa1a77SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright
158aaa1a77SRuslan Bukin * notice, this list of conditions and the following disclaimer in the
168aaa1a77SRuslan Bukin * documentation and/or other materials provided with the distribution.
178aaa1a77SRuslan Bukin *
188aaa1a77SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
198aaa1a77SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
208aaa1a77SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
218aaa1a77SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
228aaa1a77SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
238aaa1a77SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
248aaa1a77SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
258aaa1a77SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
268aaa1a77SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
278aaa1a77SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
288aaa1a77SRuslan Bukin * SUCH DAMAGE.
298aaa1a77SRuslan Bukin */
308aaa1a77SRuslan Bukin
318aaa1a77SRuslan Bukin /*
328aaa1a77SRuslan Bukin * Performance Monitoring Unit
338aaa1a77SRuslan Bukin */
348aaa1a77SRuslan Bukin
358aaa1a77SRuslan Bukin #include <sys/cdefs.h>
368aaa1a77SRuslan Bukin #include "opt_hwpmc_hooks.h"
378aaa1a77SRuslan Bukin
388aaa1a77SRuslan Bukin #include <sys/param.h>
398aaa1a77SRuslan Bukin #include <sys/systm.h>
408aaa1a77SRuslan Bukin #include <sys/bus.h>
418aaa1a77SRuslan Bukin #include <sys/kernel.h>
428aaa1a77SRuslan Bukin #include <sys/module.h>
438aaa1a77SRuslan Bukin #include <sys/malloc.h>
448aaa1a77SRuslan Bukin #include <sys/rman.h>
458aaa1a77SRuslan Bukin #include <sys/timeet.h>
468aaa1a77SRuslan Bukin #include <sys/timetc.h>
478aaa1a77SRuslan Bukin #include <sys/pmc.h>
488aaa1a77SRuslan Bukin #include <sys/pmckern.h>
498aaa1a77SRuslan Bukin
508aaa1a77SRuslan Bukin #include <machine/bus.h>
518aaa1a77SRuslan Bukin #include <machine/cpu.h>
528aaa1a77SRuslan Bukin #include <machine/intr.h>
538aaa1a77SRuslan Bukin
545e78bbb7SAndrew Turner #include "pmu.h"
558aaa1a77SRuslan Bukin
56eeaf6acbSBjoern A. Zeeb /* CCNT */
575e78bbb7SAndrew Turner #if defined(__arm__) && (__ARM_ARCH > 6)
58eeaf6acbSBjoern A. Zeeb int pmu_attched = 0;
59eeaf6acbSBjoern A. Zeeb uint32_t ccnt_hi[MAXCPU];
60eeaf6acbSBjoern A. Zeeb #endif
61eeaf6acbSBjoern A. Zeeb
62eeaf6acbSBjoern A. Zeeb #define PMU_OVSR_C 0x80000000 /* Cycle Counter */
63eeaf6acbSBjoern A. Zeeb #define PMU_IESR_C 0x80000000 /* Cycle Counter */
64eeaf6acbSBjoern A. Zeeb
658aaa1a77SRuslan Bukin static int
pmu_intr(void * arg)668aaa1a77SRuslan Bukin pmu_intr(void *arg)
678aaa1a77SRuslan Bukin {
68eeaf6acbSBjoern A. Zeeb #ifdef HWPMC_HOOKS
698aaa1a77SRuslan Bukin struct trapframe *tf;
70eeaf6acbSBjoern A. Zeeb #endif
71eeaf6acbSBjoern A. Zeeb uint32_t r;
72eeaf6acbSBjoern A. Zeeb #if defined(__arm__) && (__ARM_ARCH > 6)
73eeaf6acbSBjoern A. Zeeb u_int cpu;
748aaa1a77SRuslan Bukin
75eeaf6acbSBjoern A. Zeeb cpu = PCPU_GET(cpuid);
76eeaf6acbSBjoern A. Zeeb
77eeaf6acbSBjoern A. Zeeb r = cp15_pmovsr_get();
78eeaf6acbSBjoern A. Zeeb if (r & PMU_OVSR_C) {
79eeaf6acbSBjoern A. Zeeb atomic_add_32(&ccnt_hi[cpu], 1);
80eeaf6acbSBjoern A. Zeeb /* Clear the event. */
81eeaf6acbSBjoern A. Zeeb r &= ~PMU_OVSR_C;
82eeaf6acbSBjoern A. Zeeb cp15_pmovsr_set(PMU_OVSR_C);
83eeaf6acbSBjoern A. Zeeb }
84eeaf6acbSBjoern A. Zeeb #else
85eeaf6acbSBjoern A. Zeeb r = 1;
86eeaf6acbSBjoern A. Zeeb #endif
878aaa1a77SRuslan Bukin
888aaa1a77SRuslan Bukin #ifdef HWPMC_HOOKS
89eeaf6acbSBjoern A. Zeeb /* Only call into the HWPMC framework if we know there is work. */
90eeaf6acbSBjoern A. Zeeb if (r != 0 && pmc_intr) {
91eeaf6acbSBjoern A. Zeeb tf = arg;
92eb7c9019SMatt Macy (*pmc_intr)(tf);
93eeaf6acbSBjoern A. Zeeb }
948aaa1a77SRuslan Bukin #endif
958aaa1a77SRuslan Bukin
968aaa1a77SRuslan Bukin return (FILTER_HANDLED);
978aaa1a77SRuslan Bukin }
988aaa1a77SRuslan Bukin
995e78bbb7SAndrew Turner int
pmu_attach(device_t dev)1008aaa1a77SRuslan Bukin pmu_attach(device_t dev)
1018aaa1a77SRuslan Bukin {
1028aaa1a77SRuslan Bukin struct pmu_softc *sc;
103eeaf6acbSBjoern A. Zeeb #if defined(__arm__) && (__ARM_ARCH > 6)
104eeaf6acbSBjoern A. Zeeb uint32_t iesr;
105eeaf6acbSBjoern A. Zeeb #endif
106a5279751SMichal Meloun int err, i;
1078aaa1a77SRuslan Bukin
1088aaa1a77SRuslan Bukin sc = device_get_softc(dev);
1098aaa1a77SRuslan Bukin sc->dev = dev;
1108aaa1a77SRuslan Bukin
111bc88bb2bSRuslan Bukin for (i = 0; i < MAX_RLEN; i++) {
112a5279751SMichal Meloun if (sc->irq[i].res == NULL)
113bc88bb2bSRuslan Bukin break;
114a5279751SMichal Meloun err = bus_setup_intr(dev, sc->irq[i].res,
115a5279751SMichal Meloun INTR_MPSAFE | INTR_TYPE_MISC, pmu_intr, NULL, NULL,
116a5279751SMichal Meloun &sc->irq[i].ih);
117a5279751SMichal Meloun if (err != 0) {
118a5279751SMichal Meloun device_printf(dev,
119a5279751SMichal Meloun "Unable to setup interrupt handler.\n");
120a5279751SMichal Meloun goto fail;
121a5279751SMichal Meloun }
122a5279751SMichal Meloun if (sc->irq[i].cpuid != -1) {
123a5279751SMichal Meloun err = bus_bind_intr(dev, sc->irq[i].res,
124a5279751SMichal Meloun sc->irq[i].cpuid);
125a5279751SMichal Meloun if (err != 0) {
126a5279751SMichal Meloun device_printf(sc->dev,
127a5279751SMichal Meloun "Unable to bind interrupt.\n");
128a5279751SMichal Meloun goto fail;
129a5279751SMichal Meloun }
1308aaa1a77SRuslan Bukin }
131bc88bb2bSRuslan Bukin }
1328aaa1a77SRuslan Bukin
133eeaf6acbSBjoern A. Zeeb #if defined(__arm__) && (__ARM_ARCH > 6)
134eeaf6acbSBjoern A. Zeeb /* Initialize to 0. */
135eeaf6acbSBjoern A. Zeeb for (i = 0; i < MAXCPU; i++)
136eeaf6acbSBjoern A. Zeeb ccnt_hi[i] = 0;
137eeaf6acbSBjoern A. Zeeb
138eeaf6acbSBjoern A. Zeeb /* Enable the interrupt to fire on overflow. */
139eeaf6acbSBjoern A. Zeeb iesr = cp15_pminten_get();
140eeaf6acbSBjoern A. Zeeb iesr |= PMU_IESR_C;
141eeaf6acbSBjoern A. Zeeb cp15_pminten_set(iesr);
142eeaf6acbSBjoern A. Zeeb
143eeaf6acbSBjoern A. Zeeb /* Need this for getcyclecount() fast path. */
144eeaf6acbSBjoern A. Zeeb pmu_attched |= 1;
145eeaf6acbSBjoern A. Zeeb #endif
146eeaf6acbSBjoern A. Zeeb
1478aaa1a77SRuslan Bukin return (0);
148a5279751SMichal Meloun
149a5279751SMichal Meloun fail:
150a5279751SMichal Meloun for (i = 1; i < MAX_RLEN; i++) {
151a5279751SMichal Meloun if (sc->irq[i].ih != NULL)
152a5279751SMichal Meloun bus_teardown_intr(dev, sc->irq[i].res, sc->irq[i].ih);
153a5279751SMichal Meloun if (sc->irq[i].res != NULL)
154a5279751SMichal Meloun bus_release_resource(dev, SYS_RES_IRQ, i,
155a5279751SMichal Meloun sc->irq[i].res);
156a5279751SMichal Meloun }
157a5279751SMichal Meloun return(err);
1588aaa1a77SRuslan Bukin }
1598aaa1a77SRuslan Bukin
160