xref: /freebsd/sys/arm/arm/pmu.c (revision 685dc743)
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