Commit 83f18a55 authored by Manish chopra's avatar Manish chopra Committed by David S. Miller

netxen_nic: fw dump support

Signed-off-by: default avatarManish Chopra <manish.chopra@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2dcd5d95
......@@ -1154,6 +1154,7 @@ typedef struct {
#define NETXEN_NIC_LRO_DISABLED 0x00
#define NETXEN_NIC_BRIDGE_ENABLED 0X10
#define NETXEN_NIC_DIAG_ENABLED 0x20
#define NETXEN_FW_RESET_OWNER 0x40
#define NETXEN_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED))
......@@ -1171,6 +1172,419 @@ typedef struct {
#define __NX_DEV_UP 1
#define __NX_RESETTING 2
/* Mini Coredump FW supported version */
#define NX_MD_SUPPORT_MAJOR 4
#define NX_MD_SUPPORT_MINOR 0
#define NX_MD_SUPPORT_SUBVERSION 579
#define LSW(x) ((uint16_t)(x))
#define LSD(x) ((uint32_t)((uint64_t)(x)))
#define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
/* Mini Coredump mask level */
#define NX_DUMP_MASK_MIN 0x03
#define NX_DUMP_MASK_DEF 0x1f
#define NX_DUMP_MASK_MAX 0xff
/* Mini Coredump CDRP commands */
#define NX_CDRP_CMD_TEMP_SIZE 0x0000002f
#define NX_CDRP_CMD_GET_TEMP_HDR 0x00000030
#define NX_DUMP_STATE_ARRAY_LEN 16
#define NX_DUMP_CAP_SIZE_ARRAY_LEN 8
/* Mini Coredump sysfs entries flags*/
#define NX_FORCE_FW_DUMP_KEY 0xdeadfeed
#define NX_ENABLE_FW_DUMP 0xaddfeed
#define NX_DISABLE_FW_DUMP 0xbadfeed
#define NX_FORCE_FW_RESET 0xdeaddead
/* Flash read/write address */
#define NX_FW_DUMP_REG1 0x00130060
#define NX_FW_DUMP_REG2 0x001e0000
#define NX_FLASH_SEM2_LK 0x0013C010
#define NX_FLASH_SEM2_ULK 0x0013C014
#define NX_FLASH_LOCK_ID 0x001B2100
#define FLASH_ROM_WINDOW 0x42110030
#define FLASH_ROM_DATA 0x42150000
/* Mini Coredump register read/write routine */
#define NX_RD_DUMP_REG(addr, bar0, data) do { \
writel((addr & 0xFFFF0000), (void __iomem *) (bar0 + \
NX_FW_DUMP_REG1)); \
readl((void __iomem *) (bar0 + NX_FW_DUMP_REG1)); \
*data = readl((void __iomem *) (bar0 + NX_FW_DUMP_REG2 + \
LSW(addr))); \
} while (0)
#define NX_WR_DUMP_REG(addr, bar0, data) do { \
writel((addr & 0xFFFF0000), (void __iomem *) (bar0 + \
NX_FW_DUMP_REG1)); \
readl((void __iomem *) (bar0 + NX_FW_DUMP_REG1)); \
writel(data, (void __iomem *) (bar0 + NX_FW_DUMP_REG2 + LSW(addr)));\
readl((void __iomem *) (bar0 + NX_FW_DUMP_REG2 + LSW(addr))); \
} while (0)
/*
Entry Type Defines
*/
#define RDNOP 0
#define RDCRB 1
#define RDMUX 2
#define QUEUE 3
#define BOARD 4
#define RDSRE 5
#define RDOCM 6
#define PREGS 7
#define L1DTG 8
#define L1ITG 9
#define CACHE 10
#define L1DAT 11
#define L1INS 12
#define RDSTK 13
#define RDCON 14
#define L2DTG 21
#define L2ITG 22
#define L2DAT 23
#define L2INS 24
#define RDOC3 25
#define MEMBK 32
#define RDROM 71
#define RDMEM 72
#define RDMN 73
#define INFOR 81
#define CNTRL 98
#define TLHDR 99
#define RDEND 255
#define PRIMQ 103
#define SQG2Q 104
#define SQG3Q 105
/*
* Opcodes for Control Entries.
* These Flags are bit fields.
*/
#define NX_DUMP_WCRB 0x01
#define NX_DUMP_RWCRB 0x02
#define NX_DUMP_ANDCRB 0x04
#define NX_DUMP_ORCRB 0x08
#define NX_DUMP_POLLCRB 0x10
#define NX_DUMP_RD_SAVE 0x20
#define NX_DUMP_WRT_SAVED 0x40
#define NX_DUMP_MOD_SAVE_ST 0x80
/* Driver Flags */
#define NX_DUMP_SKIP 0x80 /* driver skipped this entry */
#define NX_DUMP_SIZE_ERR 0x40 /*entry size vs capture size mismatch*/
#define NX_PCI_READ_32(ADDR) readl((ADDR))
#define NX_PCI_WRITE_32(DATA, ADDR) writel(DATA, (ADDR))
struct netxen_minidump {
u32 pos; /* position in the dump buffer */
u8 fw_supports_md; /* FW supports Mini cordump */
u8 has_valid_dump; /* indicates valid dump */
u8 md_capture_mask; /* driver capture mask */
u8 md_enabled; /* Turn Mini Coredump on/off */
u32 md_dump_size; /* Total FW Mini Coredump size */
u32 md_capture_size; /* FW dump capture size */
u32 md_template_size; /* FW template size */
u32 md_template_ver; /* FW template version */
u64 md_timestamp; /* FW Mini dump timestamp */
void *md_template; /* FW template will be stored */
void *md_capture_buff; /* FW dump will be stored */
};
struct netxen_minidump_template_hdr {
u32 entry_type;
u32 first_entry_offset;
u32 size_of_template;
u32 capture_mask;
u32 num_of_entries;
u32 version;
u32 driver_timestamp;
u32 checksum;
u32 driver_capture_mask;
u32 driver_info_word2;
u32 driver_info_word3;
u32 driver_info_word4;
u32 saved_state_array[NX_DUMP_STATE_ARRAY_LEN];
u32 capture_size_array[NX_DUMP_CAP_SIZE_ARRAY_LEN];
u32 rsvd[0];
};
/* Common Entry Header: Common to All Entry Types */
/*
* Driver Code is for driver to write some info about the entry.
* Currently not used.
*/
struct netxen_common_entry_hdr {
u32 entry_type;
u32 entry_size;
u32 entry_capture_size;
union {
struct {
u8 entry_capture_mask;
u8 entry_code;
u8 driver_code;
u8 driver_flags;
};
u32 entry_ctrl_word;
};
};
/* Generic Entry Including Header */
struct netxen_minidump_entry {
struct netxen_common_entry_hdr hdr;
u32 entry_data00;
u32 entry_data01;
u32 entry_data02;
u32 entry_data03;
u32 entry_data04;
u32 entry_data05;
u32 entry_data06;
u32 entry_data07;
};
/* Read ROM Header */
struct netxen_minidump_entry_rdrom {
struct netxen_common_entry_hdr h;
union {
struct {
u32 select_addr_reg;
};
u32 rsvd_0;
};
union {
struct {
u8 addr_stride;
u8 addr_cnt;
u16 data_size;
};
u32 rsvd_1;
};
union {
struct {
u32 op_count;
};
u32 rsvd_2;
};
union {
struct {
u32 read_addr_reg;
};
u32 rsvd_3;
};
union {
struct {
u32 write_mask;
};
u32 rsvd_4;
};
union {
struct {
u32 read_mask;
};
u32 rsvd_5;
};
u32 read_addr;
u32 read_data_size;
};
/* Read CRB and Control Entry Header */
struct netxen_minidump_entry_crb {
struct netxen_common_entry_hdr h;
u32 addr;
union {
struct {
u8 addr_stride;
u8 state_index_a;
u16 poll_timeout;
};
u32 addr_cntrl;
};
u32 data_size;
u32 op_count;
union {
struct {
u8 opcode;
u8 state_index_v;
u8 shl;
u8 shr;
};
u32 control_value;
};
u32 value_1;
u32 value_2;
u32 value_3;
};
/* Read Memory and MN Header */
struct netxen_minidump_entry_rdmem {
struct netxen_common_entry_hdr h;
union {
struct {
u32 select_addr_reg;
};
u32 rsvd_0;
};
union {
struct {
u8 addr_stride;
u8 addr_cnt;
u16 data_size;
};
u32 rsvd_1;
};
union {
struct {
u32 op_count;
};
u32 rsvd_2;
};
union {
struct {
u32 read_addr_reg;
};
u32 rsvd_3;
};
union {
struct {
u32 cntrl_addr_reg;
};
u32 rsvd_4;
};
union {
struct {
u8 wr_byte0;
u8 wr_byte1;
u8 poll_mask;
u8 poll_cnt;
};
u32 rsvd_5;
};
u32 read_addr;
u32 read_data_size;
};
/* Read Cache L1 and L2 Header */
struct netxen_minidump_entry_cache {
struct netxen_common_entry_hdr h;
u32 tag_reg_addr;
union {
struct {
u16 tag_value_stride;
u16 init_tag_value;
};
u32 select_addr_cntrl;
};
u32 data_size;
u32 op_count;
u32 control_addr;
union {
struct {
u16 write_value;
u8 poll_mask;
u8 poll_wait;
};
u32 control_value;
};
u32 read_addr;
union {
struct {
u8 read_addr_stride;
u8 read_addr_cnt;
u16 rsvd_1;
};
u32 read_addr_cntrl;
};
};
/* Read OCM Header */
struct netxen_minidump_entry_rdocm {
struct netxen_common_entry_hdr h;
u32 rsvd_0;
union {
struct {
u32 rsvd_1;
};
u32 select_addr_cntrl;
};
u32 data_size;
u32 op_count;
u32 rsvd_2;
u32 rsvd_3;
u32 read_addr;
union {
struct {
u32 read_addr_stride;
};
u32 read_addr_cntrl;
};
};
/* Read MUX Header */
struct netxen_minidump_entry_mux {
struct netxen_common_entry_hdr h;
u32 select_addr;
union {
struct {
u32 rsvd_0;
};
u32 select_addr_cntrl;
};
u32 data_size;
u32 op_count;
u32 select_value;
u32 select_value_stride;
u32 read_addr;
u32 rsvd_1;
};
/* Read Queue Header */
struct netxen_minidump_entry_queue {
struct netxen_common_entry_hdr h;
u32 select_addr;
union {
struct {
u16 queue_id_stride;
u16 rsvd_0;
};
u32 select_addr_cntrl;
};
u32 data_size;
u32 op_count;
u32 rsvd_1;
u32 rsvd_2;
u32 read_addr;
union {
struct {
u8 read_addr_stride;
u8 read_addr_cnt;
u16 rsvd_3;
};
u32 read_addr_cntrl;
};
};
struct netxen_dummy_dma {
void *addr;
dma_addr_t phys_addr;
......@@ -1275,6 +1689,8 @@ struct netxen_adapter {
__le32 file_prd_off; /*File fw product offset*/
u32 fw_version;
const struct firmware *fw;
struct netxen_minidump mdump; /* mdump ptr */
int fw_mdump_rdy; /* for mdump ready */
};
int nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val);
......@@ -1377,13 +1793,16 @@ int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu);
int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable);
int netxen_config_bridged_mode(struct netxen_adapter *adapter, int enable);
int netxen_send_lro_cleanup(struct netxen_adapter *adapter);
int netxen_setup_minidump(struct netxen_adapter *adapter);
void netxen_dump_fw(struct netxen_adapter *adapter);
void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
struct nx_host_tx_ring *tx_ring);
/* Functions from netxen_nic_main.c */
int netxen_nic_reset_context(struct netxen_adapter *);
int nx_dev_request_reset(struct netxen_adapter *adapter);
/*
* NetXen Board information
*/
......
......@@ -83,6 +83,7 @@ netxen_issue_cmd(struct netxen_adapter *adapter, struct netxen_cmd_args *cmd)
printk(KERN_ERR "%s: failed card response code:0x%x\n",
netxen_nic_driver_name, rcode);
} else if (rsp == NX_CDRP_RSP_OK) {
cmd->rsp.cmd = NX_RCODE_SUCCESS;
if (cmd->rsp.arg2)
cmd->rsp.arg2 = NXRD32(adapter, NX_ARG2_CRB_OFFSET);
if (cmd->rsp.arg3)
......@@ -97,6 +98,148 @@ netxen_issue_cmd(struct netxen_adapter *adapter, struct netxen_cmd_args *cmd)
return rcode;
}
static int
netxen_get_minidump_template_size(struct netxen_adapter *adapter)
{
struct netxen_cmd_args cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.req.cmd = NX_CDRP_CMD_TEMP_SIZE;
memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
netxen_issue_cmd(adapter, &cmd);
if (cmd.rsp.cmd != NX_RCODE_SUCCESS) {
dev_info(&adapter->pdev->dev,
"Can't get template size %d\n", cmd.rsp.cmd);
return -EIO;
}
adapter->mdump.md_template_size = cmd.rsp.arg2;
adapter->mdump.md_template_ver = cmd.rsp.arg3;
return 0;
}
static int
netxen_get_minidump_template(struct netxen_adapter *adapter)
{
dma_addr_t md_template_addr;
void *addr;
u32 size;
struct netxen_cmd_args cmd;
size = adapter->mdump.md_template_size;
if (size == 0) {
dev_err(&adapter->pdev->dev, "Can not capture Minidump "
"template. Invalid template size.\n");
return NX_RCODE_INVALID_ARGS;
}
addr = pci_alloc_consistent(adapter->pdev, size, &md_template_addr);
if (!addr) {
dev_err(&adapter->pdev->dev, "Unable to allocate dmable memory for template.\n");
return -ENOMEM;
}
memset(addr, 0, size);
memset(&cmd, 0, sizeof(cmd));
memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
cmd.req.cmd = NX_CDRP_CMD_GET_TEMP_HDR;
cmd.req.arg1 = LSD(md_template_addr);
cmd.req.arg2 = MSD(md_template_addr);
cmd.req.arg3 |= size;
netxen_issue_cmd(adapter, &cmd);
if ((cmd.rsp.cmd == NX_RCODE_SUCCESS) && (size == cmd.rsp.arg2)) {
memcpy(adapter->mdump.md_template, addr, size);
} else {
dev_err(&adapter->pdev->dev, "Failed to get minidump template, "
"err_code : %d, requested_size : %d, actual_size : %d\n ",
cmd.rsp.cmd, size, cmd.rsp.arg2);
}
pci_free_consistent(adapter->pdev, size, addr, md_template_addr);
return 0;
}
static u32
netxen_check_template_checksum(struct netxen_adapter *adapter)
{
u64 sum = 0 ;
u32 *buff = adapter->mdump.md_template;
int count = adapter->mdump.md_template_size/sizeof(uint32_t) ;
while (count-- > 0)
sum += *buff++ ;
while (sum >> 32)
sum = (sum & 0xFFFFFFFF) + (sum >> 32) ;
return ~sum;
}
int
netxen_setup_minidump(struct netxen_adapter *adapter)
{
int err = 0, i;
u32 *template, *tmp_buf;
struct netxen_minidump_template_hdr *hdr;
err = netxen_get_minidump_template_size(adapter);
if (err) {
adapter->mdump.fw_supports_md = 0;
if ((err == NX_RCODE_CMD_INVALID) ||
(err == NX_RCODE_CMD_NOT_IMPL)) {
dev_info(&adapter->pdev->dev,
"Flashed firmware version does not support minidump, "
"minimum version required is [ %u.%u.%u ].\n ",
NX_MD_SUPPORT_MAJOR, NX_MD_SUPPORT_MINOR,
NX_MD_SUPPORT_SUBVERSION);
}
return err;
}
if (!adapter->mdump.md_template_size) {
dev_err(&adapter->pdev->dev, "Error : Invalid template size "
",should be non-zero.\n");
return -EIO;
}
adapter->mdump.md_template =
kmalloc(adapter->mdump.md_template_size, GFP_KERNEL);
if (!adapter->mdump.md_template) {
dev_err(&adapter->pdev->dev, "Unable to allocate memory "
"for minidump template.\n");
return -ENOMEM;
}
err = netxen_get_minidump_template(adapter);
if (err) {
if (err == NX_RCODE_CMD_NOT_IMPL)
adapter->mdump.fw_supports_md = 0;
goto free_template;
}
if (netxen_check_template_checksum(adapter)) {
dev_err(&adapter->pdev->dev, "Minidump template checksum Error\n");
err = -EIO;
goto free_template;
}
adapter->mdump.md_capture_mask = NX_DUMP_MASK_DEF;
tmp_buf = (u32 *) adapter->mdump.md_template;
template = (u32 *) adapter->mdump.md_template;
for (i = 0; i < adapter->mdump.md_template_size/sizeof(u32); i++)
*template++ = __le32_to_cpu(*tmp_buf++);
hdr = (struct netxen_minidump_template_hdr *)
adapter->mdump.md_template;
adapter->mdump.md_capture_buff = NULL;
adapter->mdump.fw_supports_md = 1;
adapter->mdump.md_enabled = 1;
return err;
free_template:
kfree(adapter->mdump.md_template);
adapter->mdump.md_template = NULL;
return err;
}
int
nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu)
{
......
......@@ -812,6 +812,107 @@ static int netxen_get_intr_coalesce(struct net_device *netdev,
return 0;
}
static int
netxen_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_minidump *mdump = &adapter->mdump;
if (adapter->fw_mdump_rdy)
dump->len = mdump->md_dump_size;
else
dump->len = 0;
dump->flag = mdump->md_capture_mask;
dump->version = adapter->fw_version;
return 0;
}
static int
netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val)
{
int ret = 0;
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_minidump *mdump = &adapter->mdump;
switch (val->flag) {
case NX_FORCE_FW_DUMP_KEY:
if (!mdump->md_enabled)
mdump->md_enabled = 1;
if (adapter->fw_mdump_rdy) {
netdev_info(netdev, "Previous dump not cleared, not forcing dump\n");
return ret;
}
netdev_info(netdev, "Forcing a fw dump\n");
nx_dev_request_reset(adapter);
break;
case NX_DISABLE_FW_DUMP:
if (mdump->md_enabled) {
netdev_info(netdev, "Disabling FW Dump\n");
mdump->md_enabled = 0;
}
break;
case NX_ENABLE_FW_DUMP:
if (!mdump->md_enabled) {
netdev_info(netdev, "Enabling FW dump\n");
mdump->md_enabled = 1;
}
break;
case NX_FORCE_FW_RESET:
netdev_info(netdev, "Forcing FW reset\n");
nx_dev_request_reset(adapter);
adapter->flags &= ~NETXEN_FW_RESET_OWNER;
break;
default:
if (val->flag <= NX_DUMP_MASK_MAX &&
val->flag >= NX_DUMP_MASK_MIN) {
mdump->md_capture_mask = val->flag & 0xff;
netdev_info(netdev, "Driver mask changed to: 0x%x\n",
mdump->md_capture_mask);
break;
}
netdev_info(netdev,
"Invalid dump level: 0x%x\n", val->flag);
return -EINVAL;
}
return ret;
}
static int
netxen_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
void *buffer)
{
int i, copy_sz;
u32 *hdr_ptr, *data;
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_minidump *mdump = &adapter->mdump;
if (!adapter->fw_mdump_rdy) {
netdev_info(netdev, "Dump not available\n");
return -EINVAL;
}
/* Copy template header first */
copy_sz = mdump->md_template_size;
hdr_ptr = (u32 *) mdump->md_template;
data = buffer;
for (i = 0; i < copy_sz/sizeof(u32); i++)
*data++ = cpu_to_le32(*hdr_ptr++);
/* Copy captured dump data */
memcpy(buffer + copy_sz,
mdump->md_capture_buff + mdump->md_template_size,
mdump->md_capture_size);
dump->len = copy_sz + mdump->md_capture_size;
dump->flag = mdump->md_capture_mask;
/* Free dump area once data has been captured */
vfree(mdump->md_capture_buff);
mdump->md_capture_buff = NULL;
adapter->fw_mdump_rdy = 0;
netdev_info(netdev, "extracted the fw dump Successfully\n");
return 0;
}
const struct ethtool_ops netxen_nic_ethtool_ops = {
.get_settings = netxen_nic_get_settings,
.set_settings = netxen_nic_set_settings,
......@@ -833,4 +934,7 @@ const struct ethtool_ops netxen_nic_ethtool_ops = {
.get_sset_count = netxen_get_sset_count,
.get_coalesce = netxen_get_intr_coalesce,
.set_coalesce = netxen_set_intr_coalesce,
.get_dump_flag = netxen_get_dump_flag,
.get_dump_data = netxen_get_dump_data,
.set_dump = netxen_set_dump,
};
......@@ -446,7 +446,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter)
/* resetall */
netxen_rom_lock(adapter);
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff);
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xfeffffff);
netxen_rom_unlock(adapter);
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
......@@ -1347,7 +1347,6 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
do {
val = NXRD32(adapter, CRB_CMDPEG_STATE);
switch (val) {
case PHAN_INITIALIZE_COMPLETE:
case PHAN_INITIALIZE_ACK:
......
......@@ -82,7 +82,6 @@ static void netxen_create_sysfs_entries(struct netxen_adapter *adapter);
static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter);
static void netxen_create_diag_entries(struct netxen_adapter *adapter);
static void netxen_remove_diag_entries(struct netxen_adapter *adapter);
static int nx_dev_request_aer(struct netxen_adapter *adapter);
static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter);
static int netxen_can_start_firmware(struct netxen_adapter *adapter);
......@@ -802,10 +801,10 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
static void
netxen_check_options(struct netxen_adapter *adapter)
{
u32 fw_major, fw_minor, fw_build;
u32 fw_major, fw_minor, fw_build, prev_fw_version;
char brd_name[NETXEN_MAX_SHORT_NAME];
char serial_num[32];
int i, offset, val;
int i, offset, val, err;
int *ptr32;
struct pci_dev *pdev = adapter->pdev;
......@@ -826,9 +825,22 @@ netxen_check_options(struct netxen_adapter *adapter)
fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
prev_fw_version = adapter->fw_version;
adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
/* Get FW Mini Coredump template and store it */
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
if (adapter->mdump.md_template == NULL ||
adapter->fw_version > prev_fw_version) {
kfree(adapter->mdump.md_template);
adapter->mdump.md_template = NULL;
err = netxen_setup_minidump(adapter);
if (err)
dev_err(&adapter->pdev->dev,
"Failed to setup minidump rcode = %d\n", err);
}
}
if (adapter->portnum == 0) {
get_brd_name_by_type(adapter->ahw.board_type, brd_name);
......@@ -909,7 +921,12 @@ netxen_start_firmware(struct netxen_adapter *adapter)
if (err)
return err;
if (!netxen_can_start_firmware(adapter))
err = netxen_can_start_firmware(adapter);
if (err < 0)
return err;
if (!err)
goto wait_init;
first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc));
......@@ -1528,6 +1545,18 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return err;
}
static
void netxen_cleanup_minidump(struct netxen_adapter *adapter)
{
kfree(adapter->mdump.md_template);
adapter->mdump.md_template = NULL;
if (adapter->mdump.md_capture_buff) {
vfree(adapter->mdump.md_capture_buff);
adapter->mdump.md_capture_buff = NULL;
}
}
static void __devexit netxen_nic_remove(struct pci_dev *pdev)
{
struct netxen_adapter *adapter;
......@@ -1563,8 +1592,10 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
netxen_release_firmware(adapter);
if (NX_IS_REVISION_P3(pdev->revision))
if (NX_IS_REVISION_P3(pdev->revision)) {
netxen_cleanup_minidump(adapter);
pci_disable_pcie_error_reporting(pdev);
}
pci_release_regions(pdev);
pci_disable_device(pdev);
......@@ -2316,7 +2347,7 @@ nx_incr_dev_ref_cnt(struct netxen_adapter *adapter)
static int
nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
{
int count;
int count, state;
if (netxen_api_lock(adapter))
return -EIO;
......@@ -2324,8 +2355,9 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
WARN_ON(count == 0);
NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count);
state = NXRD32(adapter, NX_CRB_DEV_STATE);
if (count == 0)
if (count == 0 && state != NX_DEV_FAILED)
NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD);
netxen_api_unlock(adapter);
......@@ -2354,7 +2386,7 @@ nx_dev_request_aer(struct netxen_adapter *adapter)
return ret;
}
static int
int
nx_dev_request_reset(struct netxen_adapter *adapter)
{
u32 state;
......@@ -2365,10 +2397,11 @@ nx_dev_request_reset(struct netxen_adapter *adapter)
state = NXRD32(adapter, NX_CRB_DEV_STATE);
if (state == NX_DEV_NEED_RESET)
if (state == NX_DEV_NEED_RESET || state == NX_DEV_FAILED)
ret = 0;
else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) {
NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET);
adapter->flags |= NETXEN_FW_RESET_OWNER;
ret = 0;
}
......@@ -2383,8 +2416,10 @@ netxen_can_start_firmware(struct netxen_adapter *adapter)
int count;
int can_start = 0;
if (netxen_api_lock(adapter))
return 0;
if (netxen_api_lock(adapter)) {
nx_incr_dev_ref_cnt(adapter);
return -1;
}
count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
......@@ -2456,8 +2491,31 @@ netxen_fwinit_work(struct work_struct *work)
struct netxen_adapter *adapter = container_of(work,
struct netxen_adapter, fw_work.work);
int dev_state;
int count;
dev_state = NXRD32(adapter, NX_CRB_DEV_STATE);
if (adapter->flags & NETXEN_FW_RESET_OWNER) {
count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
WARN_ON(count == 0);
if (count == 1) {
if (adapter->mdump.md_enabled) {
rtnl_lock();
netxen_dump_fw(adapter);
rtnl_unlock();
}
adapter->flags &= ~NETXEN_FW_RESET_OWNER;
if (netxen_api_lock(adapter)) {
clear_bit(__NX_RESETTING, &adapter->state);
NXWR32(adapter, NX_CRB_DEV_STATE,
NX_DEV_FAILED);
return;
}
count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count);
NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD);
dev_state = NX_DEV_COLD;
netxen_api_unlock(adapter);
}
}
switch (dev_state) {
case NX_DEV_COLD:
......@@ -2470,11 +2528,9 @@ netxen_fwinit_work(struct work_struct *work)
case NX_DEV_NEED_RESET:
case NX_DEV_INITALIZING:
if (++adapter->fw_wait_cnt < FW_POLL_THRESH) {
netxen_schedule_work(adapter,
netxen_fwinit_work, 2 * FW_POLL_DELAY);
return;
}
case NX_DEV_FAILED:
default:
......@@ -2482,6 +2538,15 @@ netxen_fwinit_work(struct work_struct *work)
break;
}
if (netxen_api_lock(adapter)) {
clear_bit(__NX_RESETTING, &adapter->state);
return;
}
NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_FAILED);
netxen_api_unlock(adapter);
dev_err(&adapter->pdev->dev, "%s: Device initialization Failed\n",
adapter->netdev->name);
clear_bit(__NX_RESETTING, &adapter->state);
}
......@@ -2491,7 +2556,7 @@ netxen_detach_work(struct work_struct *work)
struct netxen_adapter *adapter = container_of(work,
struct netxen_adapter, fw_work.work);
struct net_device *netdev = adapter->netdev;
int ref_cnt, delay;
int ref_cnt = 0, delay;
u32 status;
netif_device_detach(netdev);
......@@ -2510,7 +2575,8 @@ netxen_detach_work(struct work_struct *work)
if (adapter->temp == NX_TEMP_PANIC)
goto err_ret;
ref_cnt = nx_decr_dev_ref_cnt(adapter);
if (!(adapter->flags & NETXEN_FW_RESET_OWNER))
ref_cnt = nx_decr_dev_ref_cnt(adapter);
if (ref_cnt == -EIO)
goto err_ret;
......@@ -2550,7 +2616,7 @@ netxen_check_health(struct netxen_adapter *adapter)
* Send request to destroy context in case of tx timeout only
* and doesn't required in case of Fw hang
*/
if (state == NX_DEV_NEED_RESET) {
if (state == NX_DEV_NEED_RESET || state == NX_DEV_FAILED) {
adapter->need_fw_reset = 1;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
goto detach;
......
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