On Fri, 2014-02-28 at 15:18 -0800, Dan Williams wrote: > 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]. > > The usb_port_peer_mutex is held when marking hubs as disconnected > (meaning all child ports are invalid for peering) and when the ->child > pointer on a port_dev is marked NULL. Strictly speaking it seems the > latter should be sufficient for protecting collisions with port peering. > However, this still includes the lock around setting hub->disconnected > for extra protection and documentation of the window for when a peer > relationship can be established. > > [1]: usb3 3.1 section 10.3.3 > > Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> Deleted the usb_port_peer_mutex usages added by this patch. They're moot now given the locking done at the hub level. 8<--------- Subject: usb: assign usb3 external hub port peers From: Dan Williams <dan.j.williams@xxxxxxxxx> 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 Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- drivers/usb/core/port.c | 28 ++++++++++++++++++++-------- 1 files changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index cb42352b97e6..6fd827e6a9f8 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -152,17 +152,17 @@ static struct device_driver usb_port_driver = { }; /* - * Set the default peer port for root hubs. Assumes the primary_hcd is + * Set the default peer port via the peer hcd for root hubs and the + * upstream peer relationship for other hubs. Assumes the primary_hcd is * registered first */ static struct usb_port *find_default_peer(struct usb_hub *hub, int port1) { struct usb_device *hdev = hub->hdev; - struct usb_port *peer = NULL; + struct usb_device *peer_hdev = NULL; + struct usb_hub *peer_hub; 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 *peer_hcd = hcd->primary_hcd; @@ -170,14 +170,26 @@ static struct usb_port *find_default_peer(struct usb_hub *hub, int port1) return NULL; peer_hdev = peer_hcd->self.root_hub; - peer_hub = usb_hub_to_struct_hub(peer_hdev); - if (!peer_hub || port1 > peer_hdev->maxchild) + } else { + 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 NULL; + + upstream = parent_hub->ports[hdev->portnum - 1]; + if (!upstream || !upstream->peer) return NULL; - peer = peer_hub->ports[port1 - 1]; + peer_hdev = upstream->peer->child; } - return peer; + peer_hub = usb_hub_to_struct_hub(peer_hdev); + if (!peer_hub || port1 > peer_hdev->maxchild) + return NULL; + + return peer_hub->ports[port1 - 1]; } static void link_peers(struct usb_port *left, struct usb_port *right) -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html