Parcourir la source

[usb] Maintain single lists of halted endpoints and changed ports

When an EHCI hotplug action results in the controller disowning the
port, it will result in a hotplug action on the corresponding UHCI or
OHCI controller.  Allow such hotplug actions to be carried out as part
of the same call to usb_step() or usb_register_bus(), by maintaining a
single central list of changed ports.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown il y a 9 ans
Parent
révision
e4783add79
2 fichiers modifiés avec 55 ajouts et 50 suppressions
  1. 55
    44
      src/drivers/bus/usb.c
  2. 0
    6
      src/include/ipxe/usb.h

+ 55
- 44
src/drivers/bus/usb.c Voir le fichier

@@ -43,6 +43,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
43 43
 /** List of USB buses */
44 44
 struct list_head usb_buses = LIST_HEAD_INIT ( usb_buses );
45 45
 
46
+/** List of changed ports */
47
+static struct list_head usb_changed = LIST_HEAD_INIT ( usb_changed );
48
+
49
+/** List of halted endpoints */
50
+static struct list_head usb_halted = LIST_HEAD_INIT ( usb_halted );
51
+
46 52
 /******************************************************************************
47 53
  *
48 54
  * Utility functions
@@ -560,7 +566,6 @@ int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf,
560 566
 void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf,
561 567
 			int rc ) {
562 568
 	struct usb_device *usb = ep->usb;
563
-	struct usb_bus *bus = usb->port->hub->bus;
564 569
 
565 570
 	/* Decrement fill level */
566 571
 	assert ( ep->fill > 0 );
@@ -572,7 +577,7 @@ void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf,
572 577
 		       usb->name, usb_endpoint_name ( ep->address ),
573 578
 		       strerror ( rc ) );
574 579
 		list_del ( &ep->halted );
575
-		list_add_tail ( &ep->halted, &bus->halted );
580
+		list_add_tail ( &ep->halted, &usb_halted );
576 581
 	}
577 582
 
578 583
 	/* Report completion */
@@ -1576,12 +1581,12 @@ static void usb_detached ( struct usb_port *port ) {
1576 1581
 }
1577 1582
 
1578 1583
 /**
1579
- * Handle newly attached or detached USB devices
1584
+ * Handle newly attached or detached USB device
1580 1585
  *
1581 1586
  * @v port		USB port
1582 1587
  * @ret rc		Return status code
1583 1588
  */
1584
-static int usb_hotplug ( struct usb_port *port ) {
1589
+static int usb_hotplugged ( struct usb_port *port ) {
1585 1590
 	struct usb_hub *hub = port->hub;
1586 1591
 	int rc;
1587 1592
 
@@ -1621,43 +1626,26 @@ static int usb_hotplug ( struct usb_port *port ) {
1621 1626
  * @v port		USB port
1622 1627
  */
1623 1628
 void usb_port_changed ( struct usb_port *port ) {
1624
-	struct usb_hub *hub = port->hub;
1625
-	struct usb_bus *bus = hub->bus;
1626 1629
 
1627 1630
 	/* Record hub port status change */
1628 1631
 	list_del ( &port->changed );
1629
-	list_add_tail ( &port->changed, &bus->changed );
1632
+	list_add_tail ( &port->changed, &usb_changed );
1630 1633
 }
1631 1634
 
1632 1635
 /**
1633
- * USB process
1636
+ * Handle newly attached or detached USB device
1634 1637
  *
1635
- * @v bus		USB bus
1636 1638
  */
1637
-static void usb_step ( struct usb_bus *bus ) {
1638
-	struct usb_endpoint *ep;
1639
+static void usb_hotplug ( void ) {
1639 1640
 	struct usb_port *port;
1640 1641
 
1641
-	/* Poll bus */
1642
-	usb_poll ( bus );
1643
-
1644
-	/* Attempt to reset first halted endpoint in list, if any.  We
1645
-	 * do not attempt to process the complete list, since this
1646
-	 * would require extra code to allow for the facts that the
1647
-	 * halted endpoint list may change as we do so, and that
1648
-	 * resetting an endpoint may fail.
1649
-	 */
1650
-	if ( ( ep = list_first_entry ( &bus->halted, struct usb_endpoint,
1651
-				       halted ) ) != NULL )
1652
-		usb_endpoint_reset ( ep );
1653
-
1654 1642
 	/* Handle any changed ports, allowing for the fact that the
1655 1643
 	 * port list may change as we perform hotplug actions.
1656 1644
 	 */
1657
-	while ( ! list_empty ( &bus->changed ) ) {
1645
+	while ( ! list_empty ( &usb_changed ) ) {
1658 1646
 
1659 1647
 		/* Get first changed port */
1660
-		port = list_first_entry ( &bus->changed, struct usb_port,
1648
+		port = list_first_entry ( &usb_changed, struct usb_port,
1661 1649
 					  changed );
1662 1650
 		assert ( port != NULL );
1663 1651
 
@@ -1666,13 +1654,39 @@ static void usb_step ( struct usb_bus *bus ) {
1666 1654
 		INIT_LIST_HEAD ( &port->changed );
1667 1655
 
1668 1656
 		/* Perform appropriate hotplug action */
1669
-		usb_hotplug ( port );
1657
+		usb_hotplugged ( port );
1670 1658
 	}
1671 1659
 }
1672 1660
 
1661
+/**
1662
+ * USB process
1663
+ *
1664
+ * @v process		USB process
1665
+ */
1666
+static void usb_step ( struct process *process __unused ) {
1667
+	struct usb_bus *bus;
1668
+	struct usb_endpoint *ep;
1669
+
1670
+	/* Poll all buses */
1671
+	for_each_usb_bus ( bus )
1672
+		usb_poll ( bus );
1673
+
1674
+	/* Attempt to reset first halted endpoint in list, if any.  We
1675
+	 * do not attempt to process the complete list, since this
1676
+	 * would require extra code to allow for the facts that the
1677
+	 * halted endpoint list may change as we do so, and that
1678
+	 * resetting an endpoint may fail.
1679
+	 */
1680
+	if ( ( ep = list_first_entry ( &usb_halted, struct usb_endpoint,
1681
+				       halted ) ) != NULL )
1682
+		usb_endpoint_reset ( ep );
1683
+
1684
+	/* Handle any changed ports */
1685
+	usb_hotplug();
1686
+}
1687
+
1673 1688
 /** USB process */
1674
-static struct process_descriptor usb_process_desc =
1675
-	PROC_DESC ( struct usb_bus, process, usb_step );
1689
+PERMANENT_PROCESS ( usb_process, usb_step );
1676 1690
 
1677 1691
 /******************************************************************************
1678 1692
  *
@@ -1755,10 +1769,10 @@ int register_usb_hub ( struct usb_hub *hub ) {
1755 1769
 	/* Delay to allow ports to stabilise */
1756 1770
 	mdelay ( USB_PORT_DELAY_MS );
1757 1771
 
1758
-	/* Attach any devices already present */
1772
+	/* Mark all ports as changed */
1759 1773
 	for ( i = 1 ; i <= hub->ports ; i++ ) {
1760 1774
 		port = usb_port ( hub, i );
1761
-		usb_hotplug ( port );
1775
+		usb_port_changed ( port );
1762 1776
 	}
1763 1777
 
1764 1778
 	/* Some hubs seem to defer reporting device connections until
@@ -1766,7 +1780,10 @@ int register_usb_hub ( struct usb_hub *hub ) {
1766 1780
 	 * Poll the bus once now in order to pick up any such
1767 1781
 	 * connections.
1768 1782
 	 */
1769
-	usb_step ( bus );
1783
+	usb_poll ( bus );
1784
+
1785
+	/* Attach any devices already present */
1786
+	usb_hotplug();
1770 1787
 
1771 1788
 	return 0;
1772 1789
 
@@ -1862,9 +1879,6 @@ struct usb_bus * alloc_usb_bus ( struct device *dev, unsigned int ports,
1862 1879
 	bus->op = op;
1863 1880
 	INIT_LIST_HEAD ( &bus->devices );
1864 1881
 	INIT_LIST_HEAD ( &bus->hubs );
1865
-	INIT_LIST_HEAD ( &bus->changed );
1866
-	INIT_LIST_HEAD ( &bus->halted );
1867
-	process_init_stopped ( &bus->process, &usb_process_desc, NULL );
1868 1882
 	bus->host = &bus->op->bus;
1869 1883
 
1870 1884
 	/* Allocate root hub */
@@ -1904,9 +1918,6 @@ int register_usb_bus ( struct usb_bus *bus ) {
1904 1918
 	if ( ( rc = register_usb_hub ( bus->hub ) ) != 0 )
1905 1919
 		goto err_register_hub;
1906 1920
 
1907
-	/* Start bus process */
1908
-	process_add ( &bus->process );
1909
-
1910 1921
 	return 0;
1911 1922
 
1912 1923
 	unregister_usb_hub ( bus->hub );
@@ -1926,10 +1937,6 @@ void unregister_usb_bus ( struct usb_bus *bus ) {
1926 1937
 
1927 1938
 	/* Sanity checks */
1928 1939
 	assert ( bus->hub != NULL );
1929
-	assert ( process_running ( &bus->process ) );
1930
-
1931
-	/* Stop bus process */
1932
-	process_del ( &bus->process );
1933 1940
 
1934 1941
 	/* Unregister root hub */
1935 1942
 	unregister_usb_hub ( bus->hub );
@@ -1943,7 +1950,6 @@ void unregister_usb_bus ( struct usb_bus *bus ) {
1943 1950
 	/* Sanity checks */
1944 1951
 	assert ( list_empty ( &bus->devices ) );
1945 1952
 	assert ( list_empty ( &bus->hubs ) );
1946
-	assert ( ! process_running ( &bus->process ) );
1947 1953
 }
1948 1954
 
1949 1955
 /**
@@ -1952,11 +1958,16 @@ void unregister_usb_bus ( struct usb_bus *bus ) {
1952 1958
  * @v bus		USB bus
1953 1959
  */
1954 1960
 void free_usb_bus ( struct usb_bus *bus ) {
1961
+	struct usb_endpoint *ep;
1962
+	struct usb_port *port;
1955 1963
 
1956 1964
 	/* Sanity checks */
1957 1965
 	assert ( list_empty ( &bus->devices ) );
1958 1966
 	assert ( list_empty ( &bus->hubs ) );
1959
-	assert ( ! process_running ( &bus->process ) );
1967
+	list_for_each_entry ( ep, &usb_halted, halted )
1968
+		assert ( ep->usb->port->hub->bus != bus );
1969
+	list_for_each_entry ( port, &usb_changed, changed )
1970
+		assert ( port->hub->bus != bus );
1960 1971
 
1961 1972
 	/* Free root hub */
1962 1973
 	free_usb_hub ( bus->hub );

+ 0
- 6
src/include/ipxe/usb.h Voir le fichier

@@ -922,12 +922,6 @@ struct usb_bus {
922 922
 	struct list_head devices;
923 923
 	/** List of hubs */
924 924
 	struct list_head hubs;
925
-	/** List of changed ports */
926
-	struct list_head changed;
927
-	/** List of halted endpoints */
928
-	struct list_head halted;
929
-	/** Process */
930
-	struct process process;
931 925
 
932 926
 	/** Host controller operations */
933 927
 	struct usb_bus_host_operations *host;

Chargement…
Annuler
Enregistrer