Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/nick-nhusb]: src/sys/dev/usb USB 3.0 snapshot from Takahiro HAYASHI



details:   https://anonhg.NetBSD.org/src/rev/041a5b91b13e
branches:  nick-nhusb
changeset: 334199:041a5b91b13e
user:      skrll <skrll%NetBSD.org@localhost>
date:      Tue Apr 07 06:49:10 2015 +0000

description:
USB 3.0 snapshot from Takahiro HAYASHI

diffstat:

 sys/dev/usb/xhci.c |  928 ++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 749 insertions(+), 179 deletions(-)

diffs (truncated from 1460 to 300 lines):

diff -r 3cbc99a35b81 -r 041a5b91b13e sys/dev/usb/xhci.c
--- a/sys/dev/usb/xhci.c        Tue Apr 07 06:23:10 2015 +0000
+++ b/sys/dev/usb/xhci.c        Tue Apr 07 06:49:10 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: xhci.c,v 1.28.2.18 2015/04/06 19:28:40 skrll Exp $     */
+/*     $NetBSD: xhci.c,v 1.28.2.19 2015/04/07 06:49:10 skrll Exp $     */
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.18 2015/04/06 19:28:40 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.19 2015/04/07 06:49:10 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -50,6 +50,7 @@
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdivar.h>
+#include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbhist.h>
 #include <dev/usb/usb_mem.h>
 #include <dev/usb/usb_quirks.h>
@@ -126,18 +127,22 @@
     void *, int);
 
 static usbd_status xhci_configure_endpoint(struct usbd_pipe *);
-static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
+//static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
 static usbd_status xhci_reset_endpoint(struct usbd_pipe *);
-//static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
+static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
 
 static usbd_status xhci_set_dequeue(struct usbd_pipe *);
 
 static usbd_status xhci_do_command(struct xhci_softc * const,
     struct xhci_trb * const, int);
-static usbd_status xhci_init_slot(struct xhci_softc * const, uint32_t,
-    int, int, int, int);
+static usbd_status xhci_do_command1(struct xhci_softc * const,
+    struct xhci_trb * const, int, int);
+static usbd_status xhci_do_command_locked(struct xhci_softc * const,
+    struct xhci_trb * const, int);
+static usbd_status xhci_init_slot(struct usbd_device *, uint32_t, int, int);
 static usbd_status xhci_enable_slot(struct xhci_softc * const,
     uint8_t * const);
+static usbd_status xhci_disable_slot(struct xhci_softc * const, uint8_t);
 static usbd_status xhci_address_device(struct xhci_softc * const,
     uint64_t, uint8_t, bool);
 static usbd_status xhci_update_ep0_mps(struct xhci_softc * const,
@@ -228,11 +233,24 @@
 };
 
 static 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);
+}
+
+static 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);
 }
 
+static 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,
@@ -374,7 +392,7 @@
 static inline uint8_t
 xhci_ep_get_type(usb_endpoint_descriptor_t * const ed)
 {
-       u_int eptype;
+       u_int eptype = 0;
 
        switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
        case UE_CONTROL:
@@ -517,6 +535,7 @@
 
        mutex_destroy(&sc->sc_lock);
        mutex_destroy(&sc->sc_intr_lock);
+       cv_destroy(&sc->sc_softwake_cv);
 
        pool_cache_destroy(sc->sc_xferpool);
 
@@ -658,6 +677,28 @@
                        }
                        break;
                }
+               case XHCI_ID_USB_LEGACY: {
+                       uint8_t bios_sem;
+
+                       /* Take host controller from BIOS */
+                       bios_sem = xhci_read_1(sc, ecp + XHCI_XECP_BIOS_SEM);
+                       if (bios_sem) {
+                               /* sets xHCI to be owned by OS */
+                               xhci_write_1(sc, ecp + 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(sc, ecp +
+                                           XHCI_XECP_BIOS_SEM);
+                                       if (bios_sem == 0)
+                                               break;
+                                       DELAY(1000);
+                               }
+                               if (bios_sem)
+                                       printf("timed out waiting for BIOS\n");
+                       }
+                       break;
+               }
                default:
                        break;
                }
@@ -732,6 +773,7 @@
        aprint_debug_dev(sc->sc_dev, "sc_pgsz 0x%08x\n", (uint32_t)sc->sc_pgsz);
        aprint_debug_dev(sc->sc_dev, "sc_maxslots 0x%08x\n",
            (uint32_t)sc->sc_maxslots);
+       aprint_debug_dev(sc->sc_dev, "sc_maxports %d\n", sc->sc_maxports);
 
        usbd_status err;
 
@@ -825,6 +867,16 @@
            KM_SLEEP);
 
        cv_init(&sc->sc_command_cv, "xhcicmd");
+       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
+       mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+       cv_init(&sc->sc_softwake_cv, "xhciab");
+
+       sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,
+           "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
+
+       /* Set up the bus struct. */
+       sc->sc_bus.ub_methods = &xhci_bus_methods;
+       sc->sc_bus.ub_pipesize = sizeof(struct xhci_pipe);
 
        struct xhci_erste *erst;
        erst = KERNADDR(&sc->sc_eventst_dma, 0);
@@ -848,23 +900,18 @@
 #endif
 
        xhci_rt_write_4(sc, XHCI_IMAN(0), XHCI_IMAN_INTR_ENA);
-       xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
+#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);
 
        xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
        aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
            xhci_op_read_4(sc, XHCI_USBCMD));
 
-       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
-       mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
-       cv_init(&sc->sc_softwake_cv, "xhciab");
-
-       sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,
-           "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
-
-       /* Set up the bus struct. */
-       sc->sc_bus.ub_methods = &xhci_bus_methods;
-       sc->sc_bus.ub_pipesize = sizeof(struct xhci_pipe);
-
        return USBD_NORMAL_COMPLETION;
 }
 
@@ -920,9 +967,19 @@
 
        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) {
+                       return 0;
+               }
+       }
+
+#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);
@@ -934,6 +991,138 @@
        return 1;
 }
 
+/*
+ * 3 port speed types used in USB stack
+ *
+ * usbdi speed
+ *     definition: USB_SPEED_* in usb.h
+ *     They are used in struct usbd_device in USB stack.
+ *     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.
+ *     (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.
+ */
+
+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;
+       }
+       return 0;
+}
+
+/* construct slot context */
+static void
+xhci_setup_sctx(struct usbd_device *dev, uint32_t *cp)
+{
+       usb_device_descriptor_t * const dd = &dev->ud_ddesc;
+       int speed = dev->ud_speed;
+       int tthubslot, ttportnum;
+       bool ishub;
+       bool usemtt;
+
+       XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+       /* 6.2.2 */
+       /*
+        * tthubslot:
+        *   This is the slot ID of parent HS hub
+        *   if LS/FS device is connected && connected through HS hub.
+        *   This is 0 if device is not LS/FS device ||
+        *   parent hub is not HS hub ||
+        *   attached to root hub.
+        * ttportnum:
+        *   This is the downstream facing port of parent HS hub
+        *   if LS/FS device is connected.
+        *   This is 0 if device is not LS/FS device ||
+        *   parent hub is not HS hub ||
+        *   attached to root hub.
+        */
+       if (dev->ud_myhsport != NULL &&
+           dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
+           (dev->ud_myhub != NULL &&
+            dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
+           (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
+               ttportnum = dev->ud_myhsport->up_portno;
+               /* XXX addr == slot ? */
+               tthubslot = dev->ud_myhsport->up_parent->ud_addr;
+       } else {
+               ttportnum = 0;
+               tthubslot = 0;
+       }
+       DPRINTFN(4, "myhsport %p ttportnum=%d tthubslot=%d",
+           dev->ud_myhsport, ttportnum, tthubslot, 0);
+
+       /* ishub is valid after reading UDESC_DEVICE */
+       ishub = (dd->bDeviceClass == UDCLASS_HUB);
+
+       /* dev->ud_hub is valid after reading UDESC_HUB */
+       if (ishub && dev->ud_hub) {
+               usb_hub_descriptor_t *hd = &dev->ud_hub->uh_hubdesc;
+
+               cp[1] |= htole32(XHCI_SCTX_1_NUM_PORTS_SET(hd->bNbrPorts));
+               cp[2] |= htole32(XHCI_SCTX_2_TT_THINK_TIME_SET(
+                   __SHIFTOUT(UGETW(hd->wHubCharacteristics), UHD_TT_THINK)));
+               DPRINTFN(4, "nports=%d ttt=%d",
+                   hd->bNbrPorts, XHCI_SCTX_2_TT_THINK_TIME_GET(cp[2]), 0, 0);
+       }
+
+#define IS_TTHUB(dd) \
+    ((dd)->bDeviceProtocol == UDPROTO_HSHUBSTT || \
+     (dd)->bDeviceProtocol == UDPROTO_HSHUBMTT)
+



Home | Main Index | Thread Index | Old Index