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

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

145
 		iob_put ( iobuf, ( ring->mtu - iob_len ( iobuf ) ) );
145
 		iob_put ( iobuf, ( ring->mtu - iob_len ( iobuf ) ) );
146
 
146
 
147
 		/* Enqueue I/O buffer */
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
 			DBGC ( ncm, "NCM %p could not enqueue %s: %s\n", ncm,
149
 			DBGC ( ncm, "NCM %p could not enqueue %s: %s\n", ncm,
150
 			       ncm_rx_name ( ncm, ring ), strerror ( rc ) );
150
 			       ncm_rx_name ( ncm, ring ), strerror ( rc ) );
151
 			/* Leave in recycled list and wait for next refill */
151
 			/* Leave in recycled list and wait for next refill */
548
 	memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) );
548
 	memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) );
549
 
549
 
550
 	/* Enqueue I/O buffer */
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
 		return rc;
552
 		return rc;
553
 
553
 
554
 	/* Increment sequence number */
554
 	/* Increment sequence number */

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

52
 		iob_put ( iobuf, ( mtu - iob_len ( iobuf ) ) );
52
 		iob_put ( iobuf, ( mtu - iob_len ( iobuf ) ) );
53
 
53
 
54
 		/* Enqueue I/O buffer */
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
 			DBGC ( hubdev, "HUB %s could not enqueue interrupt: "
56
 			DBGC ( hubdev, "HUB %s could not enqueue interrupt: "
57
 			       "%s\n", hubdev->name, strerror ( rc ) );
57
 			       "%s\n", hubdev->name, strerror ( rc ) );
58
 			/* Leave in available list and wait for next refill */
58
 			/* Leave in available list and wait for next refill */

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

2457
  *
2457
  *
2458
  * @v ep		USB endpoint
2458
  * @v ep		USB endpoint
2459
  * @v iobuf		I/O buffer
2459
  * @v iobuf		I/O buffer
2460
+ * @v terminate		Terminate using a short packet
2460
  * @ret rc		Return status code
2461
  * @ret rc		Return status code
2461
  */
2462
  */
2462
 static int xhci_endpoint_stream ( struct usb_endpoint *ep,
2463
 static int xhci_endpoint_stream ( struct usb_endpoint *ep,
2463
-				  struct io_buffer *iobuf ) {
2464
+				  struct io_buffer *iobuf, int terminate ) {
2464
 	struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
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
 	struct xhci_trb_normal *normal;
2468
 	struct xhci_trb_normal *normal;
2469
+	size_t len = iob_len ( iobuf );
2467
 	int rc;
2470
 	int rc;
2468
 
2471
 
2469
 	/* Profile stream transfers */
2472
 	/* Profile stream transfers */
2470
 	profile_start ( &xhci_stream_profiler );
2473
 	profile_start ( &xhci_stream_profiler );
2471
 
2474
 
2472
 	/* Construct normal TRBs */
2475
 	/* Construct normal TRBs */
2473
-	normal = &trb.normal;
2476
+	memset ( &trbs, 0, sizeof ( trbs ) );
2477
+	normal = &(trb++)->normal;
2474
 	normal->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) );
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
 	normal->type = XHCI_TRB_NORMAL;
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
 	/* Enqueue TRBs */
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
 		return rc;
2491
 		return rc;
2482
 
2492
 
2483
 	/* Ring the doorbell */
2493
 	/* Ring the doorbell */

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

428
 	 *
428
 	 *
429
 	 * @v ep		USB endpoint
429
 	 * @v ep		USB endpoint
430
 	 * @v iobuf		I/O buffer
430
 	 * @v iobuf		I/O buffer
431
+	 * @v terminate		Terminate using a short packet
431
 	 * @ret rc		Return status code
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
 /** USB endpoint driver operations */
438
 /** USB endpoint driver operations */
547
 extern int usb_message ( struct usb_endpoint *ep, unsigned int request,
548
 extern int usb_message ( struct usb_endpoint *ep, unsigned int request,
548
 			 unsigned int value, unsigned int index,
549
 			 unsigned int value, unsigned int index,
549
 			 struct io_buffer *iobuf );
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
 extern void usb_complete_err ( struct usb_endpoint *ep,
553
 extern void usb_complete_err ( struct usb_endpoint *ep,
552
 			       struct io_buffer *iobuf, int rc );
554
 			       struct io_buffer *iobuf, int rc );
553
 
555
 

Loading…
Cancel
Save