Browse Source

[usb] Allow usb_stream() to enforce a terminating short packet

Some USB endpoints require that a short packet be used to terminate
transfers, since they have no other way to determine message
boundaries.  If the message length happens to be an exact multiple of
the USB packet size, then this requires the use of an additional
zero-length packet.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
58c3e7f747
5 changed files with 28 additions and 14 deletions
  1. 4
    2
      src/drivers/bus/usb.c
  2. 2
    2
      src/drivers/net/ncm.c
  3. 1
    1
      src/drivers/usb/usbhub.c
  4. 16
    6
      src/drivers/usb/xhci.c
  5. 5
    3
      src/include/ipxe/usb.h

+ 4
- 2
src/drivers/bus/usb.c View File

@@ -451,9 +451,11 @@ int usb_message ( struct usb_endpoint *ep, unsigned int request,
451 451
  *
452 452
  * @v ep		USB endpoint
453 453
  * @v iobuf		I/O buffer
454
+ * @v terminate		Terminate using a short packet
454 455
  * @ret rc		Return status code
455 456
  */
456
-int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf ) {
457
+int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf,
458
+		 int terminate ) {
457 459
 	struct usb_device *usb = ep->usb;
458 460
 	struct usb_port *port = usb->port;
459 461
 	int rc;
@@ -467,7 +469,7 @@ int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf ) {
467 469
 		return rc;
468 470
 
469 471
 	/* Enqueue stream transfer */
470
-	if ( ( rc = ep->host->stream ( ep, iobuf ) ) != 0 ) {
472
+	if ( ( rc = ep->host->stream ( ep, iobuf, terminate ) ) != 0 ) {
471 473
 		DBGC ( usb, "USB %s %s could not enqueue stream transfer: %s\n",
472 474
 		       usb->name, usb_endpoint_name ( ep->address ),
473 475
 		       strerror ( rc ) );

+ 2
- 2
src/drivers/net/ncm.c View File

@@ -145,7 +145,7 @@ static int ncm_rx_refill ( struct ncm_device *ncm, struct ncm_rx_ring *ring ) {
145 145
 		iob_put ( iobuf, ( ring->mtu - iob_len ( iobuf ) ) );
146 146
 
147 147
 		/* Enqueue I/O buffer */
148
-		if ( ( rc = usb_stream ( &ring->ep, iobuf ) ) != 0 ) {
148
+		if ( ( rc = usb_stream ( &ring->ep, iobuf, 0 ) ) != 0 ) {
149 149
 			DBGC ( ncm, "NCM %p could not enqueue %s: %s\n", ncm,
150 150
 			       ncm_rx_name ( ncm, ring ), strerror ( rc ) );
151 151
 			/* Leave in recycled list and wait for next refill */
@@ -548,7 +548,7 @@ static int ncm_out_transmit ( struct ncm_device *ncm,
548 548
 	memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) );
549 549
 
550 550
 	/* Enqueue I/O buffer */
551
-	if ( ( rc = usb_stream ( &ncm->out.ep, iobuf ) ) != 0 )
551
+	if ( ( rc = usb_stream ( &ncm->out.ep, iobuf, 0 ) ) != 0 )
552 552
 		return rc;
553 553
 
554 554
 	/* Increment sequence number */

+ 1
- 1
src/drivers/usb/usbhub.c View File

@@ -52,7 +52,7 @@ static void hub_refill ( struct usb_hub_device *hubdev ) {
52 52
 		iob_put ( iobuf, ( mtu - iob_len ( iobuf ) ) );
53 53
 
54 54
 		/* Enqueue I/O buffer */
55
-		if ( ( rc = usb_stream ( &hubdev->intr, iobuf ) ) != 0 ) {
55
+		if ( ( rc = usb_stream ( &hubdev->intr, iobuf, 0 ) ) != 0 ) {
56 56
 			DBGC ( hubdev, "HUB %s could not enqueue interrupt: "
57 57
 			       "%s\n", hubdev->name, strerror ( rc ) );
58 58
 			/* Leave in available list and wait for next refill */

+ 16
- 6
src/drivers/usb/xhci.c View File

@@ -2457,27 +2457,37 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep,
2457 2457
  *
2458 2458
  * @v ep		USB endpoint
2459 2459
  * @v iobuf		I/O buffer
2460
+ * @v terminate		Terminate using a short packet
2460 2461
  * @ret rc		Return status code
2461 2462
  */
2462 2463
 static int xhci_endpoint_stream ( struct usb_endpoint *ep,
2463
-				  struct io_buffer *iobuf ) {
2464
+				  struct io_buffer *iobuf, int terminate ) {
2464 2465
 	struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
2465
-	union xhci_trb trb;
2466
+	union xhci_trb trbs[ 1 /* Normal */ + 1 /* Possible zero-length */ ];
2467
+	union xhci_trb *trb = trbs;
2466 2468
 	struct xhci_trb_normal *normal;
2469
+	size_t len = iob_len ( iobuf );
2467 2470
 	int rc;
2468 2471
 
2469 2472
 	/* Profile stream transfers */
2470 2473
 	profile_start ( &xhci_stream_profiler );
2471 2474
 
2472 2475
 	/* Construct normal TRBs */
2473
-	normal = &trb.normal;
2476
+	memset ( &trbs, 0, sizeof ( trbs ) );
2477
+	normal = &(trb++)->normal;
2474 2478
 	normal->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) );
2475
-	normal->len = cpu_to_le32 ( iob_len ( iobuf ) );
2476
-	normal->flags = XHCI_TRB_IOC;
2479
+	normal->len = cpu_to_le32 ( len );
2477 2480
 	normal->type = XHCI_TRB_NORMAL;
2481
+	if ( terminate && ( ( len & ( ep->mtu - 1 ) ) == 0 ) ) {
2482
+		normal->flags = XHCI_TRB_CH;
2483
+		normal = &(trb++)->normal;
2484
+		normal->type = XHCI_TRB_NORMAL;
2485
+	}
2486
+	normal->flags = XHCI_TRB_IOC;
2478 2487
 
2479 2488
 	/* Enqueue TRBs */
2480
-	if ( ( rc = xhci_enqueue ( &endpoint->ring, iobuf, &trb ) ) != 0 )
2489
+	if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs,
2490
+					 ( trb - trbs ) ) ) != 0 )
2481 2491
 		return rc;
2482 2492
 
2483 2493
 	/* Ring the doorbell */

+ 5
- 3
src/include/ipxe/usb.h View File

@@ -428,10 +428,11 @@ struct usb_endpoint_host_operations {
428 428
 	 *
429 429
 	 * @v ep		USB endpoint
430 430
 	 * @v iobuf		I/O buffer
431
+	 * @v terminate		Terminate using a short packet
431 432
 	 * @ret rc		Return status code
432 433
 	 */
433
-	int ( * stream ) ( struct usb_endpoint *ep,
434
-			   struct io_buffer *iobuf );
434
+	int ( * stream ) ( struct usb_endpoint *ep, struct io_buffer *iobuf,
435
+			   int terminate );
435 436
 };
436 437
 
437 438
 /** USB endpoint driver operations */
@@ -547,7 +548,8 @@ extern void usb_endpoint_close ( struct usb_endpoint *ep );
547 548
 extern int usb_message ( struct usb_endpoint *ep, unsigned int request,
548 549
 			 unsigned int value, unsigned int index,
549 550
 			 struct io_buffer *iobuf );
550
-extern int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf );
551
+extern int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf,
552
+			int terminate );
551 553
 extern void usb_complete_err ( struct usb_endpoint *ep,
552 554
 			       struct io_buffer *iobuf, int rc );
553 555
 

Loading…
Cancel
Save