summaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt/icm.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2018-02-09 09:29:38 -0500
committerMika Westerberg <mika.westerberg@linux.intel.com>2018-03-09 04:54:09 -0500
commit79fae987518a3aa6c3c7b2e3ad5fe1e4080c12bc (patch)
tree49915c863ee7d788869caa51d004947fbad541ea /drivers/thunderbolt/icm.c
parenta03e828915c00ed0ea5aa40647c81472cfa7a984 (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/icm.c')
-rw-r--r--drivers/thunderbolt/icm.c26
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)
383 tb_switch_remove(sw); 383 tb_switch_remove(sw);
384} 384}
385 385
386static void remove_xdomain(struct tb_xdomain *xd)
387{
388 struct tb_switch *sw;
389
390 sw = tb_to_switch(xd->dev.parent);
391 tb_port_at(xd->route, sw)->xdomain = NULL;
392 tb_xdomain_remove(xd);
393}
394
386static void 395static void
387icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr) 396icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
388{ 397{
@@ -391,6 +400,7 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
391 struct tb_switch *sw, *parent_sw; 400 struct tb_switch *sw, *parent_sw;
392 struct icm *icm = tb_priv(tb); 401 struct icm *icm = tb_priv(tb);
393 bool authorized = false; 402 bool authorized = false;
403 struct tb_xdomain *xd;
394 u8 link, depth; 404 u8 link, depth;
395 u64 route; 405 u64 route;
396 int ret; 406 int ret;
@@ -467,6 +477,13 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
467 tb_switch_put(sw); 477 tb_switch_put(sw);
468 } 478 }
469 479
480 /* Remove existing XDomain connection if found */
481 xd = tb_xdomain_find_by_link_depth(tb, link, depth);
482 if (xd) {
483 remove_xdomain(xd);
484 tb_xdomain_put(xd);
485 }
486
470 parent_sw = tb_switch_find_by_link_depth(tb, link, depth - 1); 487 parent_sw = tb_switch_find_by_link_depth(tb, link, depth - 1);
471 if (!parent_sw) { 488 if (!parent_sw) {
472 tb_err(tb, "failed to find parent switch for %u.%u\n", 489 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)
529 tb_switch_put(sw); 546 tb_switch_put(sw);
530} 547}
531 548
532static void remove_xdomain(struct tb_xdomain *xd)
533{
534 struct tb_switch *sw;
535
536 sw = tb_to_switch(xd->dev.parent);
537 tb_port_at(xd->route, sw)->xdomain = NULL;
538 tb_xdomain_remove(xd);
539}
540
541static void 549static void
542icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr) 550icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
543{ 551{