diff options
Diffstat (limited to 'drivers/net/thunderbolt.c')
| -rw-r--r-- | drivers/net/thunderbolt.c | 19 | 
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index ca5e375de27c..e0d6760f3219 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c @@ -166,6 +166,8 @@ struct tbnet_ring {   * @connected_work: Worker that finalizes the ThunderboltIP connection   *		    setup and enables DMA paths for high speed data   *		    transfers + * @disconnect_work: Worker that handles tearing down the ThunderboltIP + *		     connection   * @rx_hdr: Copy of the currently processed Rx frame. Used when a   *	    network packet consists of multiple Thunderbolt frames.   *	    In host byte order. @@ -190,6 +192,7 @@ struct tbnet {  	int login_retries;  	struct delayed_work login_work;  	struct work_struct connected_work; +	struct work_struct disconnect_work;  	struct thunderbolt_ip_frame_header rx_hdr;  	struct tbnet_ring rx_ring;  	atomic_t frame_id; @@ -445,7 +448,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data)  	case TBIP_LOGOUT:  		ret = tbnet_logout_response(net, route, sequence, command_id);  		if (!ret) -			tbnet_tear_down(net, false); +			queue_work(system_long_wq, &net->disconnect_work);  		break;  	default: @@ -659,6 +662,13 @@ static void tbnet_login_work(struct work_struct *work)  	}  } +static void tbnet_disconnect_work(struct work_struct *work) +{ +	struct tbnet *net = container_of(work, typeof(*net), disconnect_work); + +	tbnet_tear_down(net, false); +} +  static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf,  			      const struct thunderbolt_ip_frame_header *hdr)  { @@ -881,6 +891,7 @@ static int tbnet_stop(struct net_device *dev)  	napi_disable(&net->napi); +	cancel_work_sync(&net->disconnect_work);  	tbnet_tear_down(net, true);  	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)  	net = netdev_priv(dev);  	INIT_DELAYED_WORK(&net->login_work, tbnet_login_work);  	INIT_WORK(&net->connected_work, tbnet_connected_work); +	INIT_WORK(&net->disconnect_work, tbnet_disconnect_work);  	mutex_init(&net->connection_lock);  	atomic_set(&net->command_id, 0);  	atomic_set(&net->frame_id, 0); @@ -1270,10 +1282,7 @@ static int __maybe_unused tbnet_suspend(struct device *dev)  	stop_login(net);  	if (netif_running(net->dev)) {  		netif_device_detach(net->dev); -		tb_ring_stop(net->rx_ring.ring); -		tb_ring_stop(net->tx_ring.ring); -		tbnet_free_buffers(&net->rx_ring); -		tbnet_free_buffers(&net->tx_ring); +		tbnet_tear_down(net, true);  	}  	return 0;  | 
