Commit 8b1ba80c authored by Dan Williams's avatar Dan Williams Committed by Greg Kroah-Hartman

usb: assign usb3 external hub port peers

Given that root hub port peers are already established, external hub peer
ports can be determined by traversing the device topology:

1/ ascend to the parent hub and find the upstream port_dev

2/ walk ->peer to find the peer port

3/ descend to the peer hub via ->child

4/ find the port with the matching port id

Note that this assumes the port labeling scheme required by the
specification [1].

[1]: usb3 3.1 section 10.3.3
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d8521afe
...@@ -187,15 +187,18 @@ static void unlink_peers(struct usb_port *left, struct usb_port *right) ...@@ -187,15 +187,18 @@ static void unlink_peers(struct usb_port *left, struct usb_port *right)
left->peer = NULL; left->peer = NULL;
} }
/* set the default peer port for root hubs */ /*
* Set the default peer port for root hubs, or via the upstream peer
* relationship for all other hubs
*/
static void find_and_link_peer(struct usb_hub *hub, int port1) static void find_and_link_peer(struct usb_hub *hub, int port1)
{ {
struct usb_port *port_dev = hub->ports[port1 - 1], *peer; struct usb_port *port_dev = hub->ports[port1 - 1], *peer;
struct usb_device *hdev = hub->hdev; struct usb_device *hdev = hub->hdev;
struct usb_device *peer_hdev;
struct usb_hub *peer_hub;
if (!hdev->parent) { if (!hdev->parent) {
struct usb_hub *peer_hub;
struct usb_device *peer_hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus); struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
struct usb_hcd *peer_hcd = hcd->shared_hcd; struct usb_hcd *peer_hcd = hcd->shared_hcd;
...@@ -203,15 +206,28 @@ static void find_and_link_peer(struct usb_hub *hub, int port1) ...@@ -203,15 +206,28 @@ static void find_and_link_peer(struct usb_hub *hub, int port1)
return; return;
peer_hdev = peer_hcd->self.root_hub; peer_hdev = peer_hcd->self.root_hub;
peer_hub = usb_hub_to_struct_hub(peer_hdev); } else {
if (!peer_hub || port1 > peer_hdev->maxchild) struct usb_port *upstream;
struct usb_device *parent = hdev->parent;
struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent);
if (!parent_hub)
return; return;
peer = peer_hub->ports[port1 - 1]; upstream = parent_hub->ports[hdev->portnum - 1];
if (!upstream || !upstream->peer)
return;
if (peer) peer_hdev = upstream->peer->child;
link_peers(port_dev, peer);
} }
peer_hub = usb_hub_to_struct_hub(peer_hdev);
if (!peer_hub || port1 > peer_hdev->maxchild)
return;
peer = peer_hub->ports[port1 - 1];
if (peer)
link_peers(port_dev, peer);
} }
int usb_hub_create_port_device(struct usb_hub *hub, int port1) int usb_hub_create_port_device(struct usb_hub *hub, int port1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment