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