18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * QLogic qlcnic NIC Driver
48c2ecf20Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <net/ip.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "qlcnic.h"
108c2ecf20Sopenharmony_ci#include "qlcnic_hdr.h"
118c2ecf20Sopenharmony_ci#include "qlcnic_83xx_hw.h"
128c2ecf20Sopenharmony_ci#include "qlcnic_hw.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define QLC_83XX_MINIDUMP_FLASH		0x520000
158c2ecf20Sopenharmony_ci#define QLC_83XX_OCM_INDEX			3
168c2ecf20Sopenharmony_ci#define QLC_83XX_PCI_INDEX			0
178c2ecf20Sopenharmony_ci#define QLC_83XX_DMA_ENGINE_INDEX		8
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic const u32 qlcnic_ms_read_data[] = {
208c2ecf20Sopenharmony_ci	0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_WCRB	BIT_0
248c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_RWCRB	BIT_1
258c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_ANDCRB	BIT_2
268c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_ORCRB	BIT_3
278c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_POLLCRB	BIT_4
288c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_RD_SAVE	BIT_5
298c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_WRT_SAVED	BIT_6
308c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_MOD_SAVE_ST	BIT_7
318c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_SKIP	BIT_7
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define QLCNIC_DUMP_MASK_MAX	0xff
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct qlcnic_pex_dma_descriptor {
368c2ecf20Sopenharmony_ci	u32	read_data_size;
378c2ecf20Sopenharmony_ci	u32	dma_desc_cmd;
388c2ecf20Sopenharmony_ci	u32	src_addr_low;
398c2ecf20Sopenharmony_ci	u32	src_addr_high;
408c2ecf20Sopenharmony_ci	u32	dma_bus_addr_low;
418c2ecf20Sopenharmony_ci	u32	dma_bus_addr_high;
428c2ecf20Sopenharmony_ci	u32	rsvd[6];
438c2ecf20Sopenharmony_ci} __packed;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct qlcnic_common_entry_hdr {
468c2ecf20Sopenharmony_ci	u32     type;
478c2ecf20Sopenharmony_ci	u32     offset;
488c2ecf20Sopenharmony_ci	u32     cap_size;
498c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
508c2ecf20Sopenharmony_ci	u8      mask;
518c2ecf20Sopenharmony_ci	u8      rsvd[2];
528c2ecf20Sopenharmony_ci	u8      flags;
538c2ecf20Sopenharmony_ci#else
548c2ecf20Sopenharmony_ci	u8      flags;
558c2ecf20Sopenharmony_ci	u8      rsvd[2];
568c2ecf20Sopenharmony_ci	u8      mask;
578c2ecf20Sopenharmony_ci#endif
588c2ecf20Sopenharmony_ci} __packed;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct __crb {
618c2ecf20Sopenharmony_ci	u32	addr;
628c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
638c2ecf20Sopenharmony_ci	u8	stride;
648c2ecf20Sopenharmony_ci	u8	rsvd1[3];
658c2ecf20Sopenharmony_ci#else
668c2ecf20Sopenharmony_ci	u8	rsvd1[3];
678c2ecf20Sopenharmony_ci	u8	stride;
688c2ecf20Sopenharmony_ci#endif
698c2ecf20Sopenharmony_ci	u32	data_size;
708c2ecf20Sopenharmony_ci	u32	no_ops;
718c2ecf20Sopenharmony_ci	u32	rsvd2[4];
728c2ecf20Sopenharmony_ci} __packed;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistruct __ctrl {
758c2ecf20Sopenharmony_ci	u32	addr;
768c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
778c2ecf20Sopenharmony_ci	u8	stride;
788c2ecf20Sopenharmony_ci	u8	index_a;
798c2ecf20Sopenharmony_ci	u16	timeout;
808c2ecf20Sopenharmony_ci#else
818c2ecf20Sopenharmony_ci	u16	timeout;
828c2ecf20Sopenharmony_ci	u8	index_a;
838c2ecf20Sopenharmony_ci	u8	stride;
848c2ecf20Sopenharmony_ci#endif
858c2ecf20Sopenharmony_ci	u32	data_size;
868c2ecf20Sopenharmony_ci	u32	no_ops;
878c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
888c2ecf20Sopenharmony_ci	u8	opcode;
898c2ecf20Sopenharmony_ci	u8	index_v;
908c2ecf20Sopenharmony_ci	u8	shl_val;
918c2ecf20Sopenharmony_ci	u8	shr_val;
928c2ecf20Sopenharmony_ci#else
938c2ecf20Sopenharmony_ci	u8	shr_val;
948c2ecf20Sopenharmony_ci	u8	shl_val;
958c2ecf20Sopenharmony_ci	u8	index_v;
968c2ecf20Sopenharmony_ci	u8	opcode;
978c2ecf20Sopenharmony_ci#endif
988c2ecf20Sopenharmony_ci	u32	val1;
998c2ecf20Sopenharmony_ci	u32	val2;
1008c2ecf20Sopenharmony_ci	u32	val3;
1018c2ecf20Sopenharmony_ci} __packed;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistruct __cache {
1048c2ecf20Sopenharmony_ci	u32	addr;
1058c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1068c2ecf20Sopenharmony_ci	u16	stride;
1078c2ecf20Sopenharmony_ci	u16	init_tag_val;
1088c2ecf20Sopenharmony_ci#else
1098c2ecf20Sopenharmony_ci	u16	init_tag_val;
1108c2ecf20Sopenharmony_ci	u16	stride;
1118c2ecf20Sopenharmony_ci#endif
1128c2ecf20Sopenharmony_ci	u32	size;
1138c2ecf20Sopenharmony_ci	u32	no_ops;
1148c2ecf20Sopenharmony_ci	u32	ctrl_addr;
1158c2ecf20Sopenharmony_ci	u32	ctrl_val;
1168c2ecf20Sopenharmony_ci	u32	read_addr;
1178c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1188c2ecf20Sopenharmony_ci	u8	read_addr_stride;
1198c2ecf20Sopenharmony_ci	u8	read_addr_num;
1208c2ecf20Sopenharmony_ci	u8	rsvd1[2];
1218c2ecf20Sopenharmony_ci#else
1228c2ecf20Sopenharmony_ci	u8	rsvd1[2];
1238c2ecf20Sopenharmony_ci	u8	read_addr_num;
1248c2ecf20Sopenharmony_ci	u8	read_addr_stride;
1258c2ecf20Sopenharmony_ci#endif
1268c2ecf20Sopenharmony_ci} __packed;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistruct __ocm {
1298c2ecf20Sopenharmony_ci	u8	rsvd[8];
1308c2ecf20Sopenharmony_ci	u32	size;
1318c2ecf20Sopenharmony_ci	u32	no_ops;
1328c2ecf20Sopenharmony_ci	u8	rsvd1[8];
1338c2ecf20Sopenharmony_ci	u32	read_addr;
1348c2ecf20Sopenharmony_ci	u32	read_addr_stride;
1358c2ecf20Sopenharmony_ci} __packed;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistruct __mem {
1388c2ecf20Sopenharmony_ci	u32	desc_card_addr;
1398c2ecf20Sopenharmony_ci	u32	dma_desc_cmd;
1408c2ecf20Sopenharmony_ci	u32	start_dma_cmd;
1418c2ecf20Sopenharmony_ci	u32	rsvd[3];
1428c2ecf20Sopenharmony_ci	u32	addr;
1438c2ecf20Sopenharmony_ci	u32	size;
1448c2ecf20Sopenharmony_ci} __packed;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistruct __mux {
1478c2ecf20Sopenharmony_ci	u32	addr;
1488c2ecf20Sopenharmony_ci	u8	rsvd[4];
1498c2ecf20Sopenharmony_ci	u32	size;
1508c2ecf20Sopenharmony_ci	u32	no_ops;
1518c2ecf20Sopenharmony_ci	u32	val;
1528c2ecf20Sopenharmony_ci	u32	val_stride;
1538c2ecf20Sopenharmony_ci	u32	read_addr;
1548c2ecf20Sopenharmony_ci	u8	rsvd2[4];
1558c2ecf20Sopenharmony_ci} __packed;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistruct __queue {
1588c2ecf20Sopenharmony_ci	u32	sel_addr;
1598c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1608c2ecf20Sopenharmony_ci	u16	stride;
1618c2ecf20Sopenharmony_ci	u8	rsvd[2];
1628c2ecf20Sopenharmony_ci#else
1638c2ecf20Sopenharmony_ci	u8	rsvd[2];
1648c2ecf20Sopenharmony_ci	u16	stride;
1658c2ecf20Sopenharmony_ci#endif
1668c2ecf20Sopenharmony_ci	u32	size;
1678c2ecf20Sopenharmony_ci	u32	no_ops;
1688c2ecf20Sopenharmony_ci	u8	rsvd2[8];
1698c2ecf20Sopenharmony_ci	u32	read_addr;
1708c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1718c2ecf20Sopenharmony_ci	u8	read_addr_stride;
1728c2ecf20Sopenharmony_ci	u8	read_addr_cnt;
1738c2ecf20Sopenharmony_ci	u8	rsvd3[2];
1748c2ecf20Sopenharmony_ci#else
1758c2ecf20Sopenharmony_ci	u8	rsvd3[2];
1768c2ecf20Sopenharmony_ci	u8	read_addr_cnt;
1778c2ecf20Sopenharmony_ci	u8	read_addr_stride;
1788c2ecf20Sopenharmony_ci#endif
1798c2ecf20Sopenharmony_ci} __packed;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistruct __pollrd {
1828c2ecf20Sopenharmony_ci	u32	sel_addr;
1838c2ecf20Sopenharmony_ci	u32	read_addr;
1848c2ecf20Sopenharmony_ci	u32	sel_val;
1858c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
1868c2ecf20Sopenharmony_ci	u16	sel_val_stride;
1878c2ecf20Sopenharmony_ci	u16	no_ops;
1888c2ecf20Sopenharmony_ci#else
1898c2ecf20Sopenharmony_ci	u16	no_ops;
1908c2ecf20Sopenharmony_ci	u16	sel_val_stride;
1918c2ecf20Sopenharmony_ci#endif
1928c2ecf20Sopenharmony_ci	u32	poll_wait;
1938c2ecf20Sopenharmony_ci	u32	poll_mask;
1948c2ecf20Sopenharmony_ci	u32	data_size;
1958c2ecf20Sopenharmony_ci	u8	rsvd[4];
1968c2ecf20Sopenharmony_ci} __packed;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistruct __mux2 {
1998c2ecf20Sopenharmony_ci	u32	sel_addr1;
2008c2ecf20Sopenharmony_ci	u32	sel_addr2;
2018c2ecf20Sopenharmony_ci	u32	sel_val1;
2028c2ecf20Sopenharmony_ci	u32	sel_val2;
2038c2ecf20Sopenharmony_ci	u32	no_ops;
2048c2ecf20Sopenharmony_ci	u32	sel_val_mask;
2058c2ecf20Sopenharmony_ci	u32	read_addr;
2068c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
2078c2ecf20Sopenharmony_ci	u8	sel_val_stride;
2088c2ecf20Sopenharmony_ci	u8	data_size;
2098c2ecf20Sopenharmony_ci	u8	rsvd[2];
2108c2ecf20Sopenharmony_ci#else
2118c2ecf20Sopenharmony_ci	u8	rsvd[2];
2128c2ecf20Sopenharmony_ci	u8	data_size;
2138c2ecf20Sopenharmony_ci	u8	sel_val_stride;
2148c2ecf20Sopenharmony_ci#endif
2158c2ecf20Sopenharmony_ci} __packed;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistruct __pollrdmwr {
2188c2ecf20Sopenharmony_ci	u32	addr1;
2198c2ecf20Sopenharmony_ci	u32	addr2;
2208c2ecf20Sopenharmony_ci	u32	val1;
2218c2ecf20Sopenharmony_ci	u32	val2;
2228c2ecf20Sopenharmony_ci	u32	poll_wait;
2238c2ecf20Sopenharmony_ci	u32	poll_mask;
2248c2ecf20Sopenharmony_ci	u32	mod_mask;
2258c2ecf20Sopenharmony_ci	u32	data_size;
2268c2ecf20Sopenharmony_ci} __packed;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistruct qlcnic_dump_entry {
2298c2ecf20Sopenharmony_ci	struct qlcnic_common_entry_hdr hdr;
2308c2ecf20Sopenharmony_ci	union {
2318c2ecf20Sopenharmony_ci		struct __crb		crb;
2328c2ecf20Sopenharmony_ci		struct __cache		cache;
2338c2ecf20Sopenharmony_ci		struct __ocm		ocm;
2348c2ecf20Sopenharmony_ci		struct __mem		mem;
2358c2ecf20Sopenharmony_ci		struct __mux		mux;
2368c2ecf20Sopenharmony_ci		struct __queue		que;
2378c2ecf20Sopenharmony_ci		struct __ctrl		ctrl;
2388c2ecf20Sopenharmony_ci		struct __pollrdmwr	pollrdmwr;
2398c2ecf20Sopenharmony_ci		struct __mux2		mux2;
2408c2ecf20Sopenharmony_ci		struct __pollrd		pollrd;
2418c2ecf20Sopenharmony_ci	} region;
2428c2ecf20Sopenharmony_ci} __packed;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cienum qlcnic_minidump_opcode {
2458c2ecf20Sopenharmony_ci	QLCNIC_DUMP_NOP		= 0,
2468c2ecf20Sopenharmony_ci	QLCNIC_DUMP_READ_CRB	= 1,
2478c2ecf20Sopenharmony_ci	QLCNIC_DUMP_READ_MUX	= 2,
2488c2ecf20Sopenharmony_ci	QLCNIC_DUMP_QUEUE	= 3,
2498c2ecf20Sopenharmony_ci	QLCNIC_DUMP_BRD_CONFIG	= 4,
2508c2ecf20Sopenharmony_ci	QLCNIC_DUMP_READ_OCM	= 6,
2518c2ecf20Sopenharmony_ci	QLCNIC_DUMP_PEG_REG	= 7,
2528c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L1_DTAG	= 8,
2538c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L1_ITAG	= 9,
2548c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L1_DATA	= 11,
2558c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L1_INST	= 12,
2568c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L2_DTAG	= 21,
2578c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L2_ITAG	= 22,
2588c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L2_DATA	= 23,
2598c2ecf20Sopenharmony_ci	QLCNIC_DUMP_L2_INST	= 24,
2608c2ecf20Sopenharmony_ci	QLCNIC_DUMP_POLL_RD	= 35,
2618c2ecf20Sopenharmony_ci	QLCNIC_READ_MUX2	= 36,
2628c2ecf20Sopenharmony_ci	QLCNIC_READ_POLLRDMWR	= 37,
2638c2ecf20Sopenharmony_ci	QLCNIC_DUMP_READ_ROM	= 71,
2648c2ecf20Sopenharmony_ci	QLCNIC_DUMP_READ_MEM	= 72,
2658c2ecf20Sopenharmony_ci	QLCNIC_DUMP_READ_CTRL	= 98,
2668c2ecf20Sopenharmony_ci	QLCNIC_DUMP_TLHDR	= 99,
2678c2ecf20Sopenharmony_ci	QLCNIC_DUMP_RDEND	= 255
2688c2ecf20Sopenharmony_ci};
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ciinline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return hdr->saved_state[index];
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ciinline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index,
2788c2ecf20Sopenharmony_ci					u32 value)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	hdr->saved_state[index] = value;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_civoid qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	hdr = fw_dump->tmpl_hdr;
2908c2ecf20Sopenharmony_ci	fw_dump->tmpl_hdr_size = hdr->size;
2918c2ecf20Sopenharmony_ci	fw_dump->version = hdr->version;
2928c2ecf20Sopenharmony_ci	fw_dump->num_entries = hdr->num_entries;
2938c2ecf20Sopenharmony_ci	fw_dump->offset = hdr->offset;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	hdr->drv_cap_mask = hdr->cap_mask;
2968c2ecf20Sopenharmony_ci	fw_dump->cap_mask = hdr->cap_mask;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	fw_dump->use_pex_dma = (hdr->capabilities & BIT_0) ? true : false;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ciinline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return hdr->cap_sizes[index];
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_civoid qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	hdr->sys_info[idx] = value;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_civoid qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	hdr->drv_cap_mask = mask;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ciinline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return hdr->saved_state[index];
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ciinline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index,
3308c2ecf20Sopenharmony_ci					u32 value)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	hdr->saved_state[index] = value;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci#define QLCNIC_TEMPLATE_VERSION (0x20001)
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_civoid qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	hdr = fw_dump->tmpl_hdr;
3448c2ecf20Sopenharmony_ci	fw_dump->tmpl_hdr_size = hdr->size;
3458c2ecf20Sopenharmony_ci	fw_dump->version = hdr->version;
3468c2ecf20Sopenharmony_ci	fw_dump->num_entries = hdr->num_entries;
3478c2ecf20Sopenharmony_ci	fw_dump->offset = hdr->offset;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	hdr->drv_cap_mask = hdr->cap_mask;
3508c2ecf20Sopenharmony_ci	fw_dump->cap_mask = hdr->cap_mask;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	fw_dump->use_pex_dma = (fw_dump->version & 0xfffff) >=
3538c2ecf20Sopenharmony_ci			       QLCNIC_TEMPLATE_VERSION;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ciinline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return hdr->cap_sizes[index];
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_civoid qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	hdr->sys_info[idx] = value;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_civoid qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	hdr = tmpl_hdr;
3758c2ecf20Sopenharmony_ci	hdr->drv_cap_mask = mask;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistruct qlcnic_dump_operations {
3798c2ecf20Sopenharmony_ci	enum qlcnic_minidump_opcode opcode;
3808c2ecf20Sopenharmony_ci	u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
3818c2ecf20Sopenharmony_ci		       __le32 *);
3828c2ecf20Sopenharmony_ci};
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
3858c2ecf20Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	int i;
3888c2ecf20Sopenharmony_ci	u32 addr, data;
3898c2ecf20Sopenharmony_ci	struct __crb *crb = &entry->region.crb;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	addr = crb->addr;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	for (i = 0; i < crb->no_ops; i++) {
3948c2ecf20Sopenharmony_ci		data = qlcnic_ind_rd(adapter, addr);
3958c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(addr);
3968c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
3978c2ecf20Sopenharmony_ci		addr += crb->stride;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci	return crb->no_ops * 2 * sizeof(u32);
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
4038c2ecf20Sopenharmony_ci			    struct qlcnic_dump_entry *entry, __le32 *buffer)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	void *hdr = adapter->ahw->fw_dump.tmpl_hdr;
4068c2ecf20Sopenharmony_ci	struct __ctrl *ctr = &entry->region.ctrl;
4078c2ecf20Sopenharmony_ci	int i, k, timeout = 0;
4088c2ecf20Sopenharmony_ci	u32 addr, data, temp;
4098c2ecf20Sopenharmony_ci	u8 no_ops;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	addr = ctr->addr;
4128c2ecf20Sopenharmony_ci	no_ops = ctr->no_ops;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	for (i = 0; i < no_ops; i++) {
4158c2ecf20Sopenharmony_ci		k = 0;
4168c2ecf20Sopenharmony_ci		for (k = 0; k < 8; k++) {
4178c2ecf20Sopenharmony_ci			if (!(ctr->opcode & (1 << k)))
4188c2ecf20Sopenharmony_ci				continue;
4198c2ecf20Sopenharmony_ci			switch (1 << k) {
4208c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_WCRB:
4218c2ecf20Sopenharmony_ci				qlcnic_ind_wr(adapter, addr, ctr->val1);
4228c2ecf20Sopenharmony_ci				break;
4238c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_RWCRB:
4248c2ecf20Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
4258c2ecf20Sopenharmony_ci				qlcnic_ind_wr(adapter, addr, data);
4268c2ecf20Sopenharmony_ci				break;
4278c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_ANDCRB:
4288c2ecf20Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
4298c2ecf20Sopenharmony_ci				qlcnic_ind_wr(adapter, addr,
4308c2ecf20Sopenharmony_ci					      (data & ctr->val2));
4318c2ecf20Sopenharmony_ci				break;
4328c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_ORCRB:
4338c2ecf20Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
4348c2ecf20Sopenharmony_ci				qlcnic_ind_wr(adapter, addr,
4358c2ecf20Sopenharmony_ci					      (data | ctr->val3));
4368c2ecf20Sopenharmony_ci				break;
4378c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_POLLCRB:
4388c2ecf20Sopenharmony_ci				while (timeout <= ctr->timeout) {
4398c2ecf20Sopenharmony_ci					data = qlcnic_ind_rd(adapter, addr);
4408c2ecf20Sopenharmony_ci					if ((data & ctr->val2) == ctr->val1)
4418c2ecf20Sopenharmony_ci						break;
4428c2ecf20Sopenharmony_ci					usleep_range(1000, 2000);
4438c2ecf20Sopenharmony_ci					timeout++;
4448c2ecf20Sopenharmony_ci				}
4458c2ecf20Sopenharmony_ci				if (timeout > ctr->timeout) {
4468c2ecf20Sopenharmony_ci					dev_info(&adapter->pdev->dev,
4478c2ecf20Sopenharmony_ci					"Timed out, aborting poll CRB\n");
4488c2ecf20Sopenharmony_ci					return -EINVAL;
4498c2ecf20Sopenharmony_ci				}
4508c2ecf20Sopenharmony_ci				break;
4518c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_RD_SAVE:
4528c2ecf20Sopenharmony_ci				temp = ctr->index_a;
4538c2ecf20Sopenharmony_ci				if (temp)
4548c2ecf20Sopenharmony_ci					addr = qlcnic_get_saved_state(adapter,
4558c2ecf20Sopenharmony_ci								      hdr,
4568c2ecf20Sopenharmony_ci								      temp);
4578c2ecf20Sopenharmony_ci				data = qlcnic_ind_rd(adapter, addr);
4588c2ecf20Sopenharmony_ci				qlcnic_set_saved_state(adapter, hdr,
4598c2ecf20Sopenharmony_ci						       ctr->index_v, data);
4608c2ecf20Sopenharmony_ci				break;
4618c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_WRT_SAVED:
4628c2ecf20Sopenharmony_ci				temp = ctr->index_v;
4638c2ecf20Sopenharmony_ci				if (temp)
4648c2ecf20Sopenharmony_ci					data = qlcnic_get_saved_state(adapter,
4658c2ecf20Sopenharmony_ci								      hdr,
4668c2ecf20Sopenharmony_ci								      temp);
4678c2ecf20Sopenharmony_ci				else
4688c2ecf20Sopenharmony_ci					data = ctr->val1;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci				temp = ctr->index_a;
4718c2ecf20Sopenharmony_ci				if (temp)
4728c2ecf20Sopenharmony_ci					addr = qlcnic_get_saved_state(adapter,
4738c2ecf20Sopenharmony_ci								      hdr,
4748c2ecf20Sopenharmony_ci								      temp);
4758c2ecf20Sopenharmony_ci				qlcnic_ind_wr(adapter, addr, data);
4768c2ecf20Sopenharmony_ci				break;
4778c2ecf20Sopenharmony_ci			case QLCNIC_DUMP_MOD_SAVE_ST:
4788c2ecf20Sopenharmony_ci				data = qlcnic_get_saved_state(adapter, hdr,
4798c2ecf20Sopenharmony_ci							      ctr->index_v);
4808c2ecf20Sopenharmony_ci				data <<= ctr->shl_val;
4818c2ecf20Sopenharmony_ci				data >>= ctr->shr_val;
4828c2ecf20Sopenharmony_ci				if (ctr->val2)
4838c2ecf20Sopenharmony_ci					data &= ctr->val2;
4848c2ecf20Sopenharmony_ci				data |= ctr->val3;
4858c2ecf20Sopenharmony_ci				data += ctr->val1;
4868c2ecf20Sopenharmony_ci				qlcnic_set_saved_state(adapter, hdr,
4878c2ecf20Sopenharmony_ci						       ctr->index_v, data);
4888c2ecf20Sopenharmony_ci				break;
4898c2ecf20Sopenharmony_ci			default:
4908c2ecf20Sopenharmony_ci				dev_info(&adapter->pdev->dev,
4918c2ecf20Sopenharmony_ci					 "Unknown opcode\n");
4928c2ecf20Sopenharmony_ci				break;
4938c2ecf20Sopenharmony_ci			}
4948c2ecf20Sopenharmony_ci		}
4958c2ecf20Sopenharmony_ci		addr += ctr->stride;
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_mux(struct qlcnic_adapter *adapter,
5018c2ecf20Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	int loop;
5048c2ecf20Sopenharmony_ci	u32 val, data = 0;
5058c2ecf20Sopenharmony_ci	struct __mux *mux = &entry->region.mux;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	val = mux->val;
5088c2ecf20Sopenharmony_ci	for (loop = 0; loop < mux->no_ops; loop++) {
5098c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, mux->addr, val);
5108c2ecf20Sopenharmony_ci		data = qlcnic_ind_rd(adapter, mux->read_addr);
5118c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(val);
5128c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
5138c2ecf20Sopenharmony_ci		val += mux->val_stride;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci	return 2 * mux->no_ops * sizeof(u32);
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_que(struct qlcnic_adapter *adapter,
5198c2ecf20Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	int i, loop;
5228c2ecf20Sopenharmony_ci	u32 cnt, addr, data, que_id = 0;
5238c2ecf20Sopenharmony_ci	struct __queue *que = &entry->region.que;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	addr = que->read_addr;
5268c2ecf20Sopenharmony_ci	cnt = que->read_addr_cnt;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	for (loop = 0; loop < que->no_ops; loop++) {
5298c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, que->sel_addr, que_id);
5308c2ecf20Sopenharmony_ci		addr = que->read_addr;
5318c2ecf20Sopenharmony_ci		for (i = 0; i < cnt; i++) {
5328c2ecf20Sopenharmony_ci			data = qlcnic_ind_rd(adapter, addr);
5338c2ecf20Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
5348c2ecf20Sopenharmony_ci			addr += que->read_addr_stride;
5358c2ecf20Sopenharmony_ci		}
5368c2ecf20Sopenharmony_ci		que_id += que->stride;
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci	return que->no_ops * cnt * sizeof(u32);
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_ocm(struct qlcnic_adapter *adapter,
5428c2ecf20Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	int i;
5458c2ecf20Sopenharmony_ci	u32 data;
5468c2ecf20Sopenharmony_ci	void __iomem *addr;
5478c2ecf20Sopenharmony_ci	struct __ocm *ocm = &entry->region.ocm;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	addr = adapter->ahw->pci_base0 + ocm->read_addr;
5508c2ecf20Sopenharmony_ci	for (i = 0; i < ocm->no_ops; i++) {
5518c2ecf20Sopenharmony_ci		data = readl(addr);
5528c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
5538c2ecf20Sopenharmony_ci		addr += ocm->read_addr_stride;
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci	return ocm->no_ops * sizeof(u32);
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic u32 qlcnic_read_rom(struct qlcnic_adapter *adapter,
5598c2ecf20Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	int i, count = 0;
5628c2ecf20Sopenharmony_ci	u32 fl_addr, size, val, lck_val, addr;
5638c2ecf20Sopenharmony_ci	struct __mem *rom = &entry->region.mem;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	fl_addr = rom->addr;
5668c2ecf20Sopenharmony_ci	size = rom->size / 4;
5678c2ecf20Sopenharmony_cilock_try:
5688c2ecf20Sopenharmony_ci	lck_val = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
5698c2ecf20Sopenharmony_ci	if (!lck_val && count < MAX_CTL_CHECK) {
5708c2ecf20Sopenharmony_ci		usleep_range(10000, 11000);
5718c2ecf20Sopenharmony_ci		count++;
5728c2ecf20Sopenharmony_ci		goto lock_try;
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
5758c2ecf20Sopenharmony_ci			    adapter->ahw->pci_func);
5768c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
5778c2ecf20Sopenharmony_ci		addr = fl_addr & 0xFFFF0000;
5788c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, FLASH_ROM_WINDOW, addr);
5798c2ecf20Sopenharmony_ci		addr = LSW(fl_addr) + FLASH_ROM_DATA;
5808c2ecf20Sopenharmony_ci		val = qlcnic_ind_rd(adapter, addr);
5818c2ecf20Sopenharmony_ci		fl_addr += 4;
5828c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(val);
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci	QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
5858c2ecf20Sopenharmony_ci	return rom->size;
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
5898c2ecf20Sopenharmony_ci				struct qlcnic_dump_entry *entry, __le32 *buffer)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	int i;
5928c2ecf20Sopenharmony_ci	u32 cnt, val, data, addr;
5938c2ecf20Sopenharmony_ci	struct __cache *l1 = &entry->region.cache;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	val = l1->init_tag_val;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	for (i = 0; i < l1->no_ops; i++) {
5988c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, l1->addr, val);
5998c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, l1->ctrl_addr, LSW(l1->ctrl_val));
6008c2ecf20Sopenharmony_ci		addr = l1->read_addr;
6018c2ecf20Sopenharmony_ci		cnt = l1->read_addr_num;
6028c2ecf20Sopenharmony_ci		while (cnt) {
6038c2ecf20Sopenharmony_ci			data = qlcnic_ind_rd(adapter, addr);
6048c2ecf20Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
6058c2ecf20Sopenharmony_ci			addr += l1->read_addr_stride;
6068c2ecf20Sopenharmony_ci			cnt--;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci		val += l1->stride;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci	return l1->no_ops * l1->read_addr_num * sizeof(u32);
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
6148c2ecf20Sopenharmony_ci				struct qlcnic_dump_entry *entry, __le32 *buffer)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	int i;
6178c2ecf20Sopenharmony_ci	u32 cnt, val, data, addr;
6188c2ecf20Sopenharmony_ci	u8 poll_mask, poll_to, time_out = 0;
6198c2ecf20Sopenharmony_ci	struct __cache *l2 = &entry->region.cache;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	val = l2->init_tag_val;
6228c2ecf20Sopenharmony_ci	poll_mask = LSB(MSW(l2->ctrl_val));
6238c2ecf20Sopenharmony_ci	poll_to = MSB(MSW(l2->ctrl_val));
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	for (i = 0; i < l2->no_ops; i++) {
6268c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, l2->addr, val);
6278c2ecf20Sopenharmony_ci		if (LSW(l2->ctrl_val))
6288c2ecf20Sopenharmony_ci			qlcnic_ind_wr(adapter, l2->ctrl_addr,
6298c2ecf20Sopenharmony_ci				      LSW(l2->ctrl_val));
6308c2ecf20Sopenharmony_ci		if (!poll_mask)
6318c2ecf20Sopenharmony_ci			goto skip_poll;
6328c2ecf20Sopenharmony_ci		do {
6338c2ecf20Sopenharmony_ci			data = qlcnic_ind_rd(adapter, l2->ctrl_addr);
6348c2ecf20Sopenharmony_ci			if (!(data & poll_mask))
6358c2ecf20Sopenharmony_ci				break;
6368c2ecf20Sopenharmony_ci			usleep_range(1000, 2000);
6378c2ecf20Sopenharmony_ci			time_out++;
6388c2ecf20Sopenharmony_ci		} while (time_out <= poll_to);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		if (time_out > poll_to) {
6418c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
6428c2ecf20Sopenharmony_ci				"Timeout exceeded in %s, aborting dump\n",
6438c2ecf20Sopenharmony_ci				__func__);
6448c2ecf20Sopenharmony_ci			return -EINVAL;
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ciskip_poll:
6478c2ecf20Sopenharmony_ci		addr = l2->read_addr;
6488c2ecf20Sopenharmony_ci		cnt = l2->read_addr_num;
6498c2ecf20Sopenharmony_ci		while (cnt) {
6508c2ecf20Sopenharmony_ci			data = qlcnic_ind_rd(adapter, addr);
6518c2ecf20Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
6528c2ecf20Sopenharmony_ci			addr += l2->read_addr_stride;
6538c2ecf20Sopenharmony_ci			cnt--;
6548c2ecf20Sopenharmony_ci		}
6558c2ecf20Sopenharmony_ci		val += l2->stride;
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci	return l2->no_ops * l2->read_addr_num * sizeof(u32);
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic u32 qlcnic_read_memory_test_agent(struct qlcnic_adapter *adapter,
6618c2ecf20Sopenharmony_ci					 struct __mem *mem, __le32 *buffer,
6628c2ecf20Sopenharmony_ci					 int *ret)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	u32 addr, data, test;
6658c2ecf20Sopenharmony_ci	int i, reg_read;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	reg_read = mem->size;
6688c2ecf20Sopenharmony_ci	addr = mem->addr;
6698c2ecf20Sopenharmony_ci	/* check for data size of multiple of 16 and 16 byte alignment */
6708c2ecf20Sopenharmony_ci	if ((addr & 0xf) || (reg_read%16)) {
6718c2ecf20Sopenharmony_ci		dev_info(&adapter->pdev->dev,
6728c2ecf20Sopenharmony_ci			 "Unaligned memory addr:0x%x size:0x%x\n",
6738c2ecf20Sopenharmony_ci			 addr, reg_read);
6748c2ecf20Sopenharmony_ci		*ret = -EINVAL;
6758c2ecf20Sopenharmony_ci		return 0;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	while (reg_read != 0) {
6818c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);
6828c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);
6838c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_START_ENABLE);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		for (i = 0; i < MAX_CTL_CHECK; i++) {
6868c2ecf20Sopenharmony_ci			test = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);
6878c2ecf20Sopenharmony_ci			if (!(test & TA_CTL_BUSY))
6888c2ecf20Sopenharmony_ci				break;
6898c2ecf20Sopenharmony_ci		}
6908c2ecf20Sopenharmony_ci		if (i == MAX_CTL_CHECK) {
6918c2ecf20Sopenharmony_ci			if (printk_ratelimit()) {
6928c2ecf20Sopenharmony_ci				dev_err(&adapter->pdev->dev,
6938c2ecf20Sopenharmony_ci					"failed to read through agent\n");
6948c2ecf20Sopenharmony_ci				*ret = -EIO;
6958c2ecf20Sopenharmony_ci				goto out;
6968c2ecf20Sopenharmony_ci			}
6978c2ecf20Sopenharmony_ci		}
6988c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++) {
6998c2ecf20Sopenharmony_ci			data = qlcnic_ind_rd(adapter, qlcnic_ms_read_data[i]);
7008c2ecf20Sopenharmony_ci			*buffer++ = cpu_to_le32(data);
7018c2ecf20Sopenharmony_ci		}
7028c2ecf20Sopenharmony_ci		addr += 16;
7038c2ecf20Sopenharmony_ci		reg_read -= 16;
7048c2ecf20Sopenharmony_ci		ret += 16;
7058c2ecf20Sopenharmony_ci		cond_resched();
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ciout:
7088c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
7098c2ecf20Sopenharmony_ci	return mem->size;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci/* DMA register base address */
7138c2ecf20Sopenharmony_ci#define QLC_DMA_REG_BASE_ADDR(dma_no)	(0x77320000 + (dma_no * 0x10000))
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci/* DMA register offsets w.r.t base address */
7168c2ecf20Sopenharmony_ci#define QLC_DMA_CMD_BUFF_ADDR_LOW	0
7178c2ecf20Sopenharmony_ci#define QLC_DMA_CMD_BUFF_ADDR_HI	4
7188c2ecf20Sopenharmony_ci#define QLC_DMA_CMD_STATUS_CTRL		8
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,
7218c2ecf20Sopenharmony_ci				struct __mem *mem)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
7248c2ecf20Sopenharmony_ci	u32 dma_no, dma_base_addr, temp_addr;
7258c2ecf20Sopenharmony_ci	int i, ret, dma_sts;
7268c2ecf20Sopenharmony_ci	void *tmpl_hdr;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	tmpl_hdr = adapter->ahw->fw_dump.tmpl_hdr;
7298c2ecf20Sopenharmony_ci	dma_no = qlcnic_get_saved_state(adapter, tmpl_hdr,
7308c2ecf20Sopenharmony_ci					QLC_83XX_DMA_ENGINE_INDEX);
7318c2ecf20Sopenharmony_ci	dma_base_addr = QLC_DMA_REG_BASE_ADDR(dma_no);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_LOW;
7348c2ecf20Sopenharmony_ci	ret = qlcnic_ind_wr(adapter, temp_addr, mem->desc_card_addr);
7358c2ecf20Sopenharmony_ci	if (ret)
7368c2ecf20Sopenharmony_ci		return ret;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_HI;
7398c2ecf20Sopenharmony_ci	ret = qlcnic_ind_wr(adapter, temp_addr, 0);
7408c2ecf20Sopenharmony_ci	if (ret)
7418c2ecf20Sopenharmony_ci		return ret;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_STATUS_CTRL;
7448c2ecf20Sopenharmony_ci	ret = qlcnic_ind_wr(adapter, temp_addr, mem->start_dma_cmd);
7458c2ecf20Sopenharmony_ci	if (ret)
7468c2ecf20Sopenharmony_ci		return ret;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* Wait for DMA to complete */
7498c2ecf20Sopenharmony_ci	temp_addr = dma_base_addr + QLC_DMA_CMD_STATUS_CTRL;
7508c2ecf20Sopenharmony_ci	for (i = 0; i < 400; i++) {
7518c2ecf20Sopenharmony_ci		dma_sts = qlcnic_ind_rd(adapter, temp_addr);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		if (dma_sts & BIT_1)
7548c2ecf20Sopenharmony_ci			usleep_range(250, 500);
7558c2ecf20Sopenharmony_ci		else
7568c2ecf20Sopenharmony_ci			break;
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (i >= 400) {
7608c2ecf20Sopenharmony_ci		dev_info(dev, "PEX DMA operation timed out");
7618c2ecf20Sopenharmony_ci		ret = -EIO;
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	return ret;
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_cistatic u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,
7688c2ecf20Sopenharmony_ci				     struct __mem *mem,
7698c2ecf20Sopenharmony_ci				     __le32 *buffer, int *ret)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
7728c2ecf20Sopenharmony_ci	u32 temp, dma_base_addr, size = 0, read_size = 0;
7738c2ecf20Sopenharmony_ci	struct qlcnic_pex_dma_descriptor *dma_descr;
7748c2ecf20Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
7758c2ecf20Sopenharmony_ci	dma_addr_t dma_phys_addr;
7768c2ecf20Sopenharmony_ci	void *dma_buffer;
7778c2ecf20Sopenharmony_ci	void *tmpl_hdr;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	tmpl_hdr = fw_dump->tmpl_hdr;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/* Check if DMA engine is available */
7828c2ecf20Sopenharmony_ci	temp = qlcnic_get_saved_state(adapter, tmpl_hdr,
7838c2ecf20Sopenharmony_ci				      QLC_83XX_DMA_ENGINE_INDEX);
7848c2ecf20Sopenharmony_ci	dma_base_addr = QLC_DMA_REG_BASE_ADDR(temp);
7858c2ecf20Sopenharmony_ci	temp = qlcnic_ind_rd(adapter,
7868c2ecf20Sopenharmony_ci			     dma_base_addr + QLC_DMA_CMD_STATUS_CTRL);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (!(temp & BIT_31)) {
7898c2ecf20Sopenharmony_ci		dev_info(dev, "%s: DMA engine is not available\n", __func__);
7908c2ecf20Sopenharmony_ci		*ret = -EIO;
7918c2ecf20Sopenharmony_ci		return 0;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/* Create DMA descriptor */
7958c2ecf20Sopenharmony_ci	dma_descr = kzalloc(sizeof(struct qlcnic_pex_dma_descriptor),
7968c2ecf20Sopenharmony_ci			    GFP_KERNEL);
7978c2ecf20Sopenharmony_ci	if (!dma_descr) {
7988c2ecf20Sopenharmony_ci		*ret = -ENOMEM;
7998c2ecf20Sopenharmony_ci		return 0;
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	/* dma_desc_cmd  0:15  = 0
8038c2ecf20Sopenharmony_ci	 * dma_desc_cmd 16:19  = mem->dma_desc_cmd 0:3
8048c2ecf20Sopenharmony_ci	 * dma_desc_cmd 20:23  = pci function number
8058c2ecf20Sopenharmony_ci	 * dma_desc_cmd 24:31  = mem->dma_desc_cmd 8:15
8068c2ecf20Sopenharmony_ci	 */
8078c2ecf20Sopenharmony_ci	dma_phys_addr = fw_dump->phys_addr;
8088c2ecf20Sopenharmony_ci	dma_buffer = fw_dump->dma_buffer;
8098c2ecf20Sopenharmony_ci	temp = 0;
8108c2ecf20Sopenharmony_ci	temp = mem->dma_desc_cmd & 0xff0f;
8118c2ecf20Sopenharmony_ci	temp |= (adapter->ahw->pci_func & 0xf) << 4;
8128c2ecf20Sopenharmony_ci	dma_descr->dma_desc_cmd = (temp << 16) & 0xffff0000;
8138c2ecf20Sopenharmony_ci	dma_descr->dma_bus_addr_low = LSD(dma_phys_addr);
8148c2ecf20Sopenharmony_ci	dma_descr->dma_bus_addr_high = MSD(dma_phys_addr);
8158c2ecf20Sopenharmony_ci	dma_descr->src_addr_high = 0;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	/* Collect memory dump using multiple DMA operations if required */
8188c2ecf20Sopenharmony_ci	while (read_size < mem->size) {
8198c2ecf20Sopenharmony_ci		if (mem->size - read_size >= QLC_PEX_DMA_READ_SIZE)
8208c2ecf20Sopenharmony_ci			size = QLC_PEX_DMA_READ_SIZE;
8218c2ecf20Sopenharmony_ci		else
8228c2ecf20Sopenharmony_ci			size = mem->size - read_size;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci		dma_descr->src_addr_low = mem->addr + read_size;
8258c2ecf20Sopenharmony_ci		dma_descr->read_data_size = size;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci		/* Write DMA descriptor to MS memory*/
8288c2ecf20Sopenharmony_ci		temp = sizeof(struct qlcnic_pex_dma_descriptor) / 16;
8298c2ecf20Sopenharmony_ci		*ret = qlcnic_ms_mem_write128(adapter, mem->desc_card_addr,
8308c2ecf20Sopenharmony_ci					      (u32 *)dma_descr, temp);
8318c2ecf20Sopenharmony_ci		if (*ret) {
8328c2ecf20Sopenharmony_ci			dev_info(dev, "Failed to write DMA descriptor to MS memory at address 0x%x\n",
8338c2ecf20Sopenharmony_ci				 mem->desc_card_addr);
8348c2ecf20Sopenharmony_ci			goto free_dma_descr;
8358c2ecf20Sopenharmony_ci		}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		*ret = qlcnic_start_pex_dma(adapter, mem);
8388c2ecf20Sopenharmony_ci		if (*ret) {
8398c2ecf20Sopenharmony_ci			dev_info(dev, "Failed to start PEX DMA operation\n");
8408c2ecf20Sopenharmony_ci			goto free_dma_descr;
8418c2ecf20Sopenharmony_ci		}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci		memcpy(buffer, dma_buffer, size);
8448c2ecf20Sopenharmony_ci		buffer += size / 4;
8458c2ecf20Sopenharmony_ci		read_size += size;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cifree_dma_descr:
8498c2ecf20Sopenharmony_ci	kfree(dma_descr);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	return read_size;
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_cistatic u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
8558c2ecf20Sopenharmony_ci			      struct qlcnic_dump_entry *entry, __le32 *buffer)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
8588c2ecf20Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
8598c2ecf20Sopenharmony_ci	struct __mem *mem = &entry->region.mem;
8608c2ecf20Sopenharmony_ci	u32 data_size;
8618c2ecf20Sopenharmony_ci	int ret = 0;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if (fw_dump->use_pex_dma) {
8648c2ecf20Sopenharmony_ci		data_size = qlcnic_read_memory_pexdma(adapter, mem, buffer,
8658c2ecf20Sopenharmony_ci						      &ret);
8668c2ecf20Sopenharmony_ci		if (ret)
8678c2ecf20Sopenharmony_ci			dev_info(dev,
8688c2ecf20Sopenharmony_ci				 "Failed to read memory dump using PEX DMA: mask[0x%x]\n",
8698c2ecf20Sopenharmony_ci				 entry->hdr.mask);
8708c2ecf20Sopenharmony_ci		else
8718c2ecf20Sopenharmony_ci			return data_size;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	data_size = qlcnic_read_memory_test_agent(adapter, mem, buffer, &ret);
8758c2ecf20Sopenharmony_ci	if (ret) {
8768c2ecf20Sopenharmony_ci		dev_info(dev,
8778c2ecf20Sopenharmony_ci			 "Failed to read memory dump using test agent method: mask[0x%x]\n",
8788c2ecf20Sopenharmony_ci			 entry->hdr.mask);
8798c2ecf20Sopenharmony_ci		return 0;
8808c2ecf20Sopenharmony_ci	} else {
8818c2ecf20Sopenharmony_ci		return data_size;
8828c2ecf20Sopenharmony_ci	}
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic u32 qlcnic_dump_nop(struct qlcnic_adapter *adapter,
8868c2ecf20Sopenharmony_ci			   struct qlcnic_dump_entry *entry, __le32 *buffer)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	entry->hdr.flags |= QLCNIC_DUMP_SKIP;
8898c2ecf20Sopenharmony_ci	return 0;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic int qlcnic_valid_dump_entry(struct device *dev,
8938c2ecf20Sopenharmony_ci				   struct qlcnic_dump_entry *entry, u32 size)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	int ret = 1;
8968c2ecf20Sopenharmony_ci	if (size != entry->hdr.cap_size) {
8978c2ecf20Sopenharmony_ci		dev_err(dev,
8988c2ecf20Sopenharmony_ci			"Invalid entry, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
8998c2ecf20Sopenharmony_ci			entry->hdr.type, entry->hdr.mask, size,
9008c2ecf20Sopenharmony_ci			entry->hdr.cap_size);
9018c2ecf20Sopenharmony_ci		ret = 0;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci	return ret;
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cistatic u32 qlcnic_read_pollrdmwr(struct qlcnic_adapter *adapter,
9078c2ecf20Sopenharmony_ci				 struct qlcnic_dump_entry *entry,
9088c2ecf20Sopenharmony_ci				 __le32 *buffer)
9098c2ecf20Sopenharmony_ci{
9108c2ecf20Sopenharmony_ci	struct __pollrdmwr *poll = &entry->region.pollrdmwr;
9118c2ecf20Sopenharmony_ci	u32 data, wait_count, poll_wait, temp;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	poll_wait = poll->poll_wait;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, poll->addr1, poll->val1);
9168c2ecf20Sopenharmony_ci	wait_count = 0;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	while (wait_count < poll_wait) {
9198c2ecf20Sopenharmony_ci		data = qlcnic_ind_rd(adapter, poll->addr1);
9208c2ecf20Sopenharmony_ci		if ((data & poll->poll_mask) != 0)
9218c2ecf20Sopenharmony_ci			break;
9228c2ecf20Sopenharmony_ci		wait_count++;
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	if (wait_count == poll_wait) {
9268c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
9278c2ecf20Sopenharmony_ci			"Timeout exceeded in %s, aborting dump\n",
9288c2ecf20Sopenharmony_ci			__func__);
9298c2ecf20Sopenharmony_ci		return 0;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	data = qlcnic_ind_rd(adapter, poll->addr2) & poll->mod_mask;
9338c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, poll->addr2, data);
9348c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, poll->addr1, poll->val2);
9358c2ecf20Sopenharmony_ci	wait_count = 0;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	while (wait_count < poll_wait) {
9388c2ecf20Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, poll->addr1);
9398c2ecf20Sopenharmony_ci		if ((temp & poll->poll_mask) != 0)
9408c2ecf20Sopenharmony_ci			break;
9418c2ecf20Sopenharmony_ci		wait_count++;
9428c2ecf20Sopenharmony_ci	}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	*buffer++ = cpu_to_le32(poll->addr2);
9458c2ecf20Sopenharmony_ci	*buffer++ = cpu_to_le32(data);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	return 2 * sizeof(u32);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistatic u32 qlcnic_read_pollrd(struct qlcnic_adapter *adapter,
9528c2ecf20Sopenharmony_ci			      struct qlcnic_dump_entry *entry, __le32 *buffer)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	struct __pollrd *pollrd = &entry->region.pollrd;
9558c2ecf20Sopenharmony_ci	u32 data, wait_count, poll_wait, sel_val;
9568c2ecf20Sopenharmony_ci	int i;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	poll_wait = pollrd->poll_wait;
9598c2ecf20Sopenharmony_ci	sel_val = pollrd->sel_val;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	for (i = 0; i < pollrd->no_ops; i++) {
9628c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, pollrd->sel_addr, sel_val);
9638c2ecf20Sopenharmony_ci		wait_count = 0;
9648c2ecf20Sopenharmony_ci		while (wait_count < poll_wait) {
9658c2ecf20Sopenharmony_ci			data = qlcnic_ind_rd(adapter, pollrd->sel_addr);
9668c2ecf20Sopenharmony_ci			if ((data & pollrd->poll_mask) != 0)
9678c2ecf20Sopenharmony_ci				break;
9688c2ecf20Sopenharmony_ci			wait_count++;
9698c2ecf20Sopenharmony_ci		}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		if (wait_count == poll_wait) {
9728c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
9738c2ecf20Sopenharmony_ci				"Timeout exceeded in %s, aborting dump\n",
9748c2ecf20Sopenharmony_ci				__func__);
9758c2ecf20Sopenharmony_ci			return 0;
9768c2ecf20Sopenharmony_ci		}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		data = qlcnic_ind_rd(adapter, pollrd->read_addr);
9798c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(sel_val);
9808c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
9818c2ecf20Sopenharmony_ci		sel_val += pollrd->sel_val_stride;
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci	return pollrd->no_ops * (2 * sizeof(u32));
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic u32 qlcnic_read_mux2(struct qlcnic_adapter *adapter,
9878c2ecf20Sopenharmony_ci			    struct qlcnic_dump_entry *entry, __le32 *buffer)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct __mux2 *mux2 = &entry->region.mux2;
9908c2ecf20Sopenharmony_ci	u32 data;
9918c2ecf20Sopenharmony_ci	u32 t_sel_val, sel_val1, sel_val2;
9928c2ecf20Sopenharmony_ci	int i;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	sel_val1 = mux2->sel_val1;
9958c2ecf20Sopenharmony_ci	sel_val2 = mux2->sel_val2;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	for (i = 0; i < mux2->no_ops; i++) {
9988c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val1);
9998c2ecf20Sopenharmony_ci		t_sel_val = sel_val1 & mux2->sel_val_mask;
10008c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
10018c2ecf20Sopenharmony_ci		data = qlcnic_ind_rd(adapter, mux2->read_addr);
10028c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(t_sel_val);
10038c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
10048c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val2);
10058c2ecf20Sopenharmony_ci		t_sel_val = sel_val2 & mux2->sel_val_mask;
10068c2ecf20Sopenharmony_ci		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
10078c2ecf20Sopenharmony_ci		data = qlcnic_ind_rd(adapter, mux2->read_addr);
10088c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(t_sel_val);
10098c2ecf20Sopenharmony_ci		*buffer++ = cpu_to_le32(data);
10108c2ecf20Sopenharmony_ci		sel_val1 += mux2->sel_val_stride;
10118c2ecf20Sopenharmony_ci		sel_val2 += mux2->sel_val_stride;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	return mux2->no_ops * (4 * sizeof(u32));
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_cistatic u32 qlcnic_83xx_dump_rom(struct qlcnic_adapter *adapter,
10188c2ecf20Sopenharmony_ci				struct qlcnic_dump_entry *entry, __le32 *buffer)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	u32 fl_addr, size;
10218c2ecf20Sopenharmony_ci	struct __mem *rom = &entry->region.mem;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	fl_addr = rom->addr;
10248c2ecf20Sopenharmony_ci	size = rom->size / 4;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	if (!qlcnic_83xx_lockless_flash_read32(adapter, fl_addr,
10278c2ecf20Sopenharmony_ci					       (u8 *)buffer, size))
10288c2ecf20Sopenharmony_ci		return rom->size;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	return 0;
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_cistatic const struct qlcnic_dump_operations qlcnic_fw_dump_ops[] = {
10348c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_NOP, qlcnic_dump_nop},
10358c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
10368c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
10378c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
10388c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom},
10398c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
10408c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
10418c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
10428c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
10438c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
10448c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
10458c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
10468c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
10478c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
10488c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
10498c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_ROM, qlcnic_read_rom},
10508c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
10518c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
10528c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
10538c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
10548c2ecf20Sopenharmony_ci};
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_cistatic const struct qlcnic_dump_operations qlcnic_83xx_fw_dump_ops[] = {
10578c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_NOP, qlcnic_dump_nop},
10588c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
10598c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
10608c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
10618c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_BRD_CONFIG, qlcnic_83xx_dump_rom},
10628c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
10638c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
10648c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
10658c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
10668c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
10678c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
10688c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
10698c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
10708c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
10718c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
10728c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_POLL_RD, qlcnic_read_pollrd},
10738c2ecf20Sopenharmony_ci	{QLCNIC_READ_MUX2, qlcnic_read_mux2},
10748c2ecf20Sopenharmony_ci	{QLCNIC_READ_POLLRDMWR, qlcnic_read_pollrdmwr},
10758c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_ROM, qlcnic_83xx_dump_rom},
10768c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
10778c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
10788c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
10798c2ecf20Sopenharmony_ci	{QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
10808c2ecf20Sopenharmony_ci};
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
10838c2ecf20Sopenharmony_ci{
10848c2ecf20Sopenharmony_ci	uint64_t sum = 0;
10858c2ecf20Sopenharmony_ci	int count = temp_size / sizeof(uint32_t);
10868c2ecf20Sopenharmony_ci	while (count-- > 0)
10878c2ecf20Sopenharmony_ci		sum += *temp_buffer++;
10888c2ecf20Sopenharmony_ci	while (sum >> 32)
10898c2ecf20Sopenharmony_ci		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
10908c2ecf20Sopenharmony_ci	return ~sum;
10918c2ecf20Sopenharmony_ci}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic int qlcnic_fw_flash_get_minidump_temp(struct qlcnic_adapter *adapter,
10948c2ecf20Sopenharmony_ci					     u8 *buffer, u32 size)
10958c2ecf20Sopenharmony_ci{
10968c2ecf20Sopenharmony_ci	int ret = 0;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
10998c2ecf20Sopenharmony_ci		return -EIO;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	if (qlcnic_83xx_lock_flash(adapter))
11028c2ecf20Sopenharmony_ci		return -EIO;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	ret = qlcnic_83xx_lockless_flash_read32(adapter,
11058c2ecf20Sopenharmony_ci						QLC_83XX_MINIDUMP_FLASH,
11068c2ecf20Sopenharmony_ci						buffer, size / sizeof(u32));
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	qlcnic_83xx_unlock_flash(adapter);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	return ret;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic int
11148c2ecf20Sopenharmony_ciqlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
11158c2ecf20Sopenharmony_ci				       struct qlcnic_cmd_args *cmd)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr tmp_hdr;
11188c2ecf20Sopenharmony_ci	u32 size = sizeof(tmp_hdr) / sizeof(u32);
11198c2ecf20Sopenharmony_ci	int ret = 0;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
11228c2ecf20Sopenharmony_ci		return -EIO;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (qlcnic_83xx_lock_flash(adapter))
11258c2ecf20Sopenharmony_ci		return -EIO;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	ret = qlcnic_83xx_lockless_flash_read32(adapter,
11288c2ecf20Sopenharmony_ci						QLC_83XX_MINIDUMP_FLASH,
11298c2ecf20Sopenharmony_ci						(u8 *)&tmp_hdr, size);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	qlcnic_83xx_unlock_flash(adapter);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	cmd->rsp.arg[2] = tmp_hdr.size;
11348c2ecf20Sopenharmony_ci	cmd->rsp.arg[3] = tmp_hdr.version;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	return ret;
11378c2ecf20Sopenharmony_ci}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_cistatic int qlcnic_fw_get_minidump_temp_size(struct qlcnic_adapter *adapter,
11408c2ecf20Sopenharmony_ci					    u32 *version, u32 *temp_size,
11418c2ecf20Sopenharmony_ci					    u8 *use_flash_temp)
11428c2ecf20Sopenharmony_ci{
11438c2ecf20Sopenharmony_ci	int err = 0;
11448c2ecf20Sopenharmony_ci	struct qlcnic_cmd_args cmd;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TEMP_SIZE))
11478c2ecf20Sopenharmony_ci		return -ENOMEM;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	err = qlcnic_issue_cmd(adapter, &cmd);
11508c2ecf20Sopenharmony_ci	if (err != QLCNIC_RCODE_SUCCESS) {
11518c2ecf20Sopenharmony_ci		if (qlcnic_fw_flash_get_minidump_temp_size(adapter, &cmd)) {
11528c2ecf20Sopenharmony_ci			qlcnic_free_mbx_args(&cmd);
11538c2ecf20Sopenharmony_ci			return -EIO;
11548c2ecf20Sopenharmony_ci		}
11558c2ecf20Sopenharmony_ci		*use_flash_temp = 1;
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	*temp_size = cmd.rsp.arg[2];
11598c2ecf20Sopenharmony_ci	*version = cmd.rsp.arg[3];
11608c2ecf20Sopenharmony_ci	qlcnic_free_mbx_args(&cmd);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (!(*temp_size))
11638c2ecf20Sopenharmony_ci		return -EIO;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
11698c2ecf20Sopenharmony_ci					     u32 *buffer, u32 temp_size)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	int err = 0, i;
11728c2ecf20Sopenharmony_ci	void *tmp_addr;
11738c2ecf20Sopenharmony_ci	__le32 *tmp_buf;
11748c2ecf20Sopenharmony_ci	struct qlcnic_cmd_args cmd;
11758c2ecf20Sopenharmony_ci	dma_addr_t tmp_addr_t = 0;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
11788c2ecf20Sopenharmony_ci				      &tmp_addr_t, GFP_KERNEL);
11798c2ecf20Sopenharmony_ci	if (!tmp_addr)
11808c2ecf20Sopenharmony_ci		return -ENOMEM;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
11838c2ecf20Sopenharmony_ci		err = -ENOMEM;
11848c2ecf20Sopenharmony_ci		goto free_mem;
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	cmd.req.arg[1] = LSD(tmp_addr_t);
11888c2ecf20Sopenharmony_ci	cmd.req.arg[2] = MSD(tmp_addr_t);
11898c2ecf20Sopenharmony_ci	cmd.req.arg[3] = temp_size;
11908c2ecf20Sopenharmony_ci	err = qlcnic_issue_cmd(adapter, &cmd);
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	tmp_buf = tmp_addr;
11938c2ecf20Sopenharmony_ci	if (err == QLCNIC_RCODE_SUCCESS) {
11948c2ecf20Sopenharmony_ci		for (i = 0; i < temp_size / sizeof(u32); i++)
11958c2ecf20Sopenharmony_ci			*buffer++ = __le32_to_cpu(*tmp_buf++);
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	qlcnic_free_mbx_args(&cmd);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_cifree_mem:
12018c2ecf20Sopenharmony_ci	dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	return err;
12048c2ecf20Sopenharmony_ci}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ciint qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	struct qlcnic_hardware_context *ahw;
12098c2ecf20Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump;
12108c2ecf20Sopenharmony_ci	u32 version, csum, *tmp_buf;
12118c2ecf20Sopenharmony_ci	u8 use_flash_temp = 0;
12128c2ecf20Sopenharmony_ci	u32 temp_size = 0;
12138c2ecf20Sopenharmony_ci	void *temp_buffer;
12148c2ecf20Sopenharmony_ci	int err;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	ahw = adapter->ahw;
12178c2ecf20Sopenharmony_ci	fw_dump = &ahw->fw_dump;
12188c2ecf20Sopenharmony_ci	err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
12198c2ecf20Sopenharmony_ci					       &use_flash_temp);
12208c2ecf20Sopenharmony_ci	if (err) {
12218c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
12228c2ecf20Sopenharmony_ci			"Can't get template size %d\n", err);
12238c2ecf20Sopenharmony_ci		return -EIO;
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	fw_dump->tmpl_hdr = vzalloc(temp_size);
12278c2ecf20Sopenharmony_ci	if (!fw_dump->tmpl_hdr)
12288c2ecf20Sopenharmony_ci		return -ENOMEM;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	tmp_buf = (u32 *)fw_dump->tmpl_hdr;
12318c2ecf20Sopenharmony_ci	if (use_flash_temp)
12328c2ecf20Sopenharmony_ci		goto flash_temp;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	err = __qlcnic_fw_cmd_get_minidump_temp(adapter, tmp_buf, temp_size);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	if (err) {
12378c2ecf20Sopenharmony_ciflash_temp:
12388c2ecf20Sopenharmony_ci		err = qlcnic_fw_flash_get_minidump_temp(adapter, (u8 *)tmp_buf,
12398c2ecf20Sopenharmony_ci							temp_size);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci		if (err) {
12428c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
12438c2ecf20Sopenharmony_ci				"Failed to get minidump template header %d\n",
12448c2ecf20Sopenharmony_ci				err);
12458c2ecf20Sopenharmony_ci			vfree(fw_dump->tmpl_hdr);
12468c2ecf20Sopenharmony_ci			fw_dump->tmpl_hdr = NULL;
12478c2ecf20Sopenharmony_ci			return -EIO;
12488c2ecf20Sopenharmony_ci		}
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	csum = qlcnic_temp_checksum((uint32_t *)tmp_buf, temp_size);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	if (csum) {
12548c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
12558c2ecf20Sopenharmony_ci			"Template header checksum validation failed\n");
12568c2ecf20Sopenharmony_ci		vfree(fw_dump->tmpl_hdr);
12578c2ecf20Sopenharmony_ci		fw_dump->tmpl_hdr = NULL;
12588c2ecf20Sopenharmony_ci		return -EIO;
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	qlcnic_cache_tmpl_hdr_values(adapter, fw_dump);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	if (fw_dump->use_pex_dma) {
12648c2ecf20Sopenharmony_ci		fw_dump->dma_buffer = NULL;
12658c2ecf20Sopenharmony_ci		temp_buffer = dma_alloc_coherent(&adapter->pdev->dev,
12668c2ecf20Sopenharmony_ci						 QLC_PEX_DMA_READ_SIZE,
12678c2ecf20Sopenharmony_ci						 &fw_dump->phys_addr,
12688c2ecf20Sopenharmony_ci						 GFP_KERNEL);
12698c2ecf20Sopenharmony_ci		if (!temp_buffer)
12708c2ecf20Sopenharmony_ci			fw_dump->use_pex_dma = false;
12718c2ecf20Sopenharmony_ci		else
12728c2ecf20Sopenharmony_ci			fw_dump->dma_buffer = temp_buffer;
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	dev_info(&adapter->pdev->dev,
12778c2ecf20Sopenharmony_ci		 "Default minidump capture mask 0x%x\n",
12788c2ecf20Sopenharmony_ci		 fw_dump->cap_mask);
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	qlcnic_enable_fw_dump_state(adapter);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	return 0;
12838c2ecf20Sopenharmony_ci}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ciint qlcnic_dump_fw(struct qlcnic_adapter *adapter)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
12888c2ecf20Sopenharmony_ci	const struct qlcnic_dump_operations *fw_dump_ops;
12898c2ecf20Sopenharmony_ci	struct qlcnic_83xx_dump_template_hdr *hdr_83xx;
12908c2ecf20Sopenharmony_ci	u32 entry_offset, dump, no_entries, buf_offset = 0;
12918c2ecf20Sopenharmony_ci	int i, k, ops_cnt, ops_index, dump_size = 0;
12928c2ecf20Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
12938c2ecf20Sopenharmony_ci	struct qlcnic_hardware_context *ahw;
12948c2ecf20Sopenharmony_ci	struct qlcnic_dump_entry *entry;
12958c2ecf20Sopenharmony_ci	void *tmpl_hdr;
12968c2ecf20Sopenharmony_ci	u32 ocm_window;
12978c2ecf20Sopenharmony_ci	__le32 *buffer;
12988c2ecf20Sopenharmony_ci	char mesg[64];
12998c2ecf20Sopenharmony_ci	char *msg[] = {mesg, NULL};
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	ahw = adapter->ahw;
13028c2ecf20Sopenharmony_ci	tmpl_hdr = fw_dump->tmpl_hdr;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	/* Return if we don't have firmware dump template header */
13058c2ecf20Sopenharmony_ci	if (!tmpl_hdr)
13068c2ecf20Sopenharmony_ci		return -EIO;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	if (!qlcnic_check_fw_dump_state(adapter)) {
13098c2ecf20Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Dump not enabled\n");
13108c2ecf20Sopenharmony_ci		return -EIO;
13118c2ecf20Sopenharmony_ci	}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	if (fw_dump->clr) {
13148c2ecf20Sopenharmony_ci		dev_info(&adapter->pdev->dev,
13158c2ecf20Sopenharmony_ci			 "Previous dump not cleared, not capturing dump\n");
13168c2ecf20Sopenharmony_ci		return -EIO;
13178c2ecf20Sopenharmony_ci	}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
13208c2ecf20Sopenharmony_ci	/* Calculate the size for dump data area only */
13218c2ecf20Sopenharmony_ci	for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
13228c2ecf20Sopenharmony_ci		if (i & fw_dump->cap_mask)
13238c2ecf20Sopenharmony_ci			dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k);
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	if (!dump_size)
13268c2ecf20Sopenharmony_ci		return -EIO;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	fw_dump->data = vzalloc(dump_size);
13298c2ecf20Sopenharmony_ci	if (!fw_dump->data)
13308c2ecf20Sopenharmony_ci		return -ENOMEM;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	buffer = fw_dump->data;
13338c2ecf20Sopenharmony_ci	fw_dump->size = dump_size;
13348c2ecf20Sopenharmony_ci	no_entries = fw_dump->num_entries;
13358c2ecf20Sopenharmony_ci	entry_offset = fw_dump->offset;
13368c2ecf20Sopenharmony_ci	qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION);
13378c2ecf20Sopenharmony_ci	qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	if (qlcnic_82xx_check(adapter)) {
13408c2ecf20Sopenharmony_ci		ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
13418c2ecf20Sopenharmony_ci		fw_dump_ops = qlcnic_fw_dump_ops;
13428c2ecf20Sopenharmony_ci	} else {
13438c2ecf20Sopenharmony_ci		hdr_83xx = tmpl_hdr;
13448c2ecf20Sopenharmony_ci		ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
13458c2ecf20Sopenharmony_ci		fw_dump_ops = qlcnic_83xx_fw_dump_ops;
13468c2ecf20Sopenharmony_ci		ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func];
13478c2ecf20Sopenharmony_ci		hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
13488c2ecf20Sopenharmony_ci		hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
13498c2ecf20Sopenharmony_ci	}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	for (i = 0; i < no_entries; i++) {
13528c2ecf20Sopenharmony_ci		entry = tmpl_hdr + entry_offset;
13538c2ecf20Sopenharmony_ci		if (!(entry->hdr.mask & fw_dump->cap_mask)) {
13548c2ecf20Sopenharmony_ci			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
13558c2ecf20Sopenharmony_ci			entry_offset += entry->hdr.offset;
13568c2ecf20Sopenharmony_ci			continue;
13578c2ecf20Sopenharmony_ci		}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci		/* Find the handler for this entry */
13608c2ecf20Sopenharmony_ci		ops_index = 0;
13618c2ecf20Sopenharmony_ci		while (ops_index < ops_cnt) {
13628c2ecf20Sopenharmony_ci			if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
13638c2ecf20Sopenharmony_ci				break;
13648c2ecf20Sopenharmony_ci			ops_index++;
13658c2ecf20Sopenharmony_ci		}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci		if (ops_index == ops_cnt) {
13688c2ecf20Sopenharmony_ci			dev_info(dev, "Skipping unknown entry opcode %d\n",
13698c2ecf20Sopenharmony_ci				 entry->hdr.type);
13708c2ecf20Sopenharmony_ci			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
13718c2ecf20Sopenharmony_ci			entry_offset += entry->hdr.offset;
13728c2ecf20Sopenharmony_ci			continue;
13738c2ecf20Sopenharmony_ci		}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		/* Collect dump for this entry */
13768c2ecf20Sopenharmony_ci		dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
13778c2ecf20Sopenharmony_ci		if (!qlcnic_valid_dump_entry(dev, entry, dump)) {
13788c2ecf20Sopenharmony_ci			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
13798c2ecf20Sopenharmony_ci			entry_offset += entry->hdr.offset;
13808c2ecf20Sopenharmony_ci			continue;
13818c2ecf20Sopenharmony_ci		}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci		buf_offset += entry->hdr.cap_size;
13848c2ecf20Sopenharmony_ci		entry_offset += entry->hdr.offset;
13858c2ecf20Sopenharmony_ci		buffer = fw_dump->data + buf_offset;
13868c2ecf20Sopenharmony_ci		cond_resched();
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	fw_dump->clr = 1;
13908c2ecf20Sopenharmony_ci	snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name);
13918c2ecf20Sopenharmony_ci	netdev_info(adapter->netdev,
13928c2ecf20Sopenharmony_ci		    "Dump data %d bytes captured, dump data address = %p, template header size %d bytes, template address = %p\n",
13938c2ecf20Sopenharmony_ci		    fw_dump->size, fw_dump->data, fw_dump->tmpl_hdr_size,
13948c2ecf20Sopenharmony_ci		    fw_dump->tmpl_hdr);
13958c2ecf20Sopenharmony_ci	/* Send a udev event to notify availability of FW dump */
13968c2ecf20Sopenharmony_ci	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	return 0;
13998c2ecf20Sopenharmony_ci}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_cistatic inline bool
14028c2ecf20Sopenharmony_ciqlcnic_83xx_md_check_extended_dump_capability(struct qlcnic_adapter *adapter)
14038c2ecf20Sopenharmony_ci{
14048c2ecf20Sopenharmony_ci	/* For special adapters (with 0x8830 device ID), where iSCSI firmware
14058c2ecf20Sopenharmony_ci	 * dump needs to be captured as part of regular firmware dump
14068c2ecf20Sopenharmony_ci	 * collection process, firmware exports it's capability through
14078c2ecf20Sopenharmony_ci	 * capability registers
14088c2ecf20Sopenharmony_ci	 */
14098c2ecf20Sopenharmony_ci	return ((adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE8830) &&
14108c2ecf20Sopenharmony_ci		(adapter->ahw->extra_capability[0] &
14118c2ecf20Sopenharmony_ci		 QLCNIC_FW_CAPABILITY_2_EXT_ISCSI_DUMP));
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_civoid qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
14158c2ecf20Sopenharmony_ci{
14168c2ecf20Sopenharmony_ci	u32 prev_version, current_version;
14178c2ecf20Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
14188c2ecf20Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
14198c2ecf20Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
14208c2ecf20Sopenharmony_ci	bool extended = false;
14218c2ecf20Sopenharmony_ci	int ret;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	prev_version = adapter->fw_version;
14248c2ecf20Sopenharmony_ci	current_version = qlcnic_83xx_get_fw_version(adapter);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
14278c2ecf20Sopenharmony_ci		vfree(fw_dump->tmpl_hdr);
14288c2ecf20Sopenharmony_ci		fw_dump->tmpl_hdr = NULL;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci		if (qlcnic_83xx_md_check_extended_dump_capability(adapter))
14318c2ecf20Sopenharmony_ci			extended = !qlcnic_83xx_extend_md_capab(adapter);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci		ret = qlcnic_fw_cmd_get_minidump_temp(adapter);
14348c2ecf20Sopenharmony_ci		if (ret)
14358c2ecf20Sopenharmony_ci			return;
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "Supports FW dump capability\n");
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci		/* Once we have minidump template with extended iSCSI dump
14408c2ecf20Sopenharmony_ci		 * capability, update the minidump capture mask to 0x1f as
14418c2ecf20Sopenharmony_ci		 * per FW requirement
14428c2ecf20Sopenharmony_ci		 */
14438c2ecf20Sopenharmony_ci		if (extended) {
14448c2ecf20Sopenharmony_ci			struct qlcnic_83xx_dump_template_hdr *hdr;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci			hdr = fw_dump->tmpl_hdr;
14478c2ecf20Sopenharmony_ci			if (!hdr)
14488c2ecf20Sopenharmony_ci				return;
14498c2ecf20Sopenharmony_ci			hdr->drv_cap_mask = 0x1f;
14508c2ecf20Sopenharmony_ci			fw_dump->cap_mask = 0x1f;
14518c2ecf20Sopenharmony_ci			dev_info(&pdev->dev,
14528c2ecf20Sopenharmony_ci				 "Extended iSCSI dump capability and updated capture mask to 0x1f\n");
14538c2ecf20Sopenharmony_ci		}
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci}
1456