170320951SEmmanuel Vadot /*- 2*052073c3SEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*052073c3SEmmanuel 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 __FBSDID("$FreeBSD$"); 3270320951SEmmanuel Vadot 3370320951SEmmanuel Vadot #include <sys/stdint.h> 3470320951SEmmanuel Vadot #include <sys/stddef.h> 3570320951SEmmanuel Vadot #include <sys/param.h> 3670320951SEmmanuel Vadot #include <sys/queue.h> 3770320951SEmmanuel Vadot #include <sys/types.h> 3870320951SEmmanuel Vadot #include <sys/systm.h> 3970320951SEmmanuel Vadot #include <sys/kernel.h> 4070320951SEmmanuel Vadot #include <sys/bus.h> 4170320951SEmmanuel Vadot #include <sys/module.h> 4270320951SEmmanuel Vadot #include <sys/lock.h> 4370320951SEmmanuel Vadot #include <sys/mutex.h> 4470320951SEmmanuel Vadot #include <sys/condvar.h> 4570320951SEmmanuel Vadot #include <sys/sysctl.h> 4670320951SEmmanuel Vadot #include <sys/sx.h> 4770320951SEmmanuel Vadot #include <sys/unistd.h> 4870320951SEmmanuel Vadot #include <sys/priv.h> 4970320951SEmmanuel Vadot #include <sys/rman.h> 5070320951SEmmanuel Vadot 5170320951SEmmanuel Vadot #include <dev/usb/usb.h> 5270320951SEmmanuel Vadot #include <dev/usb/usbdi.h> 5370320951SEmmanuel Vadot 5470320951SEmmanuel Vadot #include <dev/usb/usb_core.h> 5570320951SEmmanuel Vadot #include <dev/usb/usb_busdma.h> 5670320951SEmmanuel Vadot #include <dev/usb/usb_process.h> 5770320951SEmmanuel Vadot #include <dev/usb/usb_util.h> 5870320951SEmmanuel Vadot 5970320951SEmmanuel Vadot #include <dev/usb/usb_controller.h> 6070320951SEmmanuel Vadot #include <dev/usb/usb_bus.h> 6170320951SEmmanuel Vadot #include <dev/usb/controller/xhci.h> 6270320951SEmmanuel Vadot #include <dev/usb/controller/xhcireg.h> 6370320951SEmmanuel Vadot 64*052073c3SEmmanuel Vadot #include "generic_xhci.h" 6570320951SEmmanuel Vadot 6670320951SEmmanuel Vadot #define IS_DMA_32B 1 6770320951SEmmanuel Vadot 68*052073c3SEmmanuel Vadot int 69*052073c3SEmmanuel Vadot generic_xhci_attach(device_t dev) 7070320951SEmmanuel Vadot { 7170320951SEmmanuel Vadot struct xhci_softc *sc = device_get_softc(dev); 7270320951SEmmanuel Vadot int err = 0, rid = 0; 7370320951SEmmanuel Vadot 7470320951SEmmanuel Vadot sc->sc_bus.parent = dev; 7570320951SEmmanuel Vadot sc->sc_bus.devices = sc->sc_devices; 7670320951SEmmanuel Vadot sc->sc_bus.devices_max = XHCI_MAX_DEVICES; 7770320951SEmmanuel Vadot 7870320951SEmmanuel Vadot sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 7970320951SEmmanuel Vadot RF_ACTIVE); 8070320951SEmmanuel Vadot if (sc->sc_io_res == NULL) { 8170320951SEmmanuel Vadot device_printf(dev, "Failed to map memory\n"); 82*052073c3SEmmanuel Vadot generic_xhci_detach(dev); 8370320951SEmmanuel Vadot return (ENXIO); 8470320951SEmmanuel Vadot } 8570320951SEmmanuel Vadot 8670320951SEmmanuel Vadot sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 8770320951SEmmanuel Vadot sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 8870320951SEmmanuel Vadot sc->sc_io_size = rman_get_size(sc->sc_io_res); 8970320951SEmmanuel Vadot 9070320951SEmmanuel Vadot sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 9170320951SEmmanuel Vadot RF_SHAREABLE | RF_ACTIVE); 9270320951SEmmanuel Vadot if (sc->sc_irq_res == NULL) { 9370320951SEmmanuel Vadot device_printf(dev, "Failed to allocate IRQ\n"); 94*052073c3SEmmanuel Vadot generic_xhci_detach(dev); 9570320951SEmmanuel Vadot return (ENXIO); 9670320951SEmmanuel Vadot } 9770320951SEmmanuel Vadot 9870320951SEmmanuel Vadot sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 9970320951SEmmanuel Vadot if (sc->sc_bus.bdev == NULL) { 10070320951SEmmanuel Vadot device_printf(dev, "Failed to add USB device\n"); 101*052073c3SEmmanuel Vadot generic_xhci_detach(dev); 10270320951SEmmanuel Vadot return (ENXIO); 10370320951SEmmanuel Vadot } 10470320951SEmmanuel Vadot 10570320951SEmmanuel Vadot device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 10670320951SEmmanuel Vadot 10770320951SEmmanuel Vadot sprintf(sc->sc_vendor, XHCI_HC_VENDOR); 10870320951SEmmanuel Vadot device_set_desc(sc->sc_bus.bdev, XHCI_HC_DEVSTR); 10970320951SEmmanuel Vadot 11070320951SEmmanuel Vadot err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 11170320951SEmmanuel Vadot NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 11270320951SEmmanuel Vadot if (err != 0) { 11370320951SEmmanuel Vadot device_printf(dev, "Failed to setup error IRQ, %d\n", err); 11470320951SEmmanuel Vadot sc->sc_intr_hdl = NULL; 115*052073c3SEmmanuel Vadot generic_xhci_detach(dev); 11670320951SEmmanuel Vadot return (err); 11770320951SEmmanuel Vadot } 11870320951SEmmanuel Vadot 11970320951SEmmanuel Vadot err = xhci_init(sc, dev, IS_DMA_32B); 12070320951SEmmanuel Vadot if (err != 0) { 12170320951SEmmanuel Vadot device_printf(dev, "Failed to init XHCI, with error %d\n", err); 122*052073c3SEmmanuel Vadot generic_xhci_detach(dev); 12370320951SEmmanuel Vadot return (ENXIO); 12470320951SEmmanuel Vadot } 12570320951SEmmanuel Vadot 12670320951SEmmanuel Vadot err = xhci_start_controller(sc); 12770320951SEmmanuel Vadot if (err != 0) { 12870320951SEmmanuel Vadot device_printf(dev, "Failed to start XHCI controller, with error %d\n", err); 129*052073c3SEmmanuel Vadot generic_xhci_detach(dev); 13070320951SEmmanuel Vadot return (ENXIO); 13170320951SEmmanuel Vadot } 13270320951SEmmanuel Vadot 13370320951SEmmanuel Vadot err = device_probe_and_attach(sc->sc_bus.bdev); 13470320951SEmmanuel Vadot if (err != 0) { 13570320951SEmmanuel Vadot device_printf(dev, "Failed to initialize USB, with error %d\n", err); 136*052073c3SEmmanuel Vadot generic_xhci_detach(dev); 13770320951SEmmanuel Vadot return (ENXIO); 13870320951SEmmanuel Vadot } 13970320951SEmmanuel Vadot 14070320951SEmmanuel Vadot return (0); 14170320951SEmmanuel Vadot } 14270320951SEmmanuel Vadot 143*052073c3SEmmanuel Vadot int 144*052073c3SEmmanuel Vadot generic_xhci_detach(device_t dev) 14570320951SEmmanuel Vadot { 14670320951SEmmanuel Vadot struct xhci_softc *sc = device_get_softc(dev); 14770320951SEmmanuel Vadot int err; 14870320951SEmmanuel Vadot 14970320951SEmmanuel Vadot /* during module unload there are lots of children leftover */ 15070320951SEmmanuel Vadot device_delete_children(dev); 15170320951SEmmanuel Vadot 15270320951SEmmanuel Vadot if (sc->sc_irq_res != NULL && sc->sc_intr_hdl != NULL) { 15370320951SEmmanuel Vadot err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); 15470320951SEmmanuel Vadot if (err != 0) 15570320951SEmmanuel Vadot device_printf(dev, "Could not tear down irq, %d\n", 15670320951SEmmanuel Vadot err); 15770320951SEmmanuel Vadot sc->sc_intr_hdl = NULL; 15870320951SEmmanuel Vadot } 15970320951SEmmanuel Vadot 16070320951SEmmanuel Vadot if (sc->sc_irq_res != NULL) { 16170320951SEmmanuel Vadot bus_release_resource(dev, SYS_RES_IRQ, 16270320951SEmmanuel Vadot rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 16370320951SEmmanuel Vadot sc->sc_irq_res = NULL; 16470320951SEmmanuel Vadot } 16570320951SEmmanuel Vadot 16670320951SEmmanuel Vadot if (sc->sc_io_res != NULL) { 16770320951SEmmanuel Vadot bus_release_resource(dev, SYS_RES_MEMORY, 16870320951SEmmanuel Vadot rman_get_rid(sc->sc_io_res), sc->sc_io_res); 16970320951SEmmanuel Vadot sc->sc_io_res = NULL; 17070320951SEmmanuel Vadot } 17170320951SEmmanuel Vadot 17270320951SEmmanuel Vadot xhci_uninit(sc); 17370320951SEmmanuel Vadot 17470320951SEmmanuel Vadot return (0); 17570320951SEmmanuel Vadot } 17670320951SEmmanuel Vadot 17770320951SEmmanuel Vadot static device_method_t xhci_methods[] = { 17870320951SEmmanuel Vadot /* Device interface */ 179*052073c3SEmmanuel Vadot DEVMETHOD(device_attach, generic_xhci_attach), 180*052073c3SEmmanuel Vadot DEVMETHOD(device_detach, generic_xhci_detach), 18170320951SEmmanuel Vadot DEVMETHOD(device_suspend, bus_generic_suspend), 18270320951SEmmanuel Vadot DEVMETHOD(device_resume, bus_generic_resume), 18370320951SEmmanuel Vadot DEVMETHOD(device_shutdown, bus_generic_shutdown), 18470320951SEmmanuel Vadot 18570320951SEmmanuel Vadot DEVMETHOD_END 18670320951SEmmanuel Vadot }; 18770320951SEmmanuel Vadot 188*052073c3SEmmanuel Vadot driver_t generic_xhci_driver = { 18970320951SEmmanuel Vadot "xhci", 19070320951SEmmanuel Vadot xhci_methods, 19170320951SEmmanuel Vadot sizeof(struct xhci_softc), 19270320951SEmmanuel Vadot }; 193