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 333203 2018-05-03 07:38:45Z hselasky $"); 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"); 103318499Smarius case 0x00151912: 104318499Smarius return ("NEC uPD720202 USB 3.0 controller"); 105238015Smav 106289161Skevlo case 0x10001b73: 107289161Skevlo return ("Fresco Logic FL1000G USB 3.0 controller"); 108289161Skevlo 109249336Smav case 0x10421b21: 110249336Smav return ("ASMedia ASM1042 USB 3.0 controller"); 111290331Shselasky case 0x11421b21: 112290331Shselasky return ("ASMedia ASM1042A USB 3.0 controller"); 113249336Smav 114276968Shselasky case 0x0f358086: 115289161Skevlo return ("Intel BayTrail USB 3.0 controller"); 116262364Shselasky case 0x9c318086: 117238015Smav case 0x1e318086: 118238015Smav return ("Intel Panther Point USB 3.0 controller"); 119318499Smarius case 0x22b58086: 120318499Smarius return ("Intel Braswell USB 3.0 controller"); 121318499Smarius case 0x5aa88086: 122318499Smarius return ("Intel Apollo Lake USB 3.0 controller"); 123238551Smav case 0x8c318086: 124238551Smav return ("Intel Lynx Point USB 3.0 controller"); 125275439Smav case 0x8cb18086: 126275439Smav return ("Intel Wildcat Point USB 3.0 controller"); 127297341Smav case 0x8d318086: 128297341Smav return ("Intel Wellsburg USB 3.0 controller"); 129290331Shselasky case 0x9cb18086: 130290331Shselasky return ("Broadwell Integrated PCH-LP chipset USB 3.0 controller"); 131308739Smav case 0x9d2f8086: 132308739Smav return ("Intel Sunrise Point-LP USB 3.0 controller"); 133300312Smav case 0xa12f8086: 134300312Smav return ("Intel Sunrise Point USB 3.0 controller"); 135238015Smav 136289013Shselasky case 0xa01b177d: 137289013Shselasky return ("Cavium ThunderX USB 3.0 controller"); 138289013Shselasky 139238015Smav default: 140238015Smav break; 141238015Smav } 142238015Smav 143213379Shselasky if ((pci_get_class(self) == PCIC_SERIALBUS) 144213379Shselasky && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) 145222018Sru && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) { 146213379Shselasky return ("XHCI (generic) USB 3.0 controller"); 147213379Shselasky } 148213379Shselasky return (NULL); /* dunno */ 149213379Shselasky} 150213379Shselasky 151213379Shselaskystatic int 152213379Shselaskyxhci_pci_probe(device_t self) 153213379Shselasky{ 154213379Shselasky const char *desc = xhci_pci_match(self); 155213379Shselasky 156213379Shselasky if (desc) { 157213379Shselasky device_set_desc(self, desc); 158305589Shselasky return (BUS_PROBE_DEFAULT); 159213379Shselasky } else { 160213379Shselasky return (ENXIO); 161213379Shselasky } 162213379Shselasky} 163213379Shselasky 164253398Skibstatic int xhci_use_msi = 1; 165253398SkibTUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi); 166253398Skib 167251499Shselaskystatic void 168251499Shselaskyxhci_interrupt_poll(void *_sc) 169251499Shselasky{ 170251499Shselasky struct xhci_softc *sc = _sc; 171251499Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 172251499Shselasky xhci_interrupt(sc); 173251499Shselasky USB_BUS_LOCK(&sc->sc_bus); 174251499Shselasky usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc); 175251499Shselasky} 176251499Shselasky 177213379Shselaskystatic int 178255768Shselaskyxhci_pci_port_route(device_t self, uint32_t set, uint32_t clear) 179255768Shselasky{ 180255768Shselasky uint32_t temp; 181268884Shselasky uint32_t usb3_mask; 182268884Shselasky uint32_t usb2_mask; 183255768Shselasky 184255768Shselasky temp = pci_read_config(self, PCI_XHCI_INTEL_USB3_PSSEN, 4) | 185255768Shselasky pci_read_config(self, PCI_XHCI_INTEL_XUSB2PR, 4); 186255768Shselasky 187255768Shselasky temp |= set; 188255768Shselasky temp &= ~clear; 189255768Shselasky 190268604Shselasky /* Don't set bits which the hardware doesn't support */ 191268884Shselasky usb3_mask = pci_read_config(self, PCI_XHCI_INTEL_USB3PRM, 4); 192268884Shselasky usb2_mask = pci_read_config(self, PCI_XHCI_INTEL_USB2PRM, 4); 193268604Shselasky 194268884Shselasky pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp & usb3_mask, 4); 195268884Shselasky pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp & usb2_mask, 4); 196255768Shselasky 197255768Shselasky device_printf(self, "Port routing mask set to 0x%08x\n", temp); 198255768Shselasky 199255768Shselasky return (0); 200255768Shselasky} 201255768Shselasky 202255768Shselaskystatic int 203213379Shselaskyxhci_pci_attach(device_t self) 204213379Shselasky{ 205213379Shselasky struct xhci_softc *sc = device_get_softc(self); 206253094Skib int count, err, rid; 207289161Skevlo uint8_t usemsi = 1; 208289161Skevlo uint8_t usedma32 = 0; 209213379Shselasky 210213379Shselasky rid = PCI_XHCI_CBMEM; 211213379Shselasky sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 212213379Shselasky RF_ACTIVE); 213213379Shselasky if (!sc->sc_io_res) { 214213379Shselasky device_printf(self, "Could not map memory\n"); 215278278Shselasky return (ENOMEM); 216213379Shselasky } 217213379Shselasky sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 218213379Shselasky sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 219213379Shselasky sc->sc_io_size = rman_get_size(sc->sc_io_res); 220213379Shselasky 221279693Shselasky switch (pci_get_devid(self)) { 222279693Shselasky case 0x01941033: /* NEC uPD720200 USB 3.0 controller */ 223290331Shselasky case 0x00141912: /* NEC uPD720201 USB 3.0 controller */ 224290331Shselasky /* Don't use 64-bit DMA on these controllers. */ 225279693Shselasky usedma32 = 1; 226279693Shselasky break; 227289161Skevlo case 0x10001b73: /* FL1000G */ 228289161Skevlo /* Fresco Logic host doesn't support MSI. */ 229289161Skevlo usemsi = 0; 230279693Shselasky break; 231290331Shselasky case 0x0f358086: /* BayTrail */ 232290331Shselasky case 0x9c318086: /* Panther Point */ 233290331Shselasky case 0x1e318086: /* Panther Point */ 234290331Shselasky case 0x8c318086: /* Lynx Point */ 235290331Shselasky case 0x8cb18086: /* Wildcat Point */ 236290331Shselasky case 0x9cb18086: /* Broadwell Mobile Integrated */ 237290331Shselasky /* 238290331Shselasky * On Intel chipsets, reroute ports from EHCI to XHCI 239290331Shselasky * controller and use a different IMOD value. 240290331Shselasky */ 241290331Shselasky sc->sc_port_route = &xhci_pci_port_route; 242290331Shselasky sc->sc_imod_default = XHCI_IMOD_DEFAULT_LP; 243333203Shselasky sc->sc_ctlstep = 1; 244290331Shselasky break; 245279693Shselasky } 246290331Shselasky 247279693Shselasky if (xhci_init(sc, self, usedma32)) { 248278278Shselasky device_printf(self, "Could not initialize softc\n"); 249278278Shselasky bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 250278278Shselasky sc->sc_io_res); 251278278Shselasky return (ENXIO); 252278278Shselasky } 253278278Shselasky 254278278Shselasky pci_enable_busmaster(self); 255278278Shselasky 256251499Shselasky usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0); 257251499Shselasky 258276965Shselasky rid = 0; 259289161Skevlo if (xhci_use_msi && usemsi) { 260276965Shselasky count = 1; 261276965Shselasky if (pci_alloc_msi(self, &count) == 0) { 262276965Shselasky if (bootverbose) 263276965Shselasky device_printf(self, "MSI enabled\n"); 264276965Shselasky rid = 1; 265253094Skib } 266253094Skib } 267276965Shselasky sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 268276965Shselasky RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); 269213379Shselasky if (sc->sc_irq_res == NULL) { 270276965Shselasky pci_release_msi(self); 271213379Shselasky device_printf(self, "Could not allocate IRQ\n"); 272255768Shselasky /* goto error; FALLTHROUGH - use polling */ 273213379Shselasky } 274213379Shselasky sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 275213379Shselasky if (sc->sc_bus.bdev == NULL) { 276213379Shselasky device_printf(self, "Could not add USB device\n"); 277213379Shselasky goto error; 278213379Shselasky } 279213379Shselasky device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 280213379Shselasky 281213379Shselasky sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self)); 282213379Shselasky 283251499Shselasky if (sc->sc_irq_res != NULL) { 284251499Shselasky err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 285251499Shselasky NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 286251499Shselasky if (err != 0) { 287276965Shselasky bus_release_resource(self, SYS_RES_IRQ, 288276965Shselasky rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 289276965Shselasky sc->sc_irq_res = NULL; 290276965Shselasky pci_release_msi(self); 291251499Shselasky device_printf(self, "Could not setup IRQ, err=%d\n", err); 292251499Shselasky sc->sc_intr_hdl = NULL; 293251499Shselasky } 294213379Shselasky } 295276965Shselasky if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL) { 296276965Shselasky if (xhci_use_polling() != 0) { 297276965Shselasky device_printf(self, "Interrupt polling at %dHz\n", hz); 298276965Shselasky USB_BUS_LOCK(&sc->sc_bus); 299276965Shselasky xhci_interrupt_poll(sc); 300276965Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 301276965Shselasky } else 302276965Shselasky goto error; 303251499Shselasky } 304251499Shselasky 305228483Shselasky xhci_pci_take_controller(self); 306213379Shselasky 307213379Shselasky err = xhci_halt_controller(sc); 308213379Shselasky 309213379Shselasky if (err == 0) 310213379Shselasky err = xhci_start_controller(sc); 311213379Shselasky 312213379Shselasky if (err == 0) 313213379Shselasky err = device_probe_and_attach(sc->sc_bus.bdev); 314213379Shselasky 315213379Shselasky if (err) { 316213379Shselasky device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 317213379Shselasky goto error; 318213379Shselasky } 319213379Shselasky return (0); 320213379Shselasky 321213379Shselaskyerror: 322213379Shselasky xhci_pci_detach(self); 323213379Shselasky return (ENXIO); 324213379Shselasky} 325213379Shselasky 326213379Shselaskystatic int 327213379Shselaskyxhci_pci_detach(device_t self) 328213379Shselasky{ 329213379Shselasky struct xhci_softc *sc = device_get_softc(self); 330213379Shselasky 331213379Shselasky /* during module unload there are lots of children leftover */ 332227849Shselasky device_delete_children(self); 333213379Shselasky 334278278Shselasky usb_callout_drain(&sc->sc_callout); 335278278Shselasky xhci_halt_controller(sc); 336315252Shselasky xhci_reset_controller(sc); 337251499Shselasky 338213379Shselasky pci_disable_busmaster(self); 339213379Shselasky 340213379Shselasky if (sc->sc_irq_res && sc->sc_intr_hdl) { 341213379Shselasky bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 342213379Shselasky sc->sc_intr_hdl = NULL; 343213379Shselasky } 344213379Shselasky if (sc->sc_irq_res) { 345276965Shselasky bus_release_resource(self, SYS_RES_IRQ, 346276965Shselasky rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 347213379Shselasky sc->sc_irq_res = NULL; 348276965Shselasky pci_release_msi(self); 349213379Shselasky } 350213379Shselasky if (sc->sc_io_res) { 351213379Shselasky bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 352213379Shselasky sc->sc_io_res); 353213379Shselasky sc->sc_io_res = NULL; 354213379Shselasky } 355213379Shselasky 356213379Shselasky xhci_uninit(sc); 357213379Shselasky 358213379Shselasky return (0); 359213379Shselasky} 360213379Shselasky 361228483Shselaskystatic int 362228483Shselaskyxhci_pci_take_controller(device_t self) 363213379Shselasky{ 364213379Shselasky struct xhci_softc *sc = device_get_softc(self); 365213379Shselasky uint32_t cparams; 366213379Shselasky uint32_t eecp; 367213379Shselasky uint32_t eec; 368213379Shselasky uint16_t to; 369213379Shselasky uint8_t bios_sem; 370213379Shselasky 371213379Shselasky cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); 372213379Shselasky 373213379Shselasky eec = -1; 374213379Shselasky 375213379Shselasky /* Synchronise with the BIOS if it owns the controller. */ 376213379Shselasky for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); 377213379Shselasky eecp += XHCI_XECP_NEXT(eec) << 2) { 378213379Shselasky eec = XREAD4(sc, capa, eecp); 379213379Shselasky 380213379Shselasky if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 381213379Shselasky continue; 382213379Shselasky bios_sem = XREAD1(sc, capa, eecp + 383213379Shselasky XHCI_XECP_BIOS_SEM); 384213379Shselasky if (bios_sem == 0) 385213379Shselasky continue; 386213379Shselasky device_printf(sc->sc_bus.bdev, "waiting for BIOS " 387213379Shselasky "to give up control\n"); 388213379Shselasky XWRITE1(sc, capa, eecp + 389213379Shselasky XHCI_XECP_OS_SEM, 1); 390213379Shselasky to = 500; 391213379Shselasky while (1) { 392213379Shselasky bios_sem = XREAD1(sc, capa, eecp + 393213379Shselasky XHCI_XECP_BIOS_SEM); 394213379Shselasky if (bios_sem == 0) 395213379Shselasky break; 396213379Shselasky 397213379Shselasky if (--to == 0) { 398213379Shselasky device_printf(sc->sc_bus.bdev, 399213379Shselasky "timed out waiting for BIOS\n"); 400213379Shselasky break; 401213379Shselasky } 402213379Shselasky usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 403213379Shselasky } 404213379Shselasky } 405228483Shselasky return (0); 406213379Shselasky} 407