PERFORCE change 178075 for review

Hans Petter Selasky hselasky at FreeBSD.org
Mon May 10 23:35:50 UTC 2010


http://p4web.freebsd.org/@@178075?ac=10

Change 178075 by hselasky at hselasky_laptop001 on 2010/05/10 23:35:13

	USB CORE + USB CONTROLLER:
	
		- fix for intervalled High Speed isochronous transfers.
	
		ehci.c:
	
		- back out USB P4 change #173002 which was causing problems
		  when the first and the last microframe slot was not in the
		  smask. The problem was that the EHCI driver was then thinking
		  that the transfer was immediately complete in some cases. Which
		  could lead to freeze-like situations, which can be recovered by
		  unplugging the USB device. I have chosen a simple method over
		  a faster one, because making a faster solution takes some more
		  time to investigate, and I don't have that time right now.
	
		usb_hub.c:
	
		- overload the "bandwidth_reclaimed" bit-flag, which should
		  only be used for the UHCI. When used with the EHCI it means
		  we have allocated bandwidth for a high speed endpoint. This
		  bit is checked when allocating and freeing to avoid duplicate
		  operations. At least the close method of a USB transfer type
		  can be called two times in a row, with only one open, due
		  to the current design.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/ehci.c#51 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_hub.c#43 edit

Differences ...

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

@@ -1352,22 +1352,32 @@
 		}
 	} else if (methods == &ehci_device_isoc_hs_methods) {
 		ehci_itd_t *td;
-		uint8_t n = (xfer->nframes & 7);
 
 		/* isochronous high speed transfer */
 
 		/* check last transfer */
 		td = xfer->td_transfer_last;
 		usb_pc_cpu_invalidate(td->page_cache);
-		if (n == 0)
-			status = td->itd_status[7];
-		else
-			status = td->itd_status[n-1];
+		status = td->itd_status[0];
+		status |= td->itd_status[1];
+		status |= td->itd_status[2];
+		status |= td->itd_status[3];
+		status |= td->itd_status[4];
+		status |= td->itd_status[5];
+		status |= td->itd_status[6];
+		status |= td->itd_status[7];
 
 		/* also check first transfer */
 		td = xfer->td_transfer_first;
 		usb_pc_cpu_invalidate(td->page_cache);
 		status |= td->itd_status[0];
+		status |= td->itd_status[1];
+		status |= td->itd_status[2];
+		status |= td->itd_status[3];
+		status |= td->itd_status[4];
+		status |= td->itd_status[5];
+		status |= td->itd_status[6];
+		status |= td->itd_status[7];
 
 		/* if no transactions are active we continue */
 		if (!(status & htohc32(sc, EHCI_ITD_ACTIVE))) {
@@ -2799,14 +2809,15 @@
 	uint8_t x;
 	uint8_t td_no;
 	uint8_t page_no;
+	uint8_t shift = usbd_xfer_get_fps_shift(xfer);
 
 #ifdef USB_DEBUG
 	uint8_t once = 1;
 
 #endif
 
-	DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
-	    xfer, xfer->endpoint->isoc_next, xfer->nframes);
+	DPRINTFN(6, "xfer=%p next=%d nframes=%d shift=%d\n",
+	    xfer, xfer->endpoint->isoc_next, xfer->nframes, (int)shift);
 
 	/* get the current frame index */
 
@@ -2820,7 +2831,7 @@
 	    (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
 
 	if ((xfer->endpoint->is_synced == 0) ||
-	    (buf_offset < ((xfer->nframes + 7) / 8))) {
+	    (buf_offset < (((xfer->nframes << shift) + 7) / 8))) {
 		/*
 		 * If there is data underflow or the pipe queue is empty we
 		 * schedule the transfer a few frames ahead of the current
@@ -2844,7 +2855,7 @@
 	 */
 	xfer->isoc_time_complete =
 	    usb_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset +
-	    ((xfer->nframes + 7) / 8);
+	    (((xfer->nframes << shift) + 7) / 8);
 
 	/* get the real number of frames */
 

==== //depot/projects/usb/src/sys/dev/usb/usb_hub.c#43 (text+ko) ====

@@ -1230,6 +1230,11 @@
 	if (udev->flags.usb_mode != USB_MODE_HOST)
 		return;		/* not supported */
 
+	if (xfer->flags_int.bandwidth_reclaimed != 0)
+		return;		/* bandwidth already allocated */
+
+	xfer->flags_int.bandwidth_reclaimed = 1;
+
 	xfer->endpoint->refcount_bw++;
 	if (xfer->endpoint->refcount_bw != 1)
 		return;		/* already allocated */
@@ -1310,6 +1315,11 @@
 	if (udev->flags.usb_mode != USB_MODE_HOST)
 		return;		/* not supported */
 
+	if (xfer->flags_int.bandwidth_reclaimed == 0)
+		return;		/* bandwidth already freed */
+
+	xfer->flags_int.bandwidth_reclaimed = 0;
+
 	xfer->endpoint->refcount_bw--;
 	if (xfer->endpoint->refcount_bw != 0)
 		return;		/* still allocated */


More information about the p4-projects mailing list