1 /*- 2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * Performance Monitoring Unit 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include "opt_hwpmc_hooks.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/bus.h> 43 #include <sys/kernel.h> 44 #include <sys/module.h> 45 #include <sys/malloc.h> 46 #include <sys/rman.h> 47 #include <sys/timeet.h> 48 #include <sys/timetc.h> 49 #include <sys/pmc.h> 50 #include <sys/pmckern.h> 51 52 #include <machine/bus.h> 53 #include <machine/cpu.h> 54 #include <machine/intr.h> 55 56 #include "pmu.h" 57 58 /* CCNT */ 59 #if defined(__arm__) && (__ARM_ARCH > 6) 60 int pmu_attched = 0; 61 uint32_t ccnt_hi[MAXCPU]; 62 #endif 63 64 #define PMU_OVSR_C 0x80000000 /* Cycle Counter */ 65 #define PMU_IESR_C 0x80000000 /* Cycle Counter */ 66 67 static int 68 pmu_intr(void *arg) 69 { 70 #ifdef HWPMC_HOOKS 71 struct trapframe *tf; 72 #endif 73 uint32_t r; 74 #if defined(__arm__) && (__ARM_ARCH > 6) 75 u_int cpu; 76 77 cpu = PCPU_GET(cpuid); 78 79 r = cp15_pmovsr_get(); 80 if (r & PMU_OVSR_C) { 81 atomic_add_32(&ccnt_hi[cpu], 1); 82 /* Clear the event. */ 83 r &= ~PMU_OVSR_C; 84 cp15_pmovsr_set(PMU_OVSR_C); 85 } 86 #else 87 r = 1; 88 #endif 89 90 #ifdef HWPMC_HOOKS 91 /* Only call into the HWPMC framework if we know there is work. */ 92 if (r != 0 && pmc_intr) { 93 tf = arg; 94 (*pmc_intr)(tf); 95 } 96 #endif 97 98 return (FILTER_HANDLED); 99 } 100 101 int 102 pmu_attach(device_t dev) 103 { 104 struct pmu_softc *sc; 105 #if defined(__arm__) && (__ARM_ARCH > 6) 106 uint32_t iesr; 107 #endif 108 int err, i; 109 110 sc = device_get_softc(dev); 111 sc->dev = dev; 112 113 for (i = 0; i < MAX_RLEN; i++) { 114 if (sc->irq[i].res == NULL) 115 break; 116 err = bus_setup_intr(dev, sc->irq[i].res, 117 INTR_MPSAFE | INTR_TYPE_MISC, pmu_intr, NULL, NULL, 118 &sc->irq[i].ih); 119 if (err != 0) { 120 device_printf(dev, 121 "Unable to setup interrupt handler.\n"); 122 goto fail; 123 } 124 if (sc->irq[i].cpuid != -1) { 125 err = bus_bind_intr(dev, sc->irq[i].res, 126 sc->irq[i].cpuid); 127 if (err != 0) { 128 device_printf(sc->dev, 129 "Unable to bind interrupt.\n"); 130 goto fail; 131 } 132 } 133 } 134 135 #if defined(__arm__) && (__ARM_ARCH > 6) 136 /* Initialize to 0. */ 137 for (i = 0; i < MAXCPU; i++) 138 ccnt_hi[i] = 0; 139 140 /* Enable the interrupt to fire on overflow. */ 141 iesr = cp15_pminten_get(); 142 iesr |= PMU_IESR_C; 143 cp15_pminten_set(iesr); 144 145 /* Need this for getcyclecount() fast path. */ 146 pmu_attched |= 1; 147 #endif 148 149 return (0); 150 151 fail: 152 for (i = 1; i < MAX_RLEN; i++) { 153 if (sc->irq[i].ih != NULL) 154 bus_teardown_intr(dev, sc->irq[i].res, sc->irq[i].ih); 155 if (sc->irq[i].res != NULL) 156 bus_release_resource(dev, SYS_RES_IRQ, i, 157 sc->irq[i].res); 158 } 159 return(err); 160 } 161 162