diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2018-02-09 17:29:38 +0300 |
---|---|---|
committer | Mika Westerberg <mika.westerberg@linux.intel.com> | 2018-03-09 12:54:09 +0300 |
commit | 79fae987518a3aa6c3c7b2e3ad5fe1e4080c12bc (patch) | |
tree | 49915c863ee7d788869caa51d004947fbad541ea /drivers/thunderbolt | |
parent | a03e828915c00ed0ea5aa40647c81472cfa7a984 (diff) |
thunderbolt: Handle connecting device in place of host properly
If the system is suspended and user disconnects cable to another host
and connects it to a Thunderbolt device instead we get a warning from
driver core about adding duplicate sysfs attribute and adding the new
device fails.
Handle this properly so that we first remove the existing XDomain
connection before adding new devices.
Fixes: d1ff70241a27 ("thunderbolt: Add support for XDomain discovery protocol")
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/thunderbolt')
-rw-r--r-- | drivers/thunderbolt/icm.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index ab02d13f40b7..182226023acb 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -383,6 +383,15 @@ static void remove_switch(struct tb_switch *sw) tb_switch_remove(sw); } +static void remove_xdomain(struct tb_xdomain *xd) +{ + struct tb_switch *sw; + + sw = tb_to_switch(xd->dev.parent); + tb_port_at(xd->route, sw)->xdomain = NULL; + tb_xdomain_remove(xd); +} + static void icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr) { @@ -391,6 +400,7 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr) struct tb_switch *sw, *parent_sw; struct icm *icm = tb_priv(tb); bool authorized = false; + struct tb_xdomain *xd; u8 link, depth; u64 route; int ret; @@ -467,6 +477,13 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr) tb_switch_put(sw); } + /* Remove existing XDomain connection if found */ + xd = tb_xdomain_find_by_link_depth(tb, link, depth); + if (xd) { + remove_xdomain(xd); + tb_xdomain_put(xd); + } + parent_sw = tb_switch_find_by_link_depth(tb, link, depth - 1); if (!parent_sw) { tb_err(tb, "failed to find parent switch for %u.%u\n", @@ -529,15 +546,6 @@ icm_fr_device_disconnected(struct tb *tb, const struct icm_pkg_header *hdr) tb_switch_put(sw); } -static void remove_xdomain(struct tb_xdomain *xd) -{ - struct tb_switch *sw; - - sw = tb_to_switch(xd->dev.parent); - tb_port_at(xd->route, sw)->xdomain = NULL; - tb_xdomain_remove(xd); -} - static void icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr) { |