xref: /dpdk/drivers/net/qede/qede_regs.c (revision 68a03efeed657e6e05f281479b33b51102797e15)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2020 Marvell Semiconductor Inc.
3  * All rights reserved.
4  * www.marvell.com
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <fcntl.h>
10 #include <time.h>
11 #include <rte_ethdev.h>
12 #include "base/bcm_osal.h"
13 #include "qede_ethdev.h"
14 
15 int
16 qede_get_regs_len(struct qede_dev *qdev)
17 {
18 	struct ecore_dev *edev = &qdev->edev;
19 	int cur_engine, num_of_hwfns, regs_len = 0;
20 	uint8_t org_engine;
21 
22 	if (IS_VF(edev))
23 		return 0;
24 
25 	if (qdev->ops && qdev->ops->common) {
26 		num_of_hwfns = qdev->dev_info.common.num_hwfns;
27 		org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
28 		for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
29 			/* compute required buffer size for idle_chks and
30 			 * grcDump for each hw function
31 			 */
32 			DP_NOTICE(edev, false,
33 				"Calculating idle_chk and grcdump register length for current engine\n");
34 			qdev->ops->common->dbg_set_debug_engine(edev,
35 								cur_engine);
36 			regs_len += REGDUMP_HEADER_SIZE +
37 				qdev->ops->common->dbg_idle_chk_size(edev) +
38 				REGDUMP_HEADER_SIZE +
39 				qdev->ops->common->dbg_idle_chk_size(edev) +
40 				REGDUMP_HEADER_SIZE +
41 				qdev->ops->common->dbg_grc_size(edev) +
42 				REGDUMP_HEADER_SIZE +
43 				qdev->ops->common->dbg_reg_fifo_size(edev) +
44 				REGDUMP_HEADER_SIZE +
45 				qdev->ops->common->dbg_protection_override_size(edev) +
46 				REGDUMP_HEADER_SIZE +
47 				qdev->ops->common->dbg_igu_fifo_size(edev) +
48 				REGDUMP_HEADER_SIZE +
49 				qdev->ops->common->dbg_fw_asserts_size(edev);
50 		}
51 		/* compute required buffer size for mcp trace and add it to the
52 		 * total required buffer size
53 		 */
54 		regs_len += REGDUMP_HEADER_SIZE +
55 			    qdev->ops->common->dbg_mcp_trace_size(edev);
56 
57 		qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
58 	}
59 	DP_NOTICE(edev, false, "Total length = %u\n", regs_len);
60 
61 	return regs_len;
62 }
63 
64 static uint32_t
65 qede_calc_regdump_header(enum debug_print_features feature, int engine,
66 			 uint32_t feature_size, uint8_t omit_engine)
67 {
68 	/* insert the engine, feature and mode inside the header and
69 	 * combine it with feature size
70 	 */
71 	return (feature_size | (feature << REGDUMP_HEADER_FEATURE_SHIFT) |
72 		(omit_engine << REGDUMP_HEADER_OMIT_ENGINE_SHIFT) |
73 		(engine << REGDUMP_HEADER_ENGINE_SHIFT));
74 }
75 
76 int qede_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs)
77 {
78 	struct qede_dev *qdev = eth_dev->data->dev_private;
79 	struct ecore_dev *edev = &qdev->edev;
80 	uint32_t *buffer = regs->data;
81 	int cur_engine, num_of_hwfns;
82 	/* '1' tells the parser to omit the engine number in the output files */
83 	uint8_t omit_engine = 0;
84 	uint8_t org_engine;
85 	uint32_t feature_size;
86 	uint32_t offset = 0;
87 
88 	if (IS_VF(edev))
89 		return -ENOTSUP;
90 
91 	if (buffer == NULL) {
92 		regs->length = qede_get_regs_len(qdev);
93 		regs->width =  sizeof(uint32_t);
94 		DP_INFO(edev, "Length %u\n", regs->length);
95 		return 0;
96 	}
97 
98 	memset(buffer, 0, regs->length);
99 	num_of_hwfns = qdev->dev_info.common.num_hwfns;
100 	if (num_of_hwfns == 1)
101 		omit_engine = 1;
102 
103 	OSAL_MUTEX_ACQUIRE(&edev->dbg_lock);
104 
105 	org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
106 	for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
107 		/* collect idle_chks and grcDump for each hw function */
108 		DP_NOTICE(edev, false, "obtaining idle_chk and grcdump for current engine\n");
109 		qdev->ops->common->dbg_set_debug_engine(edev, cur_engine);
110 
111 		/* first idle_chk */
112 		qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
113 			offset + REGDUMP_HEADER_SIZE, &feature_size);
114 		*(uint32_t *)((uint8_t *)buffer + offset) =
115 			qede_calc_regdump_header(IDLE_CHK, cur_engine,
116 						 feature_size, omit_engine);
117 		offset += (feature_size + REGDUMP_HEADER_SIZE);
118 		DP_NOTICE(edev, false, "Idle Check1 feature_size %u\n",
119 			  feature_size);
120 
121 		/* second idle_chk */
122 		qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
123 			offset + REGDUMP_HEADER_SIZE, &feature_size);
124 		*(uint32_t *)((uint8_t *)buffer + offset) =
125 			qede_calc_regdump_header(IDLE_CHK, cur_engine,
126 						 feature_size, omit_engine);
127 		offset += (feature_size + REGDUMP_HEADER_SIZE);
128 		DP_NOTICE(edev, false, "Idle Check2 feature_size %u\n",
129 			  feature_size);
130 
131 		/* reg_fifo dump */
132 		qdev->ops->common->dbg_reg_fifo(edev, (uint8_t *)buffer +
133 			offset + REGDUMP_HEADER_SIZE, &feature_size);
134 		*(uint32_t *)((uint8_t *)buffer + offset) =
135 			qede_calc_regdump_header(REG_FIFO, cur_engine,
136 						 feature_size, omit_engine);
137 		offset += (feature_size + REGDUMP_HEADER_SIZE);
138 		DP_NOTICE(edev, false, "Reg fifo feature_size %u\n",
139 			  feature_size);
140 
141 		/* igu_fifo dump */
142 		qdev->ops->common->dbg_igu_fifo(edev, (uint8_t *)buffer +
143 			offset + REGDUMP_HEADER_SIZE, &feature_size);
144 		*(uint32_t *)((uint8_t *)buffer + offset) =
145 			qede_calc_regdump_header(IGU_FIFO, cur_engine,
146 						 feature_size, omit_engine);
147 		offset += (feature_size + REGDUMP_HEADER_SIZE);
148 		DP_NOTICE(edev, false, "IGU fifo feature_size %u\n",
149 			  feature_size);
150 
151 		/* protection_override dump */
152 		qdev->ops->common->dbg_protection_override(edev,
153 							   (uint8_t *)buffer +
154 			offset + REGDUMP_HEADER_SIZE, &feature_size);
155 		*(uint32_t *)((uint8_t *)buffer + offset) =
156 		       qede_calc_regdump_header(PROTECTION_OVERRIDE, cur_engine,
157 						feature_size, omit_engine);
158 		offset += (feature_size + REGDUMP_HEADER_SIZE);
159 		DP_NOTICE(edev, false, "Protection override feature_size %u\n",
160 			  feature_size);
161 
162 		/* fw_asserts dump */
163 		qdev->ops->common->dbg_fw_asserts(edev, (uint8_t *)buffer +
164 			offset + REGDUMP_HEADER_SIZE, &feature_size);
165 		*(uint32_t *)((uint8_t *)buffer + offset) =
166 			qede_calc_regdump_header(FW_ASSERTS, cur_engine,
167 						 feature_size, omit_engine);
168 		offset += (feature_size + REGDUMP_HEADER_SIZE);
169 		DP_NOTICE(edev, false, "FW assert feature_size %u\n",
170 			  feature_size);
171 
172 		/* grc dump */
173 		qdev->ops->common->dbg_grc(edev, (uint8_t *)buffer +
174 			offset + REGDUMP_HEADER_SIZE, &feature_size);
175 		*(uint32_t *)((uint8_t *)buffer + offset) =
176 			qede_calc_regdump_header(GRC_DUMP, cur_engine,
177 						 feature_size, omit_engine);
178 		offset += (feature_size + REGDUMP_HEADER_SIZE);
179 		DP_NOTICE(edev, false, "GRC dump feature_size %u\n",
180 			  feature_size);
181 	}
182 
183 	/* mcp_trace */
184 	qdev->ops->common->dbg_mcp_trace(edev, (uint8_t *)buffer +
185 		offset + REGDUMP_HEADER_SIZE, &feature_size);
186 	*(uint32_t *)((uint8_t *)buffer + offset) =
187 		qede_calc_regdump_header(MCP_TRACE, cur_engine, feature_size,
188 					 omit_engine);
189 	offset += (feature_size + REGDUMP_HEADER_SIZE);
190 	DP_NOTICE(edev, false, "MCP trace feature_size %u\n", feature_size);
191 
192 	qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
193 
194 	OSAL_MUTEX_RELEASE(&edev->dbg_lock);
195 
196 	return 0;
197 }
198 
199 static void
200 qede_set_fw_dump_file_name(struct qede_dev *qdev)
201 {
202 	time_t ltime;
203 	struct tm *tm;
204 
205 	ltime = time(NULL);
206 	tm = localtime(&ltime);
207 	snprintf(qdev->dump_file, QEDE_FW_DUMP_FILE_SIZE,
208 		 "qede_pmd_dump_%02d-%02d-%02d_%02d-%02d-%02d.bin",
209 		 tm->tm_mon + 1, (int)tm->tm_mday, 1900 + tm->tm_year,
210 		 tm->tm_hour, tm->tm_min, tm->tm_sec);
211 }
212 
213 static int
214 qede_write_fwdump(const char *dump_file, void *dump, size_t len)
215 {
216 	int err = 0;
217 	FILE *f;
218 	size_t bytes;
219 
220 	f = fopen(dump_file, "wb+");
221 
222 	if (!f) {
223 		fprintf(stderr, "Can't open file %s: %s\n",
224 			dump_file, strerror(errno));
225 		return 1;
226 	}
227 	bytes = fwrite(dump, 1, len, f);
228 	if (bytes != len) {
229 		fprintf(stderr,
230 			"Can not write all of dump data bytes=%zd len=%zd\n",
231 			bytes, len);
232 		err = 1;
233 	}
234 
235 	if (fclose(f)) {
236 		fprintf(stderr, "Can't close file %s: %s\n",
237 			dump_file, strerror(errno));
238 		err = 1;
239 	}
240 
241 	return err;
242 }
243 
244 int
245 qede_save_fw_dump(uint16_t port_id)
246 {
247 	struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id];
248 	struct rte_dev_reg_info regs;
249 	struct qede_dev *qdev = eth_dev->data->dev_private;
250 	struct ecore_dev *edev = &qdev->edev;
251 	int rc = 0;
252 
253 	if (!rte_eth_dev_is_valid_port(port_id)) {
254 		DP_ERR(edev, "port %u invalid port ID", port_id);
255 		return -ENODEV;
256 	}
257 
258 	memset(&regs, 0, sizeof(regs));
259 	regs.length = qede_get_regs_len(qdev);
260 	regs.data = OSAL_ZALLOC(eth_dev, GFP_KERNEL, regs.length);
261 	if (regs.data) {
262 		qede_get_regs(eth_dev, &regs);
263 		qede_set_fw_dump_file_name(qdev);
264 		rc = qede_write_fwdump(qdev->dump_file, regs.data, regs.length);
265 		if (!rc)
266 			DP_NOTICE(edev, false, "FW dump written to %s file\n",
267 				  qdev->dump_file);
268 		OSAL_FREE(edev, regs.data);
269 	}
270 
271 	return rc;
272 }
273