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