Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

netxen_nic: fw dump support

parent 2dcd5d95
Loading
Loading
Loading
Loading
+420 −1
Original line number Diff line number Diff line
@@ -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
 */
+143 −0
Original line number Diff line number Diff line
@@ -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)
{
+104 −0
Original line number Diff line number Diff line
@@ -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,
};
+628 −1

File changed.

Preview size limit exceeded, changes collapsed.

+1 −2
Original line number Diff line number Diff line
@@ -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:
Loading