diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-06-22 08:43:28 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-06-22 08:43:28 +0000 |
commit | 316127ebad5ed7dd44500949e55a45bc8f974743 (patch) | |
tree | c57da0ccc5d7ca6ea6f615fafe256ee0dc6e5918 /sys/dev | |
parent | 19097b03ee0e71f51bbc44f98770945e0303fb30 (diff) |
Apparently some BIOSes not supporting xHCI natively switch USB ports
back to EHCI at suspend. So route the ports back to xHCI at resume.
Problem reported by Adam Wolk, thanks!
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/xhci_pci.c | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/sys/dev/pci/xhci_pci.c b/sys/dev/pci/xhci_pci.c index bea43edc663..fd1e21d5bad 100644 --- a/sys/dev/pci/xhci_pci.c +++ b/sys/dev/pci/xhci_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xhci_pci.c,v 1.5 2014/10/30 18:25:08 mpi Exp $ */ +/* $OpenBSD: xhci_pci.c,v 1.6 2015/06/22 08:43:27 mpi Exp $ */ /* * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. @@ -61,17 +61,19 @@ struct xhci_pci_softc { struct xhci_softc sc; pci_chipset_tag_t sc_pc; pcitag_t sc_tag; + pcireg_t sc_id; void *sc_ih; /* interrupt vectoring */ }; int xhci_pci_match(struct device *, void *, void *); void xhci_pci_attach(struct device *, struct device *, void *); int xhci_pci_detach(struct device *, int); +int xhci_pci_activate(struct device *, int); void xhci_pci_takecontroller(struct xhci_pci_softc *, int); struct cfattach xhci_pci_ca = { sizeof(struct xhci_pci_softc), xhci_pci_match, xhci_pci_attach, - xhci_pci_detach, xhci_activate + xhci_pci_detach, xhci_pci_activate }; int @@ -92,10 +94,10 @@ xhci_pci_port_route(struct xhci_pci_softc *psc) { pcireg_t val; - /* + /* * Check USB3 Port Routing Mask register that indicates the ports * can be changed from OS, and turn on by USB3 Port SS Enable register. - */ + */ val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3PRM); DPRINTF(("%s: USB3PRM / USB3.0 configurable ports: 0x%08x\n", psc->sc.sc_bus.bdev.dv_xname, val)); @@ -106,7 +108,7 @@ xhci_pci_port_route(struct xhci_pci_softc *psc) psc->sc.sc_bus.bdev.dv_xname, val)); /* - * Check USB2 Port Routing Mask register that indicates the USB2.0 + * Check USB2 Port Routing Mask register that indicates the USB2.0 * ports to be controlled by xHCI HC, and switch them to xHCI HC. */ val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PRM); @@ -142,6 +144,7 @@ xhci_pci_attach(struct device *parent, struct device *self, void *aux) psc->sc_pc = pa->pa_pc; psc->sc_tag = pa->pa_tag; + psc->sc_id = pa->pa_id; psc->sc.sc_bus.dmatag = pa->pa_dmat; /* Handle quirks */ @@ -189,16 +192,8 @@ xhci_pci_attach(struct device *parent, struct device *self, void *aux) goto disestablish_ret; } - switch (PCI_VENDOR(pa->pa_id)) { - case PCI_VENDOR_INTEL: - switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_INTEL_8SERIES_XHCI: - case PCI_PRODUCT_INTEL_8SERIES_LP_XHCI: - case PCI_PRODUCT_INTEL_7SERIES_XHCI: - xhci_pci_port_route(psc); - break; - } - } + if (PCI_VENDOR(psc->sc_id) == PCI_VENDOR_INTEL) + xhci_pci_port_route(psc); /* Attach usb device. */ config_found(self, &psc->sc.sc_bus, usbctlprint); @@ -234,6 +229,24 @@ xhci_pci_detach(struct device *self, int flags) return (0); } +int +xhci_pci_activate(struct device *self, int act) +{ + struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; + + switch (act) { + case DVACT_RESUME: + if (PCI_VENDOR(psc->sc_id) == PCI_VENDOR_INTEL) + xhci_pci_port_route(psc); + break; + default: + break; + } + + return (xhci_activate(self, act)); +} + + void xhci_pci_takecontroller(struct xhci_pci_softc *psc, int silent) { |