octusb_octeon.c revision 227849
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/mips/cavium/usb/octusb_octeon.c 227849 2011-11-22 21:56:55Z hselasky $"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26188746Sthompsa * SUCH DAMAGE. 27188942Sthompsa */ 28188942Sthompsa 29188942Sthompsa#include <sys/stdint.h> 30188942Sthompsa#include <sys/stddef.h> 31184610Salfred#include <sys/param.h> 32184610Salfred#include <sys/queue.h> 33184610Salfred#include <sys/types.h> 34188942Sthompsa#include <sys/systm.h> 35188942Sthompsa#include <sys/kernel.h> 36188942Sthompsa#include <sys/bus.h> 37188942Sthompsa#include <sys/module.h> 38188942Sthompsa#include <sys/lock.h> 39188942Sthompsa#include <sys/mutex.h> 40184610Salfred#include <sys/condvar.h> 41188942Sthompsa#include <sys/sysctl.h> 42184610Salfred#include <sys/sx.h> 43184610Salfred#include <sys/unistd.h> 44184610Salfred#include <sys/callout.h> 45184610Salfred#include <sys/malloc.h> 46184610Salfred#include <sys/priv.h> 47184610Salfred#include <sys/rman.h> 48184610Salfred 49184610Salfred#include <dev/usb/usb.h> 50184610Salfred#include <dev/usb/usbdi.h> 51184610Salfred 52184610Salfred#include <dev/usb/usb_core.h> 53184610Salfred#include <dev/usb/usb_busdma.h> 54184610Salfred#include <dev/usb/usb_process.h> 55184610Salfred#include <dev/usb/usb_util.h> 56184610Salfred 57184610Salfred#include <dev/usb/usb_controller.h> 58184610Salfred#include <dev/usb/usb_bus.h> 59184610Salfred 60184610Salfred#include <contrib/octeon-sdk/cvmx.h> 61184610Salfred#include <contrib/octeon-sdk/cvmx-interrupt.h> 62184610Salfred#include <contrib/octeon-sdk/cvmx-usb.h> 63184610Salfred 64187259Sthompsa#include <mips/cavium/usb/octusb.h> 65187259Sthompsa 66187259Sthompsa#define MEM_RID 0 67188413Sthompsa 68187259Sthompsastatic device_identify_t octusb_octeon_identify; 69187259Sthompsastatic device_probe_t octusb_octeon_probe; 70184610Salfredstatic device_attach_t octusb_octeon_attach; 71192984Sthompsastatic device_detach_t octusb_octeon_detach; 72192984Sthompsastatic device_shutdown_t octusb_octeon_shutdown; 73184610Salfred 74192984Sthompsastruct octusb_octeon_softc { 75192984Sthompsa struct octusb_softc sc_dci; /* must be first */ 76189265Sthompsa}; 77184610Salfred 78184610Salfredstatic void 79184610Salfredoctusb_octeon_identify(driver_t *drv, device_t parent) 80184610Salfred{ 81184610Salfred if (octeon_has_feature(OCTEON_FEATURE_USB)) 82184610Salfred BUS_ADD_CHILD(parent, 0, "octusb", 0); 83184610Salfred} 84184610Salfred 85184610Salfredstatic int 86184610Salfredoctusb_octeon_probe(device_t dev) 87184610Salfred{ 88184610Salfred device_set_desc(dev, "Cavium Octeon USB controller"); 89184610Salfred return (0); 90184610Salfred} 91192984Sthompsa 92192984Sthompsastatic int 93192984Sthompsaoctusb_octeon_attach(device_t dev) 94192984Sthompsa{ 95192984Sthompsa struct octusb_octeon_softc *sc = device_get_softc(dev); 96192984Sthompsa int err; 97192984Sthompsa int rid; 98185948Sthompsa 99192984Sthompsa /* setup controller interface softc */ 100185948Sthompsa 101184610Salfred /* initialise some bus fields */ 102192984Sthompsa sc->sc_dci.sc_bus.parent = dev; 103184610Salfred sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 104184610Salfred sc->sc_dci.sc_bus.devices_max = OCTUSB_MAX_DEVICES; 105187259Sthompsa 106184610Salfred /* get all DMA memory */ 107184610Salfred if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 108184610Salfred USB_GET_DMA_TAG(dev), NULL)) { 109190734Sthompsa return (ENOMEM); 110190734Sthompsa } 111190734Sthompsa rid = 0; 112184610Salfred sc->sc_dci.sc_irq_res = 113184610Salfred bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 114187259Sthompsa CVMX_IRQ_USB, CVMX_IRQ_USB, 1, RF_ACTIVE); 115184610Salfred if (!(sc->sc_dci.sc_irq_res)) { 116184610Salfred goto error; 117184610Salfred } 118190734Sthompsa 119190734Sthompsa sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 120190734Sthompsa if (!(sc->sc_dci.sc_bus.bdev)) { 121184610Salfred goto error; 122184610Salfred } 123184610Salfred device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 124192984Sthompsa 125184610Salfred#if (__FreeBSD_version >= 700031) 126184610Salfred err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 127184610Salfred NULL, (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 128184610Salfred#else 129184610Salfred err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 130184610Salfred (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 131184610Salfred#endif 132184610Salfred if (err) { 133184610Salfred sc->sc_dci.sc_intr_hdl = NULL; 134184610Salfred goto error; 135184610Salfred } 136184610Salfred err = octusb_init(&sc->sc_dci); 137184610Salfred if (!err) { 138184610Salfred err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 139184610Salfred } 140184610Salfred if (err) { 141184610Salfred goto error; 142184610Salfred } 143184610Salfred return (0); 144184610Salfred 145184610Salfrederror: 146184610Salfred octusb_octeon_detach(dev); 147184610Salfred return (ENXIO); 148184610Salfred} 149184610Salfred 150184610Salfredstatic int 151189275Sthompsaoctusb_octeon_detach(device_t dev) 152188942Sthompsa{ 153188942Sthompsa struct octusb_octeon_softc *sc = device_get_softc(dev); 154184610Salfred device_t bdev; 155192984Sthompsa int err; 156184610Salfred 157184610Salfred if (sc->sc_dci.sc_bus.bdev) { 158184610Salfred bdev = sc->sc_dci.sc_bus.bdev; 159184610Salfred device_detach(bdev); 160184610Salfred device_delete_child(dev, bdev); 161184610Salfred } 162192984Sthompsa /* during module unload there are lots of children leftover */ 163184610Salfred device_delete_children(dev); 164192499Sthompsa 165184610Salfred if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 166184610Salfred /* 167184610Salfred * only call octusb_octeon_uninit() after octusb_octeon_init() 168184610Salfred */ 169184610Salfred octusb_uninit(&sc->sc_dci); 170184610Salfred 171184610Salfred err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 172184610Salfred sc->sc_dci.sc_intr_hdl); 173184610Salfred sc->sc_dci.sc_intr_hdl = NULL; 174184610Salfred } 175184610Salfred if (sc->sc_dci.sc_irq_res) { 176184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 0, 177184610Salfred sc->sc_dci.sc_irq_res); 178184610Salfred sc->sc_dci.sc_irq_res = NULL; 179192984Sthompsa } 180184610Salfred usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 181184610Salfred 182184610Salfred return (0); 183184610Salfred} 184184610Salfred 185189265Sthompsastatic int 186184610Salfredoctusb_octeon_shutdown(device_t dev) 187184610Salfred{ 188184610Salfred struct octusb_octeon_softc *sc = device_get_softc(dev); 189184610Salfred int err; 190184610Salfred 191184610Salfred err = bus_generic_shutdown(dev); 192189265Sthompsa if (err) 193184610Salfred return (err); 194184610Salfred 195184610Salfred octusb_uninit(&sc->sc_dci); 196184610Salfred 197184610Salfred return (0); 198184610Salfred} 199184610Salfred 200189265Sthompsastatic device_method_t octusb_octeon_methods[] = { 201188413Sthompsa /* Device interface */ 202188413Sthompsa DEVMETHOD(device_identify, octusb_octeon_identify), 203189265Sthompsa DEVMETHOD(device_probe, octusb_octeon_probe), 204184610Salfred DEVMETHOD(device_attach, octusb_octeon_attach), 205184610Salfred DEVMETHOD(device_detach, octusb_octeon_detach), 206189265Sthompsa DEVMETHOD(device_shutdown, octusb_octeon_shutdown), 207184610Salfred 208184610Salfred DEVMETHOD_END 209184610Salfred}; 210184610Salfred 211184610Salfredstatic driver_t octusb_octeon_driver = { 212184610Salfred "octusb", 213184610Salfred octusb_octeon_methods, 214184610Salfred sizeof(struct octusb_octeon_softc), 215184610Salfred}; 216184610Salfred 217184610Salfredstatic devclass_t octusb_octeon_devclass; 218184610Salfred 219184610SalfredDRIVER_MODULE(octusb, ciu, octusb_octeon_driver, octusb_octeon_devclass, 0, 0); 220184610Salfred