summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2018-09-24 06:20:44 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-02 13:51:16 -0400
commit86da809dda64a63fc27e05a215475325c3aaae92 (patch)
tree319f800e3890bd076292ad97cc3a212d9a934db4
parent7012040576c6ae25a47035659ee48673612c2c27 (diff)
thunderbolt: Do not handle ICM events after domain is stopped
If there is a long chain of devices connected when the driver is loaded ICM sends device connected event for each and those are put to tb->wq for later processing. Now if the driver gets unloaded in the middle, so that the work queue is not yet empty it gets flushed by tb_domain_stop(). However, by that time the root switch is already removed so the driver crashes when it tries to dereference it in ICM event handling callbacks. Fix this by checking whether the root switch is already removed. If it is we know that the domain is stopped and we should merely skip handling the event. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/thunderbolt/icm.c49
1 files changed, 20 insertions, 29 deletions
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index e1e264a9a4c7..28fc4ce75edb 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -738,14 +738,6 @@ icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
738 u8 link, depth; 738 u8 link, depth;
739 u64 route; 739 u64 route;
740 740
741 /*
742 * After NVM upgrade adding root switch device fails because we
743 * initiated reset. During that time ICM might still send
744 * XDomain connected message which we ignore here.
745 */
746 if (!tb->root_switch)
747 return;
748
749 link = pkg->link_info & ICM_LINK_INFO_LINK_MASK; 741 link = pkg->link_info & ICM_LINK_INFO_LINK_MASK;
750 depth = (pkg->link_info & ICM_LINK_INFO_DEPTH_MASK) >> 742 depth = (pkg->link_info & ICM_LINK_INFO_DEPTH_MASK) >>
751 ICM_LINK_INFO_DEPTH_SHIFT; 743 ICM_LINK_INFO_DEPTH_SHIFT;
@@ -1037,14 +1029,6 @@ icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
1037 if (pkg->hdr.packet_id) 1029 if (pkg->hdr.packet_id)
1038 return; 1030 return;
1039 1031
1040 /*
1041 * After NVM upgrade adding root switch device fails because we
1042 * initiated reset. During that time ICM might still send device
1043 * connected message which we ignore here.
1044 */
1045 if (!tb->root_switch)
1046 return;
1047
1048 route = get_route(pkg->route_hi, pkg->route_lo); 1032 route = get_route(pkg->route_hi, pkg->route_lo);
1049 authorized = pkg->link_info & ICM_LINK_INFO_APPROVED; 1033 authorized = pkg->link_info & ICM_LINK_INFO_APPROVED;
1050 security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >> 1034 security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
@@ -1408,19 +1392,26 @@ static void icm_handle_notification(struct work_struct *work)
1408 1392
1409 mutex_lock(&tb->lock); 1393 mutex_lock(&tb->lock);
1410 1394
1411 switch (n->pkg->code) { 1395 /*
1412 case ICM_EVENT_DEVICE_CONNECTED: 1396 * When the domain is stopped we flush its workqueue but before
1413 icm->device_connected(tb, n->pkg); 1397 * that the root switch is removed. In that case we should treat
1414 break; 1398 * the queued events as being canceled.
1415 case ICM_EVENT_DEVICE_DISCONNECTED: 1399 */
1416 icm->device_disconnected(tb, n->pkg); 1400 if (tb->root_switch) {
1417 break; 1401 switch (n->pkg->code) {
1418 case ICM_EVENT_XDOMAIN_CONNECTED: 1402 case ICM_EVENT_DEVICE_CONNECTED:
1419 icm->xdomain_connected(tb, n->pkg); 1403 icm->device_connected(tb, n->pkg);
1420 break; 1404 break;
1421 case ICM_EVENT_XDOMAIN_DISCONNECTED: 1405 case ICM_EVENT_DEVICE_DISCONNECTED:
1422 icm->xdomain_disconnected(tb, n->pkg); 1406 icm->device_disconnected(tb, n->pkg);
1423 break; 1407 break;
1408 case ICM_EVENT_XDOMAIN_CONNECTED:
1409 icm->xdomain_connected(tb, n->pkg);
1410 break;
1411 case ICM_EVENT_XDOMAIN_DISCONNECTED:
1412 icm->xdomain_disconnected(tb, n->pkg);
1413 break;
1414 }
1424 } 1415 }
1425 1416
1426 mutex_unlock(&tb->lock); 1417 mutex_unlock(&tb->lock);