NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/49076: USB 3.0 devices are not attached to xhci hubs
The following reply was made to PR kern/49076; it has been noted by GNATS.
From: Ryo ONODERA <ryo_on%yk.rim.or.jp@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc:
Subject: Re: kern/49076: USB 3.0 devices are not attached to xhci hubs
Date: Sun, 31 Aug 2014 20:35:52 +0900 (JST)
Hi,
Here is my trial to handle quirks like AHCI
and taking controller function that enable device detection on
Lenovo ThinkStation E32's Intel Lynx Point chipset xHC from OpenBSD.
http://www.netbsd.org/~ryoon/20140831-xhci_for_intel_lynx_point_and_lp.diff
diff --git a/pci/xhci_pci.c b/pci/xhci_pci.c
index e4cf9ec..fb2a9ab 100644
--- a/pci/xhci_pci.c
+++ b/pci/xhci_pci.c
@@ -1,4 +1,5 @@
/* $NetBSD: xhci_pci.c,v 1.3 2014/03/29 19:28:25 christos Exp $ */
+/* OpenBSD: xhci_pci.c,v 1.4 2014/07/12 17:38:51 yuo Exp */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -43,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: xhci_pci.c,v 1.3 2014/03/29
19:28:25 christos Exp $"
#include <sys/bus.h>
#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -52,6 +54,17 @@ __KERNEL_RCSID(0, "$NetBSD: xhci_pci.c,v 1.3 2014/03/29
19:28:25 christos Exp $"
#include <dev/usb/xhcireg.h>
#include <dev/usb/xhcivar.h>
+struct xhci_pci_quirk {
+ pci_vendor_id_t vendor;
+ pci_product_id_t product;
+ int quirks;
+};
+
+static const struct xhci_pci_quirk xhci_pci_quirks[] = {
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_CORE4G_M_XHCI,
+ XHCI_QUIRK_FORCE_INTR },
+};
+
struct xhci_pci_softc {
struct xhci_softc sc_xhci;
pci_chipset_tag_t sc_pc;
@@ -59,6 +72,18 @@ struct xhci_pci_softc {
};
static int
+xhci_pci_has_quirk(pci_vendor_id_t vendor, pci_product_id_t product)
+{
+ int i;
+
+ for (i = 0; i < __arraycount(xhci_pci_quirks); i++)
+ if (vendor == xhci_pci_quirks[i].vendor &&
+ product == xhci_pci_quirks[i].product)
+ return xhci_pci_quirks[i].quirks;
+ return 0;
+}
+
+static int
xhci_pci_match(device_t parent, cfdata_t match, void *aux)
{
struct pci_attach_args *pa = (struct pci_attach_args *) aux;
@@ -71,6 +96,76 @@ xhci_pci_match(device_t parent, cfdata_t match, void *aux)
return 0;
}
+static int
+xhci_pci_port_route(struct xhci_pci_softc *psc)
+{
+ struct xhci_softc * const sc = &psc->sc_xhci;
+
+ 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);
+ aprint_debug_dev(sc->sc_dev,
+ "USB3PRM / USB3.0 configurable ports: 0x%08x\n", val);
+
+ pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3_PSSEN, val);
+ val = pci_conf_read(psc->sc_pc, psc->sc_tag,PCI_XHCI_INTEL_USB3_PSSEN);
+ aprint_debug_dev(sc->sc_dev,
+ "USB3_PSSEN / Enabled USB3.0 ports under xHCI: 0x%08x\n", val);
+
+ /*
+ * 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_USB2PRM);
+ aprint_debug_dev(sc->sc_dev,
+ "XUSB2PRM / USB2.0 ports can switch from EHCI to xHCI:"
+ "0x%08x\n", val);
+ pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR, val);
+ val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR);
+ aprint_debug_dev(sc->sc_dev,
+ "XUSB2PR / USB2.0 ports under xHCI: 0x%08x\n", val);
+
+ return 0;
+}
+
+static void
+xhci_pci_takecontroller(struct xhci_pci_softc *psc, int silent)
+{
+ uint32_t cparams, xecp, eec;
+ uint8_t bios_sem;
+ int i;
+
+ cparams = xhci_read_4(&psc->sc_xhci, XHCI_HCCPARAMS);
+ eec = -1;
+
+ /* Synchronise with the BIOS if it owns the controller. */
+ for (xecp = XHCI_HCC_XECP(cparams) << 2; xecp != 0;
+ xecp = XHCI_XECP_NEXT(eec) << 2) {
+ eec = xhci_read_4(&psc->sc_xhci, xecp);
+ if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY)
+ continue;
+ bios_sem = xhci_read_1(&psc->sc_xhci,
+ xecp + XHCI_XECP_BIOS_SEM);
+ if (bios_sem) {
+ xhci_write_1(&psc->sc_xhci, xecp + XHCI_XECP_OS_SEM, 1);
+ aprint_debug("waiting for BIOS to give up control\n");
+ for (i = 0; i < 5000; i++) {
+ bios_sem = xhci_read_1(&psc->sc_xhci, xecp +
+ XHCI_XECP_BIOS_SEM);
+ if (bios_sem == 0)
+ break;
+ DELAY(1000);
+ }
+ if (silent == 0 && bios_sem)
+ printf("timed out waiting for BIOS\n");
+ }
+ }
+}
+
static void
xhci_pci_attach(device_t parent, device_t self, void *aux)
{
@@ -92,6 +187,10 @@ xhci_pci_attach(device_t parent, device_t self, void *aux)
pci_aprint_devinfo(pa, "USB Controller");
+ /* Check for quirks */
+ sc->sc_xhci_quirks = xhci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
+ PCI_PRODUCT(pa->pa_id));
+
/* check if memory space access is enabled */
csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
#ifdef DEBUG
@@ -165,12 +264,24 @@ xhci_pci_attach(device_t parent, device_t self, void
*aux)
"vendor 0x%04x", PCI_VENDOR(pa->pa_id));
#endif
+ /* Take host controller from BIOS */
+ xhci_pci_takecontroller(psc, 0);
+
err = xhci_init(sc);
if (err) {
aprint_error_dev(self, "init failed, error=%d\n", err);
goto fail;
}
+ /* Intel chipset requires SuperSpeed enable and USB2 port routing */
+ switch (PCI_VENDOR(pa->pa_id)) {
+ case PCI_VENDOR_INTEL:
+ xhci_pci_port_route(psc);
+ break;
+ default:
+ break;
+ }
+
if (!pmf_device_register1(self, xhci_suspend, xhci_resume,
xhci_shutdown))
aprint_error_dev(self, "couldn't establish power handler\n");
diff --git a/usb/xhci.c b/usb/xhci.c
index c13de65..c1cdc07 100644
--- a/usb/xhci.c
+++ b/usb/xhci.c
@@ -209,12 +209,25 @@ static const struct usbd_pipe_methods
xhci_device_intr_methods = {
.done = xhci_device_intr_done,
};
-static inline uint32_t
+inline uint32_t
+xhci_read_1(const struct xhci_softc * const sc, bus_size_t offset)
+{
+ return bus_space_read_1(sc->sc_iot, sc->sc_ioh, offset);
+}
+
+inline uint32_t
xhci_read_4(const struct xhci_softc * const sc, bus_size_t offset)
{
return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
}
+inline void
+xhci_write_1(const struct xhci_softc * const sc, bus_size_t offset,
+ uint32_t value)
+{
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, offset, value);
+}
+
#if 0 /* unused */
static inline void
xhci_write_4(const struct xhci_softc * const sc, bus_size_t offset,
@@ -899,9 +912,13 @@ xhci_intr1(struct xhci_softc * const sc)
iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
//device_printf(sc->sc_dev, "%s IMAN0 %08x\n", __func__, iman);
- if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
- return 0;
+
+ if (!(sc->sc_xhci_quirks & XHCI_QUIRK_FORCE_INTR)) {
+ if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
+ return 0;
+ }
}
+
xhci_rt_write_4(sc, XHCI_IMAN(0), iman);
iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
//device_printf(sc->sc_dev, "%s IMAN0 %08x\n", __func__, iman);
diff --git a/usb/xhcireg.h b/usb/xhcireg.h
index 480b93f..af9f224 100644
--- a/usb/xhcireg.h
+++ b/usb/xhcireg.h
@@ -38,6 +38,11 @@
#define PCI_USBREV_3_0 0x30 /* USB 3.0 */
#define PCI_XHCI_FLADJ 0x61 /* RW frame length adjust */
+#define PCI_XHCI_INTEL_XUSB2PR 0xD0 /* Intel USB2 Port Routing */
+#define PCI_XHCI_INTEL_USB2PRM 0xD4 /* Intel USB2 Port Routing Mask
*/
+#define PCI_XHCI_INTEL_USB3_PSSEN 0xD8 /* Intel USB3 Port SuperSpeed
Enable */
+#define PCI_XHCI_INTEL_USB3PRM 0xDC /* Intel USB3 Port Routing Mask
*/
+
/* XHCI capability registers */
#define XHCI_CAPLENGTH 0x00 /* RO capability */
#define XHCI_CAP_CAPLENGTH(x) ((x) & 0xFF)
@@ -188,10 +193,8 @@
/* XHCI legacy support */
#define XHCI_XECP_ID(x) ((x) & 0xFF)
#define XHCI_XECP_NEXT(x) (((x) >> 8) & 0xFF)
-#if 0
#define XHCI_XECP_BIOS_SEM 0x0002
#define XHCI_XECP_OS_SEM 0x0003
-#endif
/* XHCI capability ID's */
#define XHCI_ID_USB_LEGACY 0x0001
diff --git a/usb/xhcivar.h b/usb/xhcivar.h
index 7ddbaa2..8b5169f 100644
--- a/usb/xhcivar.h
+++ b/usb/xhcivar.h
@@ -114,8 +114,14 @@ struct xhci_softc {
uint8_t sc_addr;
uint8_t sc_conf;
+
+ int sc_xhci_quirks;
+#define XHCI_QUIRK_FORCE_INTR __BIT(0) /* force interrupt reading */
};
+uint32_t xhci_read_1(const struct xhci_softc * const, bus_size_t);
+uint32_t xhci_read_4(const struct xhci_softc * const, bus_size_t);
+void xhci_write_1(const struct xhci_softc * const, bus_size_t, uint32_t);
int xhci_init(struct xhci_softc *);
int xhci_intr(void *);
int xhci_detach(struct xhci_softc *, int);
--
Ryo ONODERA // ryo_on%yk.rim.or.jp@localhost
PGP fingerprint = 82A2 DC91 76E0 A10A 8ABB FD1B F404 27FA C7D1 15F3
Home |
Main Index |
Thread Index |
Old Index