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