ehci_pci.c revision 203693
165310Sarchie/*- 265310Sarchie * Copyright (c) 1998 The NetBSD Foundation, Inc. 365310Sarchie * All rights reserved. 465310Sarchie * 565310Sarchie * This code is derived from software contributed to The NetBSD Foundation 665310Sarchie * by Lennart Augustsson (augustss@carlstedt.se) at 765310Sarchie * Carlstedt Research & Technology. 865310Sarchie * 965310Sarchie * Redistribution and use in source and binary forms, with or without 1065310Sarchie * modification, are permitted provided that the following conditions 1165310Sarchie * are met: 1265310Sarchie * 1. Redistributions of source code must retain the above copyright 1365310Sarchie * notice, this list of conditions and the following disclaimer. 1465310Sarchie * 2. Redistributions in binary form must reproduce the above copyright 1565310Sarchie * notice, this list of conditions and the following disclaimer in the 1665310Sarchie * documentation and/or other materials provided with the distribution. 1765310Sarchie * 3. All advertising materials mentioning features or use of this software 1865310Sarchie * must display the following acknowledgement: 1965310Sarchie * This product includes software developed by the NetBSD 2065310Sarchie * Foundation, Inc. and its contributors. 2165310Sarchie * 4. Neither the name of The NetBSD Foundation nor the names of its 2265310Sarchie * contributors may be used to endorse or promote products derived 2365310Sarchie * from this software without specific prior written permission. 2465310Sarchie * 2565310Sarchie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2665310Sarchie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2765310Sarchie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2865310Sarchie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2965310Sarchie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3065310Sarchie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3165310Sarchie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3265310Sarchie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3365310Sarchie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3465310Sarchie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3565310Sarchie * POSSIBILITY OF SUCH DAMAGE. 3665310Sarchie */ 3765310Sarchie 3865310Sarchie#include <sys/cdefs.h> 3965310Sarchie__FBSDID("$FreeBSD: head/sys/dev/usb/controller/ehci_pci.c 203693 2010-02-09 00:38:40Z thompsa $"); 4065310Sarchie 4165310Sarchie/* 4265310Sarchie * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. 4365310Sarchie * 4465310Sarchie * The EHCI 1.0 spec can be found at 4565310Sarchie * http://developer.intel.com/technology/usb/download/ehci-r10.pdf 4665310Sarchie * and the USB 2.0 spec at 4765310Sarchie * http://www.usb.org/developers/docs/usb_20.zip 4865310Sarchie */ 4965310Sarchie 5065310Sarchie/* The low level controller code for EHCI has been split into 5165310Sarchie * PCI probes and EHCI specific code. This was done to facilitate the 5265310Sarchie * sharing of code between *BSD's 5365310Sarchie */ 5465310Sarchie 5565310Sarchie#include <sys/stdint.h> 5665310Sarchie#include <sys/stddef.h> 5765310Sarchie#include <sys/param.h> 5865310Sarchie#include <sys/queue.h> 5965310Sarchie#include <sys/types.h> 6065310Sarchie#include <sys/systm.h> 6165310Sarchie#include <sys/kernel.h> 6265310Sarchie#include <sys/bus.h> 6365310Sarchie#include <sys/linker_set.h> 6465310Sarchie#include <sys/module.h> 6565310Sarchie#include <sys/lock.h> 6665310Sarchie#include <sys/mutex.h> 6765310Sarchie#include <sys/condvar.h> 6865310Sarchie#include <sys/sysctl.h> 6965310Sarchie#include <sys/sx.h> 7065310Sarchie#include <sys/unistd.h> 7165310Sarchie#include <sys/callout.h> 7265310Sarchie#include <sys/malloc.h> 7365310Sarchie#include <sys/priv.h> 7465310Sarchie 7565310Sarchie#include <dev/usb/usb.h> 7665310Sarchie#include <dev/usb/usbdi.h> 7765310Sarchie 7865310Sarchie#include <dev/usb/usb_core.h> 7965310Sarchie#include <dev/usb/usb_busdma.h> 8065310Sarchie#include <dev/usb/usb_process.h> 8165310Sarchie#include <dev/usb/usb_util.h> 8265310Sarchie 8365310Sarchie#include <dev/usb/usb_controller.h> 8465310Sarchie#include <dev/usb/usb_bus.h> 8565310Sarchie#include <dev/usb/usb_pci.h> 8665310Sarchie#include <dev/usb/controller/ehci.h> 8765310Sarchie#include <dev/usb/controller/ehcireg.h> 8865310Sarchie 8965310Sarchie#define PCI_EHCI_VENDORID_ACERLABS 0x10b9 9065310Sarchie#define PCI_EHCI_VENDORID_AMD 0x1022 9165310Sarchie#define PCI_EHCI_VENDORID_APPLE 0x106b 9265310Sarchie#define PCI_EHCI_VENDORID_ATI 0x1002 9365310Sarchie#define PCI_EHCI_VENDORID_CMDTECH 0x1095 9465310Sarchie#define PCI_EHCI_VENDORID_INTEL 0x8086 9565310Sarchie#define PCI_EHCI_VENDORID_NEC 0x1033 9665310Sarchie#define PCI_EHCI_VENDORID_OPTI 0x1045 9765310Sarchie#define PCI_EHCI_VENDORID_PHILIPS 0x1131 9865310Sarchie#define PCI_EHCI_VENDORID_SIS 0x1039 9965310Sarchie#define PCI_EHCI_VENDORID_NVIDIA 0x12D2 10065310Sarchie#define PCI_EHCI_VENDORID_NVIDIA2 0x10DE 10165310Sarchie#define PCI_EHCI_VENDORID_VIA 0x1106 10265310Sarchie 10365310Sarchie#define PCI_EHCI_BASE_REG 0x10 10465310Sarchie 10565310Sarchiestatic void ehci_pci_takecontroller(device_t self); 10665310Sarchie 10765310Sarchiestatic device_probe_t ehci_pci_probe; 10865310Sarchiestatic device_attach_t ehci_pci_attach; 10965310Sarchiestatic device_detach_t ehci_pci_detach; 11065310Sarchiestatic device_suspend_t ehci_pci_suspend; 11165310Sarchiestatic device_resume_t ehci_pci_resume; 11265310Sarchiestatic device_shutdown_t ehci_pci_shutdown; 11365310Sarchie 11465310Sarchiestatic int 11565310Sarchieehci_pci_suspend(device_t self) 11665310Sarchie{ 11765310Sarchie ehci_softc_t *sc = device_get_softc(self); 11865310Sarchie int err; 11965310Sarchie 12065310Sarchie err = bus_generic_suspend(self); 12165310Sarchie if (err) 12265310Sarchie return (err); 12365310Sarchie ehci_suspend(sc); 12465310Sarchie return (0); 12565310Sarchie} 12665310Sarchie 12765310Sarchiestatic int 12865310Sarchieehci_pci_resume(device_t self) 12965310Sarchie{ 13065310Sarchie ehci_softc_t *sc = device_get_softc(self); 13165310Sarchie 13265310Sarchie ehci_pci_takecontroller(self); 13365310Sarchie ehci_resume(sc); 13465310Sarchie 13565310Sarchie bus_generic_resume(self); 13665310Sarchie 13765310Sarchie return (0); 13865310Sarchie} 13965310Sarchie 14065310Sarchiestatic int 14165310Sarchieehci_pci_shutdown(device_t self) 14265310Sarchie{ 14365310Sarchie ehci_softc_t *sc = device_get_softc(self); 14465310Sarchie int err; 14565310Sarchie 14665310Sarchie err = bus_generic_shutdown(self); 14765310Sarchie if (err) 14865310Sarchie return (err); 14965310Sarchie ehci_shutdown(sc); 15065310Sarchie 15165310Sarchie return (0); 15265310Sarchie} 15365310Sarchie 15465310Sarchiestatic const char * 15565310Sarchieehci_pci_match(device_t self) 15665310Sarchie{ 15765310Sarchie uint32_t device_id = pci_get_devid(self); 15865310Sarchie 15965310Sarchie switch (device_id) { 16065310Sarchie case 0x268c8086: 16165310Sarchie return ("Intel 63XXESB USB 2.0 controller"); 16265310Sarchie 16365310Sarchie case 0x523910b9: 16465310Sarchie return "ALi M5239 USB 2.0 controller"; 16565310Sarchie 16665310Sarchie case 0x10227463: 16765310Sarchie return "AMD 8111 USB 2.0 controller"; 16865310Sarchie 16965310Sarchie case 0x20951022: 17065310Sarchie return ("AMD CS5536 (Geode) USB 2.0 controller"); 17165310Sarchie 17265310Sarchie case 0x43451002: 17365310Sarchie return "ATI SB200 USB 2.0 controller"; 17465310Sarchie case 0x43731002: 17565310Sarchie return "ATI SB400 USB 2.0 controller"; 17665310Sarchie 17765310Sarchie case 0x25ad8086: 17865310Sarchie return "Intel 6300ESB USB 2.0 controller"; 17965310Sarchie case 0x24cd8086: 18065310Sarchie return "Intel 82801DB/L/M (ICH4) USB 2.0 controller"; 18165310Sarchie case 0x24dd8086: 18265310Sarchie return "Intel 82801EB/R (ICH5) USB 2.0 controller"; 18365310Sarchie case 0x265c8086: 18465310Sarchie return "Intel 82801FB (ICH6) USB 2.0 controller"; 18565310Sarchie case 0x27cc8086: 18665310Sarchie return "Intel 82801GB/R (ICH7) USB 2.0 controller"; 18765310Sarchie 18865310Sarchie case 0x28368086: 18965310Sarchie return "Intel 82801H (ICH8) USB 2.0 controller USB2-A"; 19065310Sarchie case 0x283a8086: 19165310Sarchie return "Intel 82801H (ICH8) USB 2.0 controller USB2-B"; 19265310Sarchie case 0x293a8086: 19365310Sarchie return "Intel 82801I (ICH9) USB 2.0 controller"; 19465310Sarchie case 0x293c8086: 19565310Sarchie return "Intel 82801I (ICH9) USB 2.0 controller"; 19665310Sarchie case 0x3a3a8086: 19765310Sarchie return "Intel 82801JI (ICH10) USB 2.0 controller USB-A"; 19865310Sarchie case 0x3a3c8086: 19965310Sarchie return "Intel 82801JI (ICH10) USB 2.0 controller USB-B"; 20065310Sarchie case 0x3b348086: 20165310Sarchie return ("Intel PCH USB 2.0 controller USB-A"); 20265310Sarchie case 0x3b3c8086: 20365310Sarchie return ("Intel PCH USB 2.0 controller USB-B"); 20465310Sarchie 20565310Sarchie case 0x00e01033: 20665310Sarchie return ("NEC uPD 720100 USB 2.0 controller"); 20765310Sarchie 20865310Sarchie case 0x006810de: 20965310Sarchie return "NVIDIA nForce2 USB 2.0 controller"; 21065310Sarchie case 0x008810de: 21165310Sarchie return "NVIDIA nForce2 Ultra 400 USB 2.0 controller"; 21265310Sarchie case 0x00d810de: 21365310Sarchie return "NVIDIA nForce3 USB 2.0 controller"; 21465310Sarchie case 0x00e810de: 21565310Sarchie return "NVIDIA nForce3 250 USB 2.0 controller"; 21665310Sarchie case 0x005b10de: 21765310Sarchie return "NVIDIA nForce4 USB 2.0 controller"; 21865310Sarchie case 0x03f210de: 21965310Sarchie return "NVIDIA nForce MCP61 USB 2.0 controller"; 22065310Sarchie case 0x0aa610de: 22165310Sarchie return "NVIDIA nForce MCP79 USB 2.0 controller"; 22265310Sarchie case 0x0aa910de: 22365310Sarchie return "NVIDIA nForce MCP79 USB 2.0 controller"; 22465310Sarchie case 0x0aaa10de: 22565310Sarchie return "NVIDIA nForce MCP79 USB 2.0 controller"; 22665310Sarchie 22765310Sarchie case 0x15621131: 22865310Sarchie return "Philips ISP156x USB 2.0 controller"; 22965310Sarchie 23065310Sarchie case 0x31041106: 23165310Sarchie return ("VIA VT6202 USB 2.0 controller"); 23265310Sarchie 23365310Sarchie default: 23465310Sarchie break; 23565310Sarchie } 23665310Sarchie 23765310Sarchie if ((pci_get_class(self) == PCIC_SERIALBUS) 23865310Sarchie && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) 23965310Sarchie && (pci_get_progif(self) == PCI_INTERFACE_EHCI)) { 24065310Sarchie return ("EHCI (generic) USB 2.0 controller"); 24165310Sarchie } 24265310Sarchie return (NULL); /* dunno */ 24365310Sarchie} 24465310Sarchie 24565310Sarchiestatic int 24665310Sarchieehci_pci_probe(device_t self) 24765310Sarchie{ 24865310Sarchie const char *desc = ehci_pci_match(self); 24965310Sarchie 25065310Sarchie if (desc) { 25165310Sarchie device_set_desc(self, desc); 25265310Sarchie return (0); 25365310Sarchie } else { 25465310Sarchie return (ENXIO); 25565310Sarchie } 25665310Sarchie} 25765310Sarchie 25865310Sarchiestatic void 25965310Sarchieehci_pci_ati_quirk(device_t self, uint8_t is_sb700) 26065310Sarchie{ 26165310Sarchie device_t smbdev; 26265310Sarchie uint32_t val; 26365310Sarchie 26465310Sarchie if (is_sb700) { 26565310Sarchie /* Lookup SMBUS PCI device */ 26665310Sarchie smbdev = pci_find_device(PCI_EHCI_VENDORID_ATI, 0x4385); 26765310Sarchie if (smbdev == NULL) 26865310Sarchie return; 26965310Sarchie val = pci_get_revid(smbdev); 27065310Sarchie if (val != 0x3a && val != 0x3b) 27165310Sarchie return; 27265310Sarchie } 27365310Sarchie 27465310Sarchie /* 27565310Sarchie * Note: this bit is described as reserved in SB700 27665310Sarchie * Register Reference Guide. 27765310Sarchie */ 27865310Sarchie val = pci_read_config(self, 0x53, 1); 27965310Sarchie if (!(val & 0x8)) { 28065310Sarchie val |= 0x8; 28165310Sarchie pci_write_config(self, 0x53, val, 1); 28265310Sarchie device_printf(self, "AMD SB600/700 quirk applied\n"); 28365310Sarchie } 28465310Sarchie} 28565310Sarchie 28665310Sarchiestatic void 28765310Sarchieehci_pci_via_quirk(device_t self) 28865310Sarchie{ 28965310Sarchie uint32_t val; 29065310Sarchie 29165310Sarchie if ((pci_get_device(self) == 0x3104) && 29265310Sarchie ((pci_get_revid(self) & 0xf0) == 0x60)) { 29365310Sarchie /* Correct schedule sleep time to 10us */ 29465310Sarchie val = pci_read_config(self, 0x4b, 1); 29565310Sarchie if (val & 0x20) 29665310Sarchie return; 29765310Sarchie pci_write_config(self, 0x4b, val, 1); 29865310Sarchie device_printf(self, "VIA-quirk applied\n"); 29965310Sarchie } 30065310Sarchie} 30165310Sarchie 30265310Sarchiestatic int 30365310Sarchieehci_pci_attach(device_t self) 30465310Sarchie{ 30565310Sarchie ehci_softc_t *sc = device_get_softc(self); 30665310Sarchie int err; 30765310Sarchie int rid; 30865310Sarchie 30965310Sarchie /* initialise some bus fields */ 31065310Sarchie sc->sc_bus.parent = self; 31165310Sarchie sc->sc_bus.devices = sc->sc_devices; 31265310Sarchie sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 31365310Sarchie 31465310Sarchie /* get all DMA memory */ 31565310Sarchie if (usb_bus_mem_alloc_all(&sc->sc_bus, 31665310Sarchie USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { 31765310Sarchie return (ENOMEM); 31865310Sarchie } 31965310Sarchie 32065310Sarchie pci_enable_busmaster(self); 32165310Sarchie 32265310Sarchie switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) { 32365310Sarchie case PCI_USB_REV_PRE_1_0: 32465310Sarchie case PCI_USB_REV_1_0: 32565310Sarchie case PCI_USB_REV_1_1: 32665310Sarchie /* 32765310Sarchie * NOTE: some EHCI USB controllers have the wrong USB 32865310Sarchie * revision number. It appears those controllers are 32965310Sarchie * fully compliant so we just ignore this value in 33065310Sarchie * some common cases. 33165310Sarchie */ 33265310Sarchie device_printf(self, "pre-2.0 USB revision (ignored)\n"); 33365310Sarchie /* fallthrough */ 33465310Sarchie case PCI_USB_REV_2_0: 33565310Sarchie break; 33665310Sarchie default: 33765310Sarchie /* Quirk for Parallels Desktop 4.0 */ 33865310Sarchie device_printf(self, "USB revision is unknown. Assuming v2.0.\n"); 33965310Sarchie break; 34065310Sarchie } 34165310Sarchie 34265310Sarchie rid = PCI_CBMEM; 34365310Sarchie sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 34465310Sarchie RF_ACTIVE); 34565310Sarchie if (!sc->sc_io_res) { 34665310Sarchie device_printf(self, "Could not map memory\n"); 34765310Sarchie goto error; 34865310Sarchie } 34965310Sarchie sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 35065310Sarchie sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 35165310Sarchie sc->sc_io_size = rman_get_size(sc->sc_io_res); 35265310Sarchie 35365310Sarchie rid = 0; 35465310Sarchie sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 35565310Sarchie RF_SHAREABLE | RF_ACTIVE); 35665310Sarchie if (sc->sc_irq_res == NULL) { 35765310Sarchie device_printf(self, "Could not allocate irq\n"); 35865310Sarchie goto error; 35965310Sarchie } 36065310Sarchie sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 36165310Sarchie if (!sc->sc_bus.bdev) { 36265310Sarchie device_printf(self, "Could not add USB device\n"); 36365310Sarchie goto error; 36465310Sarchie } 36565310Sarchie device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 36665310Sarchie 36765310Sarchie /* 36865310Sarchie * ehci_pci_match will never return NULL if ehci_pci_probe 36965310Sarchie * succeeded 37065310Sarchie */ 37165310Sarchie device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self)); 37265310Sarchie switch (pci_get_vendor(self)) { 37365310Sarchie case PCI_EHCI_VENDORID_ACERLABS: 37465310Sarchie sprintf(sc->sc_vendor, "AcerLabs"); 37565310Sarchie break; 37665310Sarchie case PCI_EHCI_VENDORID_AMD: 37765310Sarchie sprintf(sc->sc_vendor, "AMD"); 37865310Sarchie break; 37965310Sarchie case PCI_EHCI_VENDORID_APPLE: 38065310Sarchie sprintf(sc->sc_vendor, "Apple"); 38165310Sarchie break; 38265310Sarchie case PCI_EHCI_VENDORID_ATI: 38365310Sarchie sprintf(sc->sc_vendor, "ATI"); 38465310Sarchie break; 38565310Sarchie case PCI_EHCI_VENDORID_CMDTECH: 38665310Sarchie sprintf(sc->sc_vendor, "CMDTECH"); 38765310Sarchie break; 38865310Sarchie case PCI_EHCI_VENDORID_INTEL: 38965310Sarchie sprintf(sc->sc_vendor, "Intel"); 39065310Sarchie break; 39165310Sarchie case PCI_EHCI_VENDORID_NEC: 39265310Sarchie sprintf(sc->sc_vendor, "NEC"); 39365310Sarchie break; 39465310Sarchie case PCI_EHCI_VENDORID_OPTI: 39565310Sarchie sprintf(sc->sc_vendor, "OPTi"); 39665310Sarchie break; 39765310Sarchie case PCI_EHCI_VENDORID_PHILIPS: 39865310Sarchie sprintf(sc->sc_vendor, "Philips"); 39965310Sarchie break; 40065310Sarchie case PCI_EHCI_VENDORID_SIS: 40165310Sarchie sprintf(sc->sc_vendor, "SiS"); 40265310Sarchie break; 40365310Sarchie case PCI_EHCI_VENDORID_NVIDIA: 40465310Sarchie case PCI_EHCI_VENDORID_NVIDIA2: 40565310Sarchie sprintf(sc->sc_vendor, "nVidia"); 40665310Sarchie break; 40765310Sarchie case PCI_EHCI_VENDORID_VIA: 40865310Sarchie sprintf(sc->sc_vendor, "VIA"); 40965310Sarchie break; 41065310Sarchie default: 41165310Sarchie if (bootverbose) 41265310Sarchie device_printf(self, "(New EHCI DeviceId=0x%08x)\n", 41365310Sarchie pci_get_devid(self)); 41465310Sarchie sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); 41565310Sarchie } 41665310Sarchie 41765310Sarchie#if (__FreeBSD_version >= 700031) 41865310Sarchie err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 41965310Sarchie NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 42065310Sarchie#else 42165310Sarchie err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 42265310Sarchie (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 42365310Sarchie#endif 42465310Sarchie if (err) { 42565310Sarchie device_printf(self, "Could not setup irq, %d\n", err); 42665310Sarchie sc->sc_intr_hdl = NULL; 42765310Sarchie goto error; 42865310Sarchie } 42965310Sarchie ehci_pci_takecontroller(self); 43065310Sarchie 43165310Sarchie /* Undocumented quirks taken from Linux */ 43265310Sarchie 43365310Sarchie switch (pci_get_vendor(self)) { 43465310Sarchie case PCI_EHCI_VENDORID_ATI: 43565310Sarchie /* SB600 and SB700 EHCI quirk */ 43665310Sarchie switch (pci_get_device(self)) { 43765310Sarchie case 0x4386: 43865310Sarchie ehci_pci_ati_quirk(self, 0); 43965310Sarchie break; 44065310Sarchie case 0x4396: 44165310Sarchie ehci_pci_ati_quirk(self, 1); 44265310Sarchie break; 44365310Sarchie default: 44465310Sarchie break; 44565310Sarchie } 44665310Sarchie break; 44765310Sarchie 44865310Sarchie case PCI_EHCI_VENDORID_VIA: 44965310Sarchie ehci_pci_via_quirk(self); 45065310Sarchie break; 45165310Sarchie 45265310Sarchie default: 45365310Sarchie break; 45465310Sarchie } 45565310Sarchie 45665310Sarchie /* Dropped interrupts workaround */ 45765310Sarchie switch (pci_get_vendor(self)) { 45865310Sarchie case PCI_EHCI_VENDORID_ATI: 45965310Sarchie case PCI_EHCI_VENDORID_VIA: 46065310Sarchie sc->sc_flags |= EHCI_SCFLG_LOSTINTRBUG; 46165310Sarchie if (bootverbose) 46265310Sarchie device_printf(self, 46365310Sarchie "Dropped interrupts workaround enabled\n"); 46465310Sarchie break; 46565310Sarchie default: 46665310Sarchie break; 46765310Sarchie } 46865310Sarchie 46965310Sarchie /* Doorbell feature workaround */ 47065310Sarchie switch (pci_get_vendor(self)) { 47165310Sarchie case PCI_EHCI_VENDORID_NVIDIA: 47265310Sarchie case PCI_EHCI_VENDORID_NVIDIA2: 47365310Sarchie sc->sc_flags |= EHCI_SCFLG_IAADBUG; 47465310Sarchie if (bootverbose) 47565310Sarchie device_printf(self, 47665310Sarchie "Doorbell workaround enabled\n"); 47765310Sarchie break; 47865310Sarchie default: 47965310Sarchie break; 48065310Sarchie } 48165310Sarchie 48265310Sarchie err = ehci_init(sc); 48365310Sarchie if (!err) { 48465310Sarchie err = device_probe_and_attach(sc->sc_bus.bdev); 48565310Sarchie } 48665310Sarchie if (err) { 48765310Sarchie device_printf(self, "USB init failed err=%d\n", err); 48865310Sarchie goto error; 48965310Sarchie } 49065310Sarchie return (0); 49165310Sarchie 49265310Sarchieerror: 49365310Sarchie ehci_pci_detach(self); 49465310Sarchie return (ENXIO); 49565310Sarchie} 49665310Sarchie 49765310Sarchiestatic int 49865310Sarchieehci_pci_detach(device_t self) 49965310Sarchie{ 50065310Sarchie ehci_softc_t *sc = device_get_softc(self); 50165310Sarchie device_t bdev; 50265310Sarchie 50365310Sarchie if (sc->sc_bus.bdev) { 50465310Sarchie bdev = sc->sc_bus.bdev; 50565310Sarchie device_detach(bdev); 50665310Sarchie device_delete_child(self, bdev); 50765310Sarchie } 50865310Sarchie /* during module unload there are lots of children leftover */ 50965310Sarchie device_delete_all_children(self); 51065310Sarchie 51165310Sarchie pci_disable_busmaster(self); 51265310Sarchie 51365310Sarchie /* 51465310Sarchie * disable interrupts that might have been switched on in ehci_init 51565310Sarchie */ 51665310Sarchie if (sc->sc_io_res) { 51765310Sarchie EWRITE4(sc, EHCI_USBINTR, 0); 51865310Sarchie } 51965310Sarchie if (sc->sc_irq_res && sc->sc_intr_hdl) { 52065310Sarchie /* 52165310Sarchie * only call ehci_detach() after ehci_init() 52265310Sarchie */ 52365310Sarchie ehci_detach(sc); 52465310Sarchie 52565310Sarchie int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 52665310Sarchie 52765310Sarchie if (err) 52865310Sarchie /* XXX or should we panic? */ 52965310Sarchie device_printf(self, "Could not tear down irq, %d\n", 53065310Sarchie err); 53165310Sarchie sc->sc_intr_hdl = NULL; 53265310Sarchie } 53365310Sarchie if (sc->sc_irq_res) { 53465310Sarchie bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 53565310Sarchie sc->sc_irq_res = NULL; 53665310Sarchie } 53765310Sarchie if (sc->sc_io_res) { 53865310Sarchie bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM, 53965310Sarchie sc->sc_io_res); 54065310Sarchie sc->sc_io_res = NULL; 54165310Sarchie } 54265310Sarchie usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); 54365310Sarchie 54465310Sarchie return (0); 54565310Sarchie} 54665310Sarchie 54765310Sarchiestatic void 54865310Sarchieehci_pci_takecontroller(device_t self) 54965310Sarchie{ 55065310Sarchie ehci_softc_t *sc = device_get_softc(self); 55165310Sarchie uint32_t cparams; 55265310Sarchie uint32_t eec; 55365310Sarchie uint16_t to; 55465310Sarchie uint8_t eecp; 55565310Sarchie uint8_t bios_sem; 55665310Sarchie 55765310Sarchie cparams = EREAD4(sc, EHCI_HCCPARAMS); 55865310Sarchie 55965310Sarchie /* Synchronise with the BIOS if it owns the controller. */ 56065310Sarchie for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; 56165310Sarchie eecp = EHCI_EECP_NEXT(eec)) { 56265310Sarchie eec = pci_read_config(self, eecp, 4); 56365310Sarchie if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) { 56465310Sarchie continue; 56565310Sarchie } 56665310Sarchie bios_sem = pci_read_config(self, eecp + 56765310Sarchie EHCI_LEGSUP_BIOS_SEM, 1); 56865310Sarchie if (bios_sem == 0) { 56965310Sarchie continue; 57065310Sarchie } 57165310Sarchie device_printf(sc->sc_bus.bdev, "waiting for BIOS " 57265310Sarchie "to give up control\n"); 57365310Sarchie pci_write_config(self, eecp + 57465310Sarchie EHCI_LEGSUP_OS_SEM, 1, 1); 57565310Sarchie to = 500; 57665310Sarchie while (1) { 57765310Sarchie bios_sem = pci_read_config(self, eecp + 57865310Sarchie EHCI_LEGSUP_BIOS_SEM, 1); 57965310Sarchie if (bios_sem == 0) 58065310Sarchie break; 58165310Sarchie 58265310Sarchie if (--to == 0) { 58365310Sarchie device_printf(sc->sc_bus.bdev, 58465310Sarchie "timed out waiting for BIOS\n"); 58565310Sarchie break; 58665310Sarchie } 58765310Sarchie usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 58865310Sarchie } 58965310Sarchie } 59065310Sarchie} 59165310Sarchie 59265310Sarchiestatic driver_t ehci_driver = 59365310Sarchie{ 59465310Sarchie .name = "ehci", 59565310Sarchie .methods = (device_method_t[]){ 59665310Sarchie /* device interface */ 59765310Sarchie DEVMETHOD(device_probe, ehci_pci_probe), 59865310Sarchie DEVMETHOD(device_attach, ehci_pci_attach), 59965310Sarchie DEVMETHOD(device_detach, ehci_pci_detach), 60065310Sarchie DEVMETHOD(device_suspend, ehci_pci_suspend), 60165310Sarchie DEVMETHOD(device_resume, ehci_pci_resume), 60265310Sarchie DEVMETHOD(device_shutdown, ehci_pci_shutdown), 60365310Sarchie /* bus interface */ 60465310Sarchie DEVMETHOD(bus_print_child, bus_generic_print_child), 60565310Sarchie 60665310Sarchie {0, 0} 60765310Sarchie }, 60865310Sarchie .size = sizeof(struct ehci_softc), 60965310Sarchie}; 61065310Sarchie 61165310Sarchiestatic devclass_t ehci_devclass; 61265310Sarchie 61365310SarchieDRIVER_MODULE(ehci, pci, ehci_driver, ehci_devclass, 0, 0); 61465310SarchieMODULE_DEPEND(ehci, usb, 1, 1, 1); 61565310Sarchie