Hello,

Here are some xhci patches for nick-nhusb branch.


nh-xhci-cos.diff
        + Add comments. Some cosmetic changes.
nh-xhci-clearhalt.diff
        + Don't abuse pipe->up_async_task for
          xhci_clear_endpoint_stall_async_task.
          Add member struct usb_task xp_async_task to struct xhci_pipe.
nh-xhci-slot.diff
        + Fix slot leak when address_device fails.
        + Eliminate device_xname().
nh-xhci-chkxfer.diff
        + Add some sanity checks for xfer.
nh-xhci-trberr.diff
        + Rewrite if-else-if chains with switch-case.
nh-xhci-ss.diff
        + Eliminate confusing UPS_SUPER_SPEED flag and introduce
          UPS_OTHER_SPEED flag that indicates ud_speed of device is
          super speed (or more).
          uhub shall set this flag if ud_speed is super speed (or more).
        + Add the macro that checks ud_speed is super speed.
          The codes shall use this macro to check ud_speed is super speed.
        + Add speed type conversion functions.
        + Include port link status in port_status if port is super speed.
nh-xhci-quirks.diff
        + Add patch for intel chips quirk from ryoon@ in
          https://mail-index.netbsd.org/netbsd-bugs/2014/08/31/msg038109.html
          slightly modified to set quirks before calling xhci_init.
        + Set special IMOD value and route ports to xhci for intel chips.


--
t-hash

--- src/sys/dev/usb/xhci.c.orig 2015-04-07 17:55:43.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-05-25 20:33:49.000000000 +0900
@@ -26,6 +26,15 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+ * USB rev 3.1 specification
+ *  http://www.usb.org/developers/docs/usb_31_040315.zip
+ * USB rev 2.0 specification
+ *  http://www.usb.org/developers/docs/usb20_docs/usb_20_031815.zip
+ * xHCI rev 1.1 specification
+ *  
http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf
+ */
+
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.20 2015/04/07 06:52:03 skrll Exp 
$");
 
@@ -1374,7 +1383,7 @@ xhci_stop_endpoint(struct usbd_pipe *pip
 /*
  * Set TR Dequeue Pointer.
  * xCHI 1.1  4.6.10  6.4.3.9
- * Purge all of transfer requests in ring.
+ * Purge all of transfer requests on ring.
  * EPSTATE of endpoint must be ERROR or STOPPED, or CONTEXT_STATE error.
  */
 static usbd_status
@@ -1578,7 +1587,13 @@ xhci_abort_xfer(struct usbd_xfer *xfer, 
 }
 
 #if 1 /* XXX experimental */
-/* issue reset_ep and set_dequeue in thread context */
+/*
+ * Recover STALLed endpoint.
+ * xHCI 1.1 sect 4.10.2.1
+ * Issue RESET_EP to recover halt condition and SET_TR_DEQUEUE to remove
+ * all transfers on transfer ring.
+ * These are done in thread context asynchronously.
+ */
 static void
 xhci_clear_endpoint_stall_async_task(void *cookie)
 {
@@ -1624,7 +1639,6 @@ xhci_clear_endpoint_stall_async(struct u
 }
 
 #endif /* XXX experimental */
-
 /*
  * Notify roothub port status/change to uhub_intr.
  */
@@ -2765,8 +2779,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                break;
        case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
                break;
-       case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
-       {
+       case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): {
                int optval = (index >> 8) & 0xff;
                index &= 0xff;
                if (index < 1 || index > sc->sc_maxports) {




--- src/sys/dev/usb/xhci.c.orig 2015-05-25 20:33:49.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-05-25 20:48:51.000000000 +0900
@@ -116,6 +116,7 @@ fail:
 
 struct xhci_pipe {
        struct usbd_pipe xp_pipe;
+       struct usb_task xp_async_task;
 };
 
 #define XHCI_COMMAND_RING_TRBS 256
@@ -1620,6 +1621,7 @@ static usbd_status
 xhci_clear_endpoint_stall_async(struct usbd_xfer *xfer)
 {
        struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+       struct xhci_pipe * const xp = (struct xhci_pipe *)xfer->ux_pipe;
 
        XHCIHIST_FUNC(); XHCIHIST_CALLED();
        DPRINTFN(4, "xfer %p", xfer, 0, 0, 0);
@@ -1628,11 +1630,9 @@ xhci_clear_endpoint_stall_async(struct u
                return USBD_IOERROR;
        }
 
-       /* XXX never use up_async_task for incompatible type of function */
-       usb_init_task(&xfer->ux_pipe->up_async_task,
+       usb_init_task(&xp->xp_async_task,
            xhci_clear_endpoint_stall_async_task, xfer, USB_TASKQ_MPSAFE);
-       usb_add_task(xfer->ux_pipe->up_dev, &xfer->ux_pipe->up_async_task,
-           USB_TASKQ_HC);
+       usb_add_task(xfer->ux_pipe->up_dev, &xp->xp_async_task, USB_TASKQ_HC);
        DPRINTFN(4, "ends", 0, 0, 0, 0);
 
        return USBD_NORMAL_COMPLETION;




--- src/sys/dev/usb/xhci.c.orig 2015-05-25 20:48:51.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-05-25 21:00:05.000000000 +0900
@@ -2064,6 +2064,14 @@ xhci_new_device(device_t parent, struct 
                err = xhci_init_slot(dev, slot, route, rhport);
                if (err) {
                        dev->ud_hcpriv = NULL;
+                       /*
+                        * We have to disable_slot here because
+                        * xs->xs_idx == 0 when xhci_init_slot fails,
+                        * in that case usbd_remove_dev won't work.
+                        */
+                       mutex_enter(&sc->sc_lock);
+                       xhci_disable_slot(sc, slot);
+                       mutex_exit(&sc->sc_lock);
                        goto bad;
                }
 
@@ -2087,9 +2095,9 @@ xhci_new_device(device_t parent, struct 
                /* 4.8.2.1 */
                if (speed == USB_SPEED_SUPER) {
                        if (dd->bMaxPacketSize != 9) {
-                               printf("%s: invalid mps 2^%u for SS ep0,"
+                               printf("xhci%d: invalid mps 2^%u for SS ep0,"
                                    " using 512\n",
-                                   device_xname(sc->sc_dev),
+                                   device_unit(sc->sc_dev),
                                    dd->bMaxPacketSize);
                                dd->bMaxPacketSize = 9;
                        }




--- src/sys/dev/usb/xhci.c.orig 2015-05-25 21:00:05.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-05-25 21:16:40.000000000 +0900
@@ -1701,7 +1701,10 @@ xhci_handle_event(struct xhci_softc * co
                xs = &sc->sc_slots[slot];
                xr = &xs->xs_ep[dci].xe_tr;
                /* sanity check */
-               KASSERT(xs->xs_idx != 0);
+               if (xs->xs_idx == 0 || xs->xs_idx >= sc->sc_maxslots) {
+                       DPRINTFN(1, "invalid slot %u", xs->xs_idx, 0, 0, 0);
+                       break;
+               }
 
                if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
                        bus_addr_t trbp = xhci_ring_trbp(xr, 0);
@@ -1721,8 +1724,24 @@ xhci_handle_event(struct xhci_softc * co
                } else {
                        xx = (void *)(uintptr_t)(trb_0 & ~0x3);
                }
+               /* XXX this may not happen */
+               if (xx == NULL) {
+                       DPRINTFN(1, "xfer done: xx is NULL", 0, 0, 0, 0);
+                       break;
+               }
                xfer = &xx->xx_xfer;
+               /* XXX this may happen when detaching */
+               if (xfer == NULL) {
+                       DPRINTFN(1, "xfer done: xfer is NULL", 0, 0, 0, 0);
+                       break;
+               }
                DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
+               /* XXX I dunno why this happens */
+               if (!xfer->ux_pipe->up_repeat &&
+                   SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) {
+                       DPRINTFN(1, "xfer done: xfer not started", 0, 0, 0, 0);
+                       break;
+               }
 
                if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
                        DPRINTFN(14, "transfer event data: "




--- src/sys/dev/usb/xhci.c.orig 2015-05-25 21:16:40.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-05-25 21:23:00.000000000 +0900
@@ -1753,17 +1753,19 @@ xhci_handle_event(struct xhci_softc * co
                        }
                }
 
-               if (trberr == XHCI_TRB_ERROR_SUCCESS ||
-                   trberr == XHCI_TRB_ERROR_SHORT_PKT) {
+               switch (trberr) {
+               case XHCI_TRB_ERROR_SHORT_PKT:
+               case XHCI_TRB_ERROR_SUCCESS:
                        xfer->ux_actlen =
                            xfer->ux_length - XHCI_TRB_2_REM_GET(trb_2);
                        err = USBD_NORMAL_COMPLETION;
-               } else if (trberr == XHCI_TRB_ERROR_STALL ||
-                          trberr == XHCI_TRB_ERROR_BABBLE) {
-                       err = USBD_STALLED;
-                       xr->is_halted = true;
+                       break;
+               case XHCI_TRB_ERROR_STALL:
+               case XHCI_TRB_ERROR_BABBLE:
                        DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
                            trberr, slot, dci, 0);
+                       xr->is_halted = true;
+                       err = USBD_STALLED;
 #if 1 /* XXX experimental */
                        /*
                         * Stalled endpoints can be recoverd by issuing
@@ -1780,12 +1782,22 @@ xhci_handle_event(struct xhci_softc * co
                         */
                        xfer->ux_status = err;
                        xhci_clear_endpoint_stall_async(xfer);
+                       return;
+#else
                        break;
 #endif
-               } else {
+               case XHCI_TRB_ERROR_CMD_ABORTED:
+               case XHCI_TRB_ERROR_STOPPED:
+                       err = USBD_CANCELLED;
+                       break;
+               case XHCI_TRB_ERROR_NO_SLOTS:
+                       err = USBD_NO_ADDR;
+                       break;
+               default:
                        DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
                            trberr, slot, dci, 0);
                        err = USBD_IOERROR;
+                       break;
                }
                xfer->ux_status = err;
 




--- src/sys/dev/usb/xhci.c.orig 2015-05-25 21:23:00.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-05-25 21:33:48.000000000 +0900
@@ -1010,31 +1010,52 @@ xhci_intr1(struct xhci_softc * const sc)
  *     ioctl interface uses these values too.
  * port_status speed
  *     definition: UPS_*_SPEED in usb.h
- *     They are used in usb_port_status_t.
- *     Some 3.0 values overlap with 2.0 values.
+ *     They are used in usb_port_status_t and valid only for USB 2.0.
+ *     Speed value is 0 for Super Speed or more.
+ *     Note that some 3.0 values overlap with 2.0 values.
  *     (e.g. 0x200 means UPS_POER_POWER_SS in SS and
  *                 means UPS_LOW_SPEED in HS.)
  *     port status sent from hub also uses these values.
- *     (but I've never seen UPS_SUPER_SPEED in port_status from hub.)
  * xspeed:
  *     definition: Protocol Speed ID (PSI) (xHCI 1.1 7.2.1)
  *     They are used in only slot context and PORTSC reg of xhci.
- *     The difference between usbdi speed and them are that
- *     FS and LS values are swapped.
+ *     The difference between usbdi speed and xspeed is
+ *     that FS and LS values are swapped.
  */
 
+/* convert usbdi speed to xspeed */
 static int
 xhci_speed2xspeed(int speed)
 {
        switch (speed) {
        case USB_SPEED_LOW:     return 2;
        case USB_SPEED_FULL:    return 1;
-       case USB_SPEED_HIGH:    return 3;
-       case USB_SPEED_SUPER:   return 4;
-       default:
-               break;
+       default:                return speed;
+       }
+}
+
+/* convert xspeed to usbdi speed */
+static int
+xhci_xspeed2speed(int xspeed)
+{
+       switch (xspeed) {
+       case 1: return USB_SPEED_FULL;
+       case 2: return USB_SPEED_LOW;
+       default: return xspeed;
+       }
+}
+
+/* convert xspeed to port status speed */
+static int
+xhci_xspeed2psspeed(int xspeed)
+{
+       switch (xspeed) {
+       case 0: return 0;
+       case 1: return UPS_FULL_SPEED;
+       case 2: return UPS_LOW_SPEED;
+       case 3: return UPS_HIGH_SPEED;
+       default: return UPS_OTHER_SPEED;
        }
-       return 0;
 }
 
 /* construct slot context */
@@ -1185,7 +1206,7 @@ xhci_configure_endpoint(struct usbd_pipe
        if (xfertype != UE_ISOCHRONOUS)
                cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
 
-       if (speed == USB_SPEED_SUPER) {
+       if (USB_IS_SS(speed)) {
                usbd_desc_iter_t iter;
                const usb_cdc_descriptor_t *cdcd;
                const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
@@ -1239,7 +1260,7 @@ xhci_configure_endpoint(struct usbd_pipe
                } else {
                        ival = ival > 15 ? 15 : ival;
                }
-               if (speed == USB_SPEED_SUPER) {
+               if (USB_IS_SS(speed)) {
                        if (maxb > 0)
                                mps = 1024;
                } else {
@@ -1252,7 +1273,7 @@ xhci_configure_endpoint(struct usbd_pipe
                    );
                break;
        case UE_CONTROL:
-               if (speed == USB_SPEED_SUPER)
+               if (USB_IS_SS(speed))
                        mps = 512;
                else
                        mps = mps ? mps : 8;
@@ -1267,7 +1288,7 @@ xhci_configure_endpoint(struct usbd_pipe
                } else {
                        ival = ival > 15 ? 15 : ival;
                }
-               if (speed == USB_SPEED_SUPER) {
+               if (USB_IS_SS(speed)) {
                        mps = 1024;
                } else {
                        mps = mps ? mps : 1024;
@@ -1277,7 +1298,7 @@ xhci_configure_endpoint(struct usbd_pipe
                break;
 #endif
        default:
-               if (speed == USB_SPEED_SUPER)
+               if (USB_IS_SS(speed))
                        mps = 1024;
                else
                        mps = mps ? mps : 512;
@@ -1990,10 +2011,10 @@ xhci_new_device(device_t parent, struct 
        dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
        dev->ud_ep0desc.bmAttributes = UE_CONTROL;
        /* 4.3,  4.8.2.1 */
-       switch (speed) {
-       case USB_SPEED_SUPER:
+       if (USB_IS_SS(speed)) {
                USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET);
-               break;
+       } else
+       switch (speed) {
        case USB_SPEED_FULL:
                /* XXX using 64 as initial mps of ep0 in FS */
        case USB_SPEED_HIGH:
@@ -2124,7 +2145,7 @@ xhci_new_device(device_t parent, struct 
                if (err)
                        goto bad;
                /* 4.8.2.1 */
-               if (speed == USB_SPEED_SUPER) {
+               if (USB_IS_SS(speed)) {
                        if (dd->bMaxPacketSize != 9) {
                                printf("xhci%d: invalid mps 2^%u for SS ep0,"
                                    " using 512\n",
@@ -2771,34 +2792,20 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                }
                v = xhci_op_read_4(sc, XHCI_PORTSC(index));
                DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
-               switch (XHCI_PS_SPEED_GET(v)) {
-               case 1:
-                       i = UPS_FULL_SPEED;
-                       break;
-               case 2:
-                       i = UPS_LOW_SPEED;
-                       break;
-               case 3:
-                       i = UPS_HIGH_SPEED;
-                       break;
-               case 4:
-                       i = UPS_SUPER_SPEED;
-                       break;
-               default:
-                       i = 0;
-                       break;
-               }
+               i = xhci_xspeed2psspeed(XHCI_PS_SPEED_GET(v));
                if (v & XHCI_PS_CCS)    i |= UPS_CURRENT_CONNECT_STATUS;
                if (v & XHCI_PS_PED)    i |= UPS_PORT_ENABLED;
                if (v & XHCI_PS_OCA)    i |= UPS_OVERCURRENT_INDICATOR;
                //if (v & XHCI_PS_SUSP) i |= UPS_SUSPEND;
                if (v & XHCI_PS_PR)     i |= UPS_RESET;
                if (v & XHCI_PS_PP) {
-                       if (i & UPS_SUPER_SPEED)
+                       if (i & UPS_OTHER_SPEED)
                                        i |= UPS_PORT_POWER_SS;
                        else
                                        i |= UPS_PORT_POWER;
                }
+               if (i & UPS_OTHER_SPEED)
+                       i |= UPS_PORT_LS_SET(XHCI_PS_PLS_GET(v));
                USETW(ps.wPortStatus, i);
                i = 0;
                if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
@@ -2858,7 +2865,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                        xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
                        break;
                case UHF_PORT_U1_TIMEOUT:
-                       if (XHCI_PS_SPEED_GET(v) != 4) {
+                       if (USB_IS_SS(xhci_xspeed2speed(XHCI_PS_SPEED_GET(v)))){
                                return -1;
                        }
                        port = XHCI_PORTPMSC(index);
@@ -2868,7 +2875,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
                        xhci_op_write_4(sc, port, v);
                        break;
                case UHF_PORT_U2_TIMEOUT:
-                       if (XHCI_PS_SPEED_GET(v) != 4) {
+                       if (USB_IS_SS(xhci_xspeed2speed(XHCI_PS_SPEED_GET(v)))){
                                return -1;
                        }
                        port = XHCI_PORTPMSC(index);
--- src/sys/dev/usb/usb.h.orig  2015-04-07 01:29:01.000000000 +0900
+++ src/sys/dev/usb/usb.h       2015-05-14 08:05:42.000000000 +0900
@@ -561,7 +561,9 @@
 #define UPS_OVERCURRENT_INDICATOR      0x0008
 #define UPS_RESET                      0x0010
 #define UPS_PORT_L1                    0x0020
-#define UPS_PORT_LS_GET(x)             __SHIFTOUT(x, __BITS(8,5))
+#define UPS_PORT_LS_MASK               __BITS(8,5)
+#define UPS_PORT_LS_GET(x)             __SHIFTOUT(x, UPS_PORT_LS_MASK)
+#define UPS_PORT_LS_SET(x)             __SHIFTIN(x, UPS_PORT_LS_MASK)
 #define UPS_PORT_LS_U0                 0x00
 #define UPS_PORT_LS_U1                 0x01
 #define UPS_PORT_LS_U2                 0x02
@@ -580,9 +582,9 @@
 #define UPS_FULL_SPEED                 0x0000  /* for completeness */
 #define UPS_LOW_SPEED                  0x0200
 #define UPS_HIGH_SPEED                 0x0400
-#define UPS_SUPER_SPEED                        0x0800
 #define UPS_PORT_TEST                  0x0800
 #define UPS_PORT_INDICATOR             0x1000
+#define UPS_OTHER_SPEED                        0x2000  /* currently NetBSD 
specific */
        uWord           wPortChange;
 #define UPS_C_CONNECT_STATUS           0x0001
 #define UPS_C_PORT_ENABLED             0x0002
@@ -852,6 +854,7 @@
 #define USB_SPEED_FULL 2
 #define USB_SPEED_HIGH 3
 #define USB_SPEED_SUPER 4
+#define USB_IS_SS(X) ((X) == USB_SPEED_SUPER)
        int             udi_power;      /* power consumption in mA, 0 if 
selfpowered */
        int             udi_nports;
        char            udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];




--- src/sys/dev/pci/xhci_pci.c.orig     2015-04-07 01:28:57.000000000 +0900
+++ src/sys/dev/pci/xhci_pci.c  2015-05-24 00:23:37.000000000 +0900
@@ -1,4 +1,5 @@
 /*     $NetBSD: xhci_pci.c,v 1.4.2.2 2015/04/06 12:17:30 skrll 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
 #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
 #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,42 @@ xhci_pci_match(device_t parent, cfdata_t
        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_attach(device_t parent, device_t self, void *aux)
 {
@@ -92,6 +153,10 @@ xhci_pci_attach(device_t parent, device_
 
        pci_aprint_devinfo(pa, "USB Controller");
 
+       /* Check for quirks */
+       sc->sc_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
@@ -122,9 +187,9 @@ xhci_pci_attach(device_t parent, device_
        psc->sc_pc = pc;
        psc->sc_tag = tag;
 
-       hccparams = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0x10);
+       hccparams = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XHCI_HCCPARAMS);
 
-       if (pci_dma64_available(pa) && ((hccparams&1)==1))
+       if (pci_dma64_available(pa) && (XHCI_HCC_AC64(hccparams) != 0))
                sc->sc_bus.ub_dmatag = pa->pa_dmat64;
        else
                sc->sc_bus.ub_dmatag = pa->pa_dmat;
@@ -160,12 +225,24 @@ xhci_pci_attach(device_t parent, device_
            sc->sc_id_vendor);
 #endif
 
+       /* Intel chipset requires SuperSpeed enable and USB2 port routing */
+       switch (PCI_VENDOR(pa->pa_id)) {
+       case PCI_VENDOR_INTEL:
+               sc->sc_quirks |= XHCI_QUIRK_INTEL;
+               break;
+       default:
+               break;
+       }
+
        err = xhci_init(sc);
        if (err) {
                aprint_error_dev(self, "init failed, error=%d\n", err);
                goto fail;
        }
 
+       if ((sc->sc_quirks & XHCI_QUIRK_INTEL) != 0)
+               xhci_pci_port_route(psc);
+
        if (!pmf_device_register1(self, xhci_suspend, xhci_resume,
                                  xhci_shutdown))
                aprint_error_dev(self, "couldn't establish power handler\n");
--- src/sys/dev/usb/xhci.c.orig 2015-05-25 21:33:48.000000000 +0900
+++ src/sys/dev/usb/xhci.c      2015-05-25 21:37:09.000000000 +0900
@@ -910,13 +910,13 @@ xhci_init(struct xhci_softc *sc)
 #endif
 
        xhci_rt_write_4(sc, XHCI_IMAN(0), XHCI_IMAN_INTR_ENA);
-#ifdef XHCI_QUIRK_INTEL
        if ((sc->sc_quirks & XHCI_QUIRK_INTEL) != 0)
                /* Intel xhci needs interrupt rate moderated. */
                xhci_rt_write_4(sc, XHCI_IMOD(0), XHCI_IMOD_DEFAULT_LP);
        else
-#endif /* XHCI_QUIRK_INTEL */
                xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
+       aprint_debug_dev(sc->sc_dev, "setting IMOD %u\n",
+           xhci_rt_read_4(sc, XHCI_IMOD(0)));
 
        xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
        aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
@@ -977,7 +977,6 @@ xhci_intr1(struct xhci_softc * const sc)
 
        iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
        DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);
-#ifdef XHCI_QUIRK_FORCE_INTR
 
        if (!(sc->sc_quirks & XHCI_QUIRK_FORCE_INTR)) {
                if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
@@ -985,11 +984,6 @@ xhci_intr1(struct xhci_softc * const sc)
                }
        }
 
-#else
-       if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
-               return 0;
-       }
-#endif /* XHCI_QUIRK_FORCE_INTR */
        xhci_rt_write_4(sc, XHCI_IMAN(0), iman);
        iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
        DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);




Reply via email to