From bba1f3a4642c1a5280aaf287883520d3d1552c02 Mon Sep 17 00:00:00 2001 From: Jason Mei Date: Tue, 20 Feb 2024 09:49:01 +0800 Subject: [PATCH] net: ethernet: sync link status before removing The tegera_tvnet driver usually built as kernel module, to avoid rmmod/insmod cause kernel crash sync link status before rmmod Bug 4456727 Bug 4451567 Change-Id: I2b7227fef36688777b8a468678be9e63a7638c2c Signed-off-by: Jason Mei Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3079867 Reviewed-by: svcacv Reviewed-by: Manikanta Maddireddy Reviewed-by: Bibek Basu GVS: Gerrit_Virtual_Submit --- drivers/net/ethernet/nvidia/pcie/tegra_vnet.c | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c b/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c index 05fc4e5d..4748b8bd 100644 --- a/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c +++ b/drivers/net/ethernet/nvidia/pcie/tegra_vnet.c @@ -1,6 +1,18 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2019-2023, NVIDIA CORPORATION. All rights reserved. +// SPDX-License-Identifier: GPL-2.0 +/* SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #include @@ -865,8 +877,23 @@ fail: static void tvnet_host_remove(struct pci_dev *pdev) { + int ret = -1; struct tvnet_priv *tvnet = pci_get_drvdata(pdev); + if (tvnet->rx_link_state == DIR_LINK_STATE_UP) + tvnet_host_user_link_down_req(tvnet); + + ret = wait_event_interruptible_timeout(tvnet->link_state_wq, + (tvnet->rx_link_state == + DIR_LINK_STATE_DOWN), + msecs_to_jiffies(LINK_TIMEOUT)); + ret = (ret > 0) ? 0 : -ETIMEDOUT; + if (ret < 0) { + pr_err("%s: failed: tx_state: %d rx_state: %d err: %d", __func__, + tvnet->tx_link_state, tvnet->rx_link_state, ret); + tvnet->rx_link_state = DIR_LINK_STATE_UP; + } + free_irq(pci_irq_vector(pdev, 0), tvnet->ndev); free_irq(pci_irq_vector(pdev, 1), tvnet->ndev); pci_free_irq_vectors(pdev);