1233336Sgonzo/*- 2233336Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 3233336Sgonzo * All rights reserved. 4233336Sgonzo * 5233336Sgonzo * Redistribution and use in source and binary forms, with or without 6233336Sgonzo * modification, are permitted provided that the following conditions 7233336Sgonzo * are met: 8233336Sgonzo * 1. Redistributions of source code must retain the above copyright 9233336Sgonzo * notice, this list of conditions and the following disclaimer. 10233336Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11233336Sgonzo * notice, this list of conditions and the following disclaimer in the 12233336Sgonzo * documentation and/or other materials provided with the distribution. 13233336Sgonzo * 14233336Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15233336Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16233336Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17233336Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18233336Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19233336Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20233336Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21233336Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22233336Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23233336Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24233336Sgonzo * SUCH DAMAGE. 25233336Sgonzo * 26233336Sgonzo * $FreeBSD: releng/10.3/sys/mips/cavium/octeon_pmc.c 265999 2014-05-14 01:35:43Z ian $ 27233336Sgonzo */ 28233336Sgonzo 29233336Sgonzo#include <sys/cdefs.h> 30233336Sgonzo__FBSDID("$FreeBSD: releng/10.3/sys/mips/cavium/octeon_pmc.c 265999 2014-05-14 01:35:43Z ian $"); 31233336Sgonzo 32233336Sgonzo#include <sys/param.h> 33233336Sgonzo#include <sys/systm.h> 34233336Sgonzo#include <sys/bus.h> 35233336Sgonzo#include <sys/interrupt.h> 36233336Sgonzo#include <sys/kernel.h> 37233336Sgonzo#include <sys/module.h> 38233336Sgonzo#include <sys/rman.h> 39233336Sgonzo#include <sys/malloc.h> 40233336Sgonzo#include <sys/smp.h> 41233336Sgonzo#include <sys/pmc.h> 42233336Sgonzo#include <sys/pmckern.h> 43233336Sgonzo 44233336Sgonzo#include <machine/bus.h> 45233336Sgonzo#include <machine/intr_machdep.h> 46233336Sgonzo 47233336Sgonzo#include <contrib/octeon-sdk/cvmx.h> 48233336Sgonzo#include <mips/cavium/octeon_irq.h> 49233336Sgonzo 50233336Sgonzostruct octeon_pmc_softc { 51233336Sgonzo struct rman irq_rman; 52233336Sgonzo struct resource *octeon_pmc_irq; 53233336Sgonzo}; 54233336Sgonzo 55233336Sgonzostatic void octeon_pmc_identify(driver_t *, device_t); 56233336Sgonzostatic int octeon_pmc_probe(device_t); 57233336Sgonzostatic int octeon_pmc_attach(device_t); 58233336Sgonzostatic int octeon_pmc_intr(void *); 59233336Sgonzo 60233336Sgonzostatic void 61233336Sgonzoocteon_pmc_identify(driver_t *drv, device_t parent) 62233336Sgonzo{ 63233336Sgonzo if (octeon_has_feature(OCTEON_FEATURE_USB)) 64233336Sgonzo BUS_ADD_CHILD(parent, 0, "pmc", 0); 65233336Sgonzo} 66233336Sgonzo 67233336Sgonzostatic int 68233336Sgonzoocteon_pmc_probe(device_t dev) 69233336Sgonzo{ 70233336Sgonzo if (device_get_unit(dev) != 0) 71233336Sgonzo return (ENXIO); 72233336Sgonzo 73233336Sgonzo device_set_desc(dev, "Cavium Octeon Performance Counters"); 74265999Sian return (BUS_PROBE_NOWILDCARD); 75233336Sgonzo} 76233336Sgonzo 77233336Sgonzostatic int 78233336Sgonzoocteon_pmc_attach(device_t dev) 79233336Sgonzo{ 80233336Sgonzo struct octeon_pmc_softc *sc; 81233336Sgonzo int error; 82233336Sgonzo int rid; 83233336Sgonzo 84233336Sgonzo sc = device_get_softc(dev); 85233336Sgonzo 86233336Sgonzo rid = 0; 87233336Sgonzo sc->octeon_pmc_irq = bus_alloc_resource(dev, 88233336Sgonzo SYS_RES_IRQ, &rid, OCTEON_PMC_IRQ, 89233336Sgonzo OCTEON_PMC_IRQ, 1, RF_ACTIVE); 90233336Sgonzo 91233336Sgonzo if (sc->octeon_pmc_irq == NULL) { 92233336Sgonzo device_printf(dev, "could not allocate irq%d\n", OCTEON_PMC_IRQ); 93233336Sgonzo return (ENXIO); 94233336Sgonzo } 95233336Sgonzo 96233336Sgonzo error = bus_setup_intr(dev, sc->octeon_pmc_irq, 97233336Sgonzo INTR_TYPE_MISC, octeon_pmc_intr, NULL, sc, NULL); 98233336Sgonzo if (error != 0) { 99233336Sgonzo device_printf(dev, "bus_setup_intr failed: %d\n", error); 100233336Sgonzo return (error); 101233336Sgonzo } 102233336Sgonzo 103233336Sgonzo return (0); 104233336Sgonzo} 105233336Sgonzo 106233336Sgonzostatic int 107233336Sgonzoocteon_pmc_intr(void *arg) 108233336Sgonzo{ 109233336Sgonzo struct trapframe *tf = PCPU_GET(curthread)->td_intr_frame; 110233336Sgonzo 111233336Sgonzo if (pmc_intr) 112233336Sgonzo (*pmc_intr)(PCPU_GET(cpuid), tf); 113233336Sgonzo 114233336Sgonzo return (FILTER_HANDLED); 115233336Sgonzo} 116233336Sgonzo 117233336Sgonzostatic device_method_t octeon_pmc_methods[] = { 118233336Sgonzo DEVMETHOD(device_identify, octeon_pmc_identify), 119233336Sgonzo DEVMETHOD(device_probe, octeon_pmc_probe), 120233336Sgonzo DEVMETHOD(device_attach, octeon_pmc_attach), 121233336Sgonzo { 0, 0 } 122233336Sgonzo}; 123233336Sgonzo 124233336Sgonzostatic driver_t octeon_pmc_driver = { 125233336Sgonzo "pmc", 126233336Sgonzo octeon_pmc_methods, 127233336Sgonzo sizeof(struct octeon_pmc_softc), 128233336Sgonzo}; 129233336Sgonzostatic devclass_t octeon_pmc_devclass; 130233336SgonzoDRIVER_MODULE(octeon_pmc, nexus, octeon_pmc_driver, octeon_pmc_devclass, 0, 0); 131