xhci_pci.c revision 256281
1181834Sroberto/*- 2181834Sroberto * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 3181834Sroberto * 4181834Sroberto * Redistribution and use in source and binary forms, with or without 5181834Sroberto * modification, are permitted provided that the following conditions 6181834Sroberto * are met: 7181834Sroberto * 1. Redistributions of source code must retain the above copyright 8181834Sroberto * notice, this list of conditions and the following disclaimer. 9181834Sroberto * 2. Redistributions in binary form must reproduce the above copyright 10181834Sroberto * notice, this list of conditions and the following disclaimer in the 11181834Sroberto * documentation and/or other materials provided with the distribution. 12181834Sroberto * 13181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14181834Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15181834Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16181834Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17181834Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18181834Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19181834Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20181834Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21181834Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22181834Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23181834Sroberto * SUCH DAMAGE. 24181834Sroberto */ 25181834Sroberto 26181834Sroberto#include <sys/cdefs.h> 27181834Sroberto__FBSDID("$FreeBSD: stable/10/sys/dev/usb/controller/xhci_pci.c 255768 2013-09-21 21:40:57Z hselasky $"); 28181834Sroberto 29181834Sroberto#include <sys/stdint.h> 30181834Sroberto#include <sys/stddef.h> 31181834Sroberto#include <sys/param.h> 32181834Sroberto#include <sys/queue.h> 33181834Sroberto#include <sys/types.h> 34181834Sroberto#include <sys/systm.h> 35181834Sroberto#include <sys/kernel.h> 36181834Sroberto#include <sys/bus.h> 37181834Sroberto#include <sys/module.h> 38181834Sroberto#include <sys/lock.h> 39181834Sroberto#include <sys/mutex.h> 40181834Sroberto#include <sys/condvar.h> 41181834Sroberto#include <sys/sysctl.h> 42181834Sroberto#include <sys/sx.h> 43181834Sroberto#include <sys/unistd.h> 44181834Sroberto#include <sys/callout.h> 45181834Sroberto#include <sys/malloc.h> 46181834Sroberto#include <sys/priv.h> 47181834Sroberto 48181834Sroberto#include <dev/usb/usb.h> 49181834Sroberto#include <dev/usb/usbdi.h> 50181834Sroberto 51181834Sroberto#include <dev/usb/usb_core.h> 52181834Sroberto#include <dev/usb/usb_busdma.h> 53181834Sroberto#include <dev/usb/usb_process.h> 54181834Sroberto#include <dev/usb/usb_util.h> 55181834Sroberto 56181834Sroberto#include <dev/usb/usb_controller.h> 57181834Sroberto#include <dev/usb/usb_bus.h> 58181834Sroberto#include <dev/usb/usb_pci.h> 59181834Sroberto#include <dev/usb/controller/xhci.h> 60181834Sroberto#include <dev/usb/controller/xhcireg.h> 61181834Sroberto#include "usb_if.h" 62181834Sroberto 63181834Srobertostatic device_probe_t xhci_pci_probe; 64181834Srobertostatic device_attach_t xhci_pci_attach; 65181834Srobertostatic device_detach_t xhci_pci_detach; 66181834Srobertostatic usb_take_controller_t xhci_pci_take_controller; 67181834Sroberto 68181834Srobertostatic device_method_t xhci_device_methods[] = { 69181834Sroberto /* device interface */ 70181834Sroberto DEVMETHOD(device_probe, xhci_pci_probe), 71181834Sroberto DEVMETHOD(device_attach, xhci_pci_attach), 72181834Sroberto DEVMETHOD(device_detach, xhci_pci_detach), 73181834Sroberto DEVMETHOD(device_suspend, bus_generic_suspend), 74181834Sroberto DEVMETHOD(device_resume, bus_generic_resume), 75181834Sroberto DEVMETHOD(device_shutdown, bus_generic_shutdown), 76181834Sroberto DEVMETHOD(usb_take_controller, xhci_pci_take_controller), 77181834Sroberto 78181834Sroberto DEVMETHOD_END 79181834Sroberto}; 80181834Sroberto 81181834Srobertostatic driver_t xhci_driver = { 82181834Sroberto .name = "xhci", 83181834Sroberto .methods = xhci_device_methods, 84181834Sroberto .size = sizeof(struct xhci_softc), 85181834Sroberto}; 86181834Sroberto 87181834Srobertostatic devclass_t xhci_devclass; 88181834Sroberto 89181834SrobertoDRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, 0, 0); 90181834SrobertoMODULE_DEPEND(xhci, usb, 1, 1, 1); 91181834Sroberto 92181834Sroberto 93181834Srobertostatic const char * 94181834Srobertoxhci_pci_match(device_t self) 95181834Sroberto{ 96181834Sroberto uint32_t device_id = pci_get_devid(self); 97181834Sroberto 98181834Sroberto switch (device_id) { 99181834Sroberto case 0x01941033: 100181834Sroberto return ("NEC uPD720200 USB 3.0 controller"); 101181834Sroberto 102181834Sroberto case 0x10421b21: 103181834Sroberto return ("ASMedia ASM1042 USB 3.0 controller"); 104181834Sroberto 105181834Sroberto case 0x1e318086: 106181834Sroberto return ("Intel Panther Point USB 3.0 controller"); 107181834Sroberto case 0x8c318086: 108181834Sroberto return ("Intel Lynx Point USB 3.0 controller"); 109181834Sroberto 110181834Sroberto default: 111181834Sroberto break; 112181834Sroberto } 113181834Sroberto 114181834Sroberto if ((pci_get_class(self) == PCIC_SERIALBUS) 115181834Sroberto && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) 116181834Sroberto && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) { 117181834Sroberto return ("XHCI (generic) USB 3.0 controller"); 118181834Sroberto } 119181834Sroberto return (NULL); /* dunno */ 120181834Sroberto} 121181834Sroberto 122181834Srobertostatic int 123181834Srobertoxhci_pci_probe(device_t self) 124181834Sroberto{ 125181834Sroberto const char *desc = xhci_pci_match(self); 126181834Sroberto 127181834Sroberto if (desc) { 128181834Sroberto device_set_desc(self, desc); 129181834Sroberto return (0); 130181834Sroberto } else { 131181834Sroberto return (ENXIO); 132181834Sroberto } 133181834Sroberto} 134181834Sroberto 135181834Srobertostatic int xhci_use_msi = 1; 136181834SrobertoTUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi); 137181834Sroberto 138181834Srobertostatic void 139181834Srobertoxhci_interrupt_poll(void *_sc) 140181834Sroberto{ 141181834Sroberto struct xhci_softc *sc = _sc; 142181834Sroberto USB_BUS_UNLOCK(&sc->sc_bus); 143181834Sroberto xhci_interrupt(sc); 144181834Sroberto USB_BUS_LOCK(&sc->sc_bus); 145181834Sroberto usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc); 146181834Sroberto} 147181834Sroberto 148181834Srobertostatic int 149181834Srobertoxhci_pci_port_route(device_t self, uint32_t set, uint32_t clear) 150181834Sroberto{ 151181834Sroberto uint32_t temp; 152181834Sroberto 153181834Sroberto temp = pci_read_config(self, PCI_XHCI_INTEL_USB3_PSSEN, 4) | 154181834Sroberto pci_read_config(self, PCI_XHCI_INTEL_XUSB2PR, 4); 155181834Sroberto 156181834Sroberto temp |= set; 157181834Sroberto temp &= ~clear; 158181834Sroberto 159181834Sroberto pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp, 4); 160181834Sroberto pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp, 4); 161181834Sroberto 162181834Sroberto device_printf(self, "Port routing mask set to 0x%08x\n", temp); 163181834Sroberto 164181834Sroberto return (0); 165181834Sroberto} 166181834Sroberto 167181834Srobertostatic int 168181834Srobertoxhci_pci_attach(device_t self) 169181834Sroberto{ 170181834Sroberto struct xhci_softc *sc = device_get_softc(self); 171181834Sroberto int count, err, rid; 172181834Sroberto 173181834Sroberto /* XXX check for 64-bit capability */ 174181834Sroberto 175181834Sroberto if (xhci_init(sc, self)) { 176181834Sroberto device_printf(self, "Could not initialize softc\n"); 177181834Sroberto goto error; 178181834Sroberto } 179181834Sroberto 180181834Sroberto pci_enable_busmaster(self); 181181834Sroberto 182181834Sroberto rid = PCI_XHCI_CBMEM; 183181834Sroberto sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 184181834Sroberto RF_ACTIVE); 185181834Sroberto if (!sc->sc_io_res) { 186181834Sroberto device_printf(self, "Could not map memory\n"); 187181834Sroberto goto error; 188181834Sroberto } 189181834Sroberto sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 190181834Sroberto sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 191181834Sroberto sc->sc_io_size = rman_get_size(sc->sc_io_res); 192181834Sroberto 193181834Sroberto usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0); 194181834Sroberto 195181834Sroberto sc->sc_irq_rid = 0; 196181834Sroberto if (xhci_use_msi) { 197181834Sroberto count = pci_msi_count(self); 198181834Sroberto if (count >= 1) { 199181834Sroberto count = 1; 200181834Sroberto if (pci_alloc_msi(self, &count) == 0) { 201181834Sroberto if (bootverbose) 202181834Sroberto device_printf(self, "MSI enabled\n"); 203181834Sroberto sc->sc_irq_rid = 1; 204181834Sroberto } 205181834Sroberto } 206181834Sroberto } 207181834Sroberto sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, 208181834Sroberto &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE); 209181834Sroberto if (sc->sc_irq_res == NULL) { 210181834Sroberto device_printf(self, "Could not allocate IRQ\n"); 211181834Sroberto /* goto error; FALLTHROUGH - use polling */ 212181834Sroberto } 213181834Sroberto sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 214181834Sroberto if (sc->sc_bus.bdev == NULL) { 215181834Sroberto device_printf(self, "Could not add USB device\n"); 216181834Sroberto goto error; 217181834Sroberto } 218181834Sroberto device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 219181834Sroberto 220181834Sroberto sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self)); 221181834Sroberto 222181834Sroberto if (sc->sc_irq_res != NULL) { 223181834Sroberto err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 224181834Sroberto NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 225181834Sroberto if (err != 0) { 226181834Sroberto device_printf(self, "Could not setup IRQ, err=%d\n", err); 227181834Sroberto sc->sc_intr_hdl = NULL; 228181834Sroberto } 229181834Sroberto } 230181834Sroberto if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL || 231181834Sroberto xhci_use_polling() != 0) { 232181834Sroberto device_printf(self, "Interrupt polling at %dHz\n", hz); 233181834Sroberto USB_BUS_LOCK(&sc->sc_bus); 234181834Sroberto xhci_interrupt_poll(sc); 235181834Sroberto USB_BUS_UNLOCK(&sc->sc_bus); 236181834Sroberto } 237181834Sroberto 238181834Sroberto /* On Intel chipsets reroute ports from EHCI to XHCI controller. */ 239181834Sroberto switch (pci_get_devid(self)) { 240181834Sroberto case 0x1e318086: /* Panther Point */ 241181834Sroberto case 0x8c318086: /* Lynx Point */ 242181834Sroberto sc->sc_port_route = &xhci_pci_port_route; 243181834Sroberto break; 244181834Sroberto default: 245181834Sroberto break; 246181834Sroberto } 247181834Sroberto 248181834Sroberto xhci_pci_take_controller(self); 249181834Sroberto 250181834Sroberto err = xhci_halt_controller(sc); 251181834Sroberto 252181834Sroberto if (err == 0) 253181834Sroberto err = xhci_start_controller(sc); 254181834Sroberto 255181834Sroberto if (err == 0) 256181834Sroberto err = device_probe_and_attach(sc->sc_bus.bdev); 257181834Sroberto 258181834Sroberto if (err) { 259181834Sroberto device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 260181834Sroberto goto error; 261181834Sroberto } 262181834Sroberto return (0); 263181834Sroberto 264181834Srobertoerror: 265181834Sroberto xhci_pci_detach(self); 266181834Sroberto return (ENXIO); 267181834Sroberto} 268181834Sroberto 269181834Srobertostatic int 270181834Srobertoxhci_pci_detach(device_t self) 271181834Sroberto{ 272181834Sroberto struct xhci_softc *sc = device_get_softc(self); 273181834Sroberto device_t bdev; 274181834Sroberto 275181834Sroberto if (sc->sc_bus.bdev != NULL) { 276181834Sroberto bdev = sc->sc_bus.bdev; 277181834Sroberto device_detach(bdev); 278181834Sroberto device_delete_child(self, bdev); 279181834Sroberto } 280181834Sroberto /* during module unload there are lots of children leftover */ 281181834Sroberto device_delete_children(self); 282181834Sroberto 283181834Sroberto if (sc->sc_io_res) { 284181834Sroberto usb_callout_drain(&sc->sc_callout); 285181834Sroberto xhci_halt_controller(sc); 286181834Sroberto } 287181834Sroberto 288181834Sroberto pci_disable_busmaster(self); 289181834Sroberto 290181834Sroberto if (sc->sc_irq_res && sc->sc_intr_hdl) { 291181834Sroberto bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 292181834Sroberto sc->sc_intr_hdl = NULL; 293181834Sroberto } 294181834Sroberto if (sc->sc_irq_res) { 295181834Sroberto if (sc->sc_irq_rid == 1) 296181834Sroberto pci_release_msi(self); 297181834Sroberto bus_release_resource(self, SYS_RES_IRQ, sc->sc_irq_rid, 298181834Sroberto sc->sc_irq_res); 299181834Sroberto sc->sc_irq_res = NULL; 300181834Sroberto } 301181834Sroberto if (sc->sc_io_res) { 302181834Sroberto bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 303181834Sroberto sc->sc_io_res); 304181834Sroberto sc->sc_io_res = NULL; 305181834Sroberto } 306181834Sroberto 307181834Sroberto xhci_uninit(sc); 308181834Sroberto 309181834Sroberto return (0); 310181834Sroberto} 311181834Sroberto 312181834Srobertostatic int 313181834Srobertoxhci_pci_take_controller(device_t self) 314181834Sroberto{ 315181834Sroberto struct xhci_softc *sc = device_get_softc(self); 316181834Sroberto uint32_t cparams; 317181834Sroberto uint32_t eecp; 318181834Sroberto uint32_t eec; 319181834Sroberto uint16_t to; 320181834Sroberto uint8_t bios_sem; 321181834Sroberto 322181834Sroberto cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); 323181834Sroberto 324181834Sroberto eec = -1; 325181834Sroberto 326181834Sroberto /* Synchronise with the BIOS if it owns the controller. */ 327181834Sroberto for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); 328181834Sroberto eecp += XHCI_XECP_NEXT(eec) << 2) { 329181834Sroberto eec = XREAD4(sc, capa, eecp); 330181834Sroberto 331181834Sroberto if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 332181834Sroberto continue; 333181834Sroberto bios_sem = XREAD1(sc, capa, eecp + 334181834Sroberto XHCI_XECP_BIOS_SEM); 335181834Sroberto if (bios_sem == 0) 336181834Sroberto continue; 337181834Sroberto device_printf(sc->sc_bus.bdev, "waiting for BIOS " 338181834Sroberto "to give up control\n"); 339181834Sroberto XWRITE1(sc, capa, eecp + 340181834Sroberto XHCI_XECP_OS_SEM, 1); 341181834Sroberto to = 500; 342181834Sroberto while (1) { 343181834Sroberto bios_sem = XREAD1(sc, capa, eecp + 344181834Sroberto XHCI_XECP_BIOS_SEM); 345181834Sroberto if (bios_sem == 0) 346181834Sroberto break; 347181834Sroberto 348181834Sroberto if (--to == 0) { 349181834Sroberto device_printf(sc->sc_bus.bdev, 350181834Sroberto "timed out waiting for BIOS\n"); 351181834Sroberto break; 352181834Sroberto } 353181834Sroberto usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 354181834Sroberto } 355181834Sroberto } 356181834Sroberto return (0); 357181834Sroberto} 358181834Sroberto