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

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

Change 182250 by hselasky@hselasky_laptop001 on 2010/08/11 16:14:50

	
	USB controller (XHCI):
		- fix problem with single short and multi
		short multi frame USB transfers.
		- increase maximum TD data-length to 64Kbyte.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#28 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#22 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.h#18 edit

Differences ...

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

@@ -115,6 +115,7 @@
 	uint8_t direction;
 	uint8_t tbc;
 	uint8_t tlbpc;
+	uint8_t step_td;
 };
 
 static void xhci_do_poll(struct usb_bus *);
@@ -127,6 +128,7 @@
 static usb_error_t xhci_configure_endpoint(struct usb_device *, struct usb_endpoint_descriptor *, uint64_t, uint16_t, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t);
 static usb_error_t xhci_configure_mask(struct usb_device *, uint32_t, uint8_t);
 static usb_error_t xhci_cmd_evaluate_ctx(struct xhci_softc *, uint64_t, uint8_t);
+static void xhci_endpoint_doorbell(struct usb_xfer *);
 
 extern struct usb_bus_methods xhci_bus_methods;
 
@@ -632,6 +634,56 @@
 	xhci_device_done(xfer, err);
 }
 
+static void
+xhci_activate_transfer(struct usb_xfer *xfer)
+{
+	struct xhci_td *td;
+
+	td = xfer->td_transfer_cache;
+
+	usb_pc_cpu_invalidate(td->page_cache);
+
+	if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) {
+
+		/* activate the transfer */
+
+		td->td_trb[0].dwTrb3 |= htole32(XHCI_TRB_3_CYCLE_BIT);
+		usb_pc_cpu_flush(td->page_cache);
+
+		xhci_endpoint_doorbell(xfer);
+	}
+}
+
+static void
+xhci_skip_transfer(struct usb_xfer *xfer)
+{
+	struct xhci_td *td;
+	struct xhci_td *td_last;
+
+	td = xfer->td_transfer_cache;
+	td_last = xfer->td_transfer_last;
+
+	td = td->alt_next;
+
+	usb_pc_cpu_invalidate(td->page_cache);
+
+	if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) {
+
+		usb_pc_cpu_invalidate(td_last->page_cache);
+
+		/* copy LINK TRB to current waiting location */
+
+		td->td_trb[0].qwTrb0 = td_last->td_trb[td_last->ntrb].qwTrb0;
+		td->td_trb[0].dwTrb2 = td_last->td_trb[td_last->ntrb].dwTrb2;
+		usb_pc_cpu_flush(td->page_cache);
+
+		td->td_trb[0].dwTrb3 = td_last->td_trb[td_last->ntrb].dwTrb3;
+		usb_pc_cpu_flush(td->page_cache);
+
+		xhci_endpoint_doorbell(xfer);
+	}
+}
+
 /*------------------------------------------------------------------------*
  *	xhci_check_transfer
  *------------------------------------------------------------------------*/
@@ -764,12 +816,12 @@
 				if (xfer->flags_int.short_frames_ok ||
 				    xfer->flags_int.isochronous_xfr ||
 				    xfer->flags_int.control_xfr) {
-					/* try to follow follow alt next */
-					if (td->alt_next != NULL) {
-						xfer->td_transfer_cache = td->alt_next;
-						break;
-					}
+					/* follow the alt next */
+					xfer->td_transfer_cache = td->alt_next;
+					xhci_activate_transfer(xfer);
+					break;
 				}
+				xhci_skip_transfer(xfer);
 				xhci_generic_done(xfer);
 				break;
 			}
@@ -779,6 +831,7 @@
 			 */
 			DPRINTF("Following next TD\n");
 			xfer->td_transfer_cache = td->obj_next;
+			xhci_activate_transfer(xfer);
 			break;		/* there should only be one match */
 		}
 	}
@@ -1553,7 +1606,6 @@
 				 * can be sent using the wrong data
 				 * toggle value.
 				 */
-
 				if ((temp->trb_type != XHCI_TRB_TYPE_SETUP_STAGE) &&
 				    (temp->trb_type != XHCI_TRB_TYPE_STATUS_STAGE))
 					dword |= XHCI_TRB_3_ISP_BIT;
@@ -1594,8 +1646,7 @@
 		td->td_trb[x].dwTrb2 = htole32(dword);
 
 		dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
-		    XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
-		    XHCI_TRB_3_IOC_BIT;
+		    XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_IOC_BIT;
 
 		td->td_trb[x].dwTrb3 = htole32(dword);
 
@@ -1623,14 +1674,16 @@
 		goto restart;
 	}
 
-	if (temp->multishort != 0) {
-		/* remove chain bit and clear TD SIZE - end of frame */
-		td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
- 		td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
-		td->td_trb[td->ntrb].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
-		td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
-		usb_pc_cpu_flush(td->page_cache);
-	}
+	/* remove cycle bit from first if we are stepping the TRBs */
+	if (temp->step_td)
+		td->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+
+	/* remove chain bit because this is the last TRB in the chain */
+	td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
+	td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
+
+	usb_pc_cpu_flush(td->page_cache);
+
 	temp->td = td;
 	temp->td_next = td_next;
 }
@@ -1644,6 +1697,7 @@
 	uint32_t y;
 	uint8_t mult;
 
+	temp.step_td = 0;
 	temp.tbc = 0;
 	temp.tlbpc = 0;
 	temp.average = xfer->max_hc_frame_size;
@@ -1783,6 +1837,8 @@
 		/* DATA0 / DATA1 message */
 
 		temp.len = xfer->frlengths[x];
+		temp.step_td = ((xfer->endpointno & UE_DIR_IN) &&
+		    (x != 0) && (temp.multishort == 0));
 
 		x++;
 
@@ -1855,6 +1911,7 @@
 		 * Send a DATA1 message and invert the current
 		 * endpoint direction.
 		 */
+		temp.step_td = (xfer->nframes != 0);
 		temp.direction = UE_GET_DIR(xfer->endpointno) ^ UE_DIR_IN;
 		temp.len = 0;
 		temp.pc = NULL;
@@ -1867,14 +1924,6 @@
 
 	td = temp.td;
 
-	/* remove chain bit and clear TD SIZE - end of frame */
-	td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
-	td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
-	td->td_trb[td->ntrb].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15));
-	td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT);
-
-	usb_pc_cpu_flush(td->page_cache);
-
 	/* must have at least one frame! */
 
 	xfer->td_transfer_last = td;

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

@@ -305,7 +305,7 @@
 	struct xhci_trb trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS];
 };
 
-#define	XHCI_TD_PAGE_NBUF	13	/* units */
+#define	XHCI_TD_PAGE_NBUF	17	/* units, room enough for 64Kbytes */
 #define	XHCI_TD_PAGE_SIZE	4096	/* bytes */
 #define	XHCI_TD_PAYLOAD_MAX	(XHCI_TD_PAGE_SIZE * (XHCI_TD_PAGE_NBUF - 1))
 

==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.h#18 (text+ko) ====

@@ -101,7 +101,7 @@
 	usb_frlength_t bufsize;
 	usb_frlength_t bufsize_max;
 
-	uint16_t hc_max_frame_size;
+	uint32_t hc_max_frame_size;
 	uint16_t hc_max_packet_size;
 	uint8_t	hc_max_packet_count;
 	enum usb_dev_speed speed;



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