xhci_pci.c revision 275785
1343171Sdim/*- 2343171Sdim * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 3353358Sdim * 4353358Sdim * Redistribution and use in source and binary forms, with or without 5353358Sdim * modification, are permitted provided that the following conditions 6343171Sdim * are met: 7343171Sdim * 1. Redistributions of source code must retain the above copyright 8343171Sdim * notice, this list of conditions and the following disclaimer. 9343171Sdim * 2. Redistributions in binary form must reproduce the above copyright 10343171Sdim * notice, this list of conditions and the following disclaimer in the 11343171Sdim * documentation and/or other materials provided with the distribution. 12343171Sdim * 13343171Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14343171Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15343171Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16343171Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17343171Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18343171Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19343171Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20343171Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21343171Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22343171Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23343171Sdim * SUCH DAMAGE. 24343171Sdim */ 25343171Sdim 26343171Sdim#include <sys/cdefs.h> 27343171Sdim__FBSDID("$FreeBSD: stable/10/sys/dev/usb/controller/xhci_pci.c 275785 2014-12-15 08:26:36Z hselasky $"); 28343171Sdim 29343171Sdim#include <sys/stdint.h> 30343171Sdim#include <sys/stddef.h> 31343171Sdim#include <sys/param.h> 32343171Sdim#include <sys/queue.h> 33343171Sdim#include <sys/types.h> 34343171Sdim#include <sys/systm.h> 35343171Sdim#include <sys/kernel.h> 36343171Sdim#include <sys/bus.h> 37343171Sdim#include <sys/module.h> 38343171Sdim#include <sys/lock.h> 39343171Sdim#include <sys/mutex.h> 40343171Sdim#include <sys/condvar.h> 41343171Sdim#include <sys/sysctl.h> 42343171Sdim#include <sys/sx.h> 43343171Sdim#include <sys/unistd.h> 44343171Sdim#include <sys/callout.h> 45343171Sdim#include <sys/malloc.h> 46343171Sdim#include <sys/priv.h> 47343171Sdim 48343171Sdim#include <dev/usb/usb.h> 49343171Sdim#include <dev/usb/usbdi.h> 50343171Sdim 51343171Sdim#include <dev/usb/usb_core.h> 52343171Sdim#include <dev/usb/usb_busdma.h> 53343171Sdim#include <dev/usb/usb_process.h> 54343171Sdim#include <dev/usb/usb_util.h> 55343171Sdim 56343171Sdim#include <dev/usb/usb_controller.h> 57353358Sdim#include <dev/usb/usb_bus.h> 58353358Sdim#include <dev/usb/usb_pci.h> 59353358Sdim#include <dev/usb/controller/xhci.h> 60353358Sdim#include <dev/usb/controller/xhcireg.h> 61353358Sdim#include "usb_if.h" 62353358Sdim 63353358Sdimstatic device_probe_t xhci_pci_probe; 64353358Sdimstatic device_attach_t xhci_pci_attach; 65353358Sdimstatic device_detach_t xhci_pci_detach; 66353358Sdimstatic usb_take_controller_t xhci_pci_take_controller; 67353358Sdim 68353358Sdimstatic device_method_t xhci_device_methods[] = { 69353358Sdim /* device interface */ 70353358Sdim DEVMETHOD(device_probe, xhci_pci_probe), 71353358Sdim DEVMETHOD(device_attach, xhci_pci_attach), 72353358Sdim DEVMETHOD(device_detach, xhci_pci_detach), 73343171Sdim DEVMETHOD(device_suspend, bus_generic_suspend), 74343171Sdim DEVMETHOD(device_resume, bus_generic_resume), 75343171Sdim DEVMETHOD(device_shutdown, bus_generic_shutdown), 76343171Sdim DEVMETHOD(usb_take_controller, xhci_pci_take_controller), 77343171Sdim 78343171Sdim DEVMETHOD_END 79343171Sdim}; 80343171Sdim 81343171Sdimstatic driver_t xhci_driver = { 82343171Sdim .name = "xhci", 83343171Sdim .methods = xhci_device_methods, 84343171Sdim .size = sizeof(struct xhci_softc), 85343171Sdim}; 86343171Sdim 87343171Sdimstatic devclass_t xhci_devclass; 88343171Sdim 89343171SdimDRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, 0, 0); 90343171SdimMODULE_DEPEND(xhci, usb, 1, 1, 1); 91343171Sdim 92343171Sdim 93343171Sdimstatic const char * 94343171Sdimxhci_pci_match(device_t self) 95343171Sdim{ 96343171Sdim uint32_t device_id = pci_get_devid(self); 97343171Sdim 98343171Sdim switch (device_id) { 99343171Sdim case 0x01941033: 100343171Sdim return ("NEC uPD720200 USB 3.0 controller"); 101343171Sdim 102343171Sdim case 0x10421b21: 103343171Sdim return ("ASMedia ASM1042 USB 3.0 controller"); 104343171Sdim 105353358Sdim case 0x9c318086: 106353358Sdim case 0x1e318086: 107353358Sdim return ("Intel Panther Point USB 3.0 controller"); 108343171Sdim case 0x8c318086: 109343171Sdim return ("Intel Lynx Point USB 3.0 controller"); 110343171Sdim case 0x8cb18086: 111343171Sdim return ("Intel Wildcat Point USB 3.0 controller"); 112343171Sdim 113343171Sdim default: 114343171Sdim break; 115343171Sdim } 116343171Sdim 117343171Sdim if ((pci_get_class(self) == PCIC_SERIALBUS) 118343171Sdim && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) 119343171Sdim && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) { 120343171Sdim return ("XHCI (generic) USB 3.0 controller"); 121343171Sdim } 122343171Sdim return (NULL); /* dunno */ 123343171Sdim} 124343171Sdim 125343171Sdimstatic int 126343171Sdimxhci_pci_probe(device_t self) 127343171Sdim{ 128343171Sdim const char *desc = xhci_pci_match(self); 129343171Sdim 130343171Sdim if (desc) { 131343171Sdim device_set_desc(self, desc); 132353358Sdim return (0); 133353358Sdim } else { 134343171Sdim return (ENXIO); 135343171Sdim } 136353358Sdim} 137353358Sdim 138353358Sdimstatic int xhci_use_msi = 1; 139353358SdimTUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi); 140353358Sdim 141353358Sdimstatic void 142353358Sdimxhci_interrupt_poll(void *_sc) 143353358Sdim{ 144343171Sdim struct xhci_softc *sc = _sc; 145343171Sdim USB_BUS_UNLOCK(&sc->sc_bus); 146343171Sdim xhci_interrupt(sc); 147343171Sdim USB_BUS_LOCK(&sc->sc_bus); 148343171Sdim usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc); 149343171Sdim} 150343171Sdim 151343171Sdimstatic int 152343171Sdimxhci_pci_port_route(device_t self, uint32_t set, uint32_t clear) 153343171Sdim{ 154343171Sdim uint32_t temp; 155343171Sdim uint32_t usb3_mask; 156343171Sdim uint32_t usb2_mask; 157343171Sdim 158343171Sdim temp = pci_read_config(self, PCI_XHCI_INTEL_USB3_PSSEN, 4) | 159343171Sdim pci_read_config(self, PCI_XHCI_INTEL_XUSB2PR, 4); 160343171Sdim 161343171Sdim temp |= set; 162343171Sdim temp &= ~clear; 163343171Sdim 164343171Sdim /* Don't set bits which the hardware doesn't support */ 165343171Sdim usb3_mask = pci_read_config(self, PCI_XHCI_INTEL_USB3PRM, 4); 166343171Sdim usb2_mask = pci_read_config(self, PCI_XHCI_INTEL_USB2PRM, 4); 167343171Sdim 168343171Sdim pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp & usb3_mask, 4); 169343171Sdim pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp & usb2_mask, 4); 170343171Sdim 171343171Sdim device_printf(self, "Port routing mask set to 0x%08x\n", temp); 172343171Sdim 173343171Sdim return (0); 174343171Sdim} 175343171Sdim 176343171Sdimstatic int 177343171Sdimxhci_pci_attach(device_t self) 178343171Sdim{ 179343171Sdim struct xhci_softc *sc = device_get_softc(self); 180343171Sdim int count, err, rid; 181343171Sdim 182343171Sdim /* XXX check for 64-bit capability */ 183353358Sdim 184353358Sdim if (xhci_init(sc, self)) { 185353358Sdim device_printf(self, "Could not initialize softc\n"); 186353358Sdim goto error; 187353358Sdim } 188353358Sdim 189353358Sdim pci_enable_busmaster(self); 190353358Sdim 191353358Sdim rid = PCI_XHCI_CBMEM; 192353358Sdim sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 193353358Sdim RF_ACTIVE); 194353358Sdim if (!sc->sc_io_res) { 195353358Sdim device_printf(self, "Could not map memory\n"); 196353358Sdim goto error; 197353358Sdim } 198353358Sdim sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 199353358Sdim sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 200353358Sdim sc->sc_io_size = rman_get_size(sc->sc_io_res); 201353358Sdim 202353358Sdim usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0); 203353358Sdim 204353358Sdim sc->sc_irq_rid = 0; 205353358Sdim if (xhci_use_msi) { 206353358Sdim count = pci_msi_count(self); 207353358Sdim if (count >= 1) { 208353358Sdim count = 1; 209353358Sdim if (pci_alloc_msi(self, &count) == 0) { 210353358Sdim if (bootverbose) 211353358Sdim device_printf(self, "MSI enabled\n"); 212353358Sdim sc->sc_irq_rid = 1; 213353358Sdim } 214353358Sdim } 215353358Sdim } 216353358Sdim sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, 217353358Sdim &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE); 218353358Sdim if (sc->sc_irq_res == NULL) { 219353358Sdim device_printf(self, "Could not allocate IRQ\n"); 220353358Sdim /* goto error; FALLTHROUGH - use polling */ 221353358Sdim } 222353358Sdim sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 223353358Sdim if (sc->sc_bus.bdev == NULL) { 224353358Sdim device_printf(self, "Could not add USB device\n"); 225353358Sdim goto error; 226353358Sdim } 227353358Sdim device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 228353358Sdim 229353358Sdim sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self)); 230353358Sdim 231353358Sdim if (sc->sc_irq_res != NULL) { 232353358Sdim err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 233343171Sdim NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 234343171Sdim if (err != 0) { 235343171Sdim device_printf(self, "Could not setup IRQ, err=%d\n", err); 236343171Sdim sc->sc_intr_hdl = NULL; 237343171Sdim } 238360784Sdim } 239360784Sdim if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL || 240360784Sdim xhci_use_polling() != 0) { 241360784Sdim device_printf(self, "Interrupt polling at %dHz\n", hz); 242343171Sdim USB_BUS_LOCK(&sc->sc_bus); 243343171Sdim xhci_interrupt_poll(sc); 244343171Sdim USB_BUS_UNLOCK(&sc->sc_bus); 245343171Sdim } 246353358Sdim 247343171Sdim /* On Intel chipsets reroute ports from EHCI to XHCI controller. */ 248353358Sdim switch (pci_get_devid(self)) { 249343171Sdim case 0x9c318086: /* Panther Point */ 250353358Sdim case 0x1e318086: /* Panther Point */ 251343171Sdim case 0x8c318086: /* Lynx Point */ 252343171Sdim case 0x8cb18086: /* Wildcat Point */ 253343171Sdim sc->sc_port_route = &xhci_pci_port_route; 254343171Sdim sc->sc_imod_default = XHCI_IMOD_DEFAULT_LP; 255343171Sdim break; 256343171Sdim default: 257343171Sdim break; 258343171Sdim } 259343171Sdim 260343171Sdim xhci_pci_take_controller(self); 261343171Sdim 262343171Sdim err = xhci_halt_controller(sc); 263343171Sdim 264353358Sdim if (err == 0) 265343171Sdim err = xhci_start_controller(sc); 266343171Sdim 267343171Sdim if (err == 0) 268343171Sdim err = device_probe_and_attach(sc->sc_bus.bdev); 269343171Sdim 270343171Sdim if (err) { 271343171Sdim device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 272343171Sdim goto error; 273343171Sdim } 274360784Sdim return (0); 275360784Sdim 276360784Sdimerror: 277343171Sdim xhci_pci_detach(self); 278343171Sdim return (ENXIO); 279343171Sdim} 280343171Sdim 281343171Sdimstatic int 282343171Sdimxhci_pci_detach(device_t self) 283343171Sdim{ 284343171Sdim struct xhci_softc *sc = device_get_softc(self); 285343171Sdim device_t bdev; 286343171Sdim 287343171Sdim if (sc->sc_bus.bdev != NULL) { 288343171Sdim bdev = sc->sc_bus.bdev; 289343171Sdim device_detach(bdev); 290343171Sdim device_delete_child(self, bdev); 291343171Sdim } 292343171Sdim /* during module unload there are lots of children leftover */ 293343171Sdim device_delete_children(self); 294343171Sdim 295343171Sdim if (sc->sc_io_res) { 296343171Sdim usb_callout_drain(&sc->sc_callout); 297343171Sdim xhci_halt_controller(sc); 298343171Sdim } 299353358Sdim 300360784Sdim pci_disable_busmaster(self); 301360784Sdim 302360784Sdim if (sc->sc_irq_res && sc->sc_intr_hdl) { 303360784Sdim bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 304360784Sdim sc->sc_intr_hdl = NULL; 305343171Sdim } 306343171Sdim if (sc->sc_irq_res) { 307343171Sdim if (sc->sc_irq_rid == 1) 308343171Sdim pci_release_msi(self); 309343171Sdim bus_release_resource(self, SYS_RES_IRQ, sc->sc_irq_rid, 310343171Sdim sc->sc_irq_res); 311343171Sdim sc->sc_irq_res = NULL; 312343171Sdim } 313343171Sdim if (sc->sc_io_res) { 314343171Sdim bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 315343171Sdim sc->sc_io_res); 316343171Sdim sc->sc_io_res = NULL; 317343171Sdim } 318343171Sdim 319343171Sdim xhci_uninit(sc); 320343171Sdim 321343171Sdim return (0); 322360784Sdim} 323360784Sdim 324360784Sdimstatic int 325343171Sdimxhci_pci_take_controller(device_t self) 326343171Sdim{ 327343171Sdim struct xhci_softc *sc = device_get_softc(self); 328343171Sdim uint32_t cparams; 329343171Sdim uint32_t eecp; 330343171Sdim uint32_t eec; 331343171Sdim uint16_t to; 332343171Sdim uint8_t bios_sem; 333343171Sdim 334343171Sdim cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); 335343171Sdim 336343171Sdim eec = -1; 337343171Sdim 338343171Sdim /* Synchronise with the BIOS if it owns the controller. */ 339343171Sdim for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); 340343171Sdim eecp += XHCI_XECP_NEXT(eec) << 2) { 341343171Sdim eec = XREAD4(sc, capa, eecp); 342343171Sdim 343343171Sdim if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 344343171Sdim continue; 345343171Sdim bios_sem = XREAD1(sc, capa, eecp + 346343171Sdim XHCI_XECP_BIOS_SEM); 347343171Sdim if (bios_sem == 0) 348343171Sdim continue; 349343171Sdim device_printf(sc->sc_bus.bdev, "waiting for BIOS " 350343171Sdim "to give up control\n"); 351343171Sdim XWRITE1(sc, capa, eecp + 352343171Sdim XHCI_XECP_OS_SEM, 1); 353343171Sdim to = 500; 354343171Sdim while (1) { 355343171Sdim bios_sem = XREAD1(sc, capa, eecp + 356343171Sdim XHCI_XECP_BIOS_SEM); 357343171Sdim if (bios_sem == 0) 358343171Sdim break; 359343171Sdim 360343171Sdim if (--to == 0) { 361343171Sdim device_printf(sc->sc_bus.bdev, 362343171Sdim "timed out waiting for BIOS\n"); 363343171Sdim break; 364343171Sdim } 365343171Sdim usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 366343171Sdim } 367343171Sdim } 368343171Sdim return (0); 369343171Sdim} 370343171Sdim