qlcnic: Fix driver load issue in FW hang
authorAnirban Chakraborty <anirban.chakraborty@qlogic.com>
Thu, 26 Aug 2010 14:02:52 +0000 (14:02 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 27 Aug 2010 00:13:19 +0000 (17:13 -0700)
If there is a FW hang when the driver loads, it can not determine the FW operational
mode. Fix it by checking the FW state first before issuing any FW commands to
determine its capabilities and thereby detecting driver operational mode.

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/qlcnic/qlcnic.h
drivers/net/qlcnic/qlcnic_hdr.h
drivers/net/qlcnic/qlcnic_init.c
drivers/net/qlcnic/qlcnic_main.c

index d15de63ed0bb62b139b946b4d7afa19eed3fc36c..0a537044d7dab73f74530c95922c75e7aaa92cbb 100644 (file)
@@ -902,6 +902,7 @@ struct qlcnic_mac_req {
 #define QLCNIC_BRIDGE_ENABLED          0X10
 #define QLCNIC_DIAG_ENABLED            0x20
 #define QLCNIC_ESWITCH_ENABLED         0x40
+#define QLCNIC_ADAPTER_INITIALIZED     0x80
 #define QLCNIC_TAGGING_ENABLED         0x100
 #define QLCNIC_MACSPOOF                        0x200
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
index 219de9f4496fc3149c97045d601eb31c8ae669db..bce1b1d541b78fe55d9f84c63c18ed250edda5e2 100644 (file)
@@ -748,7 +748,7 @@ enum {
 #define QLCNIC_RESET_TIMEOUT_SECS      10
 #define QLCNIC_INIT_TIMEOUT_SECS       30
 #define QLCNIC_HEARTBEAT_PERIOD_MSECS  200
-#define QLCNIC_HEARTBEAT_RETRY_COUNT   30
+#define QLCNIC_HEARTBEAT_RETRY_COUNT   45
 
 #define        ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
 #define ISR_LEGACY_INT_TRIGGERED(VAL)  (((VAL) & 0x300) == 0x200)
index df91b754bb70f9f25fbea56f6c2019d4d26f2a68..eb8256bec516cc3133085492500f70c74acbd06a 100644 (file)
@@ -547,7 +547,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
 int
 qlcnic_check_fw_status(struct qlcnic_adapter *adapter)
 {
-       u32 heartbit, ret = -EIO;
+       u32 heartbit, cmdpeg_state, ret = -EIO;
        int retries = QLCNIC_HEARTBEAT_RETRY_COUNT;
 
        adapter->heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
@@ -555,10 +555,16 @@ qlcnic_check_fw_status(struct qlcnic_adapter *adapter)
                msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
                heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
                if (heartbit != adapter->heartbit) {
-                       /* Complete firmware handshake */
-                       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
-                       ret = QLCNIC_RCODE_SUCCESS;
-                       break;
+                       cmdpeg_state = QLCRD32(adapter, CRB_CMDPEG_STATE);
+                       /* Ensure peg states are initialized */
+                       if (cmdpeg_state == PHAN_INITIALIZE_COMPLETE ||
+                               cmdpeg_state == PHAN_INITIALIZE_ACK) {
+                               /* Complete firmware handshake */
+                               QLCWR32(adapter, CRB_CMDPEG_STATE,
+                                       PHAN_INITIALIZE_ACK);
+                               ret = QLCNIC_RCODE_SUCCESS;
+                               break;
+                       }
                }
        } while (--retries);
 
index 1b8f67dab9b80e8008a9af48d9a60ba256fa2b4d..6999d5aaa1572e38df980539f86520a9d4b92711 100644 (file)
@@ -566,12 +566,11 @@ err_lock:
        return ret;
 }
 
-static u32
-qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+static void
+qlcnic_check_vf(struct qlcnic_adapter *adapter)
 {
        void __iomem *msix_base_addr;
        void __iomem *priv_op;
-       struct qlcnic_info nic_info;
        u32 func;
        u32 msix_base;
        u32 op_mode, priv_level;
@@ -586,20 +585,6 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
        func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
        adapter->ahw.pci_func = func;
 
-       if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
-               adapter->capabilities = nic_info.capabilities;
-
-               if (adapter->capabilities & BIT_6)
-                       adapter->flags |= QLCNIC_ESWITCH_ENABLED;
-               else
-                       adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
-       }
-
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               adapter->nic_ops = &qlcnic_ops;
-               return adapter->fw_hal_version;
-       }
-
        /* Determine function privilege level */
        priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
        op_mode = readl(priv_op);
@@ -608,37 +593,14 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
        else
                priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
 
-       switch (priv_level) {
-       case QLCNIC_MGMT_FUNC:
-               adapter->op_mode = QLCNIC_MGMT_FUNC;
-               adapter->nic_ops = &qlcnic_ops;
-               qlcnic_init_pci_info(adapter);
-               /* Set privilege level for other functions */
-               qlcnic_set_function_modes(adapter);
-               dev_info(&adapter->pdev->dev,
-                       "HAL Version: %d, Management function\n",
-                       adapter->fw_hal_version);
-               break;
-       case QLCNIC_PRIV_FUNC:
-               adapter->op_mode = QLCNIC_PRIV_FUNC;
-               dev_info(&adapter->pdev->dev,
-                       "HAL Version: %d, Privileged function\n",
-                       adapter->fw_hal_version);
-               adapter->nic_ops = &qlcnic_ops;
-               break;
-       case QLCNIC_NON_PRIV_FUNC:
+       if (priv_level == QLCNIC_NON_PRIV_FUNC) {
                adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
                dev_info(&adapter->pdev->dev,
                        "HAL Version: %d Non Privileged function\n",
                        adapter->fw_hal_version);
                adapter->nic_ops = &qlcnic_vf_ops;
-               break;
-       default:
-               dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
-                       priv_level);
-               return 0;
-       }
-       return adapter->fw_hal_version;
+       } else
+               adapter->nic_ops = &qlcnic_ops;
 }
 
 static int
@@ -671,10 +633,7 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        adapter->ahw.pci_base0 = mem_ptr0;
        adapter->ahw.pci_len0 = pci_len0;
 
-       if (!qlcnic_get_driver_mode(adapter)) {
-               iounmap(adapter->ahw.pci_base0);
-               return -EIO;
-       }
+       qlcnic_check_vf(adapter);
 
        adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
                QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
@@ -719,6 +678,9 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 
        adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
 
+       if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED))
+               if (qlcnic_read_mac_addr(adapter))
+                       dev_warn(&pdev->dev, "failed to read mac addr\n");
        if (adapter->portnum == 0) {
                get_brd_name(adapter, brd_name);
 
@@ -836,6 +798,51 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
        netdev->vlan_features = (features & vlan_features);
 }
 
+static int
+qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
+{
+       void __iomem *priv_op;
+       u32 op_mode, priv_level;
+       int err = 0;
+
+       if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
+               return 0;
+
+       priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+       op_mode = readl(priv_op);
+       priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+       if (op_mode == QLC_DEV_DRV_DEFAULT)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+       if (adapter->capabilities & BIT_6) {
+               adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+               if (priv_level == QLCNIC_MGMT_FUNC) {
+                       adapter->op_mode = QLCNIC_MGMT_FUNC;
+                       err = qlcnic_init_pci_info(adapter);
+                       if (err)
+                               return err;
+                       /* Set privilege level for other functions */
+                       qlcnic_set_function_modes(adapter);
+                       dev_info(&adapter->pdev->dev,
+                               "HAL Version: %d, Management function\n",
+                               adapter->fw_hal_version);
+               } else if (priv_level == QLCNIC_PRIV_FUNC) {
+                       adapter->op_mode = QLCNIC_PRIV_FUNC;
+                       dev_info(&adapter->pdev->dev,
+                               "HAL Version: %d, Privileged function\n",
+                               adapter->fw_hal_version);
+               }
+       } else
+               adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       return err;
+}
+
 static int
 qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
 {
@@ -1005,8 +1012,14 @@ set_dev_ready:
        err = qlcnic_reset_npar_config(adapter);
        if (err)
                goto err_out;
-       qlcnic_dev_set_npar_ready(adapter);
        qlcnic_check_options(adapter);
+       err = qlcnic_check_eswitch_mode(adapter);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Memory allocation failed for eswitch\n");
+               goto err_out;
+       }
+       qlcnic_dev_set_npar_ready(adapter);
        adapter->need_fw_reset = 0;
 
        qlcnic_release_firmware(adapter);
@@ -1015,6 +1028,7 @@ set_dev_ready:
 err_out:
        QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
        dev_err(&adapter->pdev->dev, "Device state set to failed\n");
+
        qlcnic_release_firmware(adapter);
        return err;
 }
@@ -1419,9 +1433,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
                netdev->features |= NETIF_F_LRO;
        netdev->irq = adapter->msix_entries[0].vector;
 
-       if (qlcnic_read_mac_addr(adapter))
-               dev_warn(&pdev->dev, "failed to read mac addr\n");
-
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 
@@ -1515,9 +1526,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_iounmap;
        }
 
-       if (qlcnic_read_mac_addr(adapter))
-               dev_warn(&pdev->dev, "failed to read mac addr\n");
-
        err = qlcnic_setup_idc_param(adapter);
        if (err)
                goto err_out_iounmap;