For example:

usb2/2-1/2-1:1.0/port1/peer => ../../../../usb3/3-1/3-1:1.0/port1
usb2/2-1/2-1:1.0/port2/peer => ../../../../usb3/3-1/3-1:1.0/port2
usb2/2-1/2-1:1.0/port3/peer => ../../../../usb3/3-1/3-1:1.0/port3
usb2/2-1/2-1:1.0/port4/peer => ../../../../usb3/3-1/3-1:1.0/port4
usb2/2-0:1.0/port1/peer     => ../../../usb3/3-0:1.0/port1
usb2/2-0:1.0/port2/peer     => ../../../usb3/3-0:1.0/port2
usb2/2-0:1.0/port3/peer     => ../../../usb3/3-0:1.0/port3
usb2/2-0:1.0/port4/peer     => ../../../usb3/3-0:1.0/port4

usb3/3-1/3-1:1.0/port1/peer => ../../../../usb2/2-1/2-1:1.0/port1
usb3/3-1/3-1:1.0/port2/peer => ../../../../usb2/2-1/2-1:1.0/port2
usb3/3-1/3-1:1.0/port3/peer => ../../../../usb2/2-1/2-1:1.0/port3
usb3/3-1/3-1:1.0/port4/peer => ../../../../usb2/2-1/2-1:1.0/port4
usb3/3-0:1.0/port1/peer     => ../../../usb2/2-0:1.0/port1
usb3/3-0:1.0/port2/peer     => ../../../usb2/2-0:1.0/port2
usb3/3-0:1.0/port3/peer     => ../../../usb2/2-0:1.0/port3
usb3/3-0:1.0/port4/peer     => ../../../usb2/2-0:1.0/port4

Signed-off-by: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/usb/core/port.c |   40 +++++++++++++++++++++++++++++++---------
 1 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 8fae3cd03305..d3aacf093aa1 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -21,7 +21,7 @@
 
 #include "hub.h"
 
-DEFINE_SPINLOCK(peer_lock);
+DEFINE_MUTEX(peer_lock);
 static const struct attribute_group *port_dev_group[];
 
 static ssize_t connect_type_show(struct device *dev,
@@ -201,16 +201,20 @@ static void reset_peer(struct usb_port *port_dev, struct 
usb_port *peer)
        if (!peer)
                return;
 
-       spin_lock(&peer_lock);
-       if (port_dev->peer)
+       mutex_lock(&peer_lock);
+       if (port_dev->peer) {
                put_device(&port_dev->peer->dev);
-       if (peer->peer)
+               sysfs_remove_link(&port_dev->dev.kobj, "peer");
+       }
+       if (peer->peer) {
                put_device(&peer->peer->dev);
+               sysfs_remove_link(&peer->dev.kobj, "peer");
+       }
        port_dev->peer = peer;
        peer->peer = port_dev;
        get_device(&peer->dev);
        get_device(&port_dev->dev);
-       spin_unlock(&peer_lock);
+       mutex_unlock(&peer_lock);
 }
 
 /* assumes that location data is only set for external connectors and that
@@ -311,19 +315,33 @@ int usb_hub_create_port_device(struct usb_hub *hub, int 
port1)
        dev_dbg(&hub->hdev->dev, "port%d peer = %s\n",
                port1, peer ? dev_name(peer->dev.parent->parent) : "[none]");
        if (peer) {
-               spin_lock(&peer_lock);
+               mutex_lock(&peer_lock);
                get_device(&peer->dev);
                port_dev->peer = peer;
                WARN_ON(peer->peer);
                get_device(&port_dev->dev);
                peer->peer = port_dev;
-               spin_unlock(&peer_lock);
+               mutex_unlock(&peer_lock);
        }
 
        retval = device_add(&port_dev->dev);
        if (retval)
                goto error_register;
 
+       mutex_lock(&peer_lock);
+       peer = port_dev->peer;
+       do if (peer) {
+               retval = sysfs_create_link(&port_dev->dev.kobj,
+                                          &peer->dev.kobj, "peer");
+               if (retval)
+                       break;
+               retval = sysfs_create_link(&peer->dev.kobj,
+                                          &port_dev->dev.kobj, "peer");
+       } while (0);
+       mutex_unlock(&peer_lock);
+       if (retval)
+               goto error_links;
+
        pm_runtime_set_active(&port_dev->dev);
 
        /* It would be dangerous if user space couldn't
@@ -339,6 +357,8 @@ int usb_hub_create_port_device(struct usb_hub *hub, int 
port1)
 
 error_register:
        put_device(&port_dev->dev);
+error_links:
+       device_unregister(&port_dev->dev);
 exit:
        return retval;
 }
@@ -348,14 +368,16 @@ void usb_hub_remove_port_device(struct usb_hub *hub, int 
port1)
        struct usb_port *port_dev = hub->ports[port1 - 1];
        struct usb_port *peer = port_dev->peer;
 
-       spin_lock(&peer_lock);
+       mutex_lock(&peer_lock);
        if (peer) {
                peer->peer = NULL;
                port_dev->peer = NULL;
                put_device(&port_dev->dev);
                put_device(&peer->dev);
+               sysfs_remove_link(&port_dev->dev.kobj, "peer");
+               sysfs_remove_link(&peer->dev.kobj, "peer");
        }
-       spin_unlock(&peer_lock);
+       mutex_unlock(&peer_lock);
 
        device_unregister(&port_dev->dev);
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to