162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 2017 Chelsio Communications.  All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "t4_regs.h"
762306a36Sopenharmony_ci#include "cxgb4.h"
862306a36Sopenharmony_ci#include "cxgb4_cudbg.h"
962306a36Sopenharmony_ci#include "cudbg_zlib.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
1262306a36Sopenharmony_ci	{ CUDBG_EDC0, cudbg_collect_edc0_meminfo },
1362306a36Sopenharmony_ci	{ CUDBG_EDC1, cudbg_collect_edc1_meminfo },
1462306a36Sopenharmony_ci	{ CUDBG_MC0, cudbg_collect_mc0_meminfo },
1562306a36Sopenharmony_ci	{ CUDBG_MC1, cudbg_collect_mc1_meminfo },
1662306a36Sopenharmony_ci	{ CUDBG_HMA, cudbg_collect_hma_meminfo },
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
2062306a36Sopenharmony_ci	{ CUDBG_MBOX_LOG, cudbg_collect_mbox_log },
2162306a36Sopenharmony_ci	{ CUDBG_QDESC, cudbg_collect_qdesc },
2262306a36Sopenharmony_ci	{ CUDBG_DEV_LOG, cudbg_collect_fw_devlog },
2362306a36Sopenharmony_ci	{ CUDBG_REG_DUMP, cudbg_collect_reg_dump },
2462306a36Sopenharmony_ci	{ CUDBG_CIM_LA, cudbg_collect_cim_la },
2562306a36Sopenharmony_ci	{ CUDBG_CIM_MA_LA, cudbg_collect_cim_ma_la },
2662306a36Sopenharmony_ci	{ CUDBG_CIM_QCFG, cudbg_collect_cim_qcfg },
2762306a36Sopenharmony_ci	{ CUDBG_CIM_IBQ_TP0, cudbg_collect_cim_ibq_tp0 },
2862306a36Sopenharmony_ci	{ CUDBG_CIM_IBQ_TP1, cudbg_collect_cim_ibq_tp1 },
2962306a36Sopenharmony_ci	{ CUDBG_CIM_IBQ_ULP, cudbg_collect_cim_ibq_ulp },
3062306a36Sopenharmony_ci	{ CUDBG_CIM_IBQ_SGE0, cudbg_collect_cim_ibq_sge0 },
3162306a36Sopenharmony_ci	{ CUDBG_CIM_IBQ_SGE1, cudbg_collect_cim_ibq_sge1 },
3262306a36Sopenharmony_ci	{ CUDBG_CIM_IBQ_NCSI, cudbg_collect_cim_ibq_ncsi },
3362306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_ULP0, cudbg_collect_cim_obq_ulp0 },
3462306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_ULP1, cudbg_collect_cim_obq_ulp1 },
3562306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_ULP2, cudbg_collect_cim_obq_ulp2 },
3662306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_ULP3, cudbg_collect_cim_obq_ulp3 },
3762306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_SGE, cudbg_collect_cim_obq_sge },
3862306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_NCSI, cudbg_collect_cim_obq_ncsi },
3962306a36Sopenharmony_ci	{ CUDBG_RSS, cudbg_collect_rss },
4062306a36Sopenharmony_ci	{ CUDBG_RSS_VF_CONF, cudbg_collect_rss_vf_config },
4162306a36Sopenharmony_ci	{ CUDBG_PATH_MTU, cudbg_collect_path_mtu },
4262306a36Sopenharmony_ci	{ CUDBG_PM_STATS, cudbg_collect_pm_stats },
4362306a36Sopenharmony_ci	{ CUDBG_HW_SCHED, cudbg_collect_hw_sched },
4462306a36Sopenharmony_ci	{ CUDBG_TP_INDIRECT, cudbg_collect_tp_indirect },
4562306a36Sopenharmony_ci	{ CUDBG_SGE_INDIRECT, cudbg_collect_sge_indirect },
4662306a36Sopenharmony_ci	{ CUDBG_ULPRX_LA, cudbg_collect_ulprx_la },
4762306a36Sopenharmony_ci	{ CUDBG_TP_LA, cudbg_collect_tp_la },
4862306a36Sopenharmony_ci	{ CUDBG_MEMINFO, cudbg_collect_meminfo },
4962306a36Sopenharmony_ci	{ CUDBG_CIM_PIF_LA, cudbg_collect_cim_pif_la },
5062306a36Sopenharmony_ci	{ CUDBG_CLK, cudbg_collect_clk_info },
5162306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_RXQ0, cudbg_collect_obq_sge_rx_q0 },
5262306a36Sopenharmony_ci	{ CUDBG_CIM_OBQ_RXQ1, cudbg_collect_obq_sge_rx_q1 },
5362306a36Sopenharmony_ci	{ CUDBG_PCIE_INDIRECT, cudbg_collect_pcie_indirect },
5462306a36Sopenharmony_ci	{ CUDBG_PM_INDIRECT, cudbg_collect_pm_indirect },
5562306a36Sopenharmony_ci	{ CUDBG_TID_INFO, cudbg_collect_tid },
5662306a36Sopenharmony_ci	{ CUDBG_PCIE_CONFIG, cudbg_collect_pcie_config },
5762306a36Sopenharmony_ci	{ CUDBG_DUMP_CONTEXT, cudbg_collect_dump_context },
5862306a36Sopenharmony_ci	{ CUDBG_MPS_TCAM, cudbg_collect_mps_tcam },
5962306a36Sopenharmony_ci	{ CUDBG_VPD_DATA, cudbg_collect_vpd_data },
6062306a36Sopenharmony_ci	{ CUDBG_LE_TCAM, cudbg_collect_le_tcam },
6162306a36Sopenharmony_ci	{ CUDBG_CCTRL, cudbg_collect_cctrl },
6262306a36Sopenharmony_ci	{ CUDBG_MA_INDIRECT, cudbg_collect_ma_indirect },
6362306a36Sopenharmony_ci	{ CUDBG_ULPTX_LA, cudbg_collect_ulptx_la },
6462306a36Sopenharmony_ci	{ CUDBG_UP_CIM_INDIRECT, cudbg_collect_up_cim_indirect },
6562306a36Sopenharmony_ci	{ CUDBG_PBT_TABLE, cudbg_collect_pbt_tables },
6662306a36Sopenharmony_ci	{ CUDBG_HMA_INDIRECT, cudbg_collect_hma_indirect },
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic const struct cxgb4_collect_entity cxgb4_collect_flash_dump[] = {
7062306a36Sopenharmony_ci	{ CUDBG_FLASH, cudbg_collect_flash },
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciu32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	u32 i, entity;
7662306a36Sopenharmony_ci	u32 len = 0;
7762306a36Sopenharmony_ci	u32 wsize;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (flag & CXGB4_ETH_DUMP_HW) {
8062306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(cxgb4_collect_hw_dump); i++) {
8162306a36Sopenharmony_ci			entity = cxgb4_collect_hw_dump[i].entity;
8262306a36Sopenharmony_ci			len += cudbg_get_entity_length(adap, entity);
8362306a36Sopenharmony_ci		}
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if (flag & CXGB4_ETH_DUMP_MEM) {
8762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(cxgb4_collect_mem_dump); i++) {
8862306a36Sopenharmony_ci			entity = cxgb4_collect_mem_dump[i].entity;
8962306a36Sopenharmony_ci			len += cudbg_get_entity_length(adap, entity);
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (flag & CXGB4_ETH_DUMP_FLASH)
9462306a36Sopenharmony_ci		len += adap->params.sf_size;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* If compression is enabled, a smaller destination buffer is enough */
9762306a36Sopenharmony_ci	wsize = cudbg_get_workspace_size();
9862306a36Sopenharmony_ci	if (wsize && len > CUDBG_DUMP_BUFF_SIZE)
9962306a36Sopenharmony_ci		len = CUDBG_DUMP_BUFF_SIZE;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return len;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic void cxgb4_cudbg_collect_entity(struct cudbg_init *pdbg_init,
10562306a36Sopenharmony_ci				       struct cudbg_buffer *dbg_buff,
10662306a36Sopenharmony_ci				       const struct cxgb4_collect_entity *e_arr,
10762306a36Sopenharmony_ci				       u32 arr_size, void *buf, u32 *tot_size)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct cudbg_error cudbg_err = { 0 };
11062306a36Sopenharmony_ci	struct cudbg_entity_hdr *entity_hdr;
11162306a36Sopenharmony_ci	u32 i, total_size = 0;
11262306a36Sopenharmony_ci	int ret;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	for (i = 0; i < arr_size; i++) {
11562306a36Sopenharmony_ci		const struct cxgb4_collect_entity *e = &e_arr[i];
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		entity_hdr = cudbg_get_entity_hdr(buf, e->entity);
11862306a36Sopenharmony_ci		entity_hdr->entity_type = e->entity;
11962306a36Sopenharmony_ci		entity_hdr->start_offset = dbg_buff->offset;
12062306a36Sopenharmony_ci		memset(&cudbg_err, 0, sizeof(struct cudbg_error));
12162306a36Sopenharmony_ci		ret = e->collect_cb(pdbg_init, dbg_buff, &cudbg_err);
12262306a36Sopenharmony_ci		if (ret) {
12362306a36Sopenharmony_ci			entity_hdr->size = 0;
12462306a36Sopenharmony_ci			dbg_buff->offset = entity_hdr->start_offset;
12562306a36Sopenharmony_ci		} else {
12662306a36Sopenharmony_ci			cudbg_align_debug_buffer(dbg_buff, entity_hdr);
12762306a36Sopenharmony_ci		}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		/* Log error and continue with next entity */
13062306a36Sopenharmony_ci		if (cudbg_err.sys_err)
13162306a36Sopenharmony_ci			ret = CUDBG_SYSTEM_ERROR;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		entity_hdr->hdr_flags = ret;
13462306a36Sopenharmony_ci		entity_hdr->sys_err = cudbg_err.sys_err;
13562306a36Sopenharmony_ci		entity_hdr->sys_warn = cudbg_err.sys_warn;
13662306a36Sopenharmony_ci		total_size += entity_hdr->size;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	*tot_size += total_size;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int cudbg_alloc_compress_buff(struct cudbg_init *pdbg_init)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	u32 workspace_size;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	workspace_size = cudbg_get_workspace_size();
14762306a36Sopenharmony_ci	pdbg_init->compress_buff = vzalloc(CUDBG_COMPRESS_BUFF_SIZE +
14862306a36Sopenharmony_ci					   workspace_size);
14962306a36Sopenharmony_ci	if (!pdbg_init->compress_buff)
15062306a36Sopenharmony_ci		return -ENOMEM;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	pdbg_init->compress_buff_size = CUDBG_COMPRESS_BUFF_SIZE;
15362306a36Sopenharmony_ci	pdbg_init->workspace = (u8 *)pdbg_init->compress_buff +
15462306a36Sopenharmony_ci			       CUDBG_COMPRESS_BUFF_SIZE - workspace_size;
15562306a36Sopenharmony_ci	return 0;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic void cudbg_free_compress_buff(struct cudbg_init *pdbg_init)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	vfree(pdbg_init->compress_buff);
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ciint cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
16462306a36Sopenharmony_ci			u32 flag)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct cudbg_buffer dbg_buff = { 0 };
16762306a36Sopenharmony_ci	u32 size, min_size, total_size = 0;
16862306a36Sopenharmony_ci	struct cudbg_init cudbg_init;
16962306a36Sopenharmony_ci	struct cudbg_hdr *cudbg_hdr;
17062306a36Sopenharmony_ci	int rc;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	size = *buf_size;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	memset(&cudbg_init, 0, sizeof(struct cudbg_init));
17562306a36Sopenharmony_ci	cudbg_init.adap = adap;
17662306a36Sopenharmony_ci	cudbg_init.outbuf = buf;
17762306a36Sopenharmony_ci	cudbg_init.outbuf_size = size;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	dbg_buff.data = buf;
18062306a36Sopenharmony_ci	dbg_buff.size = size;
18162306a36Sopenharmony_ci	dbg_buff.offset = 0;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	cudbg_hdr = (struct cudbg_hdr *)buf;
18462306a36Sopenharmony_ci	cudbg_hdr->signature = CUDBG_SIGNATURE;
18562306a36Sopenharmony_ci	cudbg_hdr->hdr_len = sizeof(struct cudbg_hdr);
18662306a36Sopenharmony_ci	cudbg_hdr->major_ver = CUDBG_MAJOR_VERSION;
18762306a36Sopenharmony_ci	cudbg_hdr->minor_ver = CUDBG_MINOR_VERSION;
18862306a36Sopenharmony_ci	cudbg_hdr->max_entities = CUDBG_MAX_ENTITY;
18962306a36Sopenharmony_ci	cudbg_hdr->chip_ver = adap->params.chip;
19062306a36Sopenharmony_ci	cudbg_hdr->dump_type = CUDBG_DUMP_TYPE_MINI;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	min_size = sizeof(struct cudbg_hdr) +
19362306a36Sopenharmony_ci		   sizeof(struct cudbg_entity_hdr) *
19462306a36Sopenharmony_ci		   cudbg_hdr->max_entities;
19562306a36Sopenharmony_ci	if (size < min_size)
19662306a36Sopenharmony_ci		return -ENOMEM;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	rc = cudbg_get_workspace_size();
19962306a36Sopenharmony_ci	if (rc) {
20062306a36Sopenharmony_ci		/* Zlib available.  So, use zlib deflate */
20162306a36Sopenharmony_ci		cudbg_init.compress_type = CUDBG_COMPRESSION_ZLIB;
20262306a36Sopenharmony_ci		rc = cudbg_alloc_compress_buff(&cudbg_init);
20362306a36Sopenharmony_ci		if (rc) {
20462306a36Sopenharmony_ci			/* Ignore error and continue without compression. */
20562306a36Sopenharmony_ci			dev_warn(adap->pdev_dev,
20662306a36Sopenharmony_ci				 "Fail allocating compression buffer ret: %d.  Continuing without compression.\n",
20762306a36Sopenharmony_ci				 rc);
20862306a36Sopenharmony_ci			cudbg_init.compress_type = CUDBG_COMPRESSION_NONE;
20962306a36Sopenharmony_ci			rc = 0;
21062306a36Sopenharmony_ci		}
21162306a36Sopenharmony_ci	} else {
21262306a36Sopenharmony_ci		cudbg_init.compress_type = CUDBG_COMPRESSION_NONE;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	cudbg_hdr->compress_type = cudbg_init.compress_type;
21662306a36Sopenharmony_ci	dbg_buff.offset += min_size;
21762306a36Sopenharmony_ci	total_size = dbg_buff.offset;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (flag & CXGB4_ETH_DUMP_HW)
22062306a36Sopenharmony_ci		cxgb4_cudbg_collect_entity(&cudbg_init, &dbg_buff,
22162306a36Sopenharmony_ci					   cxgb4_collect_hw_dump,
22262306a36Sopenharmony_ci					   ARRAY_SIZE(cxgb4_collect_hw_dump),
22362306a36Sopenharmony_ci					   buf,
22462306a36Sopenharmony_ci					   &total_size);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (flag & CXGB4_ETH_DUMP_MEM)
22762306a36Sopenharmony_ci		cxgb4_cudbg_collect_entity(&cudbg_init, &dbg_buff,
22862306a36Sopenharmony_ci					   cxgb4_collect_mem_dump,
22962306a36Sopenharmony_ci					   ARRAY_SIZE(cxgb4_collect_mem_dump),
23062306a36Sopenharmony_ci					   buf,
23162306a36Sopenharmony_ci					   &total_size);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (flag & CXGB4_ETH_DUMP_FLASH)
23462306a36Sopenharmony_ci		cxgb4_cudbg_collect_entity(&cudbg_init, &dbg_buff,
23562306a36Sopenharmony_ci					   cxgb4_collect_flash_dump,
23662306a36Sopenharmony_ci					   ARRAY_SIZE(cxgb4_collect_flash_dump),
23762306a36Sopenharmony_ci					   buf,
23862306a36Sopenharmony_ci					   &total_size);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	cudbg_free_compress_buff(&cudbg_init);
24162306a36Sopenharmony_ci	cudbg_hdr->data_len = total_size;
24262306a36Sopenharmony_ci	if (cudbg_init.compress_type != CUDBG_COMPRESSION_NONE)
24362306a36Sopenharmony_ci		*buf_size = size;
24462306a36Sopenharmony_ci	else
24562306a36Sopenharmony_ci		*buf_size = total_size;
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_civoid cxgb4_init_ethtool_dump(struct adapter *adapter)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	adapter->eth_dump.flag = CXGB4_ETH_DUMP_NONE;
25262306a36Sopenharmony_ci	adapter->eth_dump.version = adapter->params.fw_vers;
25362306a36Sopenharmony_ci	adapter->eth_dump.len = 0;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int cxgb4_cudbg_vmcoredd_collect(struct vmcoredd_data *data, void *buf)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct adapter *adap = container_of(data, struct adapter, vmcoredd);
25962306a36Sopenharmony_ci	u32 len = data->size;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return cxgb4_cudbg_collect(adap, buf, &len, CXGB4_ETH_DUMP_ALL);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ciint cxgb4_cudbg_vmcore_add_dump(struct adapter *adap)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct vmcoredd_data *data = &adap->vmcoredd;
26762306a36Sopenharmony_ci	u32 len;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	len = sizeof(struct cudbg_hdr) +
27062306a36Sopenharmony_ci	      sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY;
27162306a36Sopenharmony_ci	len += CUDBG_DUMP_BUFF_SIZE;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	data->size = len;
27462306a36Sopenharmony_ci	snprintf(data->dump_name, sizeof(data->dump_name), "%s_%s",
27562306a36Sopenharmony_ci		 cxgb4_driver_name, adap->name);
27662306a36Sopenharmony_ci	data->vmcoredd_callback = cxgb4_cudbg_vmcoredd_collect;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return vmcore_add_device_dump(data);
27962306a36Sopenharmony_ci}
280