Browse Source

[xhci] Support USB1 devices attached via transaction translators

xHCI provides a somewhat convoluted mechanism for specifying details
of a transaction translator.  Hubs must be marked as such in the
device slot context.  The only opportunity to do so is as part of a
Configure Endpoint command, which can be executed only when opening
the hub's interrupt endpoint.

We add a mechanism for host controllers to intercept the opening of
hub devices, providing xHCI with an opportunity to update the internal
device slot structure for the corresponding USB device to indicate
that the device is a hub.  We then include the hub-specific details in
the input context whenever any Configure Endpoint command is issued.

When a device is opened, we record the device slot and port for its
transaction translator (if any), and supply these as part of the
Address Device command.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
f557794ab3
5 changed files with 164 additions and 33 deletions
  1. 18
    5
      src/drivers/bus/usb.c
  2. 46
    13
      src/drivers/usb/ehci.c
  3. 73
    13
      src/drivers/usb/xhci.c
  4. 6
    0
      src/drivers/usb/xhci.h
  5. 21
    2
      src/include/ipxe/usb.h

+ 18
- 5
src/drivers/bus/usb.c View File

@@ -1692,6 +1692,7 @@ struct usb_hub * alloc_usb_hub ( struct usb_bus *bus, struct usb_device *usb,
1692 1692
 		hub->protocol = usb->port->protocol;
1693 1693
 	hub->ports = ports;
1694 1694
 	hub->driver = driver;
1695
+	hub->host = &bus->op->hub;
1695 1696
 
1696 1697
 	/* Initialise port list */
1697 1698
 	for ( i = 1 ; i <= hub->ports ; i++ ) {
@@ -1721,11 +1722,18 @@ int register_usb_hub ( struct usb_hub *hub ) {
1721 1722
 	/* Add to hub list */
1722 1723
 	list_add_tail ( &hub->list, &bus->hubs );
1723 1724
 
1724
-	/* Open hub */
1725
+	/* Open hub (host controller) */
1726
+	if ( ( rc = hub->host->open ( hub ) ) != 0 ) {
1727
+		DBGC ( hub, "USB hub %s could not open: %s\n",
1728
+		       hub->name, strerror ( rc ) );
1729
+		goto err_host_open;
1730
+	}
1731
+
1732
+	/* Open hub (driver) */
1725 1733
 	if ( ( rc = hub->driver->open ( hub ) ) != 0 ) {
1726 1734
 		DBGC ( hub, "USB hub %s could not open: %s\n",
1727 1735
 		       hub->name, strerror ( rc ) );
1728
-		goto err_open;
1736
+		goto err_driver_open;
1729 1737
 	}
1730 1738
 
1731 1739
 	/* Delay to allow ports to stabilise */
@@ -1747,7 +1755,9 @@ int register_usb_hub ( struct usb_hub *hub ) {
1747 1755
 	return 0;
1748 1756
 
1749 1757
 	hub->driver->close ( hub );
1750
- err_open:
1758
+ err_driver_open:
1759
+	hub->host->close ( hub );
1760
+ err_host_open:
1751 1761
 	list_del ( &hub->list );
1752 1762
 	return rc;
1753 1763
 }
@@ -1768,9 +1778,12 @@ void unregister_usb_hub ( struct usb_hub *hub ) {
1768 1778
 			usb_detached ( port );
1769 1779
 	}
1770 1780
 
1771
-	/* Close hub */
1781
+	/* Close hub (driver) */
1772 1782
 	hub->driver->close ( hub );
1773 1783
 
1784
+	/* Close hub (host controller) */
1785
+	hub->host->close ( hub );
1786
+
1774 1787
 	/* Cancel any pending port status changes */
1775 1788
 	for ( i = 1 ; i <= hub->ports ; i++ ) {
1776 1789
 		port = usb_port ( hub, i );
@@ -1839,7 +1852,7 @@ struct usb_bus * alloc_usb_bus ( struct device *dev, unsigned int ports,
1839 1852
 	bus->host = &bus->op->bus;
1840 1853
 
1841 1854
 	/* Allocate root hub */
1842
-	bus->hub = alloc_usb_hub ( bus, NULL, ports, &op->hub );
1855
+	bus->hub = alloc_usb_hub ( bus, NULL, ports, &op->root );
1843 1856
 	if ( ! bus->hub )
1844 1857
 		goto err_alloc_hub;
1845 1858
 

+ 46
- 13
src/drivers/usb/ehci.c View File

@@ -1330,6 +1330,35 @@ static int ehci_device_address ( struct usb_device *usb ) {
1330 1330
 	return rc;
1331 1331
 }
1332 1332
 
1333
+/******************************************************************************
1334
+ *
1335
+ * Hub operations
1336
+ *
1337
+ ******************************************************************************
1338
+ */
1339
+
1340
+/**
1341
+ * Open hub
1342
+ *
1343
+ * @v hub		USB hub
1344
+ * @ret rc		Return status code
1345
+ */
1346
+static int ehci_hub_open ( struct usb_hub *hub __unused ) {
1347
+
1348
+	/* Nothing to do */
1349
+	return 0;
1350
+}
1351
+
1352
+/**
1353
+ * Close hub
1354
+ *
1355
+ * @v hub		USB hub
1356
+ */
1357
+static void ehci_hub_close ( struct usb_hub *hub __unused ) {
1358
+
1359
+	/* Nothing to do */
1360
+}
1361
+
1333 1362
 /******************************************************************************
1334 1363
  *
1335 1364
  * Root hub operations
@@ -1343,7 +1372,7 @@ static int ehci_device_address ( struct usb_device *usb ) {
1343 1372
  * @v hub		USB hub
1344 1373
  * @ret rc		Return status code
1345 1374
  */
1346
-static int ehci_hub_open ( struct usb_hub *hub ) {
1375
+static int ehci_root_open ( struct usb_hub *hub ) {
1347 1376
 	struct usb_bus *bus = hub->bus;
1348 1377
 	struct ehci_device *ehci = usb_bus_get_hostdata ( bus );
1349 1378
 	uint32_t portsc;
@@ -1374,7 +1403,7 @@ static int ehci_hub_open ( struct usb_hub *hub ) {
1374 1403
  *
1375 1404
  * @v hub		USB hub
1376 1405
  */
1377
-static void ehci_hub_close ( struct usb_hub *hub ) {
1406
+static void ehci_root_close ( struct usb_hub *hub ) {
1378 1407
 	struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
1379 1408
 
1380 1409
 	/* Route all ports back to companion controllers */
@@ -1391,7 +1420,7 @@ static void ehci_hub_close ( struct usb_hub *hub ) {
1391 1420
  * @v port		USB port
1392 1421
  * @ret rc		Return status code
1393 1422
  */
1394
-static int ehci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
1423
+static int ehci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
1395 1424
 	struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
1396 1425
 	uint32_t portsc;
1397 1426
 	unsigned int line;
@@ -1449,7 +1478,7 @@ static int ehci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
1449 1478
  * @v port		USB port
1450 1479
  * @ret rc		Return status code
1451 1480
  */
1452
-static int ehci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
1481
+static int ehci_root_disable ( struct usb_hub *hub, struct usb_port *port ) {
1453 1482
 	struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
1454 1483
 	uint32_t portsc;
1455 1484
 
@@ -1468,7 +1497,7 @@ static int ehci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
1468 1497
  * @v port		USB port
1469 1498
  * @ret rc		Return status code
1470 1499
  */
1471
-static int ehci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
1500
+static int ehci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
1472 1501
 	struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
1473 1502
 	uint32_t portsc;
1474 1503
 	unsigned int speed;
@@ -1512,8 +1541,8 @@ static int ehci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
1512 1541
  * @v ep		USB endpoint
1513 1542
  * @ret rc		Return status code
1514 1543
  */
1515
-static int ehci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
1516
-			       struct usb_endpoint *ep ) {
1544
+static int ehci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
1545
+				struct usb_endpoint *ep ) {
1517 1546
 	struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
1518 1547
 
1519 1548
 	/* Should never be called; this is a root hub */
@@ -1529,7 +1558,7 @@ static int ehci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
1529 1558
  * @v hub		USB hub
1530 1559
  * @v port		USB port
1531 1560
  */
1532
-static void ehci_hub_poll ( struct usb_hub *hub, struct usb_port *port ) {
1561
+static void ehci_root_poll ( struct usb_hub *hub, struct usb_port *port ) {
1533 1562
 	struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
1534 1563
 	uint32_t portsc;
1535 1564
 	uint32_t change;
@@ -1692,7 +1721,7 @@ static void ehci_bus_poll ( struct usb_bus *bus ) {
1692 1721
 
1693 1722
 		/* Iterate over all ports looking for status changes */
1694 1723
 		for ( i = 1 ; i <= ehci->ports ; i++ )
1695
-			ehci_hub_poll ( hub, usb_port ( hub, i ) );
1724
+			ehci_root_poll ( hub, usb_port ( hub, i ) );
1696 1725
 	}
1697 1726
 
1698 1727
 	/* Report fatal errors */
@@ -1730,10 +1759,14 @@ static struct usb_host_operations ehci_operations = {
1730 1759
 	.hub = {
1731 1760
 		.open = ehci_hub_open,
1732 1761
 		.close = ehci_hub_close,
1733
-		.enable = ehci_hub_enable,
1734
-		.disable = ehci_hub_disable,
1735
-		.speed = ehci_hub_speed,
1736
-		.clear_tt = ehci_hub_clear_tt,
1762
+	},
1763
+	.root = {
1764
+		.open = ehci_root_open,
1765
+		.close = ehci_root_close,
1766
+		.enable = ehci_root_enable,
1767
+		.disable = ehci_root_disable,
1768
+		.speed = ehci_root_speed,
1769
+		.clear_tt = ehci_root_clear_tt,
1737 1770
 	},
1738 1771
 };
1739 1772
 

+ 73
- 13
src/drivers/usb/xhci.c View File

@@ -1990,6 +1990,8 @@ static void xhci_address_device_input ( struct xhci_device *xhci,
1990 1990
 	slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( 1, 0, slot->psiv,
1991 1991
 							slot->route ) );
1992 1992
 	slot_ctx->port = slot->port;
1993
+	slot_ctx->tt_id = slot->tt_id;
1994
+	slot_ctx->tt_port = slot->tt_port;
1993 1995
 
1994 1996
 	/* Populate control endpoint context */
1995 1997
 	ep_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_EP0 ) );
@@ -2039,7 +2041,7 @@ static inline int xhci_address_device ( struct xhci_device *xhci,
2039 2041
  * @v input		Input context
2040 2042
  */
2041 2043
 static void xhci_configure_endpoint_input ( struct xhci_device *xhci,
2042
-					    struct xhci_slot *slot __unused,
2044
+					    struct xhci_slot *slot,
2043 2045
 					    struct xhci_endpoint *endpoint,
2044 2046
 					    void *input ) {
2045 2047
 	struct xhci_control_context *control_ctx;
@@ -2054,7 +2056,9 @@ static void xhci_configure_endpoint_input ( struct xhci_device *xhci,
2054 2056
 	/* Populate slot context */
2055 2057
 	slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
2056 2058
 	slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
2057
-							0, 0, 0 ) );
2059
+							( slot->ports ? 1 : 0 ),
2060
+							slot->psiv, 0 ) );
2061
+	slot_ctx->ports = slot->ports;
2058 2062
 
2059 2063
 	/* Populate endpoint context */
2060 2064
 	ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
@@ -2587,7 +2591,9 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep,
2587 2591
  */
2588 2592
 static int xhci_device_open ( struct usb_device *usb ) {
2589 2593
 	struct xhci_device *xhci = usb_bus_get_hostdata ( usb->port->hub->bus );
2594
+	struct usb_port *tt = usb_transaction_translator ( usb );
2590 2595
 	struct xhci_slot *slot;
2596
+	struct xhci_slot *tt_slot;
2591 2597
 	size_t len;
2592 2598
 	int type;
2593 2599
 	int id;
@@ -2621,6 +2627,11 @@ static int xhci_device_open ( struct usb_device *usb ) {
2621 2627
 	slot->xhci = xhci;
2622 2628
 	slot->usb = usb;
2623 2629
 	slot->id = id;
2630
+	if ( tt ) {
2631
+		tt_slot = usb_get_hostdata ( tt->hub->usb );
2632
+		slot->tt_id = tt_slot->id;
2633
+		slot->tt_port = tt->address;
2634
+	}
2624 2635
 
2625 2636
 	/* Allocate a device context */
2626 2637
 	len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
@@ -2817,6 +2828,51 @@ static void xhci_bus_poll ( struct usb_bus *bus ) {
2817 2828
 	xhci_event_poll ( xhci );
2818 2829
 }
2819 2830
 
2831
+/******************************************************************************
2832
+ *
2833
+ * Hub operations
2834
+ *
2835
+ ******************************************************************************
2836
+ */
2837
+
2838
+/**
2839
+ * Open hub
2840
+ *
2841
+ * @v hub		USB hub
2842
+ * @ret rc		Return status code
2843
+ */
2844
+static int xhci_hub_open ( struct usb_hub *hub ) {
2845
+	struct xhci_slot *slot;
2846
+
2847
+	/* Do nothing if this is the root hub */
2848
+	if ( ! hub->usb )
2849
+		return 0;
2850
+
2851
+	/* Get device slot */
2852
+	slot = usb_get_hostdata ( hub->usb );
2853
+
2854
+	/* Update device slot hub parameters.  We don't inform the
2855
+	 * hardware of this information until the hub's interrupt
2856
+	 * endpoint is opened, since the only mechanism for so doing
2857
+	 * provided by the xHCI specification is a Configure Endpoint
2858
+	 * command, and we can't issue that command until we have a
2859
+	 * non-EP0 endpoint to configure.
2860
+	 */
2861
+	slot->ports = hub->ports;
2862
+
2863
+	return 0;
2864
+}
2865
+
2866
+/**
2867
+ * Close hub
2868
+ *
2869
+ * @v hub		USB hub
2870
+ */
2871
+static void xhci_hub_close ( struct usb_hub *hub __unused ) {
2872
+
2873
+	/* Nothing to do */
2874
+}
2875
+
2820 2876
 /******************************************************************************
2821 2877
  *
2822 2878
  * Root hub operations
@@ -2830,7 +2886,7 @@ static void xhci_bus_poll ( struct usb_bus *bus ) {
2830 2886
  * @v hub		USB hub
2831 2887
  * @ret rc		Return status code
2832 2888
  */
2833
-static int xhci_hub_open ( struct usb_hub *hub ) {
2889
+static int xhci_root_open ( struct usb_hub *hub ) {
2834 2890
 	struct usb_bus *bus = hub->bus;
2835 2891
 	struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
2836 2892
 	struct usb_port *port;
@@ -2880,7 +2936,7 @@ static int xhci_hub_open ( struct usb_hub *hub ) {
2880 2936
  *
2881 2937
  * @v hub		USB hub
2882 2938
  */
2883
-static void xhci_hub_close ( struct usb_hub *hub ) {
2939
+static void xhci_root_close ( struct usb_hub *hub ) {
2884 2940
 
2885 2941
 	/* Clear hub driver private data */
2886 2942
 	usb_hub_set_drvdata ( hub, NULL );
@@ -2893,7 +2949,7 @@ static void xhci_hub_close ( struct usb_hub *hub ) {
2893 2949
  * @v port		USB port
2894 2950
  * @ret rc		Return status code
2895 2951
  */
2896
-static int xhci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
2952
+static int xhci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
2897 2953
 	struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
2898 2954
 	uint32_t portsc;
2899 2955
 	unsigned int i;
@@ -2930,7 +2986,7 @@ static int xhci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
2930 2986
  * @v port		USB port
2931 2987
  * @ret rc		Return status code
2932 2988
  */
2933
-static int xhci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
2989
+static int xhci_root_disable ( struct usb_hub *hub, struct usb_port *port ) {
2934 2990
 	struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
2935 2991
 	uint32_t portsc;
2936 2992
 
@@ -2950,7 +3006,7 @@ static int xhci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
2950 3006
  * @v port		USB port
2951 3007
  * @ret rc		Return status code
2952 3008
  */
2953
-static int xhci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
3009
+static int xhci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
2954 3010
 	struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
2955 3011
 	uint32_t portsc;
2956 3012
 	unsigned int psiv;
@@ -3000,8 +3056,8 @@ static int xhci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
3000 3056
  * @v ep		USB endpoint
3001 3057
  * @ret rc		Return status code
3002 3058
  */
3003
-static int xhci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
3004
-			       struct usb_endpoint *ep ) {
3059
+static int xhci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
3060
+				struct usb_endpoint *ep ) {
3005 3061
 	struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
3006 3062
 
3007 3063
 	/* Should never be called; this is a root hub */
@@ -3041,10 +3097,14 @@ static struct usb_host_operations xhci_operations = {
3041 3097
 	.hub = {
3042 3098
 		.open = xhci_hub_open,
3043 3099
 		.close = xhci_hub_close,
3044
-		.enable = xhci_hub_enable,
3045
-		.disable = xhci_hub_disable,
3046
-		.speed = xhci_hub_speed,
3047
-		.clear_tt = xhci_hub_clear_tt,
3100
+	},
3101
+	.root = {
3102
+		.open = xhci_root_open,
3103
+		.close = xhci_root_close,
3104
+		.enable = xhci_root_enable,
3105
+		.disable = xhci_root_disable,
3106
+		.speed = xhci_root_speed,
3107
+		.clear_tt = xhci_root_clear_tt,
3048 3108
 	},
3049 3109
 };
3050 3110
 

+ 6
- 0
src/drivers/usb/xhci.h View File

@@ -1110,6 +1110,12 @@ struct xhci_slot {
1110 1110
 	unsigned int port;
1111 1111
 	/** Protocol speed ID */
1112 1112
 	unsigned int psiv;
1113
+	/** Number of ports (if this device is a hub) */
1114
+	unsigned int ports;
1115
+	/** Transaction translator slot ID */
1116
+	unsigned int tt_id;
1117
+	/** Transaction translator port */
1118
+	unsigned int tt_port;
1113 1119
 	/** Endpoints, indexed by context ID */
1114 1120
 	struct xhci_endpoint *endpoint[XHCI_CTX_END];
1115 1121
 };

+ 21
- 2
src/include/ipxe/usb.h View File

@@ -777,6 +777,8 @@ struct usb_hub {
777 777
 	/** List of hubs */
778 778
 	struct list_head list;
779 779
 
780
+	/** Host controller operations */
781
+	struct usb_hub_host_operations *host;
780 782
 	/** Driver operations */
781 783
 	struct usb_hub_driver_operations *driver;
782 784
 	/** Driver private data */
@@ -789,7 +791,22 @@ struct usb_hub {
789 791
 	struct usb_port port[0];
790 792
 };
791 793
 
792
-/** USB hub operations */
794
+/** USB hub host controller operations */
795
+struct usb_hub_host_operations {
796
+	/** Open hub
797
+	 *
798
+	 * @v hub		USB hub
799
+	 * @ret rc		Return status code
800
+	 */
801
+	int ( * open ) ( struct usb_hub *hub );
802
+	/** Close hub
803
+	 *
804
+	 * @v hub		USB hub
805
+	 */
806
+	void ( * close ) ( struct usb_hub *hub );
807
+};
808
+
809
+/** USB hub driver operations */
793 810
 struct usb_hub_driver_operations {
794 811
 	/** Open hub
795 812
 	 *
@@ -940,8 +957,10 @@ struct usb_host_operations {
940 957
 	struct usb_device_host_operations device;
941 958
 	/** Bus operations */
942 959
 	struct usb_bus_host_operations bus;
960
+	/** Hub operations */
961
+	struct usb_hub_host_operations hub;
943 962
 	/** Root hub operations */
944
-	struct usb_hub_driver_operations hub;
963
+	struct usb_hub_driver_operations root;
945 964
 };
946 965
 
947 966
 /**

Loading…
Cancel
Save