Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Aug 2010 18:26:16 GMT
From:      Hans Petter Selasky <hselasky@skunkworks.freebsd.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 182197 for review
Message-ID:  <201008111826.o7BIQGoN084396@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@182197?ac=10

Change 182197 by hselasky@hselasky_laptop001 on 2010/08/10 16:19:57

	USB controller (XHCI):
		- correctly compute multiplier and burst bits for
		isoc. transfers.
		- isochronous transfers should not fail on
		data errors and always report success to the
		client unless there is a complete stop in
		the isochronous schedule.
		- use timeout error code instead of I/O error
		code due to the way applications handle this
		kind of error.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#25 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#21 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#25 (text+ko) ====

@@ -113,6 +113,8 @@
 	uint8_t last_frame;
 	uint8_t trb_type;
 	uint8_t direction;
+	uint8_t tbc;
+	uint8_t tlbpc;
 };
 
 static void xhci_do_poll(struct usb_bus *);
@@ -722,6 +724,7 @@
 			if (xfer->flags_int.isochronous_xfr) {
 				if (halted) {
 					halted = 0;
+					status = XHCI_TRB_ERROR_SUCCESS;
 					remainder = td->len;
 				}
 			}
@@ -1537,7 +1540,9 @@
 
 			dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
 			  XHCI_TRB_3_TYPE_SET(temp->trb_type) | 
-			  XHCI_TRB_3_FRID_SET(temp->isoc_frame);
+			  XHCI_TRB_3_FRID_SET(temp->isoc_frame) | 
+			  XHCI_TRB_3_TBC_SET(temp->tbc) |
+			  XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
 
 			if (temp->direction == UE_DIR_IN) {
 				dword |= XHCI_TRB_3_DIR_IN;
@@ -1637,7 +1642,10 @@
 	struct xhci_td *td;
 	uint32_t x;
 	uint32_t y;
+	uint8_t mult;
 
+	temp.tbc = 0;
+	temp.tlbpc = 0;
 	temp.average = xfer->max_hc_frame_size;
 	temp.max_packet_size = xfer->max_packet_size;
 	temp.sc = XHCI_BUS2SC(xfer->xroot->bus);
@@ -1663,6 +1671,20 @@
 	if (xfer->flags_int.isochronous_xfr) {
 		uint8_t shift;
 
+		/* compute multiplier for ISOCHRONOUS transfers */
+		mult = xfer->endpoint->ecomp ?
+		    (xfer->endpoint->ecomp->bmAttributes & 3) : 0;
+		/* check for USB 2.0 multiplier */
+		if (mult == 0) {
+			mult = (xfer->endpoint->edesc->
+			    wMaxPacketSize[1] >> 3) & 3;
+		}
+		/* range check */
+		if (mult > 2)
+			mult = 3;
+		else
+			mult++;
+
 		x = XREAD4(temp.sc, runt, XHCI_MFINDEX);
 
 		DPRINTF("MFINDEX=0x%08x\n", x);
@@ -1737,11 +1759,13 @@
 			xhci_setup_generic_chain_sub(&temp);
 		}
 		x = 1;
+		mult = 1;
 		temp.isoc_delta = 0;
 		temp.isoc_frame = 0;
 		temp.trb_type = XHCI_TRB_TYPE_DATA_STAGE;
 	} else {
 		x = 0;
+		mult = 1;
 		temp.isoc_delta = 0;
 		temp.isoc_frame = 0;
 		temp.trb_type = XHCI_TRB_TYPE_NORMAL;
@@ -1777,8 +1801,13 @@
 
 			temp.shortpkt = 0;
 
+			temp.tbc = 0;
+			temp.tlbpc = mult - 1;
+
 		} else if (xfer->flags_int.isochronous_xfr) {
 
+			uint8_t tdpc;
+
 			/* isochronous transfers don't have short packet termination */
 
 			temp.shortpkt = 1;
@@ -1787,6 +1816,18 @@
 
 			if (temp.len > xfer->max_frame_size)
 				temp.len = xfer->max_frame_size;
+
+			/* compute TD packet count */
+			tdpc = (temp.len + xfer->max_packet_size - 1) /
+			    xfer->max_packet_size;
+
+			temp.tbc = ((tdpc + mult - 1) / mult) - 1;
+			temp.tlbpc = (tdpc % mult);
+
+			if (temp.tlbpc == 0)
+				temp.tlbpc = mult - 1;
+			else
+				temp.tlbpc--;
 		} else {
 
 			/* regular data transfer */
@@ -2000,14 +2041,14 @@
 	switch (edesc->bmAttributes & UE_XFERTYPE) {
 	case UE_INTERRUPT:
 	case UE_ISOCHRONOUS:
-		temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size);
-		temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX);
+		temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size) |
+		    XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_PAGE_SIZE);
 		break;
 	case UE_CONTROL:
 		temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8);
 		break;
 	default:
-		temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX);
+		temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_PAGE_SIZE);
 		break;
 	}
 
@@ -3395,11 +3436,22 @@
 			/* nuke remaining buffered transfers */
 
 			for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) {
-				if (pepext->xfer[i] != NULL)
-					xhci_device_done(pepext->xfer[i], USB_ERR_IOERROR);
+				/*
+				 * NOTE: We need to use the timeout
+				 * error code here else existing
+				 * isochronous clients can get
+				 * confused:
+				 */
+				if (pepext->xfer[i] != NULL) {
+					xhci_device_done(pepext->xfer[i],
+					    USB_ERR_TIMEOUT);
+				}
 			}
 
-			/* NOTE: The USB transfer cannot vanish in this state! */
+			/*
+			 * NOTE: The USB transfer cannot vanish in
+			 * this state!
+			 */
 
 			USB_BUS_UNLOCK(&sc->sc_bus);
 

==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#21 (text+ko) ====

@@ -205,6 +205,8 @@
 #define	XHCI_TRB_3_CHAIN_BIT		(1U << 4)
 #define	XHCI_TRB_3_IOC_BIT		(1U << 5)
 #define	XHCI_TRB_3_IDT_BIT		(1U << 6)
+#define	XHCI_TRB_3_TBC_GET(x)		(((x) >> 7) & 3)
+#define	XHCI_TRB_3_TBC_SET(x)		(((x) & 3) << 7)
 #define	XHCI_TRB_3_BEI_BIT		(1U << 9)
 #define	XHCI_TRB_3_DCEP_BIT		(1U << 9)
 #define	XHCI_TRB_3_PRSV_BIT		(1U << 9)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008111826.o7BIQGoN084396>