net/qede: support registers dump
[dpdk.git] / drivers / net / qede / qede_regs.c
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(uint8_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 }