From: Sebastian Basierski <[email protected]>

Add check for FW NVM recovery mode during driver initialization and
service task. If in recovery mode, log message and unregister device

Signed-off-by: Sebastian Basierski <[email protected]>
Tested-by: Don Buchholz <[email protected]>
Signed-off-by: Jeff Kirsher <[email protected]>
---
 .../net/ethernet/intel/ixgbe/ixgbe_common.c   | 11 +++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 41 +++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_type.h |  4 ++
 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 15 +++++++
 4 files changed, 71 insertions(+)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 0bd1294ba517..970f71d5da04 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -3484,6 +3484,17 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, 
bool enable, int vf)
        IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof);
 }
 
+/**
+ * ixgbe_fw_recovery_mode - Check if in FW NVM recovery mode
+ * @hw: pointer to hardware structure
+ */
+bool ixgbe_fw_recovery_mode(struct ixgbe_hw *hw)
+{
+       if (hw->mac.ops.fw_recovery_mode)
+               return hw->mac.ops.fw_recovery_mode(hw);
+       return false;
+}
+
 /**
  *  ixgbe_get_device_caps_generic - Get additional device capabilities
  *  @hw: pointer to hardware structure
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 9a23d33a47ed..604282f03d23 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7774,6 +7774,33 @@ static void ixgbe_reset_subtask(struct ixgbe_adapter 
*adapter)
        rtnl_unlock();
 }
 
+/**
+ * ixgbe_check_fw_error - Check firmware for errors
+ * @adapter: the adapter private structure
+ *
+ * Check firmware errors in register FWSM
+ */
+static bool ixgbe_check_fw_error(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 fwsm;
+
+       /* read fwsm.ext_err_ind register and log errors */
+       fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
+
+       if (fwsm & IXGBE_FWSM_EXT_ERR_IND_MASK ||
+           !(fwsm & IXGBE_FWSM_FW_VAL_BIT))
+               e_dev_warn("Warning firmware error detected FWSM: 0x%08X\n",
+                          fwsm);
+
+       if (hw->mac.ops.fw_recovery_mode && hw->mac.ops.fw_recovery_mode(hw)) {
+               e_dev_err("Firmware recovery mode detected. Limiting 
functionality. Refer to the Intel(R) Ethernet Adapters and Devices User Guide 
for details on firmware recovery mode.\n");
+               return true;
+       }
+
+       return false;
+}
+
 /**
  * ixgbe_service_task - manages and runs subtasks
  * @work: pointer to work_struct containing our data
@@ -7792,6 +7819,15 @@ static void ixgbe_service_task(struct work_struct *work)
                ixgbe_service_event_complete(adapter);
                return;
        }
+       if (ixgbe_check_fw_error(adapter)) {
+               if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       rtnl_lock();
+                       unregister_netdev(adapter->netdev);
+                       rtnl_unlock();
+               }
+               ixgbe_service_event_complete(adapter);
+               return;
+       }
        if (adapter->flags2 & IXGBE_FLAG2_UDP_TUN_REREG_NEEDED) {
                rtnl_lock();
                adapter->flags2 &= ~IXGBE_FLAG2_UDP_TUN_REREG_NEEDED;
@@ -10716,6 +10752,11 @@ static int ixgbe_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
        if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
                netdev->features |= NETIF_F_LRO;
 
+       if (ixgbe_check_fw_error(adapter)) {
+               err = -EIO;
+               goto err_sw_init;
+       }
+
        /* make sure the EEPROM is good */
        if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) {
                e_dev_err("The EEPROM Checksum Is Not Valid\n");
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 41bcbb337e83..84f2dba39e36 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -924,6 +924,9 @@ struct ixgbe_nvm_version {
 /* Firmware Semaphore Register */
 #define IXGBE_FWSM_MODE_MASK   0xE
 #define IXGBE_FWSM_FW_MODE_PT  0x4
+#define IXGBE_FWSM_FW_NVM_RECOVERY_MODE        BIT(5)
+#define IXGBE_FWSM_EXT_ERR_IND_MASK    0x01F80000
+#define IXGBE_FWSM_FW_VAL_BIT  BIT(15)
 
 /* ARC Subsystem registers */
 #define IXGBE_HICR      0x15F00
@@ -3461,6 +3464,7 @@ struct ixgbe_mac_operations {
                              const char *);
        s32 (*get_thermal_sensor_data)(struct ixgbe_hw *);
        s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw);
+       bool (*fw_recovery_mode)(struct ixgbe_hw *hw);
        void (*disable_rx)(struct ixgbe_hw *hw);
        void (*enable_rx)(struct ixgbe_hw *hw);
        void (*set_source_address_pruning)(struct ixgbe_hw *, bool,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index a8148c7126e5..10dbaf4f6e80 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -1247,6 +1247,20 @@ static s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw)
        return 0;
 }
 
+/**
+ * ixgbe_fw_recovery_mode - Check FW NVM recovery mode
+ * @hw: pointer t hardware structure
+ *
+ * Returns true if in FW NVM recovery mode.
+ */
+static bool ixgbe_fw_recovery_mode_X550(struct ixgbe_hw *hw)
+{
+       u32 fwsm;
+
+       fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
+       return !!(fwsm & IXGBE_FWSM_FW_NVM_RECOVERY_MODE);
+}
+
 /** ixgbe_disable_rx_x550 - Disable RX unit
  *
  *  Enables the Rx DMA unit for x550
@@ -3816,6 +3830,7 @@ static s32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, 
u32 reg_addr,
        .enable_rx_buff                 = &ixgbe_enable_rx_buff_generic, \
        .get_thermal_sensor_data        = NULL, \
        .init_thermal_sensor_thresh     = NULL, \
+       .fw_recovery_mode               = &ixgbe_fw_recovery_mode_X550, \
        .enable_rx                      = &ixgbe_enable_rx_generic, \
        .disable_rx                     = &ixgbe_disable_rx_x550, \
 
-- 
2.17.1

Reply via email to