qlcnic: Store firmware dump state in CAMRAM register
authorShahed Shaikh <shahed.shaikh@qlogic.com>
Fri, 30 Aug 2013 17:51:19 +0000 (13:51 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sun, 1 Sep 2013 02:34:43 +0000 (22:34 -0400)
-Use CAMRAM register to store firmware dump state in adapter
 instead of maintaining it in each function driver separately.
-Return appropriate error code on failure

Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c

index 4e74376fdd9b99363f4cc9465be9a92e43f097a5..f9cd2744b2a0401baa3dfc470ddf935edb986502 100644 (file)
@@ -392,7 +392,7 @@ struct qlcnic_dump_template_hdr {
 
 struct qlcnic_fw_dump {
        u8      clr;    /* flag to indicate if dump is cleared */
-       u8      enable; /* enable/disable dump */
+       bool    enable; /* enable/disable dump */
        u32     size;   /* total size of the dump */
        void    *data;  /* dump data area */
        struct  qlcnic_dump_template_hdr *tmpl_hdr;
@@ -1477,6 +1477,8 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
 void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
 void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
 int qlcnic_dump_fw(struct qlcnic_adapter *);
+int qlcnic_enable_fw_dump_state(struct qlcnic_adapter *);
+bool qlcnic_check_fw_dump_state(struct qlcnic_adapter *);
 
 /* Functions from qlcnic_init.c */
 void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int);
index 0fc56160d5844b06f67da66f06fc18aed1dcf222..053a3a1770bb205e65ecf967e4aa0bb2769bf61b 100644 (file)
@@ -297,6 +297,7 @@ struct qlc_83xx_reset {
 
 #define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY         0x1
 #define QLC_83XX_IDC_GRACEFULL_RESET                   0x2
+#define QLC_83XX_IDC_DISABLE_FW_DUMP                   0x4
 #define QLC_83XX_IDC_TIMESTAMP                         0
 #define QLC_83XX_IDC_DURATION                          1
 #define QLC_83XX_IDC_INIT_TIMEOUT_SECS                 30
index 7b0c90efb365e27c7c35fec7068348e37f0d3974..332aa71798f66c8e1ab153fec89ab8dcbd93bda0 100644 (file)
@@ -1509,6 +1509,68 @@ static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
        adapter->ahw->msg_enable = msglvl;
 }
 
+int qlcnic_enable_fw_dump_state(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       u32 val;
+
+       if (qlcnic_84xx_check(adapter)) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val &= ~QLC_83XX_IDC_DISABLE_FW_DUMP;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+
+               qlcnic_83xx_unlock_driver(adapter);
+       } else {
+               fw_dump->enable = true;
+       }
+
+       dev_info(&adapter->pdev->dev, "FW dump enabled\n");
+
+       return 0;
+}
+
+static int qlcnic_disable_fw_dump_state(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       u32 val;
+
+       if (qlcnic_84xx_check(adapter)) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val |= QLC_83XX_IDC_DISABLE_FW_DUMP;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+
+               qlcnic_83xx_unlock_driver(adapter);
+       } else {
+               fw_dump->enable = false;
+       }
+
+       dev_info(&adapter->pdev->dev, "FW dump disabled\n");
+
+       return 0;
+}
+
+bool qlcnic_check_fw_dump_state(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       bool state;
+       u32 val;
+
+       if (qlcnic_84xx_check(adapter)) {
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               state = (val & QLC_83XX_IDC_DISABLE_FW_DUMP) ? false : true;
+       } else {
+               state = fw_dump->enable;
+       }
+
+       return state;
+}
+
 static int
 qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
 {
@@ -1525,7 +1587,7 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
        else
                dump->len = 0;
 
-       if (!fw_dump->enable)
+       if (!qlcnic_check_fw_dump_state(adapter))
                dump->flag = ETH_FW_DUMP_DISABLE;
        else
                dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
@@ -1573,77 +1635,111 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
        return 0;
 }
 
+static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask)
+{
+       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       struct net_device *netdev = adapter->netdev;
+
+       if (!qlcnic_check_fw_dump_state(adapter)) {
+               netdev_info(netdev,
+                           "Can not change driver mask to 0x%x. FW dump not enabled\n",
+                           mask);
+               return -EOPNOTSUPP;
+       }
+
+       fw_dump->tmpl_hdr->drv_cap_mask = mask;
+       netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask);
+       return 0;
+}
+
 static int
 qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 {
-       int i;
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       bool valid_mask = false;
+       int i, ret = 0;
        u32 state;
 
        switch (val->flag) {
        case QLCNIC_FORCE_FW_DUMP_KEY:
                if (!fw_dump->tmpl_hdr) {
                        netdev_err(netdev, "FW dump not supported\n");
-                       return -ENOTSUPP;
+                       ret = -EOPNOTSUPP;
+                       break;
                }
-               if (!fw_dump->enable) {
+
+               if (!qlcnic_check_fw_dump_state(adapter)) {
                        netdev_info(netdev, "FW dump not enabled\n");
-                       return 0;
+                       ret = -EOPNOTSUPP;
+                       break;
                }
+
                if (fw_dump->clr) {
                        netdev_info(netdev,
-                       "Previous dump not cleared, not forcing dump\n");
-                       return 0;
+                                   "Previous dump not cleared, not forcing dump\n");
+                       break;
                }
+
                netdev_info(netdev, "Forcing a FW dump\n");
                qlcnic_dev_request_reset(adapter, val->flag);
                break;
        case QLCNIC_DISABLE_FW_DUMP:
-               if (fw_dump->enable && fw_dump->tmpl_hdr) {
-                       netdev_info(netdev, "Disabling FW dump\n");
-                       fw_dump->enable = 0;
+               if (!fw_dump->tmpl_hdr) {
+                       netdev_err(netdev, "FW dump not supported\n");
+                       ret = -EOPNOTSUPP;
+                       break;
                }
-               return 0;
+
+               ret = qlcnic_disable_fw_dump_state(adapter);
+               break;
+
        case QLCNIC_ENABLE_FW_DUMP:
                if (!fw_dump->tmpl_hdr) {
                        netdev_err(netdev, "FW dump not supported\n");
-                       return -ENOTSUPP;
-               }
-               if (!fw_dump->enable) {
-                       netdev_info(netdev, "Enabling FW dump\n");
-                       fw_dump->enable = 1;
+                       ret = -EOPNOTSUPP;
+                       break;
                }
-               return 0;
+
+               ret = qlcnic_enable_fw_dump_state(adapter);
+               break;
+
        case QLCNIC_FORCE_FW_RESET:
                netdev_info(netdev, "Forcing a FW reset\n");
                qlcnic_dev_request_reset(adapter, val->flag);
                adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
-               return 0;
+               break;
+;
        case QLCNIC_SET_QUIESCENT:
        case QLCNIC_RESET_QUIESCENT:
                state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
                if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
                        netdev_info(netdev, "Device in FAILED state\n");
-               return 0;
+               break;
+
        default:
                if (!fw_dump->tmpl_hdr) {
                        netdev_err(netdev, "FW dump not supported\n");
-                       return -ENOTSUPP;
+                       ret = -EOPNOTSUPP;
+                       break;
                }
+
                for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
                        if (val->flag == qlcnic_fw_dump_level[i]) {
-                               fw_dump->tmpl_hdr->drv_cap_mask =
-                                                       val->flag;
-                               netdev_info(netdev, "Driver mask changed to: 0x%x\n",
-                                       fw_dump->tmpl_hdr->drv_cap_mask);
-                               return 0;
+                               valid_mask = true;
+                               break;
                        }
                }
-               netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag);
-               return -EINVAL;
+
+               if (valid_mask) {
+                       ret = qlcnic_set_dump_mask(adapter, val->flag);
+               } else {
+                       netdev_info(netdev, "Invalid dump level: 0x%x\n",
+                                   val->flag);
+                       ret = -EINVAL;
+               }
        }
-       return 0;
+       return ret;
 }
 
 const struct ethtool_ops qlcnic_ethtool_ops = {
index d1ed4e351ab1fbb5982613d709660e3babdf44f5..e380f0398165f45fb0c81ca3be0f060dd3f399d6 100644 (file)
@@ -3045,7 +3045,7 @@ skip_ack_check:
                qlcnic_api_unlock(adapter);
 
                rtnl_lock();
-               if (adapter->ahw->fw_dump.enable &&
+               if (qlcnic_check_fw_dump_state(adapter) &&
                    (adapter->flags & QLCNIC_FW_RESET_OWNER)) {
                        QLCDB(adapter, DRV, "Take FW dump\n");
                        qlcnic_dump_fw(adapter);
index b7871fe9916262a8189aefb4eb68f6b5067e1495..15513608d4808851917f1b5294e7733a5c4ea5cd 100644 (file)
@@ -1092,7 +1092,7 @@ flash_temp:
        else
                ahw->fw_dump.use_pex_dma = false;
 
-       ahw->fw_dump.enable = 1;
+       qlcnic_enable_fw_dump_state(adapter);
 
        return 0;
 }
@@ -1115,7 +1115,11 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 
        ahw = adapter->ahw;
 
-       if (!fw_dump->enable) {
+       /* Return if we don't have firmware dump template header */
+       if (!tmpl_hdr)
+               return -EIO;
+
+       if (!qlcnic_check_fw_dump_state(adapter)) {
                dev_info(&adapter->pdev->dev, "Dump not enabled\n");
                return -EIO;
        }