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

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

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

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

241
 	uint32_t low[5];
241
 	uint32_t low[5];
242
 	/** Extended buffer pointers (high 32 bits) */
242
 	/** Extended buffer pointers (high 32 bits) */
243
 	uint32_t high[5];
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
 } __attribute__ (( packed ));
246
 } __attribute__ (( packed ));
260
 
247
 
261
 /** Transaction error */
248
 /** Transaction error */
483
 	unsigned int flags;
470
 	unsigned int flags;
484
 };
471
 };
485
 
472
 
486
-/** Copy data to immediate data buffer */
487
-#define EHCI_FL_IMMEDIATE 0x0100
488
-
489
 /** Set initial data toggle */
473
 /** Set initial data toggle */
490
 #define EHCI_FL_TOGGLE 0x8000
474
 #define EHCI_FL_TOGGLE 0x8000
491
 
475
 

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

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

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

433
 	/** Enqueue message transfer
433
 	/** Enqueue message transfer
434
 	 *
434
 	 *
435
 	 * @v ep		USB endpoint
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
 	 * @ret rc		Return status code
437
 	 * @ret rc		Return status code
439
 	 */
438
 	 */
440
 	int ( * message ) ( struct usb_endpoint *ep,
439
 	int ( * message ) ( struct usb_endpoint *ep,
441
-			    struct usb_setup_packet *setup,
442
 			    struct io_buffer *iobuf );
440
 			    struct io_buffer *iobuf );
443
 	/** Enqueue stream transfer
441
 	/** Enqueue stream transfer
444
 	 *
442
 	 *

Loading…
Cancel
Save