170320951SEmmanuel Vadot /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3052073c3SEmmanuel Vadot * 470320951SEmmanuel Vadot * Copyright (c) 2015 Semihalf. 570320951SEmmanuel Vadot * Copyright (c) 2015 Stormshield. 670320951SEmmanuel Vadot * All rights reserved. 770320951SEmmanuel Vadot * 870320951SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 970320951SEmmanuel Vadot * modification, are permitted provided that the following conditions 1070320951SEmmanuel Vadot * are met: 1170320951SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 1270320951SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 1370320951SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 1470320951SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 1570320951SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 1670320951SEmmanuel Vadot * 1770320951SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1870320951SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1970320951SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2070320951SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2170320951SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2270320951SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2370320951SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2470320951SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2570320951SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2670320951SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2770320951SEmmanuel Vadot * SUCH DAMAGE. 2870320951SEmmanuel Vadot */ 2970320951SEmmanuel Vadot 3070320951SEmmanuel Vadot #include <sys/cdefs.h> 3170320951SEmmanuel Vadot #include <sys/stdint.h> 3270320951SEmmanuel Vadot #include <sys/stddef.h> 3370320951SEmmanuel Vadot #include <sys/param.h> 3470320951SEmmanuel Vadot #include <sys/queue.h> 3570320951SEmmanuel Vadot #include <sys/types.h> 3670320951SEmmanuel Vadot #include <sys/systm.h> 3770320951SEmmanuel Vadot #include <sys/kernel.h> 3870320951SEmmanuel Vadot #include <sys/bus.h> 3970320951SEmmanuel Vadot #include <sys/module.h> 4070320951SEmmanuel Vadot #include <sys/lock.h> 4170320951SEmmanuel Vadot #include <sys/mutex.h> 4270320951SEmmanuel Vadot #include <sys/condvar.h> 4370320951SEmmanuel Vadot #include <sys/sysctl.h> 4470320951SEmmanuel Vadot #include <sys/sx.h> 4570320951SEmmanuel Vadot #include <sys/unistd.h> 4670320951SEmmanuel Vadot #include <sys/priv.h> 4770320951SEmmanuel Vadot #include <sys/rman.h> 4870320951SEmmanuel Vadot 4970320951SEmmanuel Vadot #include <dev/usb/usb.h> 5070320951SEmmanuel Vadot #include <dev/usb/usbdi.h> 5170320951SEmmanuel Vadot 5270320951SEmmanuel Vadot #include <dev/usb/usb_core.h> 5370320951SEmmanuel Vadot #include <dev/usb/usb_busdma.h> 5470320951SEmmanuel Vadot #include <dev/usb/usb_process.h> 5570320951SEmmanuel Vadot #include <dev/usb/usb_util.h> 5670320951SEmmanuel Vadot 5770320951SEmmanuel Vadot #include <dev/usb/usb_controller.h> 5870320951SEmmanuel Vadot #include <dev/usb/usb_bus.h> 5970320951SEmmanuel Vadot #include <dev/usb/controller/xhci.h> 6070320951SEmmanuel Vadot #include <dev/usb/controller/xhcireg.h> 6170320951SEmmanuel Vadot 62052073c3SEmmanuel Vadot #include "generic_xhci.h" 6370320951SEmmanuel Vadot 64332af8c2SStephen J. Kiernan #if __SIZEOF_LONG__ == 8 65332af8c2SStephen J. Kiernan #define IS_DMA_32B 0 66332af8c2SStephen J. Kiernan #elif __SIZEOF_LONG__ == 4 6770320951SEmmanuel Vadot #define IS_DMA_32B 1 68332af8c2SStephen J. Kiernan #else 69332af8c2SStephen J. Kiernan #error unsupported long size 70332af8c2SStephen J. Kiernan #endif 7170320951SEmmanuel Vadot 72052073c3SEmmanuel Vadot int 73052073c3SEmmanuel Vadot generic_xhci_attach(device_t dev) 7470320951SEmmanuel Vadot { 7570320951SEmmanuel Vadot struct xhci_softc *sc = device_get_softc(dev); 7670320951SEmmanuel Vadot int err = 0, rid = 0; 7770320951SEmmanuel Vadot 7870320951SEmmanuel Vadot sc->sc_bus.parent = dev; 7970320951SEmmanuel Vadot sc->sc_bus.devices = sc->sc_devices; 8070320951SEmmanuel Vadot sc->sc_bus.devices_max = XHCI_MAX_DEVICES; 8170320951SEmmanuel Vadot 8270320951SEmmanuel Vadot sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 8370320951SEmmanuel Vadot RF_ACTIVE); 8470320951SEmmanuel Vadot if (sc->sc_io_res == NULL) { 8570320951SEmmanuel Vadot device_printf(dev, "Failed to map memory\n"); 86052073c3SEmmanuel Vadot generic_xhci_detach(dev); 8770320951SEmmanuel Vadot return (ENXIO); 8870320951SEmmanuel Vadot } 8970320951SEmmanuel Vadot 9070320951SEmmanuel Vadot sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 9170320951SEmmanuel Vadot sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 9270320951SEmmanuel Vadot sc->sc_io_size = rman_get_size(sc->sc_io_res); 9370320951SEmmanuel Vadot 9470320951SEmmanuel Vadot sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 9570320951SEmmanuel Vadot RF_SHAREABLE | RF_ACTIVE); 9670320951SEmmanuel Vadot if (sc->sc_irq_res == NULL) { 9770320951SEmmanuel Vadot device_printf(dev, "Failed to allocate IRQ\n"); 98052073c3SEmmanuel Vadot generic_xhci_detach(dev); 9970320951SEmmanuel Vadot return (ENXIO); 10070320951SEmmanuel Vadot } 10170320951SEmmanuel Vadot 1025b56413dSWarner Losh sc->sc_bus.bdev = device_add_child(dev, "usbus", DEVICE_UNIT_ANY); 10370320951SEmmanuel Vadot if (sc->sc_bus.bdev == NULL) { 10470320951SEmmanuel Vadot device_printf(dev, "Failed to add USB device\n"); 105052073c3SEmmanuel Vadot generic_xhci_detach(dev); 10670320951SEmmanuel Vadot return (ENXIO); 10770320951SEmmanuel Vadot } 10870320951SEmmanuel Vadot 10970320951SEmmanuel Vadot device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 11070320951SEmmanuel Vadot 11170320951SEmmanuel Vadot sprintf(sc->sc_vendor, XHCI_HC_VENDOR); 11270320951SEmmanuel Vadot device_set_desc(sc->sc_bus.bdev, XHCI_HC_DEVSTR); 11370320951SEmmanuel Vadot 11470320951SEmmanuel Vadot err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 11570320951SEmmanuel Vadot NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 11670320951SEmmanuel Vadot if (err != 0) { 11770320951SEmmanuel Vadot device_printf(dev, "Failed to setup error IRQ, %d\n", err); 11870320951SEmmanuel Vadot sc->sc_intr_hdl = NULL; 119052073c3SEmmanuel Vadot generic_xhci_detach(dev); 12070320951SEmmanuel Vadot return (err); 12170320951SEmmanuel Vadot } 12270320951SEmmanuel Vadot 123332af8c2SStephen J. Kiernan err = xhci_init(sc, dev, 124332af8c2SStephen J. Kiernan (sc->sc_quirks & XHCI_QUIRK_DMA_32B) == 0 ? IS_DMA_32B : 1); 12570320951SEmmanuel Vadot if (err != 0) { 12670320951SEmmanuel Vadot device_printf(dev, "Failed to init XHCI, with error %d\n", err); 127052073c3SEmmanuel Vadot generic_xhci_detach(dev); 12870320951SEmmanuel Vadot return (ENXIO); 12970320951SEmmanuel Vadot } 13070320951SEmmanuel Vadot 13170320951SEmmanuel Vadot err = xhci_start_controller(sc); 13270320951SEmmanuel Vadot if (err != 0) { 13370320951SEmmanuel Vadot device_printf(dev, "Failed to start XHCI controller, with error %d\n", err); 134052073c3SEmmanuel Vadot generic_xhci_detach(dev); 13570320951SEmmanuel Vadot return (ENXIO); 13670320951SEmmanuel Vadot } 13770320951SEmmanuel Vadot 13870320951SEmmanuel Vadot err = device_probe_and_attach(sc->sc_bus.bdev); 13970320951SEmmanuel Vadot if (err != 0) { 14070320951SEmmanuel Vadot device_printf(dev, "Failed to initialize USB, with error %d\n", err); 141052073c3SEmmanuel Vadot generic_xhci_detach(dev); 14270320951SEmmanuel Vadot return (ENXIO); 14370320951SEmmanuel Vadot } 14470320951SEmmanuel Vadot 14570320951SEmmanuel Vadot return (0); 14670320951SEmmanuel Vadot } 14770320951SEmmanuel Vadot 148052073c3SEmmanuel Vadot int 149052073c3SEmmanuel Vadot generic_xhci_detach(device_t dev) 15070320951SEmmanuel Vadot { 15170320951SEmmanuel Vadot struct xhci_softc *sc = device_get_softc(dev); 15270320951SEmmanuel Vadot int err; 15370320951SEmmanuel Vadot 15470320951SEmmanuel Vadot /* during module unload there are lots of children leftover */ 155*3ddaf820SJohn Baldwin err = bus_generic_detach(dev); 156*3ddaf820SJohn Baldwin if (err != 0) 157*3ddaf820SJohn Baldwin return (err); 15870320951SEmmanuel Vadot 15970320951SEmmanuel Vadot if (sc->sc_irq_res != NULL && sc->sc_intr_hdl != NULL) { 16070320951SEmmanuel Vadot err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); 16170320951SEmmanuel Vadot if (err != 0) 16270320951SEmmanuel Vadot device_printf(dev, "Could not tear down irq, %d\n", 16370320951SEmmanuel Vadot err); 16470320951SEmmanuel Vadot sc->sc_intr_hdl = NULL; 16570320951SEmmanuel Vadot } 16670320951SEmmanuel Vadot 16770320951SEmmanuel Vadot if (sc->sc_irq_res != NULL) { 16870320951SEmmanuel Vadot bus_release_resource(dev, SYS_RES_IRQ, 16970320951SEmmanuel Vadot rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 17070320951SEmmanuel Vadot sc->sc_irq_res = NULL; 17170320951SEmmanuel Vadot } 17270320951SEmmanuel Vadot 17370320951SEmmanuel Vadot if (sc->sc_io_res != NULL) { 17470320951SEmmanuel Vadot bus_release_resource(dev, SYS_RES_MEMORY, 17570320951SEmmanuel Vadot rman_get_rid(sc->sc_io_res), sc->sc_io_res); 17670320951SEmmanuel Vadot sc->sc_io_res = NULL; 17770320951SEmmanuel Vadot } 17870320951SEmmanuel Vadot 17970320951SEmmanuel Vadot xhci_uninit(sc); 18070320951SEmmanuel Vadot 18170320951SEmmanuel Vadot return (0); 18270320951SEmmanuel Vadot } 18370320951SEmmanuel Vadot 18470320951SEmmanuel Vadot static device_method_t xhci_methods[] = { 18570320951SEmmanuel Vadot /* Device interface */ 186052073c3SEmmanuel Vadot DEVMETHOD(device_attach, generic_xhci_attach), 187052073c3SEmmanuel Vadot DEVMETHOD(device_detach, generic_xhci_detach), 18870320951SEmmanuel Vadot DEVMETHOD(device_suspend, bus_generic_suspend), 18970320951SEmmanuel Vadot DEVMETHOD(device_resume, bus_generic_resume), 19070320951SEmmanuel Vadot DEVMETHOD(device_shutdown, bus_generic_shutdown), 19170320951SEmmanuel Vadot 19270320951SEmmanuel Vadot DEVMETHOD_END 19370320951SEmmanuel Vadot }; 19470320951SEmmanuel Vadot 195052073c3SEmmanuel Vadot driver_t generic_xhci_driver = { 19670320951SEmmanuel Vadot "xhci", 19770320951SEmmanuel Vadot xhci_methods, 19870320951SEmmanuel Vadot sizeof(struct xhci_softc), 19970320951SEmmanuel Vadot }; 200