Branch data Line data Source code
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 : 0 : qede_get_regs_len(struct qede_dev *qdev)
17 : : {
18 : 0 : struct ecore_dev *edev = &qdev->edev;
19 : : int cur_engine, num_of_hwfns, regs_len = 0;
20 : : uint8_t org_engine;
21 : :
22 [ # # ]: 0 : if (IS_VF(edev))
23 : : return 0;
24 : :
25 [ # # # # ]: 0 : if (qdev->ops && qdev->ops->common) {
26 : 0 : num_of_hwfns = qdev->dev_info.common.num_hwfns;
27 : 0 : org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
28 [ # # ]: 0 : 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 : 0 : DP_NOTICE(edev, false,
33 : : "Calculating idle_chk and grcdump register length for current engine\n");
34 : 0 : qdev->ops->common->dbg_set_debug_engine(edev,
35 : : cur_engine);
36 : 0 : regs_len += REGDUMP_HEADER_SIZE +
37 : 0 : qdev->ops->common->dbg_idle_chk_size(edev) +
38 : 0 : REGDUMP_HEADER_SIZE +
39 : 0 : qdev->ops->common->dbg_idle_chk_size(edev) +
40 : 0 : REGDUMP_HEADER_SIZE +
41 : 0 : qdev->ops->common->dbg_grc_size(edev) +
42 : 0 : REGDUMP_HEADER_SIZE +
43 : 0 : qdev->ops->common->dbg_reg_fifo_size(edev) +
44 : 0 : REGDUMP_HEADER_SIZE +
45 : 0 : qdev->ops->common->dbg_protection_override_size(edev) +
46 : 0 : REGDUMP_HEADER_SIZE +
47 : 0 : qdev->ops->common->dbg_igu_fifo_size(edev) +
48 : 0 : REGDUMP_HEADER_SIZE +
49 : 0 : 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 : 0 : regs_len += REGDUMP_HEADER_SIZE +
55 : 0 : qdev->ops->common->dbg_mcp_trace_size(edev);
56 : :
57 : 0 : qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
58 : : }
59 : 0 : DP_NOTICE(edev, false, "Total length = %u\n", regs_len);
60 : :
61 : 0 : 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 : 0 : return (feature_size | (feature << REGDUMP_HEADER_FEATURE_SHIFT) |
72 : 0 : (omit_engine << REGDUMP_HEADER_OMIT_ENGINE_SHIFT) |
73 : 0 : (engine << REGDUMP_HEADER_ENGINE_SHIFT));
74 : : }
75 : :
76 : 0 : int qede_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs)
77 : : {
78 : 0 : struct qede_dev *qdev = eth_dev->data->dev_private;
79 : 0 : struct ecore_dev *edev = &qdev->edev;
80 : 0 : 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 [ # # ]: 0 : if (IS_VF(edev))
89 : : return -ENOTSUP;
90 : :
91 [ # # ]: 0 : if (buffer == NULL) {
92 : 0 : regs->length = qede_get_regs_len(qdev);
93 : 0 : regs->width = sizeof(uint32_t);
94 : 0 : DP_INFO(edev, "Length %u\n", regs->length);
95 : 0 : return 0;
96 : : }
97 : :
98 [ # # ]: 0 : memset(buffer, 0, regs->length);
99 : 0 : num_of_hwfns = qdev->dev_info.common.num_hwfns;
100 [ # # ]: 0 : if (num_of_hwfns == 1)
101 : : omit_engine = 1;
102 : :
103 : 0 : OSAL_MUTEX_ACQUIRE(&edev->dbg_lock);
104 : :
105 : 0 : org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
106 [ # # ]: 0 : for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
107 : : /* collect idle_chks and grcDump for each hw function */
108 : 0 : DP_NOTICE(edev, false, "obtaining idle_chk and grcdump for current engine\n");
109 : 0 : qdev->ops->common->dbg_set_debug_engine(edev, cur_engine);
110 : :
111 : : /* first idle_chk */
112 : 0 : qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
113 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
114 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
115 : 0 : qede_calc_regdump_header(IDLE_CHK, cur_engine,
116 : : feature_size, omit_engine);
117 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
118 : 0 : DP_NOTICE(edev, false, "Idle Check1 feature_size %u\n",
119 : : feature_size);
120 : :
121 : : /* second idle_chk */
122 : 0 : qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
123 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
124 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
125 : 0 : qede_calc_regdump_header(IDLE_CHK, cur_engine,
126 : : feature_size, omit_engine);
127 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
128 : 0 : DP_NOTICE(edev, false, "Idle Check2 feature_size %u\n",
129 : : feature_size);
130 : :
131 : : /* reg_fifo dump */
132 : 0 : qdev->ops->common->dbg_reg_fifo(edev, (uint8_t *)buffer +
133 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
134 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
135 : 0 : qede_calc_regdump_header(REG_FIFO, cur_engine,
136 : : feature_size, omit_engine);
137 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
138 : 0 : DP_NOTICE(edev, false, "Reg fifo feature_size %u\n",
139 : : feature_size);
140 : :
141 : : /* igu_fifo dump */
142 : 0 : qdev->ops->common->dbg_igu_fifo(edev, (uint8_t *)buffer +
143 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
144 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
145 : 0 : qede_calc_regdump_header(IGU_FIFO, cur_engine,
146 : : feature_size, omit_engine);
147 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
148 : 0 : DP_NOTICE(edev, false, "IGU fifo feature_size %u\n",
149 : : feature_size);
150 : :
151 : : /* protection_override dump */
152 : 0 : qdev->ops->common->dbg_protection_override(edev,
153 : : (uint8_t *)buffer +
154 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
155 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
156 : 0 : qede_calc_regdump_header(PROTECTION_OVERRIDE, cur_engine,
157 : : feature_size, omit_engine);
158 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
159 : 0 : DP_NOTICE(edev, false, "Protection override feature_size %u\n",
160 : : feature_size);
161 : :
162 : : /* fw_asserts dump */
163 : 0 : qdev->ops->common->dbg_fw_asserts(edev, (uint8_t *)buffer +
164 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
165 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
166 : 0 : qede_calc_regdump_header(FW_ASSERTS, cur_engine,
167 : : feature_size, omit_engine);
168 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
169 : 0 : DP_NOTICE(edev, false, "FW assert feature_size %u\n",
170 : : feature_size);
171 : :
172 : : /* grc dump */
173 : 0 : qdev->ops->common->dbg_grc(edev, (uint8_t *)buffer +
174 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
175 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
176 : 0 : qede_calc_regdump_header(GRC_DUMP, cur_engine,
177 : : feature_size, omit_engine);
178 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
179 : 0 : DP_NOTICE(edev, false, "GRC dump feature_size %u\n",
180 : : feature_size);
181 : : }
182 : :
183 : : /* mcp_trace */
184 : 0 : qdev->ops->common->dbg_mcp_trace(edev, (uint8_t *)buffer +
185 : 0 : offset + REGDUMP_HEADER_SIZE, &feature_size);
186 : 0 : *(uint32_t *)((uint8_t *)buffer + offset) =
187 : 0 : qede_calc_regdump_header(MCP_TRACE, cur_engine, feature_size,
188 : : omit_engine);
189 : 0 : offset += (feature_size + REGDUMP_HEADER_SIZE);
190 : 0 : DP_NOTICE(edev, false, "MCP trace feature_size %u\n", feature_size);
191 : :
192 : 0 : qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
193 : :
194 : 0 : OSAL_MUTEX_RELEASE(&edev->dbg_lock);
195 : :
196 : 0 : return 0;
197 : : }
198 : :
199 : : static void
200 : 0 : qede_set_fw_dump_file_name(struct qede_dev *qdev)
201 : : {
202 : : time_t ltime;
203 : : struct tm *tm;
204 : :
205 : 0 : ltime = time(NULL);
206 : 0 : tm = localtime(<ime);
207 : 0 : snprintf(qdev->dump_file, QEDE_FW_DUMP_FILE_SIZE,
208 : : "qede_pmd_dump_%02d-%02d-%02d_%02d-%02d-%02d.bin",
209 : 0 : tm->tm_mon + 1, (int)tm->tm_mday, 1900 + tm->tm_year,
210 : : tm->tm_hour, tm->tm_min, tm->tm_sec);
211 : 0 : }
212 : :
213 : : static int
214 : 0 : 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 : 0 : f = fopen(dump_file, "wb+");
221 : :
222 [ # # ]: 0 : if (!f) {
223 : 0 : fprintf(stderr, "Can't open file %s: %s\n",
224 : 0 : dump_file, strerror(errno));
225 : 0 : return 1;
226 : : }
227 : 0 : bytes = fwrite(dump, 1, len, f);
228 [ # # ]: 0 : if (bytes != len) {
229 : 0 : fprintf(stderr,
230 : : "Can not write all of dump data bytes=%zd len=%zd\n",
231 : : bytes, len);
232 : : err = 1;
233 : : }
234 : :
235 [ # # ]: 0 : if (fclose(f)) {
236 : 0 : fprintf(stderr, "Can't close file %s: %s\n",
237 : 0 : dump_file, strerror(errno));
238 : : err = 1;
239 : : }
240 : :
241 : : return err;
242 : : }
243 : :
244 : : int
245 : 0 : qede_save_fw_dump(uint16_t port_id)
246 : : {
247 : 0 : struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id];
248 : : struct rte_dev_reg_info regs;
249 : 0 : struct qede_dev *qdev = eth_dev->data->dev_private;
250 : : struct ecore_dev *edev = &qdev->edev;
251 : : int rc = 0;
252 : :
253 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(port_id)) {
254 : 0 : DP_ERR(edev, "port %u invalid port ID", port_id);
255 : 0 : return -ENODEV;
256 : : }
257 : :
258 : : memset(®s, 0, sizeof(regs));
259 : 0 : regs.length = qede_get_regs_len(qdev);
260 : 0 : regs.data = OSAL_ZALLOC(eth_dev, GFP_KERNEL, regs.length);
261 [ # # ]: 0 : if (regs.data) {
262 : 0 : qede_get_regs(eth_dev, ®s);
263 : 0 : qede_set_fw_dump_file_name(qdev);
264 : 0 : rc = qede_write_fwdump(qdev->dump_file, regs.data, regs.length);
265 [ # # ]: 0 : if (!rc)
266 : 0 : DP_NOTICE(edev, false, "FW dump written to %s file\n",
267 : : qdev->dump_file);
268 : 0 : OSAL_FREE(edev, regs.data);
269 : : }
270 : :
271 : : return rc;
272 : : }
|