aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/thunderbolt.c14
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
665static 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
662static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf, 672static 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);