ixgbe: Additional adapter removal checks
authorMark Rustad <mark.d.rustad@intel.com>
Wed, 15 Jan 2014 02:53:17 +0000 (18:53 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Jan 2014 02:59:17 +0000 (18:59 -0800)
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 <mark.d.rustad@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

index c4b2eb1a8fa2927aa901f112419cef31d60c621f..043307024c4abf542b6014eb6ccbfc739e2d54c5 100644 (file)
@@ -1342,6 +1342,10 @@ static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg,
        static const u32 test_pattern[] = {
                0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
 
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               *data = 1;
+               return 1;
+       }
        for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
                before = ixgbe_read_reg(&adapter->hw, reg);
                ixgbe_write_reg(&adapter->hw, reg, test_pattern[pat] & write);
@@ -1364,6 +1368,10 @@ static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg,
 {
        u32 val, before;
 
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               *data = 1;
+               return 1;
+       }
        before = ixgbe_read_reg(&adapter->hw, reg);
        ixgbe_write_reg(&adapter->hw, reg, write & mask);
        val = ixgbe_read_reg(&adapter->hw, reg);
@@ -1384,6 +1392,11 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
        u32 value, before, after;
        u32 i, toggle;
 
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               e_err(drv, "Adapter removed - register test blocked\n");
+               *data = 1;
+               return 1;
+       }
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_82598EB:
                toggle = 0x7FFFF3FF;
@@ -1950,6 +1963,15 @@ static void ixgbe_diag_test(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        bool if_running = netif_running(netdev);
 
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               e_err(hw, "Adapter removed - test blocked\n");
+               data[0] = 1;
+               data[1] = 1;
+               data[2] = 1;
+               data[3] = 1;
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
        set_bit(__IXGBE_TESTING, &adapter->state);
        if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
                struct ixgbe_hw *hw = &adapter->hw;
index 9831a244d5baa2ba9c61b22f448a239d8c4f53c8..3ca59d21d0b2ee9ccde0488b6c6547975bb6e07a 100644 (file)
@@ -291,6 +291,7 @@ static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
                return;
        hw->hw_addr = NULL;
        e_dev_err("Adapter removed\n");
+       ixgbe_service_event_schedule(adapter);
 }
 
 void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
@@ -3338,6 +3339,8 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
        u32 rxdctl;
        u8 reg_idx = ring->reg_idx;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
        /* RXDCTL.EN will return 0 on 82598 if link is down, so skip it */
        if (hw->mac.type == ixgbe_mac_82598EB &&
            !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
@@ -3362,6 +3365,8 @@ void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter,
        u32 rxdctl;
        u8 reg_idx = ring->reg_idx;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
        rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
        rxdctl &= ~IXGBE_RXDCTL_ENABLE;
 
@@ -4687,6 +4692,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
        struct ixgbe_hw *hw = &adapter->hw;
        int err;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
        /* lock SFP init bit to prevent race conditions with the watchdog */
        while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
                usleep_range(1000, 2000);
@@ -6397,6 +6404,15 @@ static void ixgbe_service_task(struct work_struct *work)
        struct ixgbe_adapter *adapter = container_of(work,
                                                     struct ixgbe_adapter,
                                                     service_task);
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       rtnl_lock();
+                       ixgbe_down(adapter);
+                       rtnl_unlock();
+               }
+               ixgbe_service_event_complete(adapter);
+               return;
+       }
        ixgbe_reset_subtask(adapter);
        ixgbe_sfp_detection_subtask(adapter);
        ixgbe_sfp_link_config_subtask(adapter);