xhci_pci.c revision 297852
1213379Shselasky/*- 2213379Shselasky * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 3213379Shselasky * 4213379Shselasky * Redistribution and use in source and binary forms, with or without 5213379Shselasky * modification, are permitted provided that the following conditions 6213379Shselasky * are met: 7213379Shselasky * 1. Redistributions of source code must retain the above copyright 8213379Shselasky * notice, this list of conditions and the following disclaimer. 9213379Shselasky * 2. Redistributions in binary form must reproduce the above copyright 10213379Shselasky * notice, this list of conditions and the following disclaimer in the 11213379Shselasky * documentation and/or other materials provided with the distribution. 12213379Shselasky * 13213379Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14213379Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15213379Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16213379Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17213379Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18213379Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19213379Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20213379Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21213379Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22213379Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23213379Shselasky * SUCH DAMAGE. 24213379Shselasky */ 25213379Shselasky 26213379Shselasky#include <sys/cdefs.h> 27213379Shselasky__FBSDID("$FreeBSD: stable/10/sys/dev/usb/controller/xhci_pci.c 297852 2016-04-12 07:54:55Z mav $"); 28213379Shselasky 29213379Shselasky#include <sys/stdint.h> 30213379Shselasky#include <sys/stddef.h> 31213379Shselasky#include <sys/param.h> 32213379Shselasky#include <sys/queue.h> 33213379Shselasky#include <sys/types.h> 34213379Shselasky#include <sys/systm.h> 35213379Shselasky#include <sys/kernel.h> 36213379Shselasky#include <sys/bus.h> 37213379Shselasky#include <sys/module.h> 38213379Shselasky#include <sys/lock.h> 39213379Shselasky#include <sys/mutex.h> 40213379Shselasky#include <sys/condvar.h> 41213379Shselasky#include <sys/sysctl.h> 42213379Shselasky#include <sys/sx.h> 43213379Shselasky#include <sys/unistd.h> 44213379Shselasky#include <sys/callout.h> 45213379Shselasky#include <sys/malloc.h> 46213379Shselasky#include <sys/priv.h> 47213379Shselasky 48213379Shselasky#include <dev/usb/usb.h> 49213379Shselasky#include <dev/usb/usbdi.h> 50213379Shselasky 51213379Shselasky#include <dev/usb/usb_core.h> 52213379Shselasky#include <dev/usb/usb_busdma.h> 53213379Shselasky#include <dev/usb/usb_process.h> 54213379Shselasky#include <dev/usb/usb_util.h> 55213379Shselasky 56213379Shselasky#include <dev/usb/usb_controller.h> 57213379Shselasky#include <dev/usb/usb_bus.h> 58213379Shselasky#include <dev/usb/usb_pci.h> 59213379Shselasky#include <dev/usb/controller/xhci.h> 60213379Shselasky#include <dev/usb/controller/xhcireg.h> 61228483Shselasky#include "usb_if.h" 62213379Shselasky 63213379Shselaskystatic device_probe_t xhci_pci_probe; 64213379Shselaskystatic device_attach_t xhci_pci_attach; 65213379Shselaskystatic device_detach_t xhci_pci_detach; 66228483Shselaskystatic usb_take_controller_t xhci_pci_take_controller; 67213379Shselasky 68213379Shselaskystatic device_method_t xhci_device_methods[] = { 69213379Shselasky /* device interface */ 70213379Shselasky DEVMETHOD(device_probe, xhci_pci_probe), 71213379Shselasky DEVMETHOD(device_attach, xhci_pci_attach), 72213379Shselasky DEVMETHOD(device_detach, xhci_pci_detach), 73228483Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 74228483Shselasky DEVMETHOD(device_resume, bus_generic_resume), 75228483Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 76228483Shselasky DEVMETHOD(usb_take_controller, xhci_pci_take_controller), 77213379Shselasky 78227843Smarius DEVMETHOD_END 79213379Shselasky}; 80213379Shselasky 81213379Shselaskystatic driver_t xhci_driver = { 82213379Shselasky .name = "xhci", 83213379Shselasky .methods = xhci_device_methods, 84213379Shselasky .size = sizeof(struct xhci_softc), 85213379Shselasky}; 86213379Shselasky 87213379Shselaskystatic devclass_t xhci_devclass; 88213379Shselasky 89290331ShselaskyDRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, NULL, NULL); 90213379ShselaskyMODULE_DEPEND(xhci, usb, 1, 1, 1); 91213379Shselasky 92213379Shselaskystatic const char * 93213379Shselaskyxhci_pci_match(device_t self) 94213379Shselasky{ 95238015Smav uint32_t device_id = pci_get_devid(self); 96238015Smav 97238015Smav switch (device_id) { 98297852Smav case 0x78141022: 99297852Smav return ("AMD FCH USB 3.0 controller"); 100297852Smav 101238015Smav case 0x01941033: 102238015Smav return ("NEC uPD720200 USB 3.0 controller"); 103238015Smav 104289161Skevlo case 0x10001b73: 105289161Skevlo return ("Fresco Logic FL1000G USB 3.0 controller"); 106289161Skevlo 107249336Smav case 0x10421b21: 108249336Smav return ("ASMedia ASM1042 USB 3.0 controller"); 109290331Shselasky case 0x11421b21: 110290331Shselasky return ("ASMedia ASM1042A USB 3.0 controller"); 111249336Smav 112276968Shselasky case 0x0f358086: 113289161Skevlo return ("Intel BayTrail USB 3.0 controller"); 114262364Shselasky case 0x9c318086: 115238015Smav case 0x1e318086: 116238015Smav return ("Intel Panther Point USB 3.0 controller"); 117238551Smav case 0x8c318086: 118238551Smav return ("Intel Lynx Point USB 3.0 controller"); 119275439Smav case 0x8cb18086: 120275439Smav return ("Intel Wildcat Point USB 3.0 controller"); 121297341Smav case 0x8d318086: 122297341Smav return ("Intel Wellsburg USB 3.0 controller"); 123290331Shselasky case 0x9cb18086: 124290331Shselasky return ("Broadwell Integrated PCH-LP chipset USB 3.0 controller"); 125238015Smav 126289013Shselasky case 0xa01b177d: 127289013Shselasky return ("Cavium ThunderX USB 3.0 controller"); 128289013Shselasky 129238015Smav default: 130238015Smav break; 131238015Smav } 132238015Smav 133213379Shselasky if ((pci_get_class(self) == PCIC_SERIALBUS) 134213379Shselasky && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) 135222018Sru && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) { 136213379Shselasky return ("XHCI (generic) USB 3.0 controller"); 137213379Shselasky } 138213379Shselasky return (NULL); /* dunno */ 139213379Shselasky} 140213379Shselasky 141213379Shselaskystatic int 142213379Shselaskyxhci_pci_probe(device_t self) 143213379Shselasky{ 144213379Shselasky const char *desc = xhci_pci_match(self); 145213379Shselasky 146213379Shselasky if (desc) { 147213379Shselasky device_set_desc(self, desc); 148213379Shselasky return (0); 149213379Shselasky } else { 150213379Shselasky return (ENXIO); 151213379Shselasky } 152213379Shselasky} 153213379Shselasky 154253398Skibstatic int xhci_use_msi = 1; 155253398SkibTUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi); 156253398Skib 157251499Shselaskystatic void 158251499Shselaskyxhci_interrupt_poll(void *_sc) 159251499Shselasky{ 160251499Shselasky struct xhci_softc *sc = _sc; 161251499Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 162251499Shselasky xhci_interrupt(sc); 163251499Shselasky USB_BUS_LOCK(&sc->sc_bus); 164251499Shselasky usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc); 165251499Shselasky} 166251499Shselasky 167213379Shselaskystatic int 168255768Shselaskyxhci_pci_port_route(device_t self, uint32_t set, uint32_t clear) 169255768Shselasky{ 170255768Shselasky uint32_t temp; 171268884Shselasky uint32_t usb3_mask; 172268884Shselasky uint32_t usb2_mask; 173255768Shselasky 174255768Shselasky temp = pci_read_config(self, PCI_XHCI_INTEL_USB3_PSSEN, 4) | 175255768Shselasky pci_read_config(self, PCI_XHCI_INTEL_XUSB2PR, 4); 176255768Shselasky 177255768Shselasky temp |= set; 178255768Shselasky temp &= ~clear; 179255768Shselasky 180268604Shselasky /* Don't set bits which the hardware doesn't support */ 181268884Shselasky usb3_mask = pci_read_config(self, PCI_XHCI_INTEL_USB3PRM, 4); 182268884Shselasky usb2_mask = pci_read_config(self, PCI_XHCI_INTEL_USB2PRM, 4); 183268604Shselasky 184268884Shselasky pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp & usb3_mask, 4); 185268884Shselasky pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp & usb2_mask, 4); 186255768Shselasky 187255768Shselasky device_printf(self, "Port routing mask set to 0x%08x\n", temp); 188255768Shselasky 189255768Shselasky return (0); 190255768Shselasky} 191255768Shselasky 192255768Shselaskystatic int 193213379Shselaskyxhci_pci_attach(device_t self) 194213379Shselasky{ 195213379Shselasky struct xhci_softc *sc = device_get_softc(self); 196253094Skib int count, err, rid; 197289161Skevlo uint8_t usemsi = 1; 198289161Skevlo uint8_t usedma32 = 0; 199213379Shselasky 200213379Shselasky rid = PCI_XHCI_CBMEM; 201213379Shselasky sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 202213379Shselasky RF_ACTIVE); 203213379Shselasky if (!sc->sc_io_res) { 204213379Shselasky device_printf(self, "Could not map memory\n"); 205278278Shselasky return (ENOMEM); 206213379Shselasky } 207213379Shselasky sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 208213379Shselasky sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 209213379Shselasky sc->sc_io_size = rman_get_size(sc->sc_io_res); 210213379Shselasky 211279693Shselasky switch (pci_get_devid(self)) { 212279693Shselasky case 0x01941033: /* NEC uPD720200 USB 3.0 controller */ 213290331Shselasky case 0x00141912: /* NEC uPD720201 USB 3.0 controller */ 214290331Shselasky /* Don't use 64-bit DMA on these controllers. */ 215279693Shselasky usedma32 = 1; 216279693Shselasky break; 217289161Skevlo case 0x10001b73: /* FL1000G */ 218289161Skevlo /* Fresco Logic host doesn't support MSI. */ 219289161Skevlo usemsi = 0; 220279693Shselasky break; 221290331Shselasky case 0x0f358086: /* BayTrail */ 222290331Shselasky case 0x9c318086: /* Panther Point */ 223290331Shselasky case 0x1e318086: /* Panther Point */ 224290331Shselasky case 0x8c318086: /* Lynx Point */ 225290331Shselasky case 0x8cb18086: /* Wildcat Point */ 226290331Shselasky case 0x9cb18086: /* Broadwell Mobile Integrated */ 227290331Shselasky /* 228290331Shselasky * On Intel chipsets, reroute ports from EHCI to XHCI 229290331Shselasky * controller and use a different IMOD value. 230290331Shselasky */ 231290331Shselasky sc->sc_port_route = &xhci_pci_port_route; 232290331Shselasky sc->sc_imod_default = XHCI_IMOD_DEFAULT_LP; 233290331Shselasky break; 234279693Shselasky } 235290331Shselasky 236279693Shselasky if (xhci_init(sc, self, usedma32)) { 237278278Shselasky device_printf(self, "Could not initialize softc\n"); 238278278Shselasky bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 239278278Shselasky sc->sc_io_res); 240278278Shselasky return (ENXIO); 241278278Shselasky } 242278278Shselasky 243278278Shselasky pci_enable_busmaster(self); 244278278Shselasky 245251499Shselasky usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0); 246251499Shselasky 247276965Shselasky rid = 0; 248289161Skevlo if (xhci_use_msi && usemsi) { 249276965Shselasky count = 1; 250276965Shselasky if (pci_alloc_msi(self, &count) == 0) { 251276965Shselasky if (bootverbose) 252276965Shselasky device_printf(self, "MSI enabled\n"); 253276965Shselasky rid = 1; 254253094Skib } 255253094Skib } 256276965Shselasky sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 257276965Shselasky RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); 258213379Shselasky if (sc->sc_irq_res == NULL) { 259276965Shselasky pci_release_msi(self); 260213379Shselasky device_printf(self, "Could not allocate IRQ\n"); 261255768Shselasky /* goto error; FALLTHROUGH - use polling */ 262213379Shselasky } 263213379Shselasky sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 264213379Shselasky if (sc->sc_bus.bdev == NULL) { 265213379Shselasky device_printf(self, "Could not add USB device\n"); 266213379Shselasky goto error; 267213379Shselasky } 268213379Shselasky device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 269213379Shselasky 270213379Shselasky sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self)); 271213379Shselasky 272251499Shselasky if (sc->sc_irq_res != NULL) { 273251499Shselasky err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 274251499Shselasky NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 275251499Shselasky if (err != 0) { 276276965Shselasky bus_release_resource(self, SYS_RES_IRQ, 277276965Shselasky rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 278276965Shselasky sc->sc_irq_res = NULL; 279276965Shselasky pci_release_msi(self); 280251499Shselasky device_printf(self, "Could not setup IRQ, err=%d\n", err); 281251499Shselasky sc->sc_intr_hdl = NULL; 282251499Shselasky } 283213379Shselasky } 284276965Shselasky if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL) { 285276965Shselasky if (xhci_use_polling() != 0) { 286276965Shselasky device_printf(self, "Interrupt polling at %dHz\n", hz); 287276965Shselasky USB_BUS_LOCK(&sc->sc_bus); 288276965Shselasky xhci_interrupt_poll(sc); 289276965Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 290276965Shselasky } else 291276965Shselasky goto error; 292251499Shselasky } 293251499Shselasky 294228483Shselasky xhci_pci_take_controller(self); 295213379Shselasky 296213379Shselasky err = xhci_halt_controller(sc); 297213379Shselasky 298213379Shselasky if (err == 0) 299213379Shselasky err = xhci_start_controller(sc); 300213379Shselasky 301213379Shselasky if (err == 0) 302213379Shselasky err = device_probe_and_attach(sc->sc_bus.bdev); 303213379Shselasky 304213379Shselasky if (err) { 305213379Shselasky device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 306213379Shselasky goto error; 307213379Shselasky } 308213379Shselasky return (0); 309213379Shselasky 310213379Shselaskyerror: 311213379Shselasky xhci_pci_detach(self); 312213379Shselasky return (ENXIO); 313213379Shselasky} 314213379Shselasky 315213379Shselaskystatic int 316213379Shselaskyxhci_pci_detach(device_t self) 317213379Shselasky{ 318213379Shselasky struct xhci_softc *sc = device_get_softc(self); 319213379Shselasky device_t bdev; 320213379Shselasky 321213379Shselasky if (sc->sc_bus.bdev != NULL) { 322213379Shselasky bdev = sc->sc_bus.bdev; 323213379Shselasky device_detach(bdev); 324213379Shselasky device_delete_child(self, bdev); 325213379Shselasky } 326213379Shselasky /* during module unload there are lots of children leftover */ 327227849Shselasky device_delete_children(self); 328213379Shselasky 329278278Shselasky usb_callout_drain(&sc->sc_callout); 330278278Shselasky xhci_halt_controller(sc); 331251499Shselasky 332213379Shselasky pci_disable_busmaster(self); 333213379Shselasky 334213379Shselasky if (sc->sc_irq_res && sc->sc_intr_hdl) { 335213379Shselasky bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 336213379Shselasky sc->sc_intr_hdl = NULL; 337213379Shselasky } 338213379Shselasky if (sc->sc_irq_res) { 339276965Shselasky bus_release_resource(self, SYS_RES_IRQ, 340276965Shselasky rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 341213379Shselasky sc->sc_irq_res = NULL; 342276965Shselasky pci_release_msi(self); 343213379Shselasky } 344213379Shselasky if (sc->sc_io_res) { 345213379Shselasky bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 346213379Shselasky sc->sc_io_res); 347213379Shselasky sc->sc_io_res = NULL; 348213379Shselasky } 349213379Shselasky 350213379Shselasky xhci_uninit(sc); 351213379Shselasky 352213379Shselasky return (0); 353213379Shselasky} 354213379Shselasky 355228483Shselaskystatic int 356228483Shselaskyxhci_pci_take_controller(device_t self) 357213379Shselasky{ 358213379Shselasky struct xhci_softc *sc = device_get_softc(self); 359213379Shselasky uint32_t cparams; 360213379Shselasky uint32_t eecp; 361213379Shselasky uint32_t eec; 362213379Shselasky uint16_t to; 363213379Shselasky uint8_t bios_sem; 364213379Shselasky 365213379Shselasky cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); 366213379Shselasky 367213379Shselasky eec = -1; 368213379Shselasky 369213379Shselasky /* Synchronise with the BIOS if it owns the controller. */ 370213379Shselasky for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); 371213379Shselasky eecp += XHCI_XECP_NEXT(eec) << 2) { 372213379Shselasky eec = XREAD4(sc, capa, eecp); 373213379Shselasky 374213379Shselasky if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 375213379Shselasky continue; 376213379Shselasky bios_sem = XREAD1(sc, capa, eecp + 377213379Shselasky XHCI_XECP_BIOS_SEM); 378213379Shselasky if (bios_sem == 0) 379213379Shselasky continue; 380213379Shselasky device_printf(sc->sc_bus.bdev, "waiting for BIOS " 381213379Shselasky "to give up control\n"); 382213379Shselasky XWRITE1(sc, capa, eecp + 383213379Shselasky XHCI_XECP_OS_SEM, 1); 384213379Shselasky to = 500; 385213379Shselasky while (1) { 386213379Shselasky bios_sem = XREAD1(sc, capa, eecp + 387213379Shselasky XHCI_XECP_BIOS_SEM); 388213379Shselasky if (bios_sem == 0) 389213379Shselasky break; 390213379Shselasky 391213379Shselasky if (--to == 0) { 392213379Shselasky device_printf(sc->sc_bus.bdev, 393213379Shselasky "timed out waiting for BIOS\n"); 394213379Shselasky break; 395213379Shselasky } 396213379Shselasky usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 397213379Shselasky } 398213379Shselasky } 399228483Shselasky return (0); 400213379Shselasky} 401