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 Various improvements from t-hash (updated b...
details: https://anonhg.NetBSD.org/src/rev/1084f7160a60
branches: nick-nhusb
changeset: 334241:1084f7160a60
user: skrll <skrll%NetBSD.org@localhost>
date: Sun Sep 13 09:27:54 2015 +0000
description:
Various improvements from t-hash (updated by me)
+ Improve xhci_configure_endpoint().
+ Split off maxburst and interval calculation.
+ Start interval calculation with 10, not 11.
+ Put correct maxburst value.
+ Split off constructing endpoint context.
+ Improve xhci_event_transfer()
+ Remove case of unlikely completion codes I added.
+ Clear xr_cookies too when xhci_set_dequeue() clears xr_trb.
+ Return USBD_NO_ADDR if xhci_address_device fails with
XHCI_TRB_ERROR_NO_SLOTS.
+ Add aprint_debug xhci capability registers.
+ Add & update comments.
I checked HCCPARAMS1 against version 1.1 of the XHCI specification. Not
sure of previous version formats
diffstat:
sys/dev/usb/xhci.c | 448 +++++++++++++++++++++++++++++--------------------
sys/dev/usb/xhcireg.h | 253 +++++++++++++++------------
2 files changed, 402 insertions(+), 299 deletions(-)
diffs (truncated from 984 to 300 lines):
diff -r dff2c06993b4 -r 1084f7160a60 sys/dev/usb/xhci.c
--- a/sys/dev/usb/xhci.c Sun Sep 13 06:50:09 2015 +0000
+++ b/sys/dev/usb/xhci.c Sun Sep 13 09:27:54 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: xhci.c,v 1.28.2.36 2015/09/13 06:50:09 skrll Exp $ */
+/* $NetBSD: xhci.c,v 1.28.2.37 2015/09/13 09:27:54 skrll Exp $ */
/*
* Copyright (c) 2013 Jonathan A. Kollasch
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.36 2015/09/13 06:50:09 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.37 2015/09/13 09:27:54 skrll Exp $");
#include "opt_usb.h"
@@ -613,12 +613,46 @@
#endif
}
+#define XHCI_HCCPREV1_BITS \
+ "\177\020" /* New bitmask */ \
+ "f\020\020XECP\0" \
+ "f\014\4MAXPSA\0" \
+ "b\013CFC\0" \
+ "b\012SEC\0" \
+ "b\011SBD\0" \
+ "b\010FSE\0" \
+ "b\7NSS\0" \
+ "b\6LTC\0" \
+ "b\5LHRC\0" \
+ "b\4PIND\0" \
+ "b\3PPC\0" \
+ "b\2CZC\0" \
+ "b\1BNC\0" \
+ "b\0AC64\0" \
+ "\0"
+#define XHCI_HCCV1_x_BITS \
+ "\177\020" /* New bitmask */ \
+ "f\020\020XECP\0" \
+ "f\014\4MAXPSA\0" \
+ "b\013CFC\0" \
+ "b\012SEC\0" \
+ "b\011SPC\0" \
+ "b\010PAE\0" \
+ "b\7NSS\0" \
+ "b\6LTC\0" \
+ "b\5LHRC\0" \
+ "b\4PIND\0" \
+ "b\3PPC\0" \
+ "b\2CSZ\0" \
+ "b\1BNC\0" \
+ "b\0AC64\0" \
+ "\0"
int
xhci_init(struct xhci_softc *sc)
{
bus_size_t bsz;
- uint32_t cap, hcs1, hcs2, hcc, dboff, rtsoff;
+ uint32_t cap, hcs1, hcs2, hcs3, hcc, dboff, rtsoff;
uint32_t ecp, ecr;
uint32_t usbcmd, usbsts, pagesize, config;
int i;
@@ -635,7 +669,8 @@
caplength = XHCI_CAP_CAPLENGTH(cap);
hciversion = XHCI_CAP_HCIVERSION(cap);
- if ((hciversion < 0x0096) || (hciversion > 0x0100)) {
+ if (hciversion < XHCI_HCIVERSION_0_96 ||
+ hciversion > XHCI_HCIVERSION_1_0) {
aprint_normal_dev(sc->sc_dev,
"xHCI version %x.%x not known to be supported\n",
(hciversion >> 8) & 0xff, (hciversion >> 0) & 0xff);
@@ -655,15 +690,22 @@
sc->sc_maxintrs = XHCI_HCS1_MAXINTRS(hcs1);
sc->sc_maxports = XHCI_HCS1_MAXPORTS(hcs1);
hcs2 = xhci_cap_read_4(sc, XHCI_HCSPARAMS2);
- (void)xhci_cap_read_4(sc, XHCI_HCSPARAMS3);
+ hcs3 = xhci_cap_read_4(sc, XHCI_HCSPARAMS3);
+ aprint_debug_dev(sc->sc_dev,
+ "hcs1=%"PRIx32" hcs2=%"PRIx32" hcs3=%"PRIx32"\n", hcs1, hcs2, hcs3);
+
hcc = xhci_cap_read_4(sc, XHCI_HCCPARAMS);
-
sc->sc_ac64 = XHCI_HCC_AC64(hcc);
sc->sc_ctxsz = XHCI_HCC_CSZ(hcc) ? 64 : 32;
- aprint_debug_dev(sc->sc_dev, "ac64 %d ctxsz %d\n", sc->sc_ac64,
- sc->sc_ctxsz);
-
+
+ char sbuf[128];
+ if (hciversion < XHCI_HCIVERSION_1_0)
+ snprintb(sbuf, sizeof(sbuf), XHCI_HCCPREV1_BITS, hcc);
+ else
+ snprintb(sbuf, sizeof sbuf, XHCI_HCCV1_x_BITS, hcc);
+ aprint_debug_dev(sc->sc_dev, "hcc=%s\n", sbuf);
aprint_debug_dev(sc->sc_dev, "xECP %x\n", XHCI_HCC_XECP(hcc) * 4);
+
ecp = XHCI_HCC_XECP(hcc) * 4;
while (ecp != 0) {
ecr = xhci_read_4(sc, ecp);
@@ -1072,8 +1114,8 @@
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- /* 6.2.2 */
/*
+ * 6.2.2, Table 57-60, 6.2.2.1, 6.2.2.2
* tthubslot:
* This is the slot ID of parent HS hub
* if LS/FS device is connected && connected through HS hub.
@@ -1093,7 +1135,6 @@
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;
@@ -1156,11 +1197,174 @@
cp[3] |= htole32(0);
}
+static uint32_t
+xhci_get_maxburst(struct usbd_pipe *pipe)
+{
+ usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+ usbd_desc_iter_t iter;
+ const usb_cdc_descriptor_t *cdcd;
+ const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
+ uint32_t maxb = 0;
+ uint8_t ep;
+
+ cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(
+ pipe->up_dev, UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
+ usb_desc_iter_init(pipe->up_dev, &iter);
+ iter.cur = (const void *)cdcd;
+
+ /* find endpoint_ss_comp desc for ep of this pipe */
+ for (ep = 0;;) {
+ cdcd = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
+ if (cdcd == NULL)
+ break;
+ if (ep == 0 && cdcd->bDescriptorType == UDESC_ENDPOINT) {
+ ep = ((const usb_endpoint_descriptor_t *)cdcd)->
+ bEndpointAddress;
+ if (UE_GET_ADDR(ep) ==
+ UE_GET_ADDR(ed->bEndpointAddress)) {
+ cdcd = (const usb_cdc_descriptor_t *)
+ usb_desc_iter_next(&iter);
+ break;
+ }
+ ep = 0;
+ }
+ }
+ if (cdcd != NULL && cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
+ esscd = (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
+ maxb = esscd->bMaxBurst;
+ }
+
+ return maxb;
+}
+
/*
- * called
- * from xhci_open
- * from usbd_setup_pipe_flags
- * from usbd_open_pipe_ival
+ * Convert endpoint bInterval value to endpoint context interval value
+ * for Interrupt pipe.
+ * xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6
+ */
+static uint32_t
+xhci_bival2ival(uint32_t ival, int speed)
+{
+ if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
+ int i;
+
+ /*
+ * round ival down to "the nearest base 2 multiple of
+ * bInterval * 8".
+ * bInterval is at most 255 as its type is uByte.
+ * 255(ms) = 2040(x 125us) < 2^11, so start with 10.
+ */
+ for (i = 10; i > 0; i--) {
+ if ((ival * 8) >= (1 << i))
+ break;
+ }
+ ival = i;
+ } else {
+ /* Interval = bInterval-1 for SS/HS */
+ ival--;
+ }
+
+ return ival;
+}
+
+/*
+ * 4.8.2, 6.2.3.2
+ * construct common endpoint parameters
+ */
+static void
+xhci_setup_endp_ctx(struct usbd_pipe *pipe, uint32_t *cp)
+{
+ struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
+ usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+ const u_int dci = xhci_ep_get_dci(ed);
+ const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+ uint32_t mps = UGETW(ed->wMaxPacketSize);
+ uint32_t maxb = 0;
+ int speed = pipe->up_dev->ud_speed;
+ uint32_t ival = ed->bInterval;
+
+ cp[0] = htole32(
+ XHCI_EPCTX_0_EPSTATE_SET(0) |
+ XHCI_EPCTX_0_MULT_SET(0) | /* always 0 except SS iscoh */
+ XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
+ XHCI_EPCTX_0_LSA_SET(0) |
+ XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(0)
+ );
+ cp[1] = htole32(
+ XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(ed)) |
+ XHCI_EPCTX_1_HID_SET(0) |
+ XHCI_EPCTX_1_MAXB_SET(0)
+ );
+ if (xfertype != UE_ISOCHRONOUS)
+ cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
+
+ /* 6.2.3.4, 4.8.2.4 */
+ if (USB_IS_SS(speed)) {
+ /* UBS 3.1 9.6.6 */
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+ /* UBS 3.1 9.6.7 */
+ maxb = xhci_get_maxburst(pipe);
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
+ } else {
+ /* UBS 2.0 9.6.6 */
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(UE_GET_SIZE(mps)));
+
+ /* 6.2.3.4 */
+ if (speed == USB_SPEED_HIGH &&
+ (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)) {
+ maxb = UE_GET_TRANS(mps);
+ } else {
+ /* LS/FS or HS CTRL or HS BULK */
+ maxb = 0;
+ }
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
+ }
+
+ if (xfertype == UE_CONTROL)
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)); /* 6.2.3 */
+ else if (USB_IS_SS(speed))
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(mps));
+ else
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(UE_GET_SIZE(mps)));
+
+ switch (xfertype) {
+ case UE_CONTROL:
+ break;
+ case UE_BULK:
+ /* XXX Set MaxPStreams, HID, and LSA if streams enabled */
+ break;
+ case UE_INTERRUPT:
+ if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
+ ival = pipe->up_interval;
+
+ ival = xhci_bival2ival(ival, speed);
+ cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
+ break;
+ case UE_ISOCHRONOUS:
+ if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
+ ival = pipe->up_interval;
+
+ /* xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6 */
+ if (speed == USB_SPEED_FULL)
+ ival += 3; /* 1ms -> 125us */
+ ival--;
+ cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
+
+ if (USB_IS_SS(speed)) {
+ /* XXX if LEC = 1, set ESIT instead */
+ cp[0] |= htole32(XHCI_EPCTX_0_MULT_SET(0));
+ }
+ break;
+ default:
+ break;
+ }
+ *(uint64_t *)(&cp[2]) = htole64(
+ xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
+ XHCI_EPCTX_2_DCS_SET(1));
+}
+
+/*
+ * Construct input contexts and issue TRB
*/
static usbd_status
Home |
Main Index |
Thread Index |
Old Index