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(<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 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(®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