Browse Source

[usb] Include setup packet within I/O buffer for message transfers

The USB API currently assumes that host controllers will have
immediate data buffer space available in which to store the setup
packet.  This is true for xHCI, partially true for EHCI (which happens
to have 12 bytes of padding in each transfer descriptor due to
alignment requirements), and not true at all for UHCI.

Include the setup packet within the I/O buffer passed to the host
controller's message() method, thereby eliminating the requirement for
host controllers to provide immediate data buffers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
50e703a534
5 changed files with 41 additions and 49 deletions
  1. 20
    9
      src/drivers/bus/usb.c
  2. 10
    15
      src/drivers/usb/ehci.c
  3. 2
    18
      src/drivers/usb/ehci.h
  4. 8
    4
      src/drivers/usb/xhci.c
  5. 1
    3
      src/include/ipxe/usb.h

+ 20
- 9
src/drivers/bus/usb.c View File

@@ -460,16 +460,22 @@ static int usb_endpoint_mtu ( struct usb_endpoint *ep, size_t mtu ) {
460 460
  * @v index		Index parameter
461 461
  * @v iobuf		I/O buffer
462 462
  * @ret rc		Return status code
463
+ *
464
+ * The I/O buffer must have sufficient headroom to contain a setup
465
+ * packet.
463 466
  */
464 467
 int usb_message ( struct usb_endpoint *ep, unsigned int request,
465 468
 		  unsigned int value, unsigned int index,
466 469
 		  struct io_buffer *iobuf ) {
467 470
 	struct usb_device *usb = ep->usb;
468 471
 	struct usb_port *port = usb->port;
469
-	struct usb_setup_packet packet;
472
+	struct usb_setup_packet *packet;
470 473
 	size_t len = iob_len ( iobuf );
471 474
 	int rc;
472 475
 
476
+	/* Sanity check */
477
+	assert ( iob_headroom ( iobuf ) >= sizeof ( *packet ) );
478
+
473 479
 	/* Fail immediately if device has been unplugged */
474 480
 	if ( port->speed == USB_SPEED_NONE )
475 481
 		return -ENODEV;
@@ -484,13 +490,14 @@ int usb_message ( struct usb_endpoint *ep, unsigned int request,
484 490
 		memset ( iobuf->data, 0, len );
485 491
 
486 492
 	/* Construct setup packet */
487
-	packet.request = cpu_to_le16 ( request );
488
-	packet.value = cpu_to_le16 ( value );
489
-	packet.index = cpu_to_le16 ( index );
490
-	packet.len = cpu_to_le16 ( len );
493
+	packet = iob_push ( iobuf, sizeof ( *packet ) );
494
+	packet->request = cpu_to_le16 ( request );
495
+	packet->value = cpu_to_le16 ( value );
496
+	packet->index = cpu_to_le16 ( index );
497
+	packet->len = cpu_to_le16 ( len );
491 498
 
492 499
 	/* Enqueue message transfer */
493
-	if ( ( rc = ep->host->message ( ep, &packet, iobuf ) ) != 0 ) {
500
+	if ( ( rc = ep->host->message ( ep, iobuf ) ) != 0 ) {
494 501
 		DBGC ( usb, "USB %s %s could not enqueue message transfer: "
495 502
 		       "%s\n", usb->name, usb_endpoint_name ( ep->address ),
496 503
 		       strerror ( rc ) );
@@ -734,19 +741,23 @@ int usb_control ( struct usb_device *usb, unsigned int request,
734 741
 		  size_t len ) {
735 742
 	struct usb_bus *bus = usb->port->hub->bus;
736 743
 	struct usb_endpoint *ep = &usb->control;
737
-	struct usb_control_pseudo_header *pshdr;
738 744
 	struct io_buffer *iobuf;
739 745
 	struct io_buffer *cmplt;
746
+	union {
747
+		struct usb_setup_packet setup;
748
+		struct usb_control_pseudo_header pshdr;
749
+	} *headroom;
750
+	struct usb_control_pseudo_header *pshdr;
740 751
 	unsigned int i;
741 752
 	int rc;
742 753
 
743 754
 	/* Allocate I/O buffer */
744
-	iobuf = alloc_iob ( sizeof ( *pshdr ) + len );
755
+	iobuf = alloc_iob ( sizeof ( *headroom ) + len );
745 756
 	if ( ! iobuf ) {
746 757
 		rc = -ENOMEM;
747 758
 		goto err_alloc;
748 759
 	}
749
-	iob_reserve ( iobuf, sizeof ( *pshdr ) );
760
+	iob_reserve ( iobuf, sizeof ( *headroom ) );
750 761
 	iob_put ( iobuf, len );
751 762
 	if ( request & USB_DIR_IN ) {
752 763
 		memset ( data, 0, len );

+ 10
- 15
src/drivers/usb/ehci.c View File

@@ -528,8 +528,6 @@ static int ehci_enqueue ( struct ehci_device *ehci, struct ehci_ring *ring,
528 528
 
529 529
 	/* Fail if any portion is unreachable */
530 530
 	for ( i = 0 ; i < count ; i++ ) {
531
-		if ( xfer->flags & EHCI_FL_IMMEDIATE )
532
-			continue;
533 531
 		phys = ( virt_to_phys ( xfer[i].data ) + xfer[i].len - 1 );
534 532
 		if ( ( phys > 0xffffffffUL ) && ( ! ehci->addr64 ) )
535 533
 			return -ENOTSUP;
@@ -547,16 +545,9 @@ static int ehci_enqueue ( struct ehci_device *ehci, struct ehci_ring *ring,
547 545
 		desc->len = cpu_to_le16 ( xfer->len | toggle );
548 546
 		desc->flags = ( xfer->flags | EHCI_FL_CERR_MAX );
549 547
 
550
-		/* Copy data to immediate data buffer (if requested) */
548
+		/* Populate buffer pointers */
551 549
 		data = xfer->data;
552 550
 		len = xfer->len;
553
-		if ( xfer->flags & EHCI_FL_IMMEDIATE ) {
554
-			assert ( len <= sizeof ( desc->immediate ) );
555
-			memcpy ( desc->immediate, data, len );
556
-			data = desc->immediate;
557
-		}
558
-
559
-		/* Populate buffer pointers */
560 551
 		for ( i = 0 ; len ; i++ ) {
561 552
 
562 553
 			/* Calculate length of this fragment */
@@ -1103,28 +1094,32 @@ static int ehci_endpoint_mtu ( struct usb_endpoint *ep ) {
1103 1094
  * Enqueue message transfer
1104 1095
  *
1105 1096
  * @v ep		USB endpoint
1106
- * @v packet		Setup packet
1107 1097
  * @v iobuf		I/O buffer
1108 1098
  * @ret rc		Return status code
1109 1099
  */
1110 1100
 static int ehci_endpoint_message ( struct usb_endpoint *ep,
1111
-				   struct usb_setup_packet *packet,
1112 1101
 				   struct io_buffer *iobuf ) {
1113 1102
 	struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
1114 1103
 	struct ehci_device *ehci = endpoint->ehci;
1115
-	unsigned int input = ( packet->request & cpu_to_le16 ( USB_DIR_IN ) );
1104
+	struct usb_setup_packet *packet;
1105
+	unsigned int input;
1116 1106
 	struct ehci_transfer xfers[3];
1117 1107
 	struct ehci_transfer *xfer = xfers;
1118
-	size_t len = iob_len ( iobuf );
1108
+	size_t len;
1119 1109
 	int rc;
1120 1110
 
1121 1111
 	/* Construct setup stage */
1112
+	assert ( iob_len ( iobuf ) >= sizeof ( *packet ) );
1113
+	packet = iobuf->data;
1114
+	iob_pull ( iobuf, sizeof ( *packet ) );
1122 1115
 	xfer->data = packet;
1123 1116
 	xfer->len = sizeof ( *packet );
1124
-	xfer->flags = ( EHCI_FL_IMMEDIATE | EHCI_FL_PID_SETUP );
1117
+	xfer->flags = EHCI_FL_PID_SETUP;
1125 1118
 	xfer++;
1126 1119
 
1127 1120
 	/* Construct data stage, if applicable */
1121
+	len = iob_len ( iobuf );
1122
+	input = ( packet->request & cpu_to_le16 ( USB_DIR_IN ) );
1128 1123
 	if ( len ) {
1129 1124
 		xfer->data = iobuf->data;
1130 1125
 		xfer->len = len;

+ 2
- 18
src/drivers/usb/ehci.h View File

@@ -241,21 +241,8 @@ struct ehci_transfer_descriptor {
241 241
 	uint32_t low[5];
242 242
 	/** Extended buffer pointers (high 32 bits) */
243 243
 	uint32_t high[5];
244
-
245
-	/** Immediate data buffer
246
-	 *
247
-	 * This is not part of the hardware data structure.  Transfer
248
-	 * descriptors must be aligned to a 32-byte boundary.  Create
249
-	 * an array of descriptors therefore requires 12 bytes of
250
-	 * padding at the end of each descriptor.
251
-	 *
252
-	 * We can use this padding as an immediate data buffer (for
253
-	 * setup packets).  This avoids the need for separate
254
-	 * allocations.  As a bonus, there is no need to check this
255
-	 * buffer for reachability, since it is contained within a
256
-	 * transfer descriptor which must already be reachable.
257
-	 */
258
-	uint8_t immediate[12];
244
+	/** Reserved */
245
+	uint8_t reserved[12];
259 246
 } __attribute__ (( packed ));
260 247
 
261 248
 /** Transaction error */
@@ -483,9 +470,6 @@ struct ehci_transfer {
483 470
 	unsigned int flags;
484 471
 };
485 472
 
486
-/** Copy data to immediate data buffer */
487
-#define EHCI_FL_IMMEDIATE 0x0100
488
-
489 473
 /** Set initial data toggle */
490 474
 #define EHCI_FL_TOGGLE 0x8000
491 475
 

+ 8
- 4
src/drivers/usb/xhci.c View File

@@ -2472,16 +2472,15 @@ static int xhci_endpoint_mtu ( struct usb_endpoint *ep ) {
2472 2472
  * Enqueue message transfer
2473 2473
  *
2474 2474
  * @v ep		USB endpoint
2475
- * @v packet		Setup packet
2476 2475
  * @v iobuf		I/O buffer
2477 2476
  * @ret rc		Return status code
2478 2477
  */
2479 2478
 static int xhci_endpoint_message ( struct usb_endpoint *ep,
2480
-				   struct usb_setup_packet *packet,
2481 2479
 				   struct io_buffer *iobuf ) {
2482 2480
 	struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
2483
-	unsigned int input = ( le16_to_cpu ( packet->request ) & USB_DIR_IN );
2484
-	size_t len = iob_len ( iobuf );
2481
+	struct usb_setup_packet *packet;
2482
+	unsigned int input;
2483
+	size_t len;
2485 2484
 	union xhci_trb trbs[ 1 /* setup */ + 1 /* possible data */ +
2486 2485
 			     1 /* status */ ];
2487 2486
 	union xhci_trb *trb = trbs;
@@ -2495,11 +2494,16 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep,
2495 2494
 
2496 2495
 	/* Construct setup stage TRB */
2497 2496
 	memset ( trbs, 0, sizeof ( trbs ) );
2497
+	assert ( iob_len ( iobuf ) >= sizeof ( *packet ) );
2498
+	packet = iobuf->data;
2499
+	iob_pull ( iobuf, sizeof ( *packet ) );
2498 2500
 	setup = &(trb++)->setup;
2499 2501
 	memcpy ( &setup->packet, packet, sizeof ( setup->packet ) );
2500 2502
 	setup->len = cpu_to_le32 ( sizeof ( *packet ) );
2501 2503
 	setup->flags = XHCI_TRB_IDT;
2502 2504
 	setup->type = XHCI_TRB_SETUP;
2505
+	len = iob_len ( iobuf );
2506
+	input = ( packet->request & cpu_to_le16 ( USB_DIR_IN ) );
2503 2507
 	if ( len )
2504 2508
 		setup->direction = ( input ? XHCI_SETUP_IN : XHCI_SETUP_OUT );
2505 2509
 

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

@@ -433,12 +433,10 @@ struct usb_endpoint_host_operations {
433 433
 	/** Enqueue message transfer
434 434
 	 *
435 435
 	 * @v ep		USB endpoint
436
-	 * @v packet		Setup packet
437
-	 * @v iobuf		I/O buffer (if any)
436
+	 * @v iobuf		I/O buffer
438 437
 	 * @ret rc		Return status code
439 438
 	 */
440 439
 	int ( * message ) ( struct usb_endpoint *ep,
441
-			    struct usb_setup_packet *setup,
442 440
 			    struct io_buffer *iobuf );
443 441
 	/** Enqueue stream transfer
444 442
 	 *

Loading…
Cancel
Save