diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index 3160443ef3b9e51a2ef2c769c329ef3c7c1456a4..551b4355e85d75a13b7beecf38bb0feddb7dd928 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c @@ -372,13 +372,23 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout) break; } + /* Tear the paths down before stopping the rings. This mirrors + * tbnet_connected_work(), which enables the paths last so the + * Rx ring is primed before packets can arrive. Stopping a + * ring zeroes its descriptor base and tbnet_free_buffers() + * unmaps and frees the frame buffers, leaving anything still + * in flight with nowhere to drain to; + * __tb_path_deactivate_hop() then waits for the hop's + * 'pending' bit, which on some host routers never clears in + * that state. + */ + if (tb_xdomain_disable_paths(net->xd)) + netdev_warn(net->dev, "failed to disable DMA paths\n"); + 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); - - if (tb_xdomain_disable_paths(net->xd)) - netdev_warn(net->dev, "failed to disable DMA paths\n"); } net->login_retries = 0; @@ -1230,7 +1240,7 @@ static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id) * features here. */ dev->hw_features = NETIF_F_SG | NETIF_F_ALL_TSO | NETIF_F_GRO | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; dev->features = dev->hw_features | NETIF_F_HIGHDMA; dev->hard_header_len += sizeof(struct thunderbolt_ip_frame_header);