From 26597802b47c5b92e3a1e6d5bd7cceef9e611431 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 4 Mar 2014 03:02:45 +0000 Subject: ixgbevf: Additional adapter removal checks Additional checks are needed for a detected removal not to cause problems. Some involve simply avoiding a lot of stuff that can't do anything good, and also cases where the phony return value can cause problems. In addition, down the adapter when the removal is sensed. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ethtool.c | 22 ++++++++++++++++++++++ drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 13 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index c769a8d364b6..b2d002394e5d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -535,6 +535,10 @@ static bool reg_pattern_test(struct ixgbevf_adapter *adapter, u64 *data, { u32 pat, val, before; + if (IXGBE_REMOVED(adapter->hw.hw_addr)) { + *data = 1; + return true; + } for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { before = ixgbe_read_reg(&adapter->hw, reg); ixgbe_write_reg(&adapter->hw, reg, @@ -559,6 +563,10 @@ static bool reg_set_and_check(struct ixgbevf_adapter *adapter, u64 *data, { u32 val, before; + if (IXGBE_REMOVED(adapter->hw.hw_addr)) { + *data = 1; + return true; + } before = ixgbe_read_reg(&adapter->hw, reg); ixgbe_write_reg(&adapter->hw, reg, write & mask); val = ixgbe_read_reg(&adapter->hw, reg); @@ -578,6 +586,12 @@ static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data) const struct ixgbevf_reg_test *test; u32 i; + if (IXGBE_REMOVED(adapter->hw.hw_addr)) { + dev_err(&adapter->pdev->dev, + "Adapter removed - register test blocked\n"); + *data = 1; + return 1; + } test = reg_test_vf; /* @@ -641,6 +655,14 @@ static void ixgbevf_diag_test(struct net_device *netdev, struct ixgbevf_adapter *adapter = netdev_priv(netdev); bool if_running = netif_running(netdev); + if (IXGBE_REMOVED(adapter->hw.hw_addr)) { + dev_err(&adapter->pdev->dev, + "Adapter removed - test blocked\n"); + data[0] = 1; + data[1] = 1; + eth_test->flags |= ETH_TEST_FL_FAILED; + return; + } set_bit(__IXGBEVF_TESTING, &adapter->state); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 37c4ebe97bda..a50e892a5d21 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -107,6 +107,7 @@ static void ixgbevf_remove_adapter(struct ixgbe_hw *hw) return; hw->hw_addr = NULL; dev_err(&adapter->pdev->dev, "Adapter removed\n"); + schedule_work(&adapter->watchdog_task); } static void ixgbevf_check_remove(struct ixgbe_hw *hw, u32 reg) @@ -1301,6 +1302,8 @@ static void ixgbevf_disable_rx_queue(struct ixgbevf_adapter *adapter, u32 rxdctl; u8 reg_idx = ring->reg_idx; + if (IXGBE_REMOVED(hw->hw_addr)) + return; rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(reg_idx)); rxdctl &= ~IXGBE_RXDCTL_ENABLE; @@ -1326,6 +1329,8 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, u32 rxdctl; u8 reg_idx = ring->reg_idx; + if (IXGBE_REMOVED(hw->hw_addr)) + return; do { usleep_range(1000, 2000); rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(reg_idx)); @@ -2399,6 +2404,14 @@ static void ixgbevf_watchdog_task(struct work_struct *work) bool link_up = adapter->link_up; s32 need_reset; + if (IXGBE_REMOVED(hw->hw_addr)) { + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) { + rtnl_lock(); + ixgbevf_down(adapter); + rtnl_unlock(); + } + return; + } ixgbevf_queue_reset_subtask(adapter); adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; -- cgit v1.2.3