diff options
-rw-r--r-- | drivers/net/thunderbolt.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index 71cf9ab72fbc..e0d6760f3219 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c | |||
@@ -166,6 +166,8 @@ struct tbnet_ring { | |||
166 | * @connected_work: Worker that finalizes the ThunderboltIP connection | 166 | * @connected_work: Worker that finalizes the ThunderboltIP connection |
167 | * setup and enables DMA paths for high speed data | 167 | * setup and enables DMA paths for high speed data |
168 | * transfers | 168 | * transfers |
169 | * @disconnect_work: Worker that handles tearing down the ThunderboltIP | ||
170 | * connection | ||
169 | * @rx_hdr: Copy of the currently processed Rx frame. Used when a | 171 | * @rx_hdr: Copy of the currently processed Rx frame. Used when a |
170 | * network packet consists of multiple Thunderbolt frames. | 172 | * network packet consists of multiple Thunderbolt frames. |
171 | * In host byte order. | 173 | * In host byte order. |
@@ -190,6 +192,7 @@ struct tbnet { | |||
190 | int login_retries; | 192 | int login_retries; |
191 | struct delayed_work login_work; | 193 | struct delayed_work login_work; |
192 | struct work_struct connected_work; | 194 | struct work_struct connected_work; |
195 | struct work_struct disconnect_work; | ||
193 | struct thunderbolt_ip_frame_header rx_hdr; | 196 | struct thunderbolt_ip_frame_header rx_hdr; |
194 | struct tbnet_ring rx_ring; | 197 | struct tbnet_ring rx_ring; |
195 | atomic_t frame_id; | 198 | atomic_t frame_id; |
@@ -445,7 +448,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data) | |||
445 | case TBIP_LOGOUT: | 448 | case TBIP_LOGOUT: |
446 | ret = tbnet_logout_response(net, route, sequence, command_id); | 449 | ret = tbnet_logout_response(net, route, sequence, command_id); |
447 | if (!ret) | 450 | if (!ret) |
448 | tbnet_tear_down(net, false); | 451 | queue_work(system_long_wq, &net->disconnect_work); |
449 | break; | 452 | break; |
450 | 453 | ||
451 | default: | 454 | default: |
@@ -659,6 +662,13 @@ static void tbnet_login_work(struct work_struct *work) | |||
659 | } | 662 | } |
660 | } | 663 | } |
661 | 664 | ||
665 | static void tbnet_disconnect_work(struct work_struct *work) | ||
666 | { | ||
667 | struct tbnet *net = container_of(work, typeof(*net), disconnect_work); | ||
668 | |||
669 | tbnet_tear_down(net, false); | ||
670 | } | ||
671 | |||
662 | static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf, | 672 | static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf, |
663 | const struct thunderbolt_ip_frame_header *hdr) | 673 | const struct thunderbolt_ip_frame_header *hdr) |
664 | { | 674 | { |
@@ -881,6 +891,7 @@ static int tbnet_stop(struct net_device *dev) | |||
881 | 891 | ||
882 | napi_disable(&net->napi); | 892 | napi_disable(&net->napi); |
883 | 893 | ||
894 | cancel_work_sync(&net->disconnect_work); | ||
884 | tbnet_tear_down(net, true); | 895 | tbnet_tear_down(net, true); |
885 | 896 | ||
886 | tb_ring_free(net->rx_ring.ring); | 897 | tb_ring_free(net->rx_ring.ring); |
@@ -1195,6 +1206,7 @@ static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id) | |||
1195 | net = netdev_priv(dev); | 1206 | net = netdev_priv(dev); |
1196 | INIT_DELAYED_WORK(&net->login_work, tbnet_login_work); | 1207 | INIT_DELAYED_WORK(&net->login_work, tbnet_login_work); |
1197 | INIT_WORK(&net->connected_work, tbnet_connected_work); | 1208 | INIT_WORK(&net->connected_work, tbnet_connected_work); |
1209 | INIT_WORK(&net->disconnect_work, tbnet_disconnect_work); | ||
1198 | mutex_init(&net->connection_lock); | 1210 | mutex_init(&net->connection_lock); |
1199 | atomic_set(&net->command_id, 0); | 1211 | atomic_set(&net->command_id, 0); |
1200 | atomic_set(&net->frame_id, 0); | 1212 | atomic_set(&net->frame_id, 0); |