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 {
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);
......
......@@ -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
......
......@@ -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 = {
......
......@@ -3045,7 +3045,7 @@ qlcnic_fwinit_work(struct work_struct *work)
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);
......
......@@ -1092,7 +1092,7 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
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;
}
......
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