Browse Source

[usb] Reset endpoints without waiting for a new transfer to be enqueued

The current endpoint reset logic defers the reset until the caller
attempts to enqueue a new transfer to that endpoint.  This is
insufficient when dealing with endpoints behind a transaction
translator, since the transaction translator is a resource shared
between multiple endpoints.

We cannot reset the endpoint as part of the completion handling, since
that would introduce recursive calls to usb_poll().  Instead, we
add the endpoint to a list of halted endpoints, and perform the reset
on the next call to usb_step().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
de6f4e3ede
2 changed files with 70 additions and 31 deletions
  1. 64
    28
      src/drivers/bus/usb.c
  2. 6
    3
      src/include/ipxe/usb.h

+ 64
- 28
src/drivers/bus/usb.c View File

296
 		goto err_already;
296
 		goto err_already;
297
 	}
297
 	}
298
 	usb->ep[idx] = ep;
298
 	usb->ep[idx] = ep;
299
-
300
-	/* Clear any stale error status */
301
-	ep->rc = 0;
299
+	INIT_LIST_HEAD ( &ep->halted );
302
 
300
 
303
 	/* Open endpoint */
301
 	/* Open endpoint */
304
 	if ( ( rc = ep->host->open ( ep ) ) != 0 ) {
302
 	if ( ( rc = ep->host->open ( ep ) ) != 0 ) {
342
 
340
 
343
 	/* Remove from endpoint list */
341
 	/* Remove from endpoint list */
344
 	usb->ep[idx] = NULL;
342
 	usb->ep[idx] = NULL;
343
+	list_del ( &ep->halted );
345
 
344
 
346
 	/* Discard any recycled buffers, if applicable */
345
 	/* Discard any recycled buffers, if applicable */
347
 	if ( ep->max )
346
 	if ( ep->max )
359
 	unsigned int type;
358
 	unsigned int type;
360
 	int rc;
359
 	int rc;
361
 
360
 
361
+	/* Sanity check */
362
+	assert ( ! list_empty ( &ep->halted ) );
363
+
362
 	/* Reset endpoint */
364
 	/* Reset endpoint */
363
 	if ( ( rc = ep->host->reset ( ep ) ) != 0 ) {
365
 	if ( ( rc = ep->host->reset ( ep ) ) != 0 ) {
364
 		DBGC ( usb, "USB %s %s could not reset: %s\n",
366
 		DBGC ( usb, "USB %s %s could not reset: %s\n",
379
 		return rc;
381
 		return rc;
380
 	}
382
 	}
381
 
383
 
382
-	/* Clear recorded error */
383
-	ep->rc = 0;
384
+	/* Remove from list of halted endpoints */
385
+	list_del ( &ep->halted );
386
+	INIT_LIST_HEAD ( &ep->halted );
384
 
387
 
385
 	DBGC ( usb, "USB %s %s reset\n",
388
 	DBGC ( usb, "USB %s %s reset\n",
386
 	       usb->name, usb_endpoint_name ( ep->address ) );
389
 	       usb->name, usb_endpoint_name ( ep->address ) );
434
 		return -ENODEV;
437
 		return -ENODEV;
435
 
438
 
436
 	/* Reset endpoint if required */
439
 	/* Reset endpoint if required */
437
-	if ( ( ep->rc != 0 ) && ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) )
440
+	if ( ( ! list_empty ( &ep->halted ) ) &&
441
+	     ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) )
438
 		return rc;
442
 		return rc;
439
 
443
 
440
 	/* Zero input data buffer (if applicable) */
444
 	/* Zero input data buffer (if applicable) */
480
 		return -ENODEV;
484
 		return -ENODEV;
481
 
485
 
482
 	/* Reset endpoint if required */
486
 	/* Reset endpoint if required */
483
-	if ( ( ep->rc != 0 ) && ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) )
487
+	if ( ( ! list_empty ( &ep->halted ) ) &&
488
+	     ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) )
484
 		return rc;
489
 		return rc;
485
 
490
 
486
 	/* Enqueue stream transfer */
491
 	/* Enqueue stream transfer */
507
 void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf,
512
 void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf,
508
 			int rc ) {
513
 			int rc ) {
509
 	struct usb_device *usb = ep->usb;
514
 	struct usb_device *usb = ep->usb;
515
+	struct usb_bus *bus = usb->port->hub->bus;
510
 
516
 
511
 	/* Decrement fill level */
517
 	/* Decrement fill level */
512
 	assert ( ep->fill > 0 );
518
 	assert ( ep->fill > 0 );
513
 	ep->fill--;
519
 	ep->fill--;
514
 
520
 
515
-	/* Record error (if any) */
516
-	ep->rc = rc;
521
+	/* Schedule reset, if applicable */
517
 	if ( ( rc != 0 ) && ep->open ) {
522
 	if ( ( rc != 0 ) && ep->open ) {
518
 		DBGC ( usb, "USB %s %s completion failed: %s\n",
523
 		DBGC ( usb, "USB %s %s completion failed: %s\n",
519
 		       usb->name, usb_endpoint_name ( ep->address ),
524
 		       usb->name, usb_endpoint_name ( ep->address ),
520
 		       strerror ( rc ) );
525
 		       strerror ( rc ) );
526
+		list_del ( &ep->halted );
527
+		list_add_tail ( &ep->halted, &bus->halted );
521
 	}
528
 	}
522
 
529
 
523
 	/* Report completion */
530
 	/* Report completion */
642
  ******************************************************************************
649
  ******************************************************************************
643
  */
650
  */
644
 
651
 
652
+/** USB control transfer pseudo-header */
653
+struct usb_control_pseudo_header {
654
+	/** Completion status */
655
+	int rc;
656
+};
657
+
645
 /**
658
 /**
646
  * Complete USB control transfer
659
  * Complete USB control transfer
647
  *
660
  *
652
 static void usb_control_complete ( struct usb_endpoint *ep,
665
 static void usb_control_complete ( struct usb_endpoint *ep,
653
 				   struct io_buffer *iobuf, int rc ) {
666
 				   struct io_buffer *iobuf, int rc ) {
654
 	struct usb_device *usb = ep->usb;
667
 	struct usb_device *usb = ep->usb;
668
+	struct usb_control_pseudo_header *pshdr;
655
 
669
 
656
-	/* Check for failures */
670
+	/* Record completion status in buffer */
671
+	pshdr = iob_push ( iobuf, sizeof ( *pshdr ) );
672
+	pshdr->rc = rc;
657
 	if ( rc != 0 ) {
673
 	if ( rc != 0 ) {
658
 		DBGC ( usb, "USB %s control transaction failed: %s\n",
674
 		DBGC ( usb, "USB %s control transaction failed: %s\n",
659
 		       usb->name, strerror ( rc ) );
675
 		       usb->name, strerror ( rc ) );
660
-		free_iob ( iobuf );
661
-		return;
662
 	}
676
 	}
663
 
677
 
664
 	/* Add to list of completed I/O buffers */
678
 	/* Add to list of completed I/O buffers */
686
 		  size_t len ) {
700
 		  size_t len ) {
687
 	struct usb_bus *bus = usb->port->hub->bus;
701
 	struct usb_bus *bus = usb->port->hub->bus;
688
 	struct usb_endpoint *ep = &usb->control;
702
 	struct usb_endpoint *ep = &usb->control;
703
+	struct usb_control_pseudo_header *pshdr;
689
 	struct io_buffer *iobuf;
704
 	struct io_buffer *iobuf;
690
 	struct io_buffer *cmplt;
705
 	struct io_buffer *cmplt;
691
 	unsigned int i;
706
 	unsigned int i;
692
 	int rc;
707
 	int rc;
693
 
708
 
694
 	/* Allocate I/O buffer */
709
 	/* Allocate I/O buffer */
695
-	iobuf = alloc_iob ( len );
710
+	iobuf = alloc_iob ( sizeof ( *pshdr ) + len );
696
 	if ( ! iobuf ) {
711
 	if ( ! iobuf ) {
697
 		rc = -ENOMEM;
712
 		rc = -ENOMEM;
698
 		goto err_alloc;
713
 		goto err_alloc;
699
 	}
714
 	}
715
+	iob_reserve ( iobuf, sizeof ( *pshdr ) );
700
 	iob_put ( iobuf, len );
716
 	iob_put ( iobuf, len );
701
 	if ( request & USB_DIR_IN ) {
717
 	if ( request & USB_DIR_IN ) {
702
 		memset ( data, 0, len );
718
 		memset ( data, 0, len );
722
 			/* Remove from completion list */
738
 			/* Remove from completion list */
723
 			list_del ( &cmplt->list );
739
 			list_del ( &cmplt->list );
724
 
740
 
741
+			/* Extract and strip completion status */
742
+			pshdr = cmplt->data;
743
+			iob_pull ( cmplt, sizeof ( *pshdr ) );
744
+			rc = pshdr->rc;
745
+
725
 			/* Discard stale completions */
746
 			/* Discard stale completions */
726
 			if ( cmplt != iobuf ) {
747
 			if ( cmplt != iobuf ) {
727
-				DBGC ( usb, "USB %s stale control "
728
-				       "completion:\n", usb->name );
748
+				DBGC ( usb, "USB %s stale control completion: "
749
+				       "%s\n", usb->name, strerror ( rc ) );
729
 				DBGC_HDA ( usb, 0, cmplt->data,
750
 				DBGC_HDA ( usb, 0, cmplt->data,
730
 					   iob_len ( cmplt ) );
751
 					   iob_len ( cmplt ) );
731
 				free_iob ( cmplt );
752
 				free_iob ( cmplt );
732
 				continue;
753
 				continue;
733
 			}
754
 			}
734
 
755
 
756
+			/* Fail immediately if completion was in error */
757
+			if ( rc != 0 ) {
758
+				free_iob ( cmplt );
759
+				return rc;
760
+			}
761
+
735
 			/* Copy completion to data buffer, if applicable */
762
 			/* Copy completion to data buffer, if applicable */
736
 			assert ( iob_len ( cmplt ) <= len );
763
 			assert ( iob_len ( cmplt ) <= len );
737
 			if ( request & USB_DIR_IN )
764
 			if ( request & USB_DIR_IN )
740
 			return 0;
767
 			return 0;
741
 		}
768
 		}
742
 
769
 
743
-		/* Fail immediately if endpoint is in an error state */
744
-		if ( ep->rc )
745
-			return ep->rc;
746
-
747
 		/* Delay */
770
 		/* Delay */
748
 		mdelay ( 1 );
771
 		mdelay ( 1 );
749
 	}
772
 	}
1549
 	struct usb_bus *bus = hub->bus;
1572
 	struct usb_bus *bus = hub->bus;
1550
 
1573
 
1551
 	/* Record hub port status change */
1574
 	/* Record hub port status change */
1552
-	list_del ( &port->list );
1553
-	list_add_tail ( &port->list, &bus->changed );
1575
+	list_del ( &port->changed );
1576
+	list_add_tail ( &port->changed, &bus->changed );
1554
 }
1577
 }
1555
 
1578
 
1556
 /**
1579
 /**
1559
  * @v bus		USB bus
1582
  * @v bus		USB bus
1560
  */
1583
  */
1561
 static void usb_step ( struct usb_bus *bus ) {
1584
 static void usb_step ( struct usb_bus *bus ) {
1585
+	struct usb_endpoint *ep;
1562
 	struct usb_port *port;
1586
 	struct usb_port *port;
1563
 
1587
 
1564
 	/* Poll bus */
1588
 	/* Poll bus */
1565
 	usb_poll ( bus );
1589
 	usb_poll ( bus );
1566
 
1590
 
1591
+	/* Attempt to reset first halted endpoint in list, if any.  We
1592
+	 * do not attempt to process the complete list, since this
1593
+	 * would require extra code to allow for the facts that the
1594
+	 * halted endpoint list may change as we do so, and that
1595
+	 * resetting an endpoint may fail.
1596
+	 */
1597
+	if ( ( ep = list_first_entry ( &bus->halted, struct usb_endpoint,
1598
+				       halted ) ) != NULL )
1599
+		usb_endpoint_reset ( ep );
1600
+
1567
 	/* Handle any changed ports, allowing for the fact that the
1601
 	/* Handle any changed ports, allowing for the fact that the
1568
 	 * port list may change as we perform hotplug actions.
1602
 	 * port list may change as we perform hotplug actions.
1569
 	 */
1603
 	 */
1570
 	while ( ! list_empty ( &bus->changed ) ) {
1604
 	while ( ! list_empty ( &bus->changed ) ) {
1571
 
1605
 
1572
 		/* Get first changed port */
1606
 		/* Get first changed port */
1573
-		port = list_first_entry ( &bus->changed, struct usb_port, list);
1607
+		port = list_first_entry ( &bus->changed, struct usb_port,
1608
+					  changed );
1574
 		assert ( port != NULL );
1609
 		assert ( port != NULL );
1575
 
1610
 
1576
 		/* Remove from list of changed ports */
1611
 		/* Remove from list of changed ports */
1577
-		list_del ( &port->list );
1578
-		INIT_LIST_HEAD ( &port->list );
1612
+		list_del ( &port->changed );
1613
+		INIT_LIST_HEAD ( &port->changed );
1579
 
1614
 
1580
 		/* Perform appropriate hotplug action */
1615
 		/* Perform appropriate hotplug action */
1581
 		usb_hotplug ( port );
1616
 		usb_hotplug ( port );
1628
 		port->address = i;
1663
 		port->address = i;
1629
 		if ( usb )
1664
 		if ( usb )
1630
 			port->protocol = usb->port->protocol;
1665
 			port->protocol = usb->port->protocol;
1631
-		INIT_LIST_HEAD ( &port->list );
1666
+		INIT_LIST_HEAD ( &port->changed );
1632
 	}
1667
 	}
1633
 
1668
 
1634
 	return hub;
1669
 	return hub;
1702
 	/* Cancel any pending port status changes */
1737
 	/* Cancel any pending port status changes */
1703
 	for ( i = 1 ; i <= hub->ports ; i++ ) {
1738
 	for ( i = 1 ; i <= hub->ports ; i++ ) {
1704
 		port = usb_port ( hub, i );
1739
 		port = usb_port ( hub, i );
1705
-		list_del ( &port->list );
1706
-		INIT_LIST_HEAD ( &port->list );
1740
+		list_del ( &port->changed );
1741
+		INIT_LIST_HEAD ( &port->changed );
1707
 	}
1742
 	}
1708
 
1743
 
1709
 	/* Remove from hub list */
1744
 	/* Remove from hub list */
1724
 		port = usb_port ( hub, i );
1759
 		port = usb_port ( hub, i );
1725
 		assert ( ! port->attached );
1760
 		assert ( ! port->attached );
1726
 		assert ( port->usb == NULL );
1761
 		assert ( port->usb == NULL );
1727
-		assert ( list_empty ( &port->list ) );
1762
+		assert ( list_empty ( &port->changed ) );
1728
 	}
1763
 	}
1729
 
1764
 
1730
 	/* Free hub */
1765
 	/* Free hub */
1762
 	INIT_LIST_HEAD ( &bus->devices );
1797
 	INIT_LIST_HEAD ( &bus->devices );
1763
 	INIT_LIST_HEAD ( &bus->hubs );
1798
 	INIT_LIST_HEAD ( &bus->hubs );
1764
 	INIT_LIST_HEAD ( &bus->changed );
1799
 	INIT_LIST_HEAD ( &bus->changed );
1800
+	INIT_LIST_HEAD ( &bus->halted );
1765
 	process_init_stopped ( &bus->process, &usb_process_desc, NULL );
1801
 	process_init_stopped ( &bus->process, &usb_process_desc, NULL );
1766
 	bus->host = &bus->op->bus;
1802
 	bus->host = &bus->op->bus;
1767
 
1803
 

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

380
 
380
 
381
 	/** Endpoint is open */
381
 	/** Endpoint is open */
382
 	int open;
382
 	int open;
383
-	/** Current failure state (if any) */
384
-	int rc;
385
 	/** Buffer fill level */
383
 	/** Buffer fill level */
386
 	unsigned int fill;
384
 	unsigned int fill;
387
 
385
 
386
+	/** List of halted endpoints */
387
+	struct list_head halted;
388
+
388
 	/** Host controller operations */
389
 	/** Host controller operations */
389
 	struct usb_endpoint_host_operations *host;
390
 	struct usb_endpoint_host_operations *host;
390
 	/** Host controller private data */
391
 	/** Host controller private data */
754
 	 */
755
 	 */
755
 	struct usb_device *usb;
756
 	struct usb_device *usb;
756
 	/** List of changed ports */
757
 	/** List of changed ports */
757
-	struct list_head list;
758
+	struct list_head changed;
758
 };
759
 };
759
 
760
 
760
 /** A USB hub */
761
 /** A USB hub */
888
 	struct list_head hubs;
889
 	struct list_head hubs;
889
 	/** List of changed ports */
890
 	/** List of changed ports */
890
 	struct list_head changed;
891
 	struct list_head changed;
892
+	/** List of halted endpoints */
893
+	struct list_head halted;
891
 	/** Process */
894
 	/** Process */
892
 	struct process process;
895
 	struct process process;
893
 
896
 

Loading…
Cancel
Save