Skip to content

Commit 86da809

Browse files
westerigregkh
authored andcommitted
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>
1 parent 7012040 commit 86da809

File tree

1 file changed

+20
-29
lines changed

1 file changed

+20
-29
lines changed

drivers/thunderbolt/icm.c

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -738,14 +738,6 @@ icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
738738
u8 link, depth;
739739
u64 route;
740740

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-
749741
link = pkg->link_info & ICM_LINK_INFO_LINK_MASK;
750742
depth = (pkg->link_info & ICM_LINK_INFO_DEPTH_MASK) >>
751743
ICM_LINK_INFO_DEPTH_SHIFT;
@@ -1037,14 +1029,6 @@ icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
10371029
if (pkg->hdr.packet_id)
10381030
return;
10391031

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-
10481032
route = get_route(pkg->route_hi, pkg->route_lo);
10491033
authorized = pkg->link_info & ICM_LINK_INFO_APPROVED;
10501034
security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
@@ -1408,19 +1392,26 @@ static void icm_handle_notification(struct work_struct *work)
14081392

14091393
mutex_lock(&tb->lock);
14101394

1411-
switch (n->pkg->code) {
1412-
case ICM_EVENT_DEVICE_CONNECTED:
1413-
icm->device_connected(tb, n->pkg);
1414-
break;
1415-
case ICM_EVENT_DEVICE_DISCONNECTED:
1416-
icm->device_disconnected(tb, n->pkg);
1417-
break;
1418-
case ICM_EVENT_XDOMAIN_CONNECTED:
1419-
icm->xdomain_connected(tb, n->pkg);
1420-
break;
1421-
case ICM_EVENT_XDOMAIN_DISCONNECTED:
1422-
icm->xdomain_disconnected(tb, n->pkg);
1423-
break;
1395+
/*
1396+
* When the domain is stopped we flush its workqueue but before
1397+
* that the root switch is removed. In that case we should treat
1398+
* the queued events as being canceled.
1399+
*/
1400+
if (tb->root_switch) {
1401+
switch (n->pkg->code) {
1402+
case ICM_EVENT_DEVICE_CONNECTED:
1403+
icm->device_connected(tb, n->pkg);
1404+
break;
1405+
case ICM_EVENT_DEVICE_DISCONNECTED:
1406+
icm->device_disconnected(tb, n->pkg);
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+
}
14241415
}
14251416

14261417
mutex_unlock(&tb->lock);

0 commit comments

Comments
 (0)