1 /*- 2 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/stdint.h> 30 #include <sys/stddef.h> 31 #include <sys/param.h> 32 #include <sys/queue.h> 33 #include <sys/types.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/bus.h> 37 #include <sys/linker_set.h> 38 #include <sys/module.h> 39 #include <sys/lock.h> 40 #include <sys/mutex.h> 41 #include <sys/condvar.h> 42 #include <sys/sysctl.h> 43 #include <sys/sx.h> 44 #include <sys/unistd.h> 45 #include <sys/callout.h> 46 #include <sys/malloc.h> 47 #include <sys/priv.h> 48 49 #include <dev/usb/usb.h> 50 #include <dev/usb/usbdi.h> 51 52 #include <dev/usb/usb_core.h> 53 #include <dev/usb/usb_busdma.h> 54 #include <dev/usb/usb_process.h> 55 #include <dev/usb/usb_util.h> 56 57 #include <dev/usb/usb_controller.h> 58 #include <dev/usb/usb_bus.h> 59 #include <dev/usb/usb_pci.h> 60 #include <dev/usb/controller/xhci.h> 61 #include <dev/usb/controller/xhcireg.h> 62 63 static device_probe_t xhci_pci_probe; 64 static device_attach_t xhci_pci_attach; 65 static device_detach_t xhci_pci_detach; 66 static device_suspend_t xhci_pci_suspend; 67 static device_resume_t xhci_pci_resume; 68 static device_shutdown_t xhci_pci_shutdown; 69 static void xhci_pci_takecontroller(device_t); 70 71 static device_method_t xhci_device_methods[] = { 72 /* device interface */ 73 DEVMETHOD(device_probe, xhci_pci_probe), 74 DEVMETHOD(device_attach, xhci_pci_attach), 75 DEVMETHOD(device_detach, xhci_pci_detach), 76 DEVMETHOD(device_suspend, xhci_pci_suspend), 77 DEVMETHOD(device_resume, xhci_pci_resume), 78 DEVMETHOD(device_shutdown, xhci_pci_shutdown), 79 /* bus interface */ 80 DEVMETHOD(bus_print_child, bus_generic_print_child), 81 82 {0, 0} 83 }; 84 85 static driver_t xhci_driver = { 86 .name = "xhci", 87 .methods = xhci_device_methods, 88 .size = sizeof(struct xhci_softc), 89 }; 90 91 static devclass_t xhci_devclass; 92 93 DRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, 0, 0); 94 MODULE_DEPEND(xhci, usb, 1, 1, 1); 95 96 static int 97 xhci_pci_suspend(device_t self) 98 { 99 struct xhci_softc *sc = device_get_softc(self); 100 int err; 101 102 err = bus_generic_suspend(self); 103 if (err) 104 return (err); 105 xhci_suspend(sc); 106 return (0); 107 } 108 109 static int 110 xhci_pci_resume(device_t self) 111 { 112 struct xhci_softc *sc = device_get_softc(self); 113 114 xhci_pci_takecontroller(self); 115 xhci_resume(sc); 116 117 bus_generic_resume(self); 118 119 return (0); 120 } 121 122 static int 123 xhci_pci_shutdown(device_t self) 124 { 125 struct xhci_softc *sc = device_get_softc(self); 126 int err; 127 128 err = bus_generic_shutdown(self); 129 if (err) 130 return (err); 131 xhci_shutdown(sc); 132 133 return (0); 134 } 135 136 static const char * 137 xhci_pci_match(device_t self) 138 { 139 if ((pci_get_class(self) == PCIC_SERIALBUS) 140 && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) 141 && (pci_get_progif(self) == PCI_INTERFACE_XHCI)) { 142 return ("XHCI (generic) USB 3.0 controller"); 143 } 144 return (NULL); /* dunno */ 145 } 146 147 static int 148 xhci_pci_probe(device_t self) 149 { 150 const char *desc = xhci_pci_match(self); 151 152 if (desc) { 153 device_set_desc(self, desc); 154 return (0); 155 } else { 156 return (ENXIO); 157 } 158 } 159 160 static int 161 xhci_pci_attach(device_t self) 162 { 163 struct xhci_softc *sc = device_get_softc(self); 164 int err; 165 int rid; 166 167 /* XXX check for 64-bit capability */ 168 169 if (xhci_init(sc, self)) { 170 device_printf(self, "Could not initialize softc\n"); 171 goto error; 172 } 173 174 pci_enable_busmaster(self); 175 176 rid = PCI_XHCI_CBMEM; 177 sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 178 RF_ACTIVE); 179 if (!sc->sc_io_res) { 180 device_printf(self, "Could not map memory\n"); 181 goto error; 182 } 183 sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 184 sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 185 sc->sc_io_size = rman_get_size(sc->sc_io_res); 186 187 rid = 0; 188 sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 189 RF_SHAREABLE | RF_ACTIVE); 190 if (sc->sc_irq_res == NULL) { 191 device_printf(self, "Could not allocate IRQ\n"); 192 goto error; 193 } 194 sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 195 if (sc->sc_bus.bdev == NULL) { 196 device_printf(self, "Could not add USB device\n"); 197 goto error; 198 } 199 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 200 201 sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self)); 202 203 #if (__FreeBSD_version >= 700031) 204 err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 205 NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 206 #else 207 err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 208 (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 209 #endif 210 if (err) { 211 device_printf(self, "Could not setup IRQ, err=%d\n", err); 212 sc->sc_intr_hdl = NULL; 213 goto error; 214 } 215 xhci_pci_takecontroller(self); 216 217 err = xhci_halt_controller(sc); 218 219 if (err == 0) 220 err = xhci_start_controller(sc); 221 222 if (err == 0) 223 err = device_probe_and_attach(sc->sc_bus.bdev); 224 225 if (err) { 226 device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 227 goto error; 228 } 229 return (0); 230 231 error: 232 xhci_pci_detach(self); 233 return (ENXIO); 234 } 235 236 static int 237 xhci_pci_detach(device_t self) 238 { 239 struct xhci_softc *sc = device_get_softc(self); 240 device_t bdev; 241 242 if (sc->sc_bus.bdev != NULL) { 243 bdev = sc->sc_bus.bdev; 244 device_detach(bdev); 245 device_delete_child(self, bdev); 246 } 247 /* during module unload there are lots of children leftover */ 248 device_delete_all_children(self); 249 250 pci_disable_busmaster(self); 251 252 if (sc->sc_irq_res && sc->sc_intr_hdl) { 253 254 xhci_halt_controller(sc); 255 256 bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 257 sc->sc_intr_hdl = NULL; 258 } 259 if (sc->sc_irq_res) { 260 bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 261 sc->sc_irq_res = NULL; 262 } 263 if (sc->sc_io_res) { 264 bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 265 sc->sc_io_res); 266 sc->sc_io_res = NULL; 267 } 268 269 xhci_uninit(sc); 270 271 return (0); 272 } 273 274 static void 275 xhci_pci_takecontroller(device_t self) 276 { 277 struct xhci_softc *sc = device_get_softc(self); 278 uint32_t cparams; 279 uint32_t eecp; 280 uint32_t eec; 281 uint16_t to; 282 uint8_t bios_sem; 283 284 cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); 285 286 eec = -1; 287 288 /* Synchronise with the BIOS if it owns the controller. */ 289 for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); 290 eecp += XHCI_XECP_NEXT(eec) << 2) { 291 eec = XREAD4(sc, capa, eecp); 292 293 if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 294 continue; 295 bios_sem = XREAD1(sc, capa, eecp + 296 XHCI_XECP_BIOS_SEM); 297 if (bios_sem == 0) 298 continue; 299 device_printf(sc->sc_bus.bdev, "waiting for BIOS " 300 "to give up control\n"); 301 XWRITE1(sc, capa, eecp + 302 XHCI_XECP_OS_SEM, 1); 303 to = 500; 304 while (1) { 305 bios_sem = XREAD1(sc, capa, eecp + 306 XHCI_XECP_BIOS_SEM); 307 if (bios_sem == 0) 308 break; 309 310 if (--to == 0) { 311 device_printf(sc->sc_bus.bdev, 312 "timed out waiting for BIOS\n"); 313 break; 314 } 315 usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 316 } 317 } 318 } 319