162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic qlcnic NIC Driver
462306a36Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <net/ip.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "qlcnic.h"
1062306a36Sopenharmony_ci#include "qlcnic_hdr.h"
1162306a36Sopenharmony_ci#include "qlcnic_83xx_hw.h"
1262306a36Sopenharmony_ci#include "qlcnic_hw.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define QLC_83XX_MINIDUMP_FLASH		0x520000
1562306a36Sopenharmony_ci#define QLC_83XX_OCM_INDEX			3
1662306a36Sopenharmony_ci#define QLC_83XX_PCI_INDEX			0
1762306a36Sopenharmony_ci#define QLC_83XX_DMA_ENGINE_INDEX		8
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic const u32 qlcnic_ms_read_data[] = {
2062306a36Sopenharmony_ci	0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define QLCNIC_DUMP_WCRB	BIT_0
2462306a36Sopenharmony_ci#define QLCNIC_DUMP_RWCRB	BIT_1
2562306a36Sopenharmony_ci#define QLCNIC_DUMP_ANDCRB	BIT_2
2662306a36Sopenharmony_ci#define QLCNIC_DUMP_ORCRB	BIT_3
2762306a36Sopenharmony_ci#define QLCNIC_DUMP_POLLCRB	BIT_4
2862306a36Sopenharmony_ci#define QLCNIC_DUMP_RD_SAVE	BIT_5
2962306a36Sopenharmony_ci#define QLCNIC_DUMP_WRT_SAVED	BIT_6
3062306a36Sopenharmony_ci#define QLCNIC_DUMP_MOD_SAVE_ST	BIT_7
3162306a36Sopenharmony_ci#define QLCNIC_DUMP_SKIP	BIT_7
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define QLCNIC_DUMP_MASK_MAX	0xff
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct qlcnic_pex_dma_descriptor {
3662306a36Sopenharmony_ci	u32	read_data_size;
3762306a36Sopenharmony_ci	u32	dma_desc_cmd;
3862306a36Sopenharmony_ci	u32	src_addr_low;
3962306a36Sopenharmony_ci	u32	src_addr_high;
4062306a36Sopenharmony_ci	u32	dma_bus_addr_low;
4162306a36Sopenharmony_ci	u32	dma_bus_addr_high;
4262306a36Sopenharmony_ci	u32	rsvd[6];
4362306a36Sopenharmony_ci} __packed;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct qlcnic_common_entry_hdr {
4662306a36Sopenharmony_ci	u32     type;
4762306a36Sopenharmony_ci	u32     offset;
4862306a36Sopenharmony_ci	u32     cap_size;
4962306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
5062306a36Sopenharmony_ci	u8      mask;
5162306a36Sopenharmony_ci	u8      rsvd[2];
5262306a36Sopenharmony_ci	u8      flags;
5362306a36Sopenharmony_ci#else
5462306a36Sopenharmony_ci	u8      flags;
5562306a36Sopenharmony_ci	u8      rsvd[2];
5662306a36Sopenharmony_ci	u8      mask;
5762306a36Sopenharmony_ci#endif
5862306a36Sopenharmony_ci} __packed;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct __crb {
6162306a36Sopenharmony_ci	u32	addr;
6262306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
6362306a36Sopenharmony_ci	u8	stride;
6462306a36Sopenharmony_ci	u8	rsvd1[3];
6562306a36Sopenharmony_ci#else
6662306a36Sopenharmony_ci	u8	rsvd1[3];
6762306a36Sopenharmony_ci	u8	stride;
6862306a36Sopenharmony_ci#endif
6962306a36Sopenharmony_ci	u32	data_size;
7062306a36Sopenharmony_ci	u32	no_ops;
7162306a36Sopenharmony_ci	u32	rsvd2[4];
7262306a36Sopenharmony_ci} __packed;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistruct __ctrl {
7562306a36Sopenharmony_ci	u32	addr;
7662306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
7762306a36Sopenharmony_ci	u8	stride;
7862306a36Sopenharmony_ci	u8	index_a;
7962306a36Sopenharmony_ci	u16	timeout;
8062306a36Sopenharmony_ci#else
8162306a36Sopenharmony_ci	u16	timeout;
8262306a36Sopenharmony_ci	u8	index_a;
8362306a36Sopenharmony_ci	u8	stride;
8462306a36Sopenharmony_ci#endif
8562306a36Sopenharmony_ci	u32	data_size;
8662306a36Sopenharmony_ci	u32	no_ops;
8762306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
8862306a36Sopenharmony_ci	u8	opcode;
8962306a36Sopenharmony_ci	u8	index_v;
9062306a36Sopenharmony_ci	u8	shl_val;
9162306a36Sopenharmony_ci	u8	shr_val;
9262306a36Sopenharmony_ci#else
9362306a36Sopenharmony_ci	u8	shr_val;
9462306a36Sopenharmony_ci	u8	shl_val;
9562306a36Sopenharmony_ci	u8	index_v;
9662306a36Sopenharmony_ci	u8	opcode;
9762306a36Sopenharmony_ci#endif
9862306a36Sopenharmony_ci	u32	val1;
9962306a36Sopenharmony_ci	u32	val2;
10062306a36Sopenharmony_ci	u32	val3;
10162306a36Sopenharmony_ci} __packed;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistruct __cache {
10462306a36Sopenharmony_ci	u32	addr;
10562306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
10662306a36Sopenharmony_ci	u16	stride;
10762306a36Sopenharmony_ci	u16	init_tag_val;
10862306a36Sopenharmony_ci#else
10962306a36Sopenharmony_ci	u16	init_tag_val;
11062306a36Sopenharmony_ci	u16	stride;
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci	u32	size;
11362306a36Sopenharmony_ci	u32	no_ops;
11462306a36Sopenharmony_ci	u32	ctrl_addr;
11562306a36Sopenharmony_ci	u32	ctrl_val;
11662306a36Sopenharmony_ci	u32	read_addr;
11762306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
11862306a36Sopenharmony_ci	u8	read_addr_stride;
11962306a36Sopenharmony_ci	u8	read_addr_num;
12062306a36Sopenharmony_ci	u8	rsvd1[2];
12162306a36Sopenharmony_ci#else
12262306a36Sopenharmony_ci	u8	rsvd1[2];
12362306a36Sopenharmony_ci	u8	read_addr_num;
12462306a36Sopenharmony_ci	u8	read_addr_stride;
12562306a36Sopenharmony_ci#endif
12662306a36Sopenharmony_ci} __packed;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistruct __ocm {
12962306a36Sopenharmony_ci	u8	rsvd[8];
13062306a36Sopenharmony_ci	u32	size;
13162306a36Sopenharmony_ci	u32	no_ops;
13262306a36Sopenharmony_ci	u8	rsvd1[8];
13362306a36Sopenharmony_ci	u32	read_addr;
13462306a36Sopenharmony_ci	u32	read_addr_stride;
13562306a36Sopenharmony_ci} __packed;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistruct __mem {
13862306a36Sopenharmony_ci	u32	desc_card_addr;
13962306a36Sopenharmony_ci	u32	dma_desc_cmd;
14062306a36Sopenharmony_ci	u32	start_dma_cmd;
14162306a36Sopenharmony_ci	u32	rsvd[3];
14262306a36Sopenharmony_ci	u32	addr;
14362306a36Sopenharmony_ci	u32	size;
14462306a36Sopenharmony_ci} __packed;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistruct __mux {
14762306a36Sopenharmony_ci	u32	addr;
14862306a36Sopenharmony_ci	u8	rsvd[4];
14962306a36Sopenharmony_ci	u32	size;
15062306a36Sopenharmony_ci	u32	no_ops;
15162306a36Sopenharmony_ci	u32	val;
15262306a36Sopenharmony_ci	u32	val_stride;
15362306a36Sopenharmony_ci	u32	read_addr;
15462306a36Sopenharmony_ci	u8	rsvd2[4];
15562306a36Sopenharmony_ci} __packed;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistruct __queue {
15862306a36Sopenharmony_ci	u32	sel_addr;
15962306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
16062306a36Sopenharmony_ci	u16	stride;
16162306a36Sopenharmony_ci	u8	rsvd[2];
16262306a36Sopenharmony_ci#else
16362306a36Sopenharmony_ci	u8	rsvd[2];
16462306a36Sopenharmony_ci	u16	stride;
16562306a36Sopenharmony_ci#endif
16662306a36Sopenharmony_ci	u32	size;
16762306a36Sopenharmony_ci	u32	no_ops;
16862306a36Sopenharmony_ci	u8	rsvd2[8];
16962306a36Sopenharmony_ci	u32	read_addr;
17062306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
17162306a36Sopenharmony_ci	u8	read_addr_stride;
17262306a36Sopenharmony_ci	u8	read_addr_cnt;
17362306a36Sopenharmony_ci	u8	rsvd3[2];
17462306a36Sopenharmony_ci#else
17562306a36Sopenharmony_ci	u8	rsvd3[2];
17662306a36Sopenharmony_ci	u8	read_addr_cnt;
17762306a36Sopenharmony_ci	u8	read_addr_stride;
17862306a36Sopenharmony_ci#endif
17962306a36Sopenharmony_ci} __packed;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistruct __pollrd {
18262306a36Sopenharmony_ci	u32	sel_addr;
18362306a36Sopenharmony_ci	u32	read_addr;
18462306a36Sopenharmony_ci	u32	sel_val;
18562306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
18662306a36Sopenharmony_ci	u16	sel_val_stride;
18762306a36Sopenharmony_ci	u16	no_ops;
18862306a36Sopenharmony_ci#else
18962306a36Sopenharmony_ci	u16	no_ops;
19062306a36Sopenharmony_ci	u16	sel_val_stride;
19162306a36Sopenharmony_ci#endif
19262306a36Sopenharmony_ci	u32	poll_wait;
19362306a36Sopenharmony_ci	u32	poll_mask;
19462306a36Sopenharmony_ci	u32	data_size;
19562306a36Sopenharmony_ci	u8	rsvd[4];
19662306a36Sopenharmony_ci} __packed;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistruct __mux2 {
19962306a36Sopenharmony_ci	u32	sel_addr1;
20062306a36Sopenharmony_ci	u32	sel_addr2;
20162306a36Sopenharmony_ci	u32	sel_val1;
20262306a36Sopenharmony_ci	u32	sel_val2;
20362306a36Sopenharmony_ci	u32	no_ops;
20462306a36Sopenharmony_ci	u32	sel_val_mask;
20562306a36Sopenharmony_ci	u32	read_addr;
20662306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
20762306a36Sopenharmony_ci	u8	sel_val_stride;
20862306a36Sopenharmony_ci	u8	data_size;
20962306a36Sopenharmony_ci	u8	rsvd[2];
21062306a36Sopenharmony_ci#else
21162306a36Sopenharmony_ci	u8	rsvd[2];
21262306a36Sopenharmony_ci	u8	data_size;
21362306a36Sopenharmony_ci	u8	sel_val_stride;
21462306a36Sopenharmony_ci#endif
21562306a36Sopenharmony_ci} __packed;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistruct __pollrdmwr {
21862306a36Sopenharmony_ci	u32	addr1;
21962306a36Sopenharmony_ci	u32	addr2;
22062306a36Sopenharmony_ci	u32	val1;
22162306a36Sopenharmony_ci	u32	val2;
22262306a36Sopenharmony_ci	u32	poll_wait;
22362306a36Sopenharmony_ci	u32	poll_mask;
22462306a36Sopenharmony_ci	u32	mod_mask;
22562306a36Sopenharmony_ci	u32	data_size;
22662306a36Sopenharmony_ci} __packed;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistruct qlcnic_dump_entry {
22962306a36Sopenharmony_ci	struct qlcnic_common_entry_hdr hdr;
23062306a36Sopenharmony_ci	union {
23162306a36Sopenharmony_ci		struct __crb		crb;
23262306a36Sopenharmony_ci		struct __cache		cache;
23362306a36Sopenharmony_ci		struct __ocm		ocm;
23462306a36Sopenharmony_ci		struct __mem		mem;
23562306a36Sopenharmony_ci		struct __mux		mux;
23662306a36Sopenharmony_ci		struct __queue		que;
23762306a36Sopenharmony_ci		struct __ctrl		ctrl;
23862306a36Sopenharmony_ci		struct __pollrdmwr	pollrdmwr;
23962306a36Sopenharmony_ci		struct __mux2		mux2;
24062306a36Sopenharmony_ci		struct __pollrd		pollrd;
24162306a36Sopenharmony_ci	} region;
24262306a36Sopenharmony_ci} __packed;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cienum qlcnic_minidump_opcode {
24562306a36Sopenharmony_ci	QLCNIC_DUMP_NOP		= 0,
24662306a36Sopenharmony_ci	QLCNIC_DUMP_READ_CRB	= 1,
24762306a36Sopenharmony_ci	QLCNIC_DUMP_READ_MUX	= 2,
24862306a36Sopenharmony_ci	QLCNIC_DUMP_QUEUE	= 3,
24962306a36Sopenharmony_ci	QLCNIC_DUMP_BRD_CONFIG	= 4,
25062306a36Sopenharmony_ci	QLCNIC_DUMP_READ_OCM	= 6,
25162306a36Sopenharmony_ci	QLCNIC_DUMP_PEG_REG	= 7,
25262306a36Sopenharmony_ci	QLCNIC_DUMP_L1_DTAG	= 8,
25362306a36Sopenharmony_ci	QLCNIC_DUMP_L1_ITAG	= 9,
25462306a36Sopenharmony_ci	QLCNIC_DUMP_L1_DATA	= 11,
25562306a36Sopenharmony_ci	QLCNIC_DUMP_L1_INST	= 12,
25662306a36Sopenharmony_ci	QLCNIC_DUMP_L2_DTAG	= 21,
25762306a36Sopenharmony_ci	QLCNIC_DUMP_L2_ITAG	= 22,
25862306a36Sopenharmony_ci	QLCNIC_DUMP_L2_DATA	= 23,
25962306a36Sopenharmony_ci	QLCNIC_DUMP_L2_INST	= 24,
26062306a36Sopenharmony_ci	QLCNIC_DUMP_POLL_RD	= 35,
26162306a36Sopenharmony_ci	QLCNIC_READ_MUX2	= 36,
26262306a36Sopenharmony_ci	QLCNIC_READ_POLLRDMWR	= 37,
26362306a36Sopenharmony_ci	QLCNIC_DUMP_READ_ROM	= 71,
26462306a36Sopenharmony_ci	QLCNIC_DUMP_READ_MEM	= 72,
26562306a36Sopenharmony_ci	QLCNIC_DUMP_READ_CTRL	= 98,
26662306a36Sopenharmony_ci	QLCNIC_DUMP_TLHDR	= 99,
26762306a36Sopenharmony_ci	QLCNIC_DUMP_RDEND	= 255
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ciinline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return hdr->saved_state[index];
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ciinline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index,
27862306a36Sopenharmony_ci					u32 value)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	hdr->saved_state[index] = value;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_civoid qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	hdr = fw_dump->tmpl_hdr;
29062306a36Sopenharmony_ci	fw_dump->tmpl_hdr_size = hdr->size;
29162306a36Sopenharmony_ci	fw_dump->version = hdr->version;
29262306a36Sopenharmony_ci	fw_dump->num_entries = hdr->num_entries;
29362306a36Sopenharmony_ci	fw_dump->offset = hdr->offset;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	hdr->drv_cap_mask = hdr->cap_mask;
29662306a36Sopenharmony_ci	fw_dump->cap_mask = hdr->cap_mask;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	fw_dump->use_pex_dma = (hdr->capabilities & BIT_0) ? true : false;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciinline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return hdr->cap_sizes[index];
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_civoid qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	hdr->sys_info[idx] = value;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_civoid qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	hdr->drv_cap_mask = mask;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ciinline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return hdr->saved_state[index];
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ciinline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index,
33062306a36Sopenharmony_ci					u32 value)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	hdr->saved_state[index] = value;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci#define QLCNIC_TEMPLATE_VERSION (0x20001)
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_civoid qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	hdr = fw_dump->tmpl_hdr;
34462306a36Sopenharmony_ci	fw_dump->tmpl_hdr_size = hdr->size;
34562306a36Sopenharmony_ci	fw_dump->version = hdr->version;
34662306a36Sopenharmony_ci	fw_dump->num_entries = hdr->num_entries;
34762306a36Sopenharmony_ci	fw_dump->offset = hdr->offset;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	hdr->drv_cap_mask = hdr->cap_mask;
35062306a36Sopenharmony_ci	fw_dump->cap_mask = hdr->cap_mask;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	fw_dump->use_pex_dma = (fw_dump->version & 0xfffff) >=
35362306a36Sopenharmony_ci			       QLCNIC_TEMPLATE_VERSION;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ciinline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return hdr->cap_sizes[index];
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_civoid qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	hdr->sys_info[idx] = value;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	hdr = tmpl_hdr;
37562306a36Sopenharmony_ci	hdr->drv_cap_mask = mask;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistruct qlcnic_dump_operations {
37962306a36Sopenharmony_ci	enum qlcnic_minidump_opcode opcode;
38062306a36Sopenharmony_ci	u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
38162306a36Sopenharmony_ci		       __le32 *);
38262306a36Sopenharmony_ci};
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
38562306a36Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	int i;
38862306a36Sopenharmony_ci	u32 addr, data;
38962306a36Sopenharmony_ci	struct __crb *crb = &entry->region.crb;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	addr = crb->addr;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	for (i = 0; i < crb->no_ops; i++) {
39462306a36Sopenharmony_ci		data = qlcnic_ind_rd(adapter, addr);
39562306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(addr);
39662306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
39762306a36Sopenharmony_ci		addr += crb->stride;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci	return crb->no_ops * 2 * sizeof(u32);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
40362306a36Sopenharmony_ci			    struct qlcnic_dump_entry *entry, __le32 *buffer)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	void *hdr = adapter->ahw->fw_dump.tmpl_hdr;
40662306a36Sopenharmony_ci	struct __ctrl *ctr = &entry->region.ctrl;
40762306a36Sopenharmony_ci	int i, k, timeout = 0;
40862306a36Sopenharmony_ci	u32 addr, data, temp;
40962306a36Sopenharmony_ci	u8 no_ops;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	addr = ctr->addr;
41262306a36Sopenharmony_ci	no_ops = ctr->no_ops;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	for (i = 0; i < no_ops; i++) {
41562306a36Sopenharmony_ci		k = 0;
41662306a36Sopenharmony_ci		for (k = 0; k < 8; k++) {
41762306a36Sopenharmony_ci			if (!(ctr->opcode & (1 << k)))
41862306a36Sopenharmony_ci				continue;
41962306a36Sopenharmony_ci			switch (1 << k) {
42062306a36Sopenharmony_ci			case QLCNIC_DUMP_WCRB:
42162306a36Sopenharmony_ci				qlcnic_ind_wr(adapter, addr, ctr->val1);
42262306a36Sopenharmony_ci				break;
42362306a36Sopenharmony_ci			case QLCNIC_DUMP_RWCRB:
42462306a36Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
42562306a36Sopenharmony_ci				qlcnic_ind_wr(adapter, addr, data);
42662306a36Sopenharmony_ci				break;
42762306a36Sopenharmony_ci			case QLCNIC_DUMP_ANDCRB:
42862306a36Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
42962306a36Sopenharmony_ci				qlcnic_ind_wr(adapter, addr,
43062306a36Sopenharmony_ci					      (data & ctr->val2));
43162306a36Sopenharmony_ci				break;
43262306a36Sopenharmony_ci			case QLCNIC_DUMP_ORCRB:
43362306a36Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
43462306a36Sopenharmony_ci				qlcnic_ind_wr(adapter, addr,
43562306a36Sopenharmony_ci					      (data | ctr->val3));
43662306a36Sopenharmony_ci				break;
43762306a36Sopenharmony_ci			case QLCNIC_DUMP_POLLCRB:
43862306a36Sopenharmony_ci				while (timeout <= ctr->timeout) {
43962306a36Sopenharmony_ci					data = qlcnic_ind_rd(adapter, addr);
44062306a36Sopenharmony_ci					if ((data & ctr->val2) == ctr->val1)
44162306a36Sopenharmony_ci						break;
44262306a36Sopenharmony_ci					usleep_range(1000, 2000);
44362306a36Sopenharmony_ci					timeout++;
44462306a36Sopenharmony_ci				}
44562306a36Sopenharmony_ci				if (timeout > ctr->timeout) {
44662306a36Sopenharmony_ci					dev_info(&adapter->pdev->dev,
44762306a36Sopenharmony_ci					"Timed out, aborting poll CRB\n");
44862306a36Sopenharmony_ci					return -EINVAL;
44962306a36Sopenharmony_ci				}
45062306a36Sopenharmony_ci				break;
45162306a36Sopenharmony_ci			case QLCNIC_DUMP_RD_SAVE:
45262306a36Sopenharmony_ci				temp = ctr->index_a;
45362306a36Sopenharmony_ci				if (temp)
45462306a36Sopenharmony_ci					addr = qlcnic_get_saved_state(adapter,
45562306a36Sopenharmony_ci								      hdr,
45662306a36Sopenharmony_ci								      temp);
45762306a36Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
45862306a36Sopenharmony_ci				qlcnic_set_saved_state(adapter, hdr,
45962306a36Sopenharmony_ci						       ctr->index_v, data);
46062306a36Sopenharmony_ci				break;
46162306a36Sopenharmony_ci			case QLCNIC_DUMP_WRT_SAVED:
46262306a36Sopenharmony_ci				temp = ctr->index_v;
46362306a36Sopenharmony_ci				if (temp)
46462306a36Sopenharmony_ci					data = qlcnic_get_saved_state(adapter,
46562306a36Sopenharmony_ci								      hdr,
46662306a36Sopenharmony_ci								      temp);
46762306a36Sopenharmony_ci				else
46862306a36Sopenharmony_ci					data = ctr->val1;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci				temp = ctr->index_a;
47162306a36Sopenharmony_ci				if (temp)
47262306a36Sopenharmony_ci					addr = qlcnic_get_saved_state(adapter,
47362306a36Sopenharmony_ci								      hdr,
47462306a36Sopenharmony_ci								      temp);
47562306a36Sopenharmony_ci				qlcnic_ind_wr(adapter, addr, data);
47662306a36Sopenharmony_ci				break;
47762306a36Sopenharmony_ci			case QLCNIC_DUMP_MOD_SAVE_ST:
47862306a36Sopenharmony_ci				data = qlcnic_get_saved_state(adapter, hdr,
47962306a36Sopenharmony_ci							      ctr->index_v);
48062306a36Sopenharmony_ci				data <<= ctr->shl_val;
48162306a36Sopenharmony_ci				data >>= ctr->shr_val;
48262306a36Sopenharmony_ci				if (ctr->val2)
48362306a36Sopenharmony_ci					data &= ctr->val2;
48462306a36Sopenharmony_ci				data |= ctr->val3;
48562306a36Sopenharmony_ci				data += ctr->val1;
48662306a36Sopenharmony_ci				qlcnic_set_saved_state(adapter, hdr,
48762306a36Sopenharmony_ci						       ctr->index_v, data);
48862306a36Sopenharmony_ci				break;
48962306a36Sopenharmony_ci			default:
49062306a36Sopenharmony_ci				dev_info(&adapter->pdev->dev,
49162306a36Sopenharmony_ci					 "Unknown opcode\n");
49262306a36Sopenharmony_ci				break;
49362306a36Sopenharmony_ci			}
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci		addr += ctr->stride;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci	return 0;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic u32 qlcnic_dump_mux(struct qlcnic_adapter *adapter,
50162306a36Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	int loop;
50462306a36Sopenharmony_ci	u32 val, data = 0;
50562306a36Sopenharmony_ci	struct __mux *mux = &entry->region.mux;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	val = mux->val;
50862306a36Sopenharmony_ci	for (loop = 0; loop < mux->no_ops; loop++) {
50962306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, mux->addr, val);
51062306a36Sopenharmony_ci		data = qlcnic_ind_rd(adapter, mux->read_addr);
51162306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(val);
51262306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
51362306a36Sopenharmony_ci		val += mux->val_stride;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	return 2 * mux->no_ops * sizeof(u32);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic u32 qlcnic_dump_que(struct qlcnic_adapter *adapter,
51962306a36Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	int i, loop;
52262306a36Sopenharmony_ci	u32 cnt, addr, data, que_id = 0;
52362306a36Sopenharmony_ci	struct __queue *que = &entry->region.que;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	addr = que->read_addr;
52662306a36Sopenharmony_ci	cnt = que->read_addr_cnt;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	for (loop = 0; loop < que->no_ops; loop++) {
52962306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, que->sel_addr, que_id);
53062306a36Sopenharmony_ci		addr = que->read_addr;
53162306a36Sopenharmony_ci		for (i = 0; i < cnt; i++) {
53262306a36Sopenharmony_ci			data = qlcnic_ind_rd(adapter, addr);
53362306a36Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
53462306a36Sopenharmony_ci			addr += que->read_addr_stride;
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci		que_id += que->stride;
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci	return que->no_ops * cnt * sizeof(u32);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic u32 qlcnic_dump_ocm(struct qlcnic_adapter *adapter,
54262306a36Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	int i;
54562306a36Sopenharmony_ci	u32 data;
54662306a36Sopenharmony_ci	void __iomem *addr;
54762306a36Sopenharmony_ci	struct __ocm *ocm = &entry->region.ocm;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	addr = adapter->ahw->pci_base0 + ocm->read_addr;
55062306a36Sopenharmony_ci	for (i = 0; i < ocm->no_ops; i++) {
55162306a36Sopenharmony_ci		data = readl(addr);
55262306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
55362306a36Sopenharmony_ci		addr += ocm->read_addr_stride;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci	return ocm->no_ops * sizeof(u32);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic u32 qlcnic_read_rom(struct qlcnic_adapter *adapter,
55962306a36Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	int i, count = 0;
56262306a36Sopenharmony_ci	u32 fl_addr, size, val, lck_val, addr;
56362306a36Sopenharmony_ci	struct __mem *rom = &entry->region.mem;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	fl_addr = rom->addr;
56662306a36Sopenharmony_ci	size = rom->size / 4;
56762306a36Sopenharmony_cilock_try:
56862306a36Sopenharmony_ci	lck_val = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
56962306a36Sopenharmony_ci	if (!lck_val && count < MAX_CTL_CHECK) {
57062306a36Sopenharmony_ci		usleep_range(10000, 11000);
57162306a36Sopenharmony_ci		count++;
57262306a36Sopenharmony_ci		goto lock_try;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
57562306a36Sopenharmony_ci			    adapter->ahw->pci_func);
57662306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
57762306a36Sopenharmony_ci		addr = fl_addr & 0xFFFF0000;
57862306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, FLASH_ROM_WINDOW, addr);
57962306a36Sopenharmony_ci		addr = LSW(fl_addr) + FLASH_ROM_DATA;
58062306a36Sopenharmony_ci		val = qlcnic_ind_rd(adapter, addr);
58162306a36Sopenharmony_ci		fl_addr += 4;
58262306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(val);
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci	QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
58562306a36Sopenharmony_ci	return rom->size;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic u32 qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
58962306a36Sopenharmony_ci				struct qlcnic_dump_entry *entry, __le32 *buffer)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	int i;
59262306a36Sopenharmony_ci	u32 cnt, val, data, addr;
59362306a36Sopenharmony_ci	struct __cache *l1 = &entry->region.cache;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	val = l1->init_tag_val;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	for (i = 0; i < l1->no_ops; i++) {
59862306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, l1->addr, val);
59962306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, l1->ctrl_addr, LSW(l1->ctrl_val));
60062306a36Sopenharmony_ci		addr = l1->read_addr;
60162306a36Sopenharmony_ci		cnt = l1->read_addr_num;
60262306a36Sopenharmony_ci		while (cnt) {
60362306a36Sopenharmony_ci			data = qlcnic_ind_rd(adapter, addr);
60462306a36Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
60562306a36Sopenharmony_ci			addr += l1->read_addr_stride;
60662306a36Sopenharmony_ci			cnt--;
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci		val += l1->stride;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci	return l1->no_ops * l1->read_addr_num * sizeof(u32);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
61462306a36Sopenharmony_ci				struct qlcnic_dump_entry *entry, __le32 *buffer)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	int i;
61762306a36Sopenharmony_ci	u32 cnt, val, data, addr;
61862306a36Sopenharmony_ci	u8 poll_mask, poll_to, time_out = 0;
61962306a36Sopenharmony_ci	struct __cache *l2 = &entry->region.cache;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	val = l2->init_tag_val;
62262306a36Sopenharmony_ci	poll_mask = LSB(MSW(l2->ctrl_val));
62362306a36Sopenharmony_ci	poll_to = MSB(MSW(l2->ctrl_val));
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	for (i = 0; i < l2->no_ops; i++) {
62662306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, l2->addr, val);
62762306a36Sopenharmony_ci		if (LSW(l2->ctrl_val))
62862306a36Sopenharmony_ci			qlcnic_ind_wr(adapter, l2->ctrl_addr,
62962306a36Sopenharmony_ci				      LSW(l2->ctrl_val));
63062306a36Sopenharmony_ci		if (!poll_mask)
63162306a36Sopenharmony_ci			goto skip_poll;
63262306a36Sopenharmony_ci		do {
63362306a36Sopenharmony_ci			data = qlcnic_ind_rd(adapter, l2->ctrl_addr);
63462306a36Sopenharmony_ci			if (!(data & poll_mask))
63562306a36Sopenharmony_ci				break;
63662306a36Sopenharmony_ci			usleep_range(1000, 2000);
63762306a36Sopenharmony_ci			time_out++;
63862306a36Sopenharmony_ci		} while (time_out <= poll_to);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci		if (time_out > poll_to) {
64162306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
64262306a36Sopenharmony_ci				"Timeout exceeded in %s, aborting dump\n",
64362306a36Sopenharmony_ci				__func__);
64462306a36Sopenharmony_ci			return -EINVAL;
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ciskip_poll:
64762306a36Sopenharmony_ci		addr = l2->read_addr;
64862306a36Sopenharmony_ci		cnt = l2->read_addr_num;
64962306a36Sopenharmony_ci		while (cnt) {
65062306a36Sopenharmony_ci			data = qlcnic_ind_rd(adapter, addr);
65162306a36Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
65262306a36Sopenharmony_ci			addr += l2->read_addr_stride;
65362306a36Sopenharmony_ci			cnt--;
65462306a36Sopenharmony_ci		}
65562306a36Sopenharmony_ci		val += l2->stride;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci	return l2->no_ops * l2->read_addr_num * sizeof(u32);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic u32 qlcnic_read_memory_test_agent(struct qlcnic_adapter *adapter,
66162306a36Sopenharmony_ci					 struct __mem *mem, __le32 *buffer,
66262306a36Sopenharmony_ci					 int *ret)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	u32 addr, data, test;
66562306a36Sopenharmony_ci	int i, reg_read;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	reg_read = mem->size;
66862306a36Sopenharmony_ci	addr = mem->addr;
66962306a36Sopenharmony_ci	/* check for data size of multiple of 16 and 16 byte alignment */
67062306a36Sopenharmony_ci	if ((addr & 0xf) || (reg_read%16)) {
67162306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev,
67262306a36Sopenharmony_ci			 "Unaligned memory addr:0x%x size:0x%x\n",
67362306a36Sopenharmony_ci			 addr, reg_read);
67462306a36Sopenharmony_ci		*ret = -EINVAL;
67562306a36Sopenharmony_ci		return 0;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	while (reg_read != 0) {
68162306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);
68262306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);
68362306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_START_ENABLE);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		for (i = 0; i < MAX_CTL_CHECK; i++) {
68662306a36Sopenharmony_ci			test = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);
68762306a36Sopenharmony_ci			if (!(test & TA_CTL_BUSY))
68862306a36Sopenharmony_ci				break;
68962306a36Sopenharmony_ci		}
69062306a36Sopenharmony_ci		if (i == MAX_CTL_CHECK) {
69162306a36Sopenharmony_ci			if (printk_ratelimit()) {
69262306a36Sopenharmony_ci				dev_err(&adapter->pdev->dev,
69362306a36Sopenharmony_ci					"failed to read through agent\n");
69462306a36Sopenharmony_ci				*ret = -EIO;
69562306a36Sopenharmony_ci				goto out;
69662306a36Sopenharmony_ci			}
69762306a36Sopenharmony_ci		}
69862306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
69962306a36Sopenharmony_ci			data = qlcnic_ind_rd(adapter, qlcnic_ms_read_data[i]);
70062306a36Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
70162306a36Sopenharmony_ci		}
70262306a36Sopenharmony_ci		addr += 16;
70362306a36Sopenharmony_ci		reg_read -= 16;
70462306a36Sopenharmony_ci		ret += 16;
70562306a36Sopenharmony_ci		cond_resched();
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ciout:
70862306a36Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
70962306a36Sopenharmony_ci	return mem->size;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci/* DMA register base address */
71362306a36Sopenharmony_ci#define QLC_DMA_REG_BASE_ADDR(dma_no)	(0x77320000 + (dma_no * 0x10000))
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/* DMA register offsets w.r.t base address */
71662306a36Sopenharmony_ci#define QLC_DMA_CMD_BUFF_ADDR_LOW	0
71762306a36Sopenharmony_ci#define QLC_DMA_CMD_BUFF_ADDR_HI	4
71862306a36Sopenharmony_ci#define QLC_DMA_CMD_STATUS_CTRL		8
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,
72162306a36Sopenharmony_ci				struct __mem *mem)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
72462306a36Sopenharmony_ci	u32 dma_no, dma_base_addr, temp_addr;
72562306a36Sopenharmony_ci	int i, ret, dma_sts;
72662306a36Sopenharmony_ci	void *tmpl_hdr;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	tmpl_hdr = adapter->ahw->fw_dump.tmpl_hdr;
72962306a36Sopenharmony_ci	dma_no = qlcnic_get_saved_state(adapter, tmpl_hdr,
73062306a36Sopenharmony_ci					QLC_83XX_DMA_ENGINE_INDEX);
73162306a36Sopenharmony_ci	dma_base_addr = QLC_DMA_REG_BASE_ADDR(dma_no);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_LOW;
73462306a36Sopenharmony_ci	ret = qlcnic_ind_wr(adapter, temp_addr, mem->desc_card_addr);
73562306a36Sopenharmony_ci	if (ret)
73662306a36Sopenharmony_ci		return ret;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_HI;
73962306a36Sopenharmony_ci	ret = qlcnic_ind_wr(adapter, temp_addr, 0);
74062306a36Sopenharmony_ci	if (ret)
74162306a36Sopenharmony_ci		return ret;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_STATUS_CTRL;
74462306a36Sopenharmony_ci	ret = qlcnic_ind_wr(adapter, temp_addr, mem->start_dma_cmd);
74562306a36Sopenharmony_ci	if (ret)
74662306a36Sopenharmony_ci		return ret;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	/* Wait for DMA to complete */
74962306a36Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_STATUS_CTRL;
75062306a36Sopenharmony_ci	for (i = 0; i < 400; i++) {
75162306a36Sopenharmony_ci		dma_sts = qlcnic_ind_rd(adapter, temp_addr);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		if (dma_sts & BIT_1)
75462306a36Sopenharmony_ci			usleep_range(250, 500);
75562306a36Sopenharmony_ci		else
75662306a36Sopenharmony_ci			break;
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (i >= 400) {
76062306a36Sopenharmony_ci		dev_info(dev, "PEX DMA operation timed out");
76162306a36Sopenharmony_ci		ret = -EIO;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	return ret;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,
76862306a36Sopenharmony_ci				     struct __mem *mem,
76962306a36Sopenharmony_ci				     __le32 *buffer, int *ret)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
77262306a36Sopenharmony_ci	u32 temp, dma_base_addr, size = 0, read_size = 0;
77362306a36Sopenharmony_ci	struct qlcnic_pex_dma_descriptor *dma_descr;
77462306a36Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
77562306a36Sopenharmony_ci	dma_addr_t dma_phys_addr;
77662306a36Sopenharmony_ci	void *dma_buffer;
77762306a36Sopenharmony_ci	void *tmpl_hdr;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	tmpl_hdr = fw_dump->tmpl_hdr;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* Check if DMA engine is available */
78262306a36Sopenharmony_ci	temp = qlcnic_get_saved_state(adapter, tmpl_hdr,
78362306a36Sopenharmony_ci				      QLC_83XX_DMA_ENGINE_INDEX);
78462306a36Sopenharmony_ci	dma_base_addr = QLC_DMA_REG_BASE_ADDR(temp);
78562306a36Sopenharmony_ci	temp = qlcnic_ind_rd(adapter,
78662306a36Sopenharmony_ci			     dma_base_addr + QLC_DMA_CMD_STATUS_CTRL);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (!(temp & BIT_31)) {
78962306a36Sopenharmony_ci		dev_info(dev, "%s: DMA engine is not available\n", __func__);
79062306a36Sopenharmony_ci		*ret = -EIO;
79162306a36Sopenharmony_ci		return 0;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/* Create DMA descriptor */
79562306a36Sopenharmony_ci	dma_descr = kzalloc(sizeof(struct qlcnic_pex_dma_descriptor),
79662306a36Sopenharmony_ci			    GFP_KERNEL);
79762306a36Sopenharmony_ci	if (!dma_descr) {
79862306a36Sopenharmony_ci		*ret = -ENOMEM;
79962306a36Sopenharmony_ci		return 0;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* dma_desc_cmd  0:15  = 0
80362306a36Sopenharmony_ci	 * dma_desc_cmd 16:19  = mem->dma_desc_cmd 0:3
80462306a36Sopenharmony_ci	 * dma_desc_cmd 20:23  = pci function number
80562306a36Sopenharmony_ci	 * dma_desc_cmd 24:31  = mem->dma_desc_cmd 8:15
80662306a36Sopenharmony_ci	 */
80762306a36Sopenharmony_ci	dma_phys_addr = fw_dump->phys_addr;
80862306a36Sopenharmony_ci	dma_buffer = fw_dump->dma_buffer;
80962306a36Sopenharmony_ci	temp = 0;
81062306a36Sopenharmony_ci	temp = mem->dma_desc_cmd & 0xff0f;
81162306a36Sopenharmony_ci	temp |= (adapter->ahw->pci_func & 0xf) << 4;
81262306a36Sopenharmony_ci	dma_descr->dma_desc_cmd = (temp << 16) & 0xffff0000;
81362306a36Sopenharmony_ci	dma_descr->dma_bus_addr_low = LSD(dma_phys_addr);
81462306a36Sopenharmony_ci	dma_descr->dma_bus_addr_high = MSD(dma_phys_addr);
81562306a36Sopenharmony_ci	dma_descr->src_addr_high = 0;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* Collect memory dump using multiple DMA operations if required */
81862306a36Sopenharmony_ci	while (read_size < mem->size) {
81962306a36Sopenharmony_ci		if (mem->size - read_size >= QLC_PEX_DMA_READ_SIZE)
82062306a36Sopenharmony_ci			size = QLC_PEX_DMA_READ_SIZE;
82162306a36Sopenharmony_ci		else
82262306a36Sopenharmony_ci			size = mem->size - read_size;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		dma_descr->src_addr_low = mem->addr + read_size;
82562306a36Sopenharmony_ci		dma_descr->read_data_size = size;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci		/* Write DMA descriptor to MS memory*/
82862306a36Sopenharmony_ci		temp = sizeof(struct qlcnic_pex_dma_descriptor) / 16;
82962306a36Sopenharmony_ci		*ret = qlcnic_ms_mem_write128(adapter, mem->desc_card_addr,
83062306a36Sopenharmony_ci					      (u32 *)dma_descr, temp);
83162306a36Sopenharmony_ci		if (*ret) {
83262306a36Sopenharmony_ci			dev_info(dev, "Failed to write DMA descriptor to MS memory at address 0x%x\n",
83362306a36Sopenharmony_ci				 mem->desc_card_addr);
83462306a36Sopenharmony_ci			goto free_dma_descr;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		*ret = qlcnic_start_pex_dma(adapter, mem);
83862306a36Sopenharmony_ci		if (*ret) {
83962306a36Sopenharmony_ci			dev_info(dev, "Failed to start PEX DMA operation\n");
84062306a36Sopenharmony_ci			goto free_dma_descr;
84162306a36Sopenharmony_ci		}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		memcpy(buffer, dma_buffer, size);
84462306a36Sopenharmony_ci		buffer += size / 4;
84562306a36Sopenharmony_ci		read_size += size;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cifree_dma_descr:
84962306a36Sopenharmony_ci	kfree(dma_descr);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	return read_size;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
85562306a36Sopenharmony_ci			      struct qlcnic_dump_entry *entry, __le32 *buffer)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
85862306a36Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
85962306a36Sopenharmony_ci	struct __mem *mem = &entry->region.mem;
86062306a36Sopenharmony_ci	u32 data_size;
86162306a36Sopenharmony_ci	int ret = 0;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (fw_dump->use_pex_dma) {
86462306a36Sopenharmony_ci		data_size = qlcnic_read_memory_pexdma(adapter, mem, buffer,
86562306a36Sopenharmony_ci						      &ret);
86662306a36Sopenharmony_ci		if (ret)
86762306a36Sopenharmony_ci			dev_info(dev,
86862306a36Sopenharmony_ci				 "Failed to read memory dump using PEX DMA: mask[0x%x]\n",
86962306a36Sopenharmony_ci				 entry->hdr.mask);
87062306a36Sopenharmony_ci		else
87162306a36Sopenharmony_ci			return data_size;
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	data_size = qlcnic_read_memory_test_agent(adapter, mem, buffer, &ret);
87562306a36Sopenharmony_ci	if (ret) {
87662306a36Sopenharmony_ci		dev_info(dev,
87762306a36Sopenharmony_ci			 "Failed to read memory dump using test agent method: mask[0x%x]\n",
87862306a36Sopenharmony_ci			 entry->hdr.mask);
87962306a36Sopenharmony_ci		return 0;
88062306a36Sopenharmony_ci	} else {
88162306a36Sopenharmony_ci		return data_size;
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic u32 qlcnic_dump_nop(struct qlcnic_adapter *adapter,
88662306a36Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	entry->hdr.flags |= QLCNIC_DUMP_SKIP;
88962306a36Sopenharmony_ci	return 0;
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic int qlcnic_valid_dump_entry(struct device *dev,
89362306a36Sopenharmony_ci				   struct qlcnic_dump_entry *entry, u32 size)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	int ret = 1;
89662306a36Sopenharmony_ci	if (size != entry->hdr.cap_size) {
89762306a36Sopenharmony_ci		dev_err(dev,
89862306a36Sopenharmony_ci			"Invalid entry, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
89962306a36Sopenharmony_ci			entry->hdr.type, entry->hdr.mask, size,
90062306a36Sopenharmony_ci			entry->hdr.cap_size);
90162306a36Sopenharmony_ci		ret = 0;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci	return ret;
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic u32 qlcnic_read_pollrdmwr(struct qlcnic_adapter *adapter,
90762306a36Sopenharmony_ci				 struct qlcnic_dump_entry *entry,
90862306a36Sopenharmony_ci				 __le32 *buffer)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	struct __pollrdmwr *poll = &entry->region.pollrdmwr;
91162306a36Sopenharmony_ci	u32 data, wait_count, poll_wait, temp;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	poll_wait = poll->poll_wait;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, poll->addr1, poll->val1);
91662306a36Sopenharmony_ci	wait_count = 0;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	while (wait_count < poll_wait) {
91962306a36Sopenharmony_ci		data = qlcnic_ind_rd(adapter, poll->addr1);
92062306a36Sopenharmony_ci		if ((data & poll->poll_mask) != 0)
92162306a36Sopenharmony_ci			break;
92262306a36Sopenharmony_ci		wait_count++;
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	if (wait_count == poll_wait) {
92662306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
92762306a36Sopenharmony_ci			"Timeout exceeded in %s, aborting dump\n",
92862306a36Sopenharmony_ci			__func__);
92962306a36Sopenharmony_ci		return 0;
93062306a36Sopenharmony_ci	}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	data = qlcnic_ind_rd(adapter, poll->addr2) & poll->mod_mask;
93362306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, poll->addr2, data);
93462306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, poll->addr1, poll->val2);
93562306a36Sopenharmony_ci	wait_count = 0;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	while (wait_count < poll_wait) {
93862306a36Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, poll->addr1);
93962306a36Sopenharmony_ci		if ((temp & poll->poll_mask) != 0)
94062306a36Sopenharmony_ci			break;
94162306a36Sopenharmony_ci		wait_count++;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	*buffer++ = cpu_to_le32(poll->addr2);
94562306a36Sopenharmony_ci	*buffer++ = cpu_to_le32(data);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return 2 * sizeof(u32);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic u32 qlcnic_read_pollrd(struct qlcnic_adapter *adapter,
95262306a36Sopenharmony_ci			      struct qlcnic_dump_entry *entry, __le32 *buffer)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct __pollrd *pollrd = &entry->region.pollrd;
95562306a36Sopenharmony_ci	u32 data, wait_count, poll_wait, sel_val;
95662306a36Sopenharmony_ci	int i;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	poll_wait = pollrd->poll_wait;
95962306a36Sopenharmony_ci	sel_val = pollrd->sel_val;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	for (i = 0; i < pollrd->no_ops; i++) {
96262306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, pollrd->sel_addr, sel_val);
96362306a36Sopenharmony_ci		wait_count = 0;
96462306a36Sopenharmony_ci		while (wait_count < poll_wait) {
96562306a36Sopenharmony_ci			data = qlcnic_ind_rd(adapter, pollrd->sel_addr);
96662306a36Sopenharmony_ci			if ((data & pollrd->poll_mask) != 0)
96762306a36Sopenharmony_ci				break;
96862306a36Sopenharmony_ci			wait_count++;
96962306a36Sopenharmony_ci		}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		if (wait_count == poll_wait) {
97262306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
97362306a36Sopenharmony_ci				"Timeout exceeded in %s, aborting dump\n",
97462306a36Sopenharmony_ci				__func__);
97562306a36Sopenharmony_ci			return 0;
97662306a36Sopenharmony_ci		}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		data = qlcnic_ind_rd(adapter, pollrd->read_addr);
97962306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(sel_val);
98062306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
98162306a36Sopenharmony_ci		sel_val += pollrd->sel_val_stride;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci	return pollrd->no_ops * (2 * sizeof(u32));
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_cistatic u32 qlcnic_read_mux2(struct qlcnic_adapter *adapter,
98762306a36Sopenharmony_ci			    struct qlcnic_dump_entry *entry, __le32 *buffer)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	struct __mux2 *mux2 = &entry->region.mux2;
99062306a36Sopenharmony_ci	u32 data;
99162306a36Sopenharmony_ci	u32 t_sel_val, sel_val1, sel_val2;
99262306a36Sopenharmony_ci	int i;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	sel_val1 = mux2->sel_val1;
99562306a36Sopenharmony_ci	sel_val2 = mux2->sel_val2;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	for (i = 0; i < mux2->no_ops; i++) {
99862306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val1);
99962306a36Sopenharmony_ci		t_sel_val = sel_val1 & mux2->sel_val_mask;
100062306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
100162306a36Sopenharmony_ci		data = qlcnic_ind_rd(adapter, mux2->read_addr);
100262306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(t_sel_val);
100362306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
100462306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val2);
100562306a36Sopenharmony_ci		t_sel_val = sel_val2 & mux2->sel_val_mask;
100662306a36Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
100762306a36Sopenharmony_ci		data = qlcnic_ind_rd(adapter, mux2->read_addr);
100862306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(t_sel_val);
100962306a36Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
101062306a36Sopenharmony_ci		sel_val1 += mux2->sel_val_stride;
101162306a36Sopenharmony_ci		sel_val2 += mux2->sel_val_stride;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	return mux2->no_ops * (4 * sizeof(u32));
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic u32 qlcnic_83xx_dump_rom(struct qlcnic_adapter *adapter,
101862306a36Sopenharmony_ci				struct qlcnic_dump_entry *entry, __le32 *buffer)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	u32 fl_addr, size;
102162306a36Sopenharmony_ci	struct __mem *rom = &entry->region.mem;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	fl_addr = rom->addr;
102462306a36Sopenharmony_ci	size = rom->size / 4;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (!qlcnic_83xx_lockless_flash_read32(adapter, fl_addr,
102762306a36Sopenharmony_ci					       (u8 *)buffer, size))
102862306a36Sopenharmony_ci		return rom->size;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return 0;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistatic const struct qlcnic_dump_operations qlcnic_fw_dump_ops[] = {
103462306a36Sopenharmony_ci	{QLCNIC_DUMP_NOP, qlcnic_dump_nop},
103562306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
103662306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
103762306a36Sopenharmony_ci	{QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
103862306a36Sopenharmony_ci	{QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom},
103962306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
104062306a36Sopenharmony_ci	{QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
104162306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
104262306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
104362306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
104462306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
104562306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
104662306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
104762306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
104862306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
104962306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_ROM, qlcnic_read_rom},
105062306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
105162306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
105262306a36Sopenharmony_ci	{QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
105362306a36Sopenharmony_ci	{QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
105462306a36Sopenharmony_ci};
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistatic const struct qlcnic_dump_operations qlcnic_83xx_fw_dump_ops[] = {
105762306a36Sopenharmony_ci	{QLCNIC_DUMP_NOP, qlcnic_dump_nop},
105862306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
105962306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
106062306a36Sopenharmony_ci	{QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
106162306a36Sopenharmony_ci	{QLCNIC_DUMP_BRD_CONFIG, qlcnic_83xx_dump_rom},
106262306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
106362306a36Sopenharmony_ci	{QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
106462306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
106562306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
106662306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
106762306a36Sopenharmony_ci	{QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
106862306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
106962306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
107062306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
107162306a36Sopenharmony_ci	{QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
107262306a36Sopenharmony_ci	{QLCNIC_DUMP_POLL_RD, qlcnic_read_pollrd},
107362306a36Sopenharmony_ci	{QLCNIC_READ_MUX2, qlcnic_read_mux2},
107462306a36Sopenharmony_ci	{QLCNIC_READ_POLLRDMWR, qlcnic_read_pollrdmwr},
107562306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_ROM, qlcnic_83xx_dump_rom},
107662306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
107762306a36Sopenharmony_ci	{QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
107862306a36Sopenharmony_ci	{QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
107962306a36Sopenharmony_ci	{QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
108062306a36Sopenharmony_ci};
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	uint64_t sum = 0;
108562306a36Sopenharmony_ci	int count = temp_size / sizeof(uint32_t);
108662306a36Sopenharmony_ci	while (count-- > 0)
108762306a36Sopenharmony_ci		sum += *temp_buffer++;
108862306a36Sopenharmony_ci	while (sum >> 32)
108962306a36Sopenharmony_ci		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
109062306a36Sopenharmony_ci	return ~sum;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic int qlcnic_fw_flash_get_minidump_temp(struct qlcnic_adapter *adapter,
109462306a36Sopenharmony_ci					     u8 *buffer, u32 size)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	int ret = 0;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
109962306a36Sopenharmony_ci		return -EIO;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	if (qlcnic_83xx_lock_flash(adapter))
110262306a36Sopenharmony_ci		return -EIO;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	ret = qlcnic_83xx_lockless_flash_read32(adapter,
110562306a36Sopenharmony_ci						QLC_83XX_MINIDUMP_FLASH,
110662306a36Sopenharmony_ci						buffer, size / sizeof(u32));
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	qlcnic_83xx_unlock_flash(adapter);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	return ret;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int
111462306a36Sopenharmony_ciqlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
111562306a36Sopenharmony_ci				       struct qlcnic_cmd_args *cmd)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr tmp_hdr;
111862306a36Sopenharmony_ci	u32 size = sizeof(tmp_hdr) / sizeof(u32);
111962306a36Sopenharmony_ci	int ret = 0;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
112262306a36Sopenharmony_ci		return -EIO;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (qlcnic_83xx_lock_flash(adapter))
112562306a36Sopenharmony_ci		return -EIO;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	ret = qlcnic_83xx_lockless_flash_read32(adapter,
112862306a36Sopenharmony_ci						QLC_83XX_MINIDUMP_FLASH,
112962306a36Sopenharmony_ci						(u8 *)&tmp_hdr, size);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	qlcnic_83xx_unlock_flash(adapter);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	cmd->rsp.arg[2] = tmp_hdr.size;
113462306a36Sopenharmony_ci	cmd->rsp.arg[3] = tmp_hdr.version;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	return ret;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_cistatic int qlcnic_fw_get_minidump_temp_size(struct qlcnic_adapter *adapter,
114062306a36Sopenharmony_ci					    u32 *version, u32 *temp_size,
114162306a36Sopenharmony_ci					    u8 *use_flash_temp)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	int err = 0;
114462306a36Sopenharmony_ci	struct qlcnic_cmd_args cmd;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TEMP_SIZE))
114762306a36Sopenharmony_ci		return -ENOMEM;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	err = qlcnic_issue_cmd(adapter, &cmd);
115062306a36Sopenharmony_ci	if (err != QLCNIC_RCODE_SUCCESS) {
115162306a36Sopenharmony_ci		if (qlcnic_fw_flash_get_minidump_temp_size(adapter, &cmd)) {
115262306a36Sopenharmony_ci			qlcnic_free_mbx_args(&cmd);
115362306a36Sopenharmony_ci			return -EIO;
115462306a36Sopenharmony_ci		}
115562306a36Sopenharmony_ci		*use_flash_temp = 1;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	*temp_size = cmd.rsp.arg[2];
115962306a36Sopenharmony_ci	*version = cmd.rsp.arg[3];
116062306a36Sopenharmony_ci	qlcnic_free_mbx_args(&cmd);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (!(*temp_size))
116362306a36Sopenharmony_ci		return -EIO;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	return 0;
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
116962306a36Sopenharmony_ci					     u32 *buffer, u32 temp_size)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	int err = 0, i;
117262306a36Sopenharmony_ci	void *tmp_addr;
117362306a36Sopenharmony_ci	__le32 *tmp_buf;
117462306a36Sopenharmony_ci	struct qlcnic_cmd_args cmd;
117562306a36Sopenharmony_ci	dma_addr_t tmp_addr_t = 0;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
117862306a36Sopenharmony_ci				      &tmp_addr_t, GFP_KERNEL);
117962306a36Sopenharmony_ci	if (!tmp_addr)
118062306a36Sopenharmony_ci		return -ENOMEM;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
118362306a36Sopenharmony_ci		err = -ENOMEM;
118462306a36Sopenharmony_ci		goto free_mem;
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	cmd.req.arg[1] = LSD(tmp_addr_t);
118862306a36Sopenharmony_ci	cmd.req.arg[2] = MSD(tmp_addr_t);
118962306a36Sopenharmony_ci	cmd.req.arg[3] = temp_size;
119062306a36Sopenharmony_ci	err = qlcnic_issue_cmd(adapter, &cmd);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	tmp_buf = tmp_addr;
119362306a36Sopenharmony_ci	if (err == QLCNIC_RCODE_SUCCESS) {
119462306a36Sopenharmony_ci		for (i = 0; i < temp_size / sizeof(u32); i++)
119562306a36Sopenharmony_ci			*buffer++ = __le32_to_cpu(*tmp_buf++);
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	qlcnic_free_mbx_args(&cmd);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cifree_mem:
120162306a36Sopenharmony_ci	dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	return err;
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ciint qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw;
120962306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump;
121062306a36Sopenharmony_ci	u32 version, csum, *tmp_buf;
121162306a36Sopenharmony_ci	u8 use_flash_temp = 0;
121262306a36Sopenharmony_ci	u32 temp_size = 0;
121362306a36Sopenharmony_ci	void *temp_buffer;
121462306a36Sopenharmony_ci	int err;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	ahw = adapter->ahw;
121762306a36Sopenharmony_ci	fw_dump = &ahw->fw_dump;
121862306a36Sopenharmony_ci	err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
121962306a36Sopenharmony_ci					       &use_flash_temp);
122062306a36Sopenharmony_ci	if (err) {
122162306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
122262306a36Sopenharmony_ci			"Can't get template size %d\n", err);
122362306a36Sopenharmony_ci		return -EIO;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	fw_dump->tmpl_hdr = vzalloc(temp_size);
122762306a36Sopenharmony_ci	if (!fw_dump->tmpl_hdr)
122862306a36Sopenharmony_ci		return -ENOMEM;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	tmp_buf = (u32 *)fw_dump->tmpl_hdr;
123162306a36Sopenharmony_ci	if (use_flash_temp)
123262306a36Sopenharmony_ci		goto flash_temp;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	err = __qlcnic_fw_cmd_get_minidump_temp(adapter, tmp_buf, temp_size);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	if (err) {
123762306a36Sopenharmony_ciflash_temp:
123862306a36Sopenharmony_ci		err = qlcnic_fw_flash_get_minidump_temp(adapter, (u8 *)tmp_buf,
123962306a36Sopenharmony_ci							temp_size);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		if (err) {
124262306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
124362306a36Sopenharmony_ci				"Failed to get minidump template header %d\n",
124462306a36Sopenharmony_ci				err);
124562306a36Sopenharmony_ci			vfree(fw_dump->tmpl_hdr);
124662306a36Sopenharmony_ci			fw_dump->tmpl_hdr = NULL;
124762306a36Sopenharmony_ci			return -EIO;
124862306a36Sopenharmony_ci		}
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	csum = qlcnic_temp_checksum((uint32_t *)tmp_buf, temp_size);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (csum) {
125462306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
125562306a36Sopenharmony_ci			"Template header checksum validation failed\n");
125662306a36Sopenharmony_ci		vfree(fw_dump->tmpl_hdr);
125762306a36Sopenharmony_ci		fw_dump->tmpl_hdr = NULL;
125862306a36Sopenharmony_ci		return -EIO;
125962306a36Sopenharmony_ci	}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	qlcnic_cache_tmpl_hdr_values(adapter, fw_dump);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	if (fw_dump->use_pex_dma) {
126462306a36Sopenharmony_ci		fw_dump->dma_buffer = NULL;
126562306a36Sopenharmony_ci		temp_buffer = dma_alloc_coherent(&adapter->pdev->dev,
126662306a36Sopenharmony_ci						 QLC_PEX_DMA_READ_SIZE,
126762306a36Sopenharmony_ci						 &fw_dump->phys_addr,
126862306a36Sopenharmony_ci						 GFP_KERNEL);
126962306a36Sopenharmony_ci		if (!temp_buffer)
127062306a36Sopenharmony_ci			fw_dump->use_pex_dma = false;
127162306a36Sopenharmony_ci		else
127262306a36Sopenharmony_ci			fw_dump->dma_buffer = temp_buffer;
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	dev_info(&adapter->pdev->dev,
127762306a36Sopenharmony_ci		 "Default minidump capture mask 0x%x\n",
127862306a36Sopenharmony_ci		 fw_dump->cap_mask);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	qlcnic_enable_fw_dump_state(adapter);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	return 0;
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ciint qlcnic_dump_fw(struct qlcnic_adapter *adapter)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
128862306a36Sopenharmony_ci	const struct qlcnic_dump_operations *fw_dump_ops;
128962306a36Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr_83xx;
129062306a36Sopenharmony_ci	u32 entry_offset, dump, no_entries, buf_offset = 0;
129162306a36Sopenharmony_ci	int i, k, ops_cnt, ops_index, dump_size = 0;
129262306a36Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
129362306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw;
129462306a36Sopenharmony_ci	struct qlcnic_dump_entry *entry;
129562306a36Sopenharmony_ci	void *tmpl_hdr;
129662306a36Sopenharmony_ci	u32 ocm_window;
129762306a36Sopenharmony_ci	__le32 *buffer;
129862306a36Sopenharmony_ci	char mesg[64];
129962306a36Sopenharmony_ci	char *msg[] = {mesg, NULL};
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	ahw = adapter->ahw;
130262306a36Sopenharmony_ci	tmpl_hdr = fw_dump->tmpl_hdr;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/* Return if we don't have firmware dump template header */
130562306a36Sopenharmony_ci	if (!tmpl_hdr)
130662306a36Sopenharmony_ci		return -EIO;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (!qlcnic_check_fw_dump_state(adapter)) {
130962306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Dump not enabled\n");
131062306a36Sopenharmony_ci		return -EIO;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (fw_dump->clr) {
131462306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev,
131562306a36Sopenharmony_ci			 "Previous dump not cleared, not capturing dump\n");
131662306a36Sopenharmony_ci		return -EIO;
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
132062306a36Sopenharmony_ci	/* Calculate the size for dump data area only */
132162306a36Sopenharmony_ci	for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
132262306a36Sopenharmony_ci		if (i & fw_dump->cap_mask)
132362306a36Sopenharmony_ci			dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (!dump_size)
132662306a36Sopenharmony_ci		return -EIO;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	fw_dump->data = vzalloc(dump_size);
132962306a36Sopenharmony_ci	if (!fw_dump->data)
133062306a36Sopenharmony_ci		return -ENOMEM;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	buffer = fw_dump->data;
133362306a36Sopenharmony_ci	fw_dump->size = dump_size;
133462306a36Sopenharmony_ci	no_entries = fw_dump->num_entries;
133562306a36Sopenharmony_ci	entry_offset = fw_dump->offset;
133662306a36Sopenharmony_ci	qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION);
133762306a36Sopenharmony_ci	qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter)) {
134062306a36Sopenharmony_ci		ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
134162306a36Sopenharmony_ci		fw_dump_ops = qlcnic_fw_dump_ops;
134262306a36Sopenharmony_ci	} else {
134362306a36Sopenharmony_ci		hdr_83xx = tmpl_hdr;
134462306a36Sopenharmony_ci		ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
134562306a36Sopenharmony_ci		fw_dump_ops = qlcnic_83xx_fw_dump_ops;
134662306a36Sopenharmony_ci		ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func];
134762306a36Sopenharmony_ci		hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
134862306a36Sopenharmony_ci		hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	for (i = 0; i < no_entries; i++) {
135262306a36Sopenharmony_ci		entry = tmpl_hdr + entry_offset;
135362306a36Sopenharmony_ci		if (!(entry->hdr.mask & fw_dump->cap_mask)) {
135462306a36Sopenharmony_ci			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
135562306a36Sopenharmony_ci			entry_offset += entry->hdr.offset;
135662306a36Sopenharmony_ci			continue;
135762306a36Sopenharmony_ci		}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		/* Find the handler for this entry */
136062306a36Sopenharmony_ci		ops_index = 0;
136162306a36Sopenharmony_ci		while (ops_index < ops_cnt) {
136262306a36Sopenharmony_ci			if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
136362306a36Sopenharmony_ci				break;
136462306a36Sopenharmony_ci			ops_index++;
136562306a36Sopenharmony_ci		}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci		if (ops_index == ops_cnt) {
136862306a36Sopenharmony_ci			dev_info(dev, "Skipping unknown entry opcode %d\n",
136962306a36Sopenharmony_ci				 entry->hdr.type);
137062306a36Sopenharmony_ci			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
137162306a36Sopenharmony_ci			entry_offset += entry->hdr.offset;
137262306a36Sopenharmony_ci			continue;
137362306a36Sopenharmony_ci		}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci		/* Collect dump for this entry */
137662306a36Sopenharmony_ci		dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
137762306a36Sopenharmony_ci		if (!qlcnic_valid_dump_entry(dev, entry, dump)) {
137862306a36Sopenharmony_ci			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
137962306a36Sopenharmony_ci			entry_offset += entry->hdr.offset;
138062306a36Sopenharmony_ci			continue;
138162306a36Sopenharmony_ci		}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci		buf_offset += entry->hdr.cap_size;
138462306a36Sopenharmony_ci		entry_offset += entry->hdr.offset;
138562306a36Sopenharmony_ci		buffer = fw_dump->data + buf_offset;
138662306a36Sopenharmony_ci		cond_resched();
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	fw_dump->clr = 1;
139062306a36Sopenharmony_ci	snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name);
139162306a36Sopenharmony_ci	netdev_info(adapter->netdev,
139262306a36Sopenharmony_ci		    "Dump data %d bytes captured, dump data address = %p, template header size %d bytes, template address = %p\n",
139362306a36Sopenharmony_ci		    fw_dump->size, fw_dump->data, fw_dump->tmpl_hdr_size,
139462306a36Sopenharmony_ci		    fw_dump->tmpl_hdr);
139562306a36Sopenharmony_ci	/* Send a udev event to notify availability of FW dump */
139662306a36Sopenharmony_ci	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	return 0;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic inline bool
140262306a36Sopenharmony_ciqlcnic_83xx_md_check_extended_dump_capability(struct qlcnic_adapter *adapter)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	/* For special adapters (with 0x8830 device ID), where iSCSI firmware
140562306a36Sopenharmony_ci	 * dump needs to be captured as part of regular firmware dump
140662306a36Sopenharmony_ci	 * collection process, firmware exports it's capability through
140762306a36Sopenharmony_ci	 * capability registers
140862306a36Sopenharmony_ci	 */
140962306a36Sopenharmony_ci	return ((adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE8830) &&
141062306a36Sopenharmony_ci		(adapter->ahw->extra_capability[0] &
141162306a36Sopenharmony_ci		 QLCNIC_FW_CAPABILITY_2_EXT_ISCSI_DUMP));
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_civoid qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	u32 prev_version, current_version;
141762306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
141862306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
141962306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
142062306a36Sopenharmony_ci	bool extended = false;
142162306a36Sopenharmony_ci	int ret;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	prev_version = adapter->fw_version;
142462306a36Sopenharmony_ci	current_version = qlcnic_83xx_get_fw_version(adapter);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
142762306a36Sopenharmony_ci		vfree(fw_dump->tmpl_hdr);
142862306a36Sopenharmony_ci		fw_dump->tmpl_hdr = NULL;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		if (qlcnic_83xx_md_check_extended_dump_capability(adapter))
143162306a36Sopenharmony_ci			extended = !qlcnic_83xx_extend_md_capab(adapter);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		ret = qlcnic_fw_cmd_get_minidump_temp(adapter);
143462306a36Sopenharmony_ci		if (ret)
143562306a36Sopenharmony_ci			return;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci		dev_info(&pdev->dev, "Supports FW dump capability\n");
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci		/* Once we have minidump template with extended iSCSI dump
144062306a36Sopenharmony_ci		 * capability, update the minidump capture mask to 0x1f as
144162306a36Sopenharmony_ci		 * per FW requirement
144262306a36Sopenharmony_ci		 */
144362306a36Sopenharmony_ci		if (extended) {
144462306a36Sopenharmony_ci			struct qlcnic_83xx_dump_template_hdr *hdr;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci			hdr = fw_dump->tmpl_hdr;
144762306a36Sopenharmony_ci			if (!hdr)
144862306a36Sopenharmony_ci				return;
144962306a36Sopenharmony_ci			hdr->drv_cap_mask = 0x1f;
145062306a36Sopenharmony_ci			fw_dump->cap_mask = 0x1f;
145162306a36Sopenharmony_ci			dev_info(&pdev->dev,
145262306a36Sopenharmony_ci				 "Extended iSCSI dump capability and updated capture mask to 0x1f\n");
145362306a36Sopenharmony_ci		}
145462306a36Sopenharmony_ci	}
145562306a36Sopenharmony_ci}
1456