Commit 890b6e02 authored by Shahed Shaikh's avatar Shahed Shaikh Committed by David S. Miller

qlcnic: Store firmware dump state in CAMRAM register

-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: default avatarShahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7010bb65
...@@ -392,7 +392,7 @@ struct qlcnic_dump_template_hdr { ...@@ -392,7 +392,7 @@ struct qlcnic_dump_template_hdr {
struct qlcnic_fw_dump { struct qlcnic_fw_dump {
u8 clr; /* flag to indicate if dump is cleared */ 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 */ u32 size; /* total size of the dump */
void *data; /* dump data area */ void *data; /* dump data area */
struct qlcnic_dump_template_hdr *tmpl_hdr; struct qlcnic_dump_template_hdr *tmpl_hdr;
...@@ -1477,6 +1477,8 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter); ...@@ -1477,6 +1477,8 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter); void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter); void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
int qlcnic_dump_fw(struct qlcnic_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 */ /* Functions from qlcnic_init.c */
void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int); void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int);
......
...@@ -297,6 +297,7 @@ struct qlc_83xx_reset { ...@@ -297,6 +297,7 @@ struct qlc_83xx_reset {
#define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1 #define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1
#define QLC_83XX_IDC_GRACEFULL_RESET 0x2 #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_TIMESTAMP 0
#define QLC_83XX_IDC_DURATION 1 #define QLC_83XX_IDC_DURATION 1
#define QLC_83XX_IDC_INIT_TIMEOUT_SECS 30 #define QLC_83XX_IDC_INIT_TIMEOUT_SECS 30
......
...@@ -1509,6 +1509,68 @@ static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl) ...@@ -1509,6 +1509,68 @@ static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
adapter->ahw->msg_enable = 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 static int
qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) 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) ...@@ -1525,7 +1587,7 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
else else
dump->len = 0; dump->len = 0;
if (!fw_dump->enable) if (!qlcnic_check_fw_dump_state(adapter))
dump->flag = ETH_FW_DUMP_DISABLE; dump->flag = ETH_FW_DUMP_DISABLE;
else else
dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; 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, ...@@ -1573,77 +1635,111 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
return 0; 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 static int
qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
{ {
int i;
struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
bool valid_mask = false;
int i, ret = 0;
u32 state; u32 state;
switch (val->flag) { switch (val->flag) {
case QLCNIC_FORCE_FW_DUMP_KEY: case QLCNIC_FORCE_FW_DUMP_KEY:
if (!fw_dump->tmpl_hdr) { if (!fw_dump->tmpl_hdr) {
netdev_err(netdev, "FW dump not supported\n"); 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"); netdev_info(netdev, "FW dump not enabled\n");
return 0; ret = -EOPNOTSUPP;
break;
} }
if (fw_dump->clr) { if (fw_dump->clr) {
netdev_info(netdev, netdev_info(netdev,
"Previous dump not cleared, not forcing dump\n"); "Previous dump not cleared, not forcing dump\n");
return 0; break;
} }
netdev_info(netdev, "Forcing a FW dump\n"); netdev_info(netdev, "Forcing a FW dump\n");
qlcnic_dev_request_reset(adapter, val->flag); qlcnic_dev_request_reset(adapter, val->flag);
break; break;
case QLCNIC_DISABLE_FW_DUMP: case QLCNIC_DISABLE_FW_DUMP:
if (fw_dump->enable && fw_dump->tmpl_hdr) { if (!fw_dump->tmpl_hdr) {
netdev_info(netdev, "Disabling FW dump\n"); netdev_err(netdev, "FW dump not supported\n");
fw_dump->enable = 0; ret = -EOPNOTSUPP;
break;
} }
return 0;
ret = qlcnic_disable_fw_dump_state(adapter);
break;
case QLCNIC_ENABLE_FW_DUMP: case QLCNIC_ENABLE_FW_DUMP:
if (!fw_dump->tmpl_hdr) { if (!fw_dump->tmpl_hdr) {
netdev_err(netdev, "FW dump not supported\n"); netdev_err(netdev, "FW dump not supported\n");
return -ENOTSUPP; ret = -EOPNOTSUPP;
} break;
if (!fw_dump->enable) {
netdev_info(netdev, "Enabling FW dump\n");
fw_dump->enable = 1;
} }
return 0;
ret = qlcnic_enable_fw_dump_state(adapter);
break;
case QLCNIC_FORCE_FW_RESET: case QLCNIC_FORCE_FW_RESET:
netdev_info(netdev, "Forcing a FW reset\n"); netdev_info(netdev, "Forcing a FW reset\n");
qlcnic_dev_request_reset(adapter, val->flag); qlcnic_dev_request_reset(adapter, val->flag);
adapter->flags &= ~QLCNIC_FW_RESET_OWNER; adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
return 0; break;
;
case QLCNIC_SET_QUIESCENT: case QLCNIC_SET_QUIESCENT:
case QLCNIC_RESET_QUIESCENT: case QLCNIC_RESET_QUIESCENT:
state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
netdev_info(netdev, "Device in FAILED state\n"); netdev_info(netdev, "Device in FAILED state\n");
return 0; break;
default: default:
if (!fw_dump->tmpl_hdr) { if (!fw_dump->tmpl_hdr) {
netdev_err(netdev, "FW dump not supported\n"); netdev_err(netdev, "FW dump not supported\n");
return -ENOTSUPP; ret = -EOPNOTSUPP;
break;
} }
for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) { for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
if (val->flag == qlcnic_fw_dump_level[i]) { if (val->flag == qlcnic_fw_dump_level[i]) {
fw_dump->tmpl_hdr->drv_cap_mask = valid_mask = true;
val->flag; break;
netdev_info(netdev, "Driver mask changed to: 0x%x\n",
fw_dump->tmpl_hdr->drv_cap_mask);
return 0;
} }
} }
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 = { const struct ethtool_ops qlcnic_ethtool_ops = {
......
...@@ -3045,7 +3045,7 @@ qlcnic_fwinit_work(struct work_struct *work) ...@@ -3045,7 +3045,7 @@ qlcnic_fwinit_work(struct work_struct *work)
qlcnic_api_unlock(adapter); qlcnic_api_unlock(adapter);
rtnl_lock(); rtnl_lock();
if (adapter->ahw->fw_dump.enable && if (qlcnic_check_fw_dump_state(adapter) &&
(adapter->flags & QLCNIC_FW_RESET_OWNER)) { (adapter->flags & QLCNIC_FW_RESET_OWNER)) {
QLCDB(adapter, DRV, "Take FW dump\n"); QLCDB(adapter, DRV, "Take FW dump\n");
qlcnic_dump_fw(adapter); qlcnic_dump_fw(adapter);
......
...@@ -1092,7 +1092,7 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter) ...@@ -1092,7 +1092,7 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
else else
ahw->fw_dump.use_pex_dma = false; ahw->fw_dump.use_pex_dma = false;
ahw->fw_dump.enable = 1; qlcnic_enable_fw_dump_state(adapter);
return 0; return 0;
} }
...@@ -1115,7 +1115,11 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) ...@@ -1115,7 +1115,11 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
ahw = adapter->ahw; 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"); dev_info(&adapter->pdev->dev, "Dump not enabled\n");
return -EIO; return -EIO;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment