113540260SHans Petter Selasky /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 433cbbf26SHans Petter Selasky * Copyright (c) 2010-2022 Hans Petter Selasky 513540260SHans Petter Selasky * 613540260SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 713540260SHans Petter Selasky * modification, are permitted provided that the following conditions 813540260SHans Petter Selasky * are met: 913540260SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 1013540260SHans Petter Selasky * notice, this list of conditions and the following disclaimer. 1113540260SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 1213540260SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 1313540260SHans Petter Selasky * documentation and/or other materials provided with the distribution. 1413540260SHans Petter Selasky * 1513540260SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1613540260SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1713540260SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1813540260SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1913540260SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2013540260SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2113540260SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2213540260SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2313540260SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2413540260SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2513540260SHans Petter Selasky * SUCH DAMAGE. 2613540260SHans Petter Selasky */ 2713540260SHans Petter Selasky 2813540260SHans Petter Selasky #include <sys/cdefs.h> 2913540260SHans Petter Selasky #include <sys/stdint.h> 3013540260SHans Petter Selasky #include <sys/stddef.h> 3113540260SHans Petter Selasky #include <sys/param.h> 3213540260SHans Petter Selasky #include <sys/queue.h> 3313540260SHans Petter Selasky #include <sys/types.h> 3413540260SHans Petter Selasky #include <sys/systm.h> 3513540260SHans Petter Selasky #include <sys/kernel.h> 3613540260SHans Petter Selasky #include <sys/bus.h> 3713540260SHans Petter Selasky #include <sys/module.h> 3813540260SHans Petter Selasky #include <sys/lock.h> 3913540260SHans Petter Selasky #include <sys/mutex.h> 4013540260SHans Petter Selasky #include <sys/condvar.h> 4113540260SHans Petter Selasky #include <sys/sysctl.h> 4213540260SHans Petter Selasky #include <sys/sx.h> 4313540260SHans Petter Selasky #include <sys/unistd.h> 4413540260SHans Petter Selasky #include <sys/callout.h> 4513540260SHans Petter Selasky #include <sys/malloc.h> 4613540260SHans Petter Selasky #include <sys/priv.h> 4713540260SHans Petter Selasky 4813540260SHans Petter Selasky #include <dev/usb/usb.h> 4913540260SHans Petter Selasky #include <dev/usb/usbdi.h> 5013540260SHans Petter Selasky 5113540260SHans Petter Selasky #include <dev/usb/usb_core.h> 5213540260SHans Petter Selasky #include <dev/usb/usb_busdma.h> 5313540260SHans Petter Selasky #include <dev/usb/usb_process.h> 5413540260SHans Petter Selasky #include <dev/usb/usb_util.h> 5513540260SHans Petter Selasky 5613540260SHans Petter Selasky #include <dev/usb/usb_controller.h> 5713540260SHans Petter Selasky #include <dev/usb/usb_bus.h> 5813540260SHans Petter Selasky #include <dev/usb/usb_pci.h> 5913540260SHans Petter Selasky #include <dev/usb/controller/xhci.h> 6013540260SHans Petter Selasky #include <dev/usb/controller/xhcireg.h> 612e141748SHans Petter Selasky #include "usb_if.h" 6213540260SHans Petter Selasky 6342cf33ddSHans Petter Selasky #define PCI_XHCI_VENDORID_AMD 0x1022 6442cf33ddSHans Petter Selasky #define PCI_XHCI_VENDORID_INTEL 0x8086 652a31a06bSAlexander Motin #define PCI_XHCI_VENDORID_VMWARE 0x15ad 660d7064d5SDmitry Luhtionov #define PCI_XHCI_VENDORID_ZHAOXIN 0x1d17 6742cf33ddSHans Petter Selasky 6813540260SHans Petter Selasky static device_probe_t xhci_pci_probe; 6913540260SHans Petter Selasky static device_detach_t xhci_pci_detach; 702e141748SHans Petter Selasky static usb_take_controller_t xhci_pci_take_controller; 7113540260SHans Petter Selasky 7213540260SHans Petter Selasky static device_method_t xhci_device_methods[] = { 7313540260SHans Petter Selasky /* device interface */ 7413540260SHans Petter Selasky DEVMETHOD(device_probe, xhci_pci_probe), 7513540260SHans Petter Selasky DEVMETHOD(device_attach, xhci_pci_attach), 7613540260SHans Petter Selasky DEVMETHOD(device_detach, xhci_pci_detach), 772e141748SHans Petter Selasky DEVMETHOD(device_suspend, bus_generic_suspend), 782e141748SHans Petter Selasky DEVMETHOD(device_resume, bus_generic_resume), 792e141748SHans Petter Selasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 802e141748SHans Petter Selasky DEVMETHOD(usb_take_controller, xhci_pci_take_controller), 8113540260SHans Petter Selasky 824b7ec270SMarius Strobl DEVMETHOD_END 8313540260SHans Petter Selasky }; 8413540260SHans Petter Selasky 8531e34625SAndrew Turner DEFINE_CLASS_0(xhci, xhci_pci_driver, xhci_device_methods, 8631e34625SAndrew Turner sizeof(struct xhci_softc)); 8713540260SHans Petter Selasky 88bc9372d7SJohn Baldwin DRIVER_MODULE(xhci, pci, xhci_pci_driver, NULL, NULL); 8913540260SHans Petter Selasky MODULE_DEPEND(xhci, usb, 1, 1, 1); 9013540260SHans Petter Selasky 9113540260SHans Petter Selasky static const char * 9213540260SHans Petter Selasky xhci_pci_match(device_t self) 9313540260SHans Petter Selasky { 94f0d0cee0SAlexander Motin uint32_t device_id = pci_get_devid(self); 95f0d0cee0SAlexander Motin 96f0d0cee0SAlexander Motin switch (device_id) { 97d171d2f2SAlexander Motin case 0x145c1022: 98d171d2f2SAlexander Motin return ("AMD KERNCZ USB 3.0 controller"); 994b4cce02SGleb Smirnoff case 0x148c1022: 1004b4cce02SGleb Smirnoff return ("AMD Starship USB 3.0 controller"); 1014b4cce02SGleb Smirnoff case 0x149c1022: 1024b4cce02SGleb Smirnoff return ("AMD Matisse USB 3.0 controller"); 1034cc4b5e2SDmitry Luhtionov case 0x15e01022: 1044cc4b5e2SDmitry Luhtionov case 0x15e11022: 1054cc4b5e2SDmitry Luhtionov return ("AMD Raven USB 3.1 controller"); 10666ad2538SConrad Meyer case 0x43ba1022: 10766ad2538SConrad Meyer return ("AMD X399 USB 3.0 controller"); 108ca0a66baSMark Johnston case 0x43b91022: /* X370 */ 109ca0a66baSMark Johnston case 0x43bb1022: /* B350 */ 11083e67a9dSMarius Strobl return ("AMD 300 Series USB 3.1 controller"); 11183e67a9dSMarius Strobl case 0x43d51022: 11283e67a9dSMarius Strobl return ("AMD 400 Series USB 3.1 controller"); 113379797d4SJung-uk Kim case 0x78121022: 11415e01a35SAlexander Motin case 0x78141022: 11542cf33ddSHans Petter Selasky case 0x79141022: 11642cf33ddSHans Petter Selasky return ("AMD FCH USB 3.0 controller"); 11715e01a35SAlexander Motin 1182a31a06bSAlexander Motin case 0x077815ad: 1192a31a06bSAlexander Motin case 0x077915ad: 1202a31a06bSAlexander Motin return ("VMware USB 3.0 controller"); 1212a31a06bSAlexander Motin 122d82c0ebcSHans Petter Selasky case 0x145f1d94: 123d82c0ebcSHans Petter Selasky return ("Hygon USB 3.0 controller"); 124d82c0ebcSHans Petter Selasky 125f0d0cee0SAlexander Motin case 0x01941033: 126f0d0cee0SAlexander Motin return ("NEC uPD720200 USB 3.0 controller"); 1275df8285dSBruce M Simpson case 0x00151912: 1285df8285dSBruce M Simpson return ("NEC uPD720202 USB 3.0 controller"); 129f0d0cee0SAlexander Motin 130dd4c1590SKevin Lo case 0x10001b73: 131dd4c1590SKevin Lo return ("Fresco Logic FL1000G USB 3.0 controller"); 132082895ebSZhenlei Huang case 0x10091b73: 133082895ebSZhenlei Huang return ("Fresco Logic FL1009 USB 3.0 controller"); 134f0db235bSMarius Strobl case 0x11001b73: 135f0db235bSMarius Strobl return ("Fresco Logic FL1100 USB 3.0 controller"); 136dd4c1590SKevin Lo 137ec5cd818SAlexander Motin case 0x10421b21: 138ec5cd818SAlexander Motin return ("ASMedia ASM1042 USB 3.0 controller"); 13943bc87c4SMarius Strobl case 0x11421b21: 14043bc87c4SMarius Strobl return ("ASMedia ASM1042A USB 3.0 controller"); 141e85af89fSHans Petter Selasky case 0x13431b21: 142e85af89fSHans Petter Selasky return ("ASMedia ASM1143 USB 3.1 controller"); 1434b4cce02SGleb Smirnoff case 0x32421b21: 1444b4cce02SGleb Smirnoff return ("ASMedia ASM3242 USB 3.2 controller"); 145ec5cd818SAlexander Motin 146cfb0e4d7SAlexander Motin case 0x0b278086: 147cfb0e4d7SAlexander Motin return ("Intel Goshen Ridge Thunderbolt 4 USB controller"); 1487eb88464SKevin Lo case 0x0f358086: 149dd4c1590SKevin Lo return ("Intel BayTrail USB 3.0 controller"); 150cfb0e4d7SAlexander Motin case 0x11388086: 151cfb0e4d7SAlexander Motin return ("Intel Maple Ridge Thunderbolt 4 USB controller"); 152cfb0e4d7SAlexander Motin case 0x15c18086: 153cfb0e4d7SAlexander Motin case 0x15d48086: 154cfb0e4d7SAlexander Motin case 0x15db8086: 155cfb0e4d7SAlexander Motin return ("Intel Alpine Ridge Thunderbolt 3 USB controller"); 156cfb0e4d7SAlexander Motin case 0x15e98086: 157cfb0e4d7SAlexander Motin case 0x15ec8086: 158cfb0e4d7SAlexander Motin case 0x15f08086: 159cfb0e4d7SAlexander Motin return ("Intel Titan Ridge Thunderbolt 3 USB controller"); 160eb76cfbcSAlexander Motin case 0x19d08086: 161eb76cfbcSAlexander Motin return ("Intel Denverton USB 3.0 controller"); 16277bea00cSHans Petter Selasky case 0x9c318086: 163f0d0cee0SAlexander Motin case 0x1e318086: 164f0d0cee0SAlexander Motin return ("Intel Panther Point USB 3.0 controller"); 165c5c43da8SMarius Strobl case 0x22b58086: 166c5c43da8SMarius Strobl return ("Intel Braswell USB 3.0 controller"); 167c834f30aSHans Petter Selasky case 0x31a88086: 168c834f30aSHans Petter Selasky return ("Intel Gemini Lake USB 3.0 controller"); 16983d7b2f3SAlexander Motin case 0x34ed8086: 17083d7b2f3SAlexander Motin return ("Intel Ice Lake-LP USB 3.1 controller"); 17183d7b2f3SAlexander Motin case 0x43ed8086: 17283d7b2f3SAlexander Motin return ("Intel Tiger Lake-H USB 3.2 controller"); 17383d7b2f3SAlexander Motin case 0x461e8086: 17483d7b2f3SAlexander Motin return ("Intel Alder Lake-P Thunderbolt 4 USB controller"); 17583d7b2f3SAlexander Motin case 0x51ed8086: 17683d7b2f3SAlexander Motin return ("Intel Alder Lake USB 3.2 controller"); 177c5c43da8SMarius Strobl case 0x5aa88086: 178c5c43da8SMarius Strobl return ("Intel Apollo Lake USB 3.0 controller"); 179dc238358SAlexander Motin case 0x7ae08086: 180dc238358SAlexander Motin return ("Intel Alder Lake USB 3.2 controller"); 18183d7b2f3SAlexander Motin case 0x8a138086: 18283d7b2f3SAlexander Motin return ("Intel Ice Lake Thunderbolt 3 USB controller"); 183f4f6d5e0SAlexander Motin case 0x8c318086: 184f4f6d5e0SAlexander Motin return ("Intel Lynx Point USB 3.0 controller"); 185e67f3becSAlexander Motin case 0x8cb18086: 186e67f3becSAlexander Motin return ("Intel Wildcat Point USB 3.0 controller"); 187cb6b0ad1SAlexander Motin case 0x8d318086: 188cb6b0ad1SAlexander Motin return ("Intel Wellsburg USB 3.0 controller"); 18983d7b2f3SAlexander Motin case 0x9a138086: 19083d7b2f3SAlexander Motin return ("Intel Tiger Lake-LP Thunderbolt 4 USB controller"); 19183d7b2f3SAlexander Motin case 0x9a178086: 19283d7b2f3SAlexander Motin return ("Intel Tiger Lake-H Thunderbolt 4 USB controller"); 1934be283b9SHans Petter Selasky case 0x9cb18086: 1944be283b9SHans Petter Selasky return ("Broadwell Integrated PCH-LP chipset USB 3.0 controller"); 1952b064d46SAlexander Motin case 0x9d2f8086: 1962b064d46SAlexander Motin return ("Intel Sunrise Point-LP USB 3.0 controller"); 19783d7b2f3SAlexander Motin case 0xa0ed8086: 19883d7b2f3SAlexander Motin return ("Intel Tiger Lake-LP USB 3.2 controller"); 19971733a50SAlexander Motin case 0xa12f8086: 20071733a50SAlexander Motin return ("Intel Sunrise Point USB 3.0 controller"); 201aaa9b2b3SAlexander Motin case 0xa1af8086: 202aaa9b2b3SAlexander Motin return ("Intel Lewisburg USB 3.0 controller"); 203aaa9b2b3SAlexander Motin case 0xa2af8086: 204aaa9b2b3SAlexander Motin return ("Intel Union Point USB 3.0 controller"); 2053194b270SHans Petter Selasky case 0xa36d8086: 206b55bfda7SHans Petter Selasky return ("Intel Cannon Lake USB 3.1 controller"); 207f0d0cee0SAlexander Motin 208aafbd025SEd Maste case 0xa01b177d: 209aafbd025SEd Maste return ("Cavium ThunderX USB 3.0 controller"); 210aafbd025SEd Maste 2114b4cce02SGleb Smirnoff case 0x1ada10de: 2124b4cce02SGleb Smirnoff return ("NVIDIA TU106 USB 3.1 controller"); 2134b4cce02SGleb Smirnoff 214f50f5393SZhenlei Huang case 0x92021d17: 2150d7064d5SDmitry Luhtionov return ("Zhaoxin ZX-100 USB 3.0 controller"); 216f50f5393SZhenlei Huang case 0x92031d17: 2170d7064d5SDmitry Luhtionov return ("Zhaoxin ZX-200 USB 3.0 controller"); 218f50f5393SZhenlei Huang case 0x92041d17: 2190d7064d5SDmitry Luhtionov return ("Zhaoxin ZX-E USB 3.0 controller"); 2200d7064d5SDmitry Luhtionov 221f0d0cee0SAlexander Motin default: 222f0d0cee0SAlexander Motin break; 223f0d0cee0SAlexander Motin } 224f0d0cee0SAlexander Motin 22513540260SHans Petter Selasky if ((pci_get_class(self) == PCIC_SERIALBUS) 22613540260SHans Petter Selasky && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) 227934d7bccSRuslan Ermilov && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) { 22813540260SHans Petter Selasky return ("XHCI (generic) USB 3.0 controller"); 22913540260SHans Petter Selasky } 23013540260SHans Petter Selasky return (NULL); /* dunno */ 23113540260SHans Petter Selasky } 23213540260SHans Petter Selasky 23313540260SHans Petter Selasky static int 23413540260SHans Petter Selasky xhci_pci_probe(device_t self) 23513540260SHans Petter Selasky { 23613540260SHans Petter Selasky const char *desc = xhci_pci_match(self); 23713540260SHans Petter Selasky 23813540260SHans Petter Selasky if (desc) { 23913540260SHans Petter Selasky device_set_desc(self, desc); 2409b0e3c5aSNeel Natu return (BUS_PROBE_DEFAULT); 24113540260SHans Petter Selasky } else { 24213540260SHans Petter Selasky return (ENXIO); 24313540260SHans Petter Selasky } 24413540260SHans Petter Selasky } 24513540260SHans Petter Selasky 24631b67ab2SKonstantin Belousov static int xhci_use_msi = 1; 24731b67ab2SKonstantin Belousov TUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi); 2482245b38fSAndrew Turner static int xhci_use_msix = 1; 2492245b38fSAndrew Turner TUNABLE_INT("hw.usb.xhci.msix", &xhci_use_msix); 25031b67ab2SKonstantin Belousov 25197d729cfSHans Petter Selasky static void 25297d729cfSHans Petter Selasky xhci_interrupt_poll(void *_sc) 25397d729cfSHans Petter Selasky { 25497d729cfSHans Petter Selasky struct xhci_softc *sc = _sc; 25597d729cfSHans Petter Selasky USB_BUS_UNLOCK(&sc->sc_bus); 25697d729cfSHans Petter Selasky xhci_interrupt(sc); 25797d729cfSHans Petter Selasky USB_BUS_LOCK(&sc->sc_bus); 25897d729cfSHans Petter Selasky usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc); 25997d729cfSHans Petter Selasky } 26097d729cfSHans Petter Selasky 26113540260SHans Petter Selasky static int 2624c5d1323SHans Petter Selasky xhci_pci_port_route(device_t self, uint32_t set, uint32_t clear) 2634c5d1323SHans Petter Selasky { 2644c5d1323SHans Petter Selasky uint32_t temp; 2650a54509fSHans Petter Selasky uint32_t usb3_mask; 2660a54509fSHans Petter Selasky uint32_t usb2_mask; 2674c5d1323SHans Petter Selasky 2684c5d1323SHans Petter Selasky temp = pci_read_config(self, PCI_XHCI_INTEL_USB3_PSSEN, 4) | 2694c5d1323SHans Petter Selasky pci_read_config(self, PCI_XHCI_INTEL_XUSB2PR, 4); 2704c5d1323SHans Petter Selasky 2714c5d1323SHans Petter Selasky temp |= set; 2724c5d1323SHans Petter Selasky temp &= ~clear; 2734c5d1323SHans Petter Selasky 27488e0a639SHans Petter Selasky /* Don't set bits which the hardware doesn't support */ 2750a54509fSHans Petter Selasky usb3_mask = pci_read_config(self, PCI_XHCI_INTEL_USB3PRM, 4); 2760a54509fSHans Petter Selasky usb2_mask = pci_read_config(self, PCI_XHCI_INTEL_USB2PRM, 4); 27788e0a639SHans Petter Selasky 2780a54509fSHans Petter Selasky pci_write_config(self, PCI_XHCI_INTEL_USB3_PSSEN, temp & usb3_mask, 4); 2790a54509fSHans Petter Selasky pci_write_config(self, PCI_XHCI_INTEL_XUSB2PR, temp & usb2_mask, 4); 2804c5d1323SHans Petter Selasky 2814c5d1323SHans Petter Selasky device_printf(self, "Port routing mask set to 0x%08x\n", temp); 2824c5d1323SHans Petter Selasky 2834c5d1323SHans Petter Selasky return (0); 2844c5d1323SHans Petter Selasky } 2854c5d1323SHans Petter Selasky 28631e34625SAndrew Turner int 28713540260SHans Petter Selasky xhci_pci_attach(device_t self) 28813540260SHans Petter Selasky { 28913540260SHans Petter Selasky struct xhci_softc *sc = device_get_softc(self); 2902245b38fSAndrew Turner int count, err, msix_table, rid; 291dd4c1590SKevin Lo uint8_t usemsi = 1; 292dd4c1590SKevin Lo uint8_t usedma32 = 0; 29313540260SHans Petter Selasky 29413540260SHans Petter Selasky rid = PCI_XHCI_CBMEM; 29513540260SHans Petter Selasky sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 29613540260SHans Petter Selasky RF_ACTIVE); 29713540260SHans Petter Selasky if (!sc->sc_io_res) { 29813540260SHans Petter Selasky device_printf(self, "Could not map memory\n"); 299b217d184SHans Petter Selasky return (ENOMEM); 30013540260SHans Petter Selasky } 30113540260SHans Petter Selasky sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 30213540260SHans Petter Selasky sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 30313540260SHans Petter Selasky sc->sc_io_size = rman_get_size(sc->sc_io_res); 30413540260SHans Petter Selasky 3050c31a8b0SHans Petter Selasky switch (pci_get_devid(self)) { 30619837718SHans Petter Selasky case 0x10091b73: /* Fresco Logic FL1009 USB3.0 xHCI Controller */ 30733cbbf26SHans Petter Selasky case 0x8241104c: /* TUSB73x0 USB3.0 xHCI Controller */ 30833cbbf26SHans Petter Selasky sc->sc_no_deconfigure = 1; 30933cbbf26SHans Petter Selasky break; 3100c31a8b0SHans Petter Selasky case 0x01941033: /* NEC uPD720200 USB 3.0 controller */ 3110e8fa8c3SHans Petter Selasky case 0x00141912: /* NEC uPD720201 USB 3.0 controller */ 31243bc87c4SMarius Strobl /* Don't use 64-bit DMA on these controllers. */ 3130c31a8b0SHans Petter Selasky usedma32 = 1; 3140c31a8b0SHans Petter Selasky break; 315dd4c1590SKevin Lo case 0x10001b73: /* FL1000G */ 316dd4c1590SKevin Lo /* Fresco Logic host doesn't support MSI. */ 317dd4c1590SKevin Lo usemsi = 0; 318dd4c1590SKevin Lo break; 31943bc87c4SMarius Strobl case 0x0f358086: /* BayTrail */ 32043bc87c4SMarius Strobl case 0x9c318086: /* Panther Point */ 32143bc87c4SMarius Strobl case 0x1e318086: /* Panther Point */ 32243bc87c4SMarius Strobl case 0x8c318086: /* Lynx Point */ 32343bc87c4SMarius Strobl case 0x8cb18086: /* Wildcat Point */ 3244be283b9SHans Petter Selasky case 0x9cb18086: /* Broadwell Mobile Integrated */ 32543bc87c4SMarius Strobl /* 32643bc87c4SMarius Strobl * On Intel chipsets, reroute ports from EHCI to XHCI 32743bc87c4SMarius Strobl * controller and use a different IMOD value. 32843bc87c4SMarius Strobl */ 32943bc87c4SMarius Strobl sc->sc_port_route = &xhci_pci_port_route; 33043bc87c4SMarius Strobl sc->sc_imod_default = XHCI_IMOD_DEFAULT_LP; 331dd7ea6c2SHans Petter Selasky sc->sc_ctlstep = 1; 3320c31a8b0SHans Petter Selasky break; 33333cbbf26SHans Petter Selasky default: 33433cbbf26SHans Petter Selasky break; 3350c31a8b0SHans Petter Selasky } 3360c31a8b0SHans Petter Selasky 3370c31a8b0SHans Petter Selasky if (xhci_init(sc, self, usedma32)) { 338b217d184SHans Petter Selasky device_printf(self, "Could not initialize softc\n"); 339b217d184SHans Petter Selasky bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 340b217d184SHans Petter Selasky sc->sc_io_res); 341b217d184SHans Petter Selasky return (ENXIO); 342b217d184SHans Petter Selasky } 343b217d184SHans Petter Selasky 344b217d184SHans Petter Selasky pci_enable_busmaster(self); 345b217d184SHans Petter Selasky 34697d729cfSHans Petter Selasky usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0); 34797d729cfSHans Petter Selasky 348dcf83ff0SMarius Strobl rid = 0; 3492245b38fSAndrew Turner if (xhci_use_msix && (msix_table = pci_msix_table_bar(self)) >= 0) { 350116bc582SKonstantin Belousov if (msix_table == PCI_XHCI_CBMEM) { 351116bc582SKonstantin Belousov sc->sc_msix_res = sc->sc_io_res; 352116bc582SKonstantin Belousov } else { 353116bc582SKonstantin Belousov sc->sc_msix_res = bus_alloc_resource_any(self, 354116bc582SKonstantin Belousov SYS_RES_MEMORY, &msix_table, RF_ACTIVE); 3552245b38fSAndrew Turner if (sc->sc_msix_res == NULL) { 3562245b38fSAndrew Turner /* May not be enabled */ 3572245b38fSAndrew Turner device_printf(self, 3582245b38fSAndrew Turner "Unable to map MSI-X table\n"); 359116bc582SKonstantin Belousov } 360116bc582SKonstantin Belousov } 361116bc582SKonstantin Belousov if (sc->sc_msix_res != NULL) { 3622245b38fSAndrew Turner count = 1; 3632245b38fSAndrew Turner if (pci_alloc_msix(self, &count) == 0) { 3642245b38fSAndrew Turner if (bootverbose) 3652245b38fSAndrew Turner device_printf(self, "MSI-X enabled\n"); 3662245b38fSAndrew Turner rid = 1; 3672245b38fSAndrew Turner } else { 368116bc582SKonstantin Belousov if (sc->sc_msix_res != sc->sc_io_res) { 369116bc582SKonstantin Belousov bus_release_resource(self, 370116bc582SKonstantin Belousov SYS_RES_MEMORY, 3712245b38fSAndrew Turner msix_table, sc->sc_msix_res); 372116bc582SKonstantin Belousov } 3732245b38fSAndrew Turner sc->sc_msix_res = NULL; 3742245b38fSAndrew Turner } 3752245b38fSAndrew Turner } 3762245b38fSAndrew Turner } 3772245b38fSAndrew Turner if (rid == 0 && xhci_use_msi && usemsi) { 37889d02670SKonstantin Belousov count = 1; 37989d02670SKonstantin Belousov if (pci_alloc_msi(self, &count) == 0) { 38089d02670SKonstantin Belousov if (bootverbose) 38189d02670SKonstantin Belousov device_printf(self, "MSI enabled\n"); 382dcf83ff0SMarius Strobl rid = 1; 38389d02670SKonstantin Belousov } 38489d02670SKonstantin Belousov } 385dcf83ff0SMarius Strobl sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 386dcf83ff0SMarius Strobl RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); 38713540260SHans Petter Selasky if (sc->sc_irq_res == NULL) { 388dcf83ff0SMarius Strobl pci_release_msi(self); 38913540260SHans Petter Selasky device_printf(self, "Could not allocate IRQ\n"); 3904c5d1323SHans Petter Selasky /* goto error; FALLTHROUGH - use polling */ 39113540260SHans Petter Selasky } 3925b56413dSWarner Losh sc->sc_bus.bdev = device_add_child(self, "usbus", DEVICE_UNIT_ANY); 39313540260SHans Petter Selasky if (sc->sc_bus.bdev == NULL) { 39413540260SHans Petter Selasky device_printf(self, "Could not add USB device\n"); 39513540260SHans Petter Selasky goto error; 39613540260SHans Petter Selasky } 39713540260SHans Petter Selasky device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 39813540260SHans Petter Selasky 39942cf33ddSHans Petter Selasky switch (pci_get_vendor(self)) { 40042cf33ddSHans Petter Selasky case PCI_XHCI_VENDORID_AMD: 40142cf33ddSHans Petter Selasky strlcpy(sc->sc_vendor, "AMD", sizeof(sc->sc_vendor)); 40242cf33ddSHans Petter Selasky break; 40342cf33ddSHans Petter Selasky case PCI_XHCI_VENDORID_INTEL: 40442cf33ddSHans Petter Selasky strlcpy(sc->sc_vendor, "Intel", sizeof(sc->sc_vendor)); 40542cf33ddSHans Petter Selasky break; 4062a31a06bSAlexander Motin case PCI_XHCI_VENDORID_VMWARE: 4072a31a06bSAlexander Motin strlcpy(sc->sc_vendor, "VMware", sizeof(sc->sc_vendor)); 4082a31a06bSAlexander Motin break; 4090d7064d5SDmitry Luhtionov case PCI_XHCI_VENDORID_ZHAOXIN: 4100d7064d5SDmitry Luhtionov strlcpy(sc->sc_vendor, "Zhaoxin", sizeof(sc->sc_vendor)); 4110d7064d5SDmitry Luhtionov break; 41242cf33ddSHans Petter Selasky default: 41342cf33ddSHans Petter Selasky if (bootverbose) 41442cf33ddSHans Petter Selasky device_printf(self, "(New XHCI DeviceId=0x%08x)\n", 41542cf33ddSHans Petter Selasky pci_get_devid(self)); 41642cf33ddSHans Petter Selasky snprintf(sc->sc_vendor, sizeof(sc->sc_vendor), 41742cf33ddSHans Petter Selasky "(0x%04x)", pci_get_vendor(self)); 41842cf33ddSHans Petter Selasky break; 41942cf33ddSHans Petter Selasky } 42013540260SHans Petter Selasky 4213346ae0dSHans Petter Selasky if (sc->sc_irq_res != NULL && xhci_use_polling() == 0) { 42213540260SHans Petter Selasky err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 42313540260SHans Petter Selasky NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); 42497d729cfSHans Petter Selasky if (err != 0) { 425dcf83ff0SMarius Strobl bus_release_resource(self, SYS_RES_IRQ, 426dcf83ff0SMarius Strobl rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 427dcf83ff0SMarius Strobl sc->sc_irq_res = NULL; 428dcf83ff0SMarius Strobl pci_release_msi(self); 42913540260SHans Petter Selasky device_printf(self, "Could not setup IRQ, err=%d\n", err); 43013540260SHans Petter Selasky sc->sc_intr_hdl = NULL; 43113540260SHans Petter Selasky } 43297d729cfSHans Petter Selasky } 433dcf83ff0SMarius Strobl if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL) { 434dcf83ff0SMarius Strobl if (xhci_use_polling() != 0) { 43597d729cfSHans Petter Selasky device_printf(self, "Interrupt polling at %dHz\n", hz); 43697d729cfSHans Petter Selasky USB_BUS_LOCK(&sc->sc_bus); 43797d729cfSHans Petter Selasky xhci_interrupt_poll(sc); 43897d729cfSHans Petter Selasky USB_BUS_UNLOCK(&sc->sc_bus); 439dcf83ff0SMarius Strobl } else 440dcf83ff0SMarius Strobl goto error; 44197d729cfSHans Petter Selasky } 44297d729cfSHans Petter Selasky 4432e141748SHans Petter Selasky xhci_pci_take_controller(self); 44413540260SHans Petter Selasky 44513540260SHans Petter Selasky err = xhci_halt_controller(sc); 44613540260SHans Petter Selasky 44713540260SHans Petter Selasky if (err == 0) 44813540260SHans Petter Selasky err = xhci_start_controller(sc); 44913540260SHans Petter Selasky 45013540260SHans Petter Selasky if (err == 0) 45113540260SHans Petter Selasky err = device_probe_and_attach(sc->sc_bus.bdev); 45213540260SHans Petter Selasky 45313540260SHans Petter Selasky if (err) { 45413540260SHans Petter Selasky device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 45513540260SHans Petter Selasky goto error; 45613540260SHans Petter Selasky } 45713540260SHans Petter Selasky return (0); 45813540260SHans Petter Selasky 45913540260SHans Petter Selasky error: 46013540260SHans Petter Selasky xhci_pci_detach(self); 46113540260SHans Petter Selasky return (ENXIO); 46213540260SHans Petter Selasky } 46313540260SHans Petter Selasky 46413540260SHans Petter Selasky static int 46513540260SHans Petter Selasky xhci_pci_detach(device_t self) 46613540260SHans Petter Selasky { 46713540260SHans Petter Selasky struct xhci_softc *sc = device_get_softc(self); 468*3ddaf820SJohn Baldwin int error; 46913540260SHans Petter Selasky 47013540260SHans Petter Selasky /* during module unload there are lots of children leftover */ 471*3ddaf820SJohn Baldwin error = bus_generic_detach(self); 472*3ddaf820SJohn Baldwin if (error != 0) 473*3ddaf820SJohn Baldwin return (error); 47413540260SHans Petter Selasky 47597d729cfSHans Petter Selasky usb_callout_drain(&sc->sc_callout); 47697d729cfSHans Petter Selasky xhci_halt_controller(sc); 477f515174bSHans Petter Selasky xhci_reset_controller(sc); 47897d729cfSHans Petter Selasky 47913540260SHans Petter Selasky pci_disable_busmaster(self); 48013540260SHans Petter Selasky 48113540260SHans Petter Selasky if (sc->sc_irq_res && sc->sc_intr_hdl) { 48213540260SHans Petter Selasky bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 48313540260SHans Petter Selasky sc->sc_intr_hdl = NULL; 48413540260SHans Petter Selasky } 48513540260SHans Petter Selasky if (sc->sc_irq_res) { 486dcf83ff0SMarius Strobl bus_release_resource(self, SYS_RES_IRQ, 487dcf83ff0SMarius Strobl rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 48813540260SHans Petter Selasky sc->sc_irq_res = NULL; 489dcf83ff0SMarius Strobl pci_release_msi(self); 49013540260SHans Petter Selasky } 491116bc582SKonstantin Belousov if (sc->sc_msix_res != NULL && sc->sc_msix_res != sc->sc_io_res) { 492116bc582SKonstantin Belousov bus_release_resource(self, SYS_RES_MEMORY, 493116bc582SKonstantin Belousov rman_get_rid(sc->sc_msix_res), sc->sc_msix_res); 494116bc582SKonstantin Belousov sc->sc_msix_res = NULL; 495116bc582SKonstantin Belousov } 49613540260SHans Petter Selasky if (sc->sc_io_res) { 49713540260SHans Petter Selasky bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, 49813540260SHans Petter Selasky sc->sc_io_res); 49913540260SHans Petter Selasky sc->sc_io_res = NULL; 50013540260SHans Petter Selasky } 50113540260SHans Petter Selasky 50213540260SHans Petter Selasky xhci_uninit(sc); 50313540260SHans Petter Selasky 50413540260SHans Petter Selasky return (0); 50513540260SHans Petter Selasky } 50613540260SHans Petter Selasky 5072e141748SHans Petter Selasky static int 5082e141748SHans Petter Selasky xhci_pci_take_controller(device_t self) 50913540260SHans Petter Selasky { 51013540260SHans Petter Selasky struct xhci_softc *sc = device_get_softc(self); 51113540260SHans Petter Selasky uint32_t cparams; 51213540260SHans Petter Selasky uint32_t eecp; 51313540260SHans Petter Selasky uint32_t eec; 51413540260SHans Petter Selasky uint16_t to; 51513540260SHans Petter Selasky uint8_t bios_sem; 51613540260SHans Petter Selasky 51713540260SHans Petter Selasky cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); 51813540260SHans Petter Selasky 51913540260SHans Petter Selasky eec = -1; 52013540260SHans Petter Selasky 52113540260SHans Petter Selasky /* Synchronise with the BIOS if it owns the controller. */ 52213540260SHans Petter Selasky for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); 52313540260SHans Petter Selasky eecp += XHCI_XECP_NEXT(eec) << 2) { 52413540260SHans Petter Selasky eec = XREAD4(sc, capa, eecp); 52513540260SHans Petter Selasky 52613540260SHans Petter Selasky if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 52713540260SHans Petter Selasky continue; 52813540260SHans Petter Selasky bios_sem = XREAD1(sc, capa, eecp + 52913540260SHans Petter Selasky XHCI_XECP_BIOS_SEM); 53013540260SHans Petter Selasky if (bios_sem == 0) 53113540260SHans Petter Selasky continue; 53213540260SHans Petter Selasky device_printf(sc->sc_bus.bdev, "waiting for BIOS " 53313540260SHans Petter Selasky "to give up control\n"); 53413540260SHans Petter Selasky XWRITE1(sc, capa, eecp + 53513540260SHans Petter Selasky XHCI_XECP_OS_SEM, 1); 53613540260SHans Petter Selasky to = 500; 53713540260SHans Petter Selasky while (1) { 53813540260SHans Petter Selasky bios_sem = XREAD1(sc, capa, eecp + 53913540260SHans Petter Selasky XHCI_XECP_BIOS_SEM); 54013540260SHans Petter Selasky if (bios_sem == 0) 54113540260SHans Petter Selasky break; 54213540260SHans Petter Selasky 54313540260SHans Petter Selasky if (--to == 0) { 54413540260SHans Petter Selasky device_printf(sc->sc_bus.bdev, 54513540260SHans Petter Selasky "timed out waiting for BIOS\n"); 54613540260SHans Petter Selasky break; 54713540260SHans Petter Selasky } 54813540260SHans Petter Selasky usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 54913540260SHans Petter Selasky } 55013540260SHans Petter Selasky } 5512e141748SHans Petter Selasky return (0); 55213540260SHans Petter Selasky } 553