1
2
3
4
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
15int
16qede_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
30
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
52
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
64static uint32_t
65qede_calc_regdump_header(enum debug_print_features feature, int engine,
66 uint32_t feature_size, uint8_t omit_engine)
67{
68
69
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
76int 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
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
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
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
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
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
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
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
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
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
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
199static void
200qede_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(<ime);
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
213static int
214qede_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
244int
245qede_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(®s, 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, ®s);
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