1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2012-2014, 2018-2026 Intel Corporation 4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH 5 * Copyright (C) 2015-2017 Intel Deutschland GmbH 6 */ 7 #include <linux/devcoredump.h> 8 #include "iwl-drv.h" 9 #include "runtime.h" 10 #include "dbg.h" 11 #include "debugfs.h" 12 #include "iwl-io.h" 13 #include "iwl-prph.h" 14 #include "iwl-csr.h" 15 #include "pnvm.h" 16 17 /* 18 * Note: This structure is read from the device with IO accesses, 19 * and the reading already does the endian conversion. As it is 20 * read with u32-sized accesses, any members with a different size 21 * need to be ordered correctly though! 22 */ 23 struct iwl_error_event_table { 24 u32 valid; /* (nonzero) valid, (0) log is empty */ 25 u32 error_id; /* type of error */ 26 u32 trm_hw_status0; /* TRM HW status */ 27 u32 trm_hw_status1; /* TRM HW status */ 28 u32 blink2; /* branch link */ 29 u32 ilink1; /* interrupt link */ 30 u32 ilink2; /* interrupt link */ 31 u32 data1; /* error-specific data */ 32 u32 data2; /* error-specific data */ 33 u32 data3; /* error-specific data */ 34 u32 bcon_time; /* beacon timer */ 35 u32 tsf_low; /* network timestamp function timer */ 36 u32 tsf_hi; /* network timestamp function timer */ 37 u32 gp1; /* GP1 timer register */ 38 u32 gp2; /* GP2 timer register */ 39 u32 fw_rev_type; /* firmware revision type */ 40 u32 major; /* uCode version major */ 41 u32 minor; /* uCode version minor */ 42 u32 hw_ver; /* HW Silicon version */ 43 u32 brd_ver; /* HW board version */ 44 u32 log_pc; /* log program counter */ 45 u32 frame_ptr; /* frame pointer */ 46 u32 stack_ptr; /* stack pointer */ 47 u32 hcmd; /* last host command header */ 48 u32 isr0; /* isr status register LMPM_NIC_ISR0: 49 * rxtx_flag */ 50 u32 isr1; /* isr status register LMPM_NIC_ISR1: 51 * host_flag */ 52 u32 isr2; /* isr status register LMPM_NIC_ISR2: 53 * enc_flag */ 54 u32 isr3; /* isr status register LMPM_NIC_ISR3: 55 * time_flag */ 56 u32 isr4; /* isr status register LMPM_NIC_ISR4: 57 * wico interrupt */ 58 u32 last_cmd_id; /* last HCMD id handled by the firmware */ 59 u32 wait_event; /* wait event() caller address */ 60 u32 l2p_control; /* L2pControlField */ 61 u32 l2p_duration; /* L2pDurationField */ 62 u32 l2p_mhvalid; /* L2pMhValidBits */ 63 u32 l2p_addr_match; /* L2pAddrMatchStat */ 64 u32 lmpm_pmg_sel; /* indicate which clocks are turned on 65 * (LMPM_PMG_SEL) */ 66 u32 u_timestamp; /* indicate when the date and time of the 67 * compilation */ 68 u32 flow_handler; /* FH read/write pointers, RX credit */ 69 } __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; 70 71 /* 72 * UMAC error struct - relevant starting from family 8000 chip. 73 * Note: This structure is read from the device with IO accesses, 74 * and the reading already does the endian conversion. As it is 75 * read with u32-sized accesses, any members with a different size 76 * need to be ordered correctly though! 77 */ 78 struct iwl_umac_error_event_table { 79 u32 valid; /* (nonzero) valid, (0) log is empty */ 80 u32 error_id; /* type of error */ 81 u32 blink1; /* branch link */ 82 u32 blink2; /* branch link */ 83 u32 ilink1; /* interrupt link */ 84 u32 ilink2; /* interrupt link */ 85 u32 data1; /* error-specific data */ 86 u32 data2; /* error-specific data */ 87 u32 data3; /* error-specific data */ 88 u32 umac_major; 89 u32 umac_minor; 90 u32 frame_pointer; /* core register 27*/ 91 u32 stack_pointer; /* core register 28 */ 92 u32 cmd_header; /* latest host cmd sent to UMAC */ 93 u32 nic_isr_pref; /* ISR status register */ 94 } __packed; 95 96 #define ERROR_START_OFFSET (1 * sizeof(u32)) 97 #define ERROR_ELEM_SIZE (7 * sizeof(u32)) 98 99 static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) 100 { 101 struct iwl_trans *trans = fwrt->trans; 102 struct iwl_umac_error_event_table table = {}; 103 u32 base = fwrt->trans->dbg.umac_error_event_table; 104 char pnvm_name[MAX_PNVM_NAME]; 105 106 if (!base && 107 !(fwrt->trans->dbg.error_event_table_tlv_status & 108 IWL_ERROR_EVENT_TABLE_UMAC)) 109 return; 110 111 iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); 112 113 if (table.valid) 114 fwrt->dump.umac_err_id = table.error_id; 115 116 if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { 117 IWL_ERR(trans, "Start IWL Error Log Dump:\n"); 118 IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", 119 fwrt->trans->status, table.valid); 120 } 121 122 if ((table.error_id & ~FW_SYSASSERT_CPU_MASK) == 123 FW_SYSASSERT_PNVM_MISSING) { 124 iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); 125 IWL_ERR(fwrt, "PNVM data is missing, please install %s\n", 126 pnvm_name); 127 } 128 129 IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id, 130 iwl_fw_lookup_assert_desc(table.error_id)); 131 IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2); 132 IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1); 133 IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2); 134 IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3); 135 IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header); 136 } 137 138 static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num) 139 { 140 struct iwl_trans *trans = fwrt->trans; 141 struct iwl_error_event_table table = {}; 142 u32 val, base = fwrt->trans->dbg.lmac_error_event_table[lmac_num]; 143 144 if (fwrt->cur_fw_img == IWL_UCODE_INIT) { 145 if (!base) 146 base = fwrt->fw->init_errlog_ptr; 147 } else { 148 if (!base) 149 base = fwrt->fw->inst_errlog_ptr; 150 } 151 152 if (!base) { 153 IWL_ERR(fwrt, 154 "Not valid error log pointer 0x%08X for %s uCode\n", 155 base, 156 (fwrt->cur_fw_img == IWL_UCODE_INIT) 157 ? "Init" : "RT"); 158 return; 159 } 160 161 /* check if there is a HW error */ 162 val = iwl_trans_read_mem32(trans, base); 163 if (iwl_trans_is_hw_error_value(val)) { 164 int err; 165 166 IWL_ERR(trans, "HW error, resetting before reading\n"); 167 168 /* reset the device */ 169 err = iwl_trans_sw_reset(trans); 170 if (err) 171 return; 172 173 err = iwl_trans_activate_nic(trans); 174 if (err) 175 return; 176 } 177 178 iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); 179 180 if (table.valid) 181 fwrt->dump.lmac_err_id[lmac_num] = table.error_id; 182 183 if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { 184 IWL_ERR(trans, "Start IWL Error Log Dump:\n"); 185 IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", 186 fwrt->trans->status, table.valid); 187 } 188 189 /* Do not change this output - scripts rely on it */ 190 191 IWL_ERR(fwrt, "Loaded firmware version: %s\n", fwrt->fw->fw_version); 192 193 IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id, 194 iwl_fw_lookup_assert_desc(table.error_id)); 195 IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2); 196 IWL_ERR(fwrt, "0x%08X | data1\n", table.data1); 197 IWL_ERR(fwrt, "0x%08X | data2\n", table.data2); 198 IWL_ERR(fwrt, "0x%08X | data3\n", table.data3); 199 } 200 201 /* 202 * TCM error struct. 203 * Note: This structure is read from the device with IO accesses, 204 * and the reading already does the endian conversion. As it is 205 * read with u32-sized accesses, any members with a different size 206 * need to be ordered correctly though! 207 */ 208 struct iwl_tcm_error_event_table { 209 u32 valid; 210 u32 error_id; 211 u32 blink2; 212 u32 ilink1; 213 u32 ilink2; 214 u32 data1, data2, data3; 215 u32 logpc; 216 u32 frame_pointer; 217 u32 stack_pointer; 218 u32 msgid; 219 u32 isr; 220 u32 hw_status[5]; 221 u32 sw_status[1]; 222 u32 reserved[4]; 223 } __packed; /* TCM_LOG_ERROR_TABLE_API_S_VER_1 */ 224 225 static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt, int idx) 226 { 227 struct iwl_trans *trans = fwrt->trans; 228 struct iwl_tcm_error_event_table table = {}; 229 u32 base = fwrt->trans->dbg.tcm_error_event_table[idx]; 230 u32 flag = idx ? IWL_ERROR_EVENT_TABLE_TCM2 : 231 IWL_ERROR_EVENT_TABLE_TCM1; 232 233 if (!base || !(fwrt->trans->dbg.error_event_table_tlv_status & flag)) 234 return; 235 236 iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); 237 238 IWL_ERR(fwrt, "TCM%d status:\n", idx + 1); 239 IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); 240 IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2); 241 IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1); 242 IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2); 243 IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3); 244 } 245 246 /* 247 * RCM error struct. 248 * Note: This structure is read from the device with IO accesses, 249 * and the reading already does the endian conversion. As it is 250 * read with u32-sized accesses, any members with a different size 251 * need to be ordered correctly though! 252 */ 253 struct iwl_rcm_error_event_table { 254 u32 valid; 255 u32 error_id; 256 u32 blink2; 257 u32 ilink1; 258 u32 ilink2; 259 u32 data1, data2, data3; 260 u32 logpc; 261 u32 frame_pointer; 262 u32 stack_pointer; 263 u32 msgid; 264 u32 isr; 265 u32 frame_hw_status; 266 u32 mbx_lmac_to_rcm_req; 267 u32 mbx_rcm_to_lmac_req; 268 u32 mh_ctl; 269 u32 mh_addr1_lo; 270 u32 mh_info; 271 u32 mh_err; 272 u32 reserved[3]; 273 } __packed; /* RCM_LOG_ERROR_TABLE_API_S_VER_1 */ 274 275 static void iwl_fwrt_dump_rcm_error_log(struct iwl_fw_runtime *fwrt, int idx) 276 { 277 struct iwl_trans *trans = fwrt->trans; 278 struct iwl_rcm_error_event_table table = {}; 279 u32 base = fwrt->trans->dbg.rcm_error_event_table[idx]; 280 u32 flag = idx ? IWL_ERROR_EVENT_TABLE_RCM2 : 281 IWL_ERROR_EVENT_TABLE_RCM1; 282 283 if (!base || !(fwrt->trans->dbg.error_event_table_tlv_status & flag)) 284 return; 285 286 iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); 287 288 IWL_ERR(fwrt, "RCM%d status:\n", idx + 1); 289 IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); 290 IWL_ERR(fwrt, "0x%08X | rcm interruptlink2\n", table.ilink2); 291 IWL_ERR(fwrt, "0x%08X | rcm data1\n", table.data1); 292 IWL_ERR(fwrt, "0x%08X | rcm data2\n", table.data2); 293 IWL_ERR(fwrt, "0x%08X | rcm data3\n", table.data3); 294 } 295 296 static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) 297 { 298 struct iwl_trans *trans = fwrt->trans; 299 u32 error, data1; 300 301 if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { 302 error = UMAG_SB_CPU_2_STATUS; 303 data1 = UMAG_SB_CPU_1_STATUS; 304 } else if (fwrt->trans->mac_cfg->device_family >= 305 IWL_DEVICE_FAMILY_8000) { 306 error = SB_CPU_2_STATUS; 307 data1 = SB_CPU_1_STATUS; 308 } else { 309 return; 310 } 311 312 error = iwl_read_umac_prph(trans, error); 313 314 IWL_ERR(trans, "IML/ROM dump:\n"); 315 316 if (error & 0xFFFF0000) 317 IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16); 318 319 IWL_ERR(fwrt, "0x%08X | IML/ROM error/state\n", error); 320 IWL_ERR(fwrt, "0x%08X | IML/ROM data1\n", 321 iwl_read_umac_prph(trans, data1)); 322 323 if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000) 324 IWL_ERR(fwrt, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n", 325 iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); 326 } 327 328 #define FSEQ_REG(x) { .addr = (x), .str = #x, } 329 330 static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt) 331 { 332 struct iwl_trans *trans = fwrt->trans; 333 int i; 334 struct { 335 u32 addr; 336 const char *str; 337 } fseq_regs[] = { 338 FSEQ_REG(FSEQ_ERROR_CODE), 339 FSEQ_REG(FSEQ_TOP_INIT_VERSION), 340 FSEQ_REG(FSEQ_CNVIO_INIT_VERSION), 341 FSEQ_REG(FSEQ_OTP_VERSION), 342 FSEQ_REG(FSEQ_TOP_CONTENT_VERSION), 343 FSEQ_REG(FSEQ_ALIVE_TOKEN), 344 FSEQ_REG(FSEQ_CNVI_ID), 345 FSEQ_REG(FSEQ_CNVR_ID), 346 FSEQ_REG(CNVI_AUX_MISC_CHIP), 347 FSEQ_REG(CNVR_AUX_MISC_CHIP), 348 FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), 349 FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), 350 FSEQ_REG(FSEQ_PREV_CNVIO_INIT_VERSION), 351 FSEQ_REG(FSEQ_WIFI_FSEQ_VERSION), 352 FSEQ_REG(FSEQ_BT_FSEQ_VERSION), 353 FSEQ_REG(FSEQ_CLASS_TP_VERSION), 354 }; 355 356 if (!iwl_trans_grab_nic_access(trans)) 357 return; 358 359 IWL_ERR(fwrt, "Fseq Registers:\n"); 360 361 for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) 362 IWL_ERR(fwrt, "0x%08X | %s\n", 363 iwl_read_prph_no_grab(trans, fseq_regs[i].addr), 364 fseq_regs[i].str); 365 366 iwl_trans_release_nic_access(trans); 367 } 368 369 void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) 370 { 371 struct iwl_pc_data *pc_data; 372 u8 count; 373 374 if (!iwl_trans_device_enabled(fwrt->trans)) { 375 IWL_ERR(fwrt, 376 "DEVICE_ENABLED bit is not set. Aborting dump.\n"); 377 return; 378 } 379 380 iwl_fwrt_dump_lmac_error_log(fwrt, 0); 381 if (fwrt->trans->dbg.lmac_error_event_table[1]) 382 iwl_fwrt_dump_lmac_error_log(fwrt, 1); 383 iwl_fwrt_dump_umac_error_log(fwrt); 384 iwl_fwrt_dump_tcm_error_log(fwrt, 0); 385 iwl_fwrt_dump_rcm_error_log(fwrt, 0); 386 if (fwrt->trans->dbg.tcm_error_event_table[1]) 387 iwl_fwrt_dump_tcm_error_log(fwrt, 1); 388 if (fwrt->trans->dbg.rcm_error_event_table[1]) 389 iwl_fwrt_dump_rcm_error_log(fwrt, 1); 390 iwl_fwrt_dump_iml_error_log(fwrt); 391 iwl_fwrt_dump_fseq_regs(fwrt); 392 if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { 393 pc_data = fwrt->trans->dbg.pc_data; 394 395 if (!iwl_trans_grab_nic_access(fwrt->trans)) 396 return; 397 for (count = 0; count < fwrt->trans->dbg.num_pc; 398 count++, pc_data++) 399 IWL_ERR(fwrt, "%s: 0x%x\n", 400 pc_data->pc_name, 401 iwl_read_prph_no_grab(fwrt->trans, 402 pc_data->pc_address)); 403 iwl_trans_release_nic_access(fwrt->trans); 404 } 405 406 if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { 407 u32 scratch = iwl_read32(fwrt->trans, CSR_FUNC_SCRATCH); 408 409 IWL_ERR(fwrt, "Function Scratch status:\n"); 410 IWL_ERR(fwrt, "0x%08X | Func Scratch\n", scratch); 411 } 412 } 413 IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs); 414 415 bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id) 416 { 417 struct error_table_start { 418 /* cf. struct iwl_error_event_table */ 419 u32 valid; 420 __le32 err_id; 421 } err_info = {}; 422 int ret; 423 424 if (err_id) 425 *err_id = 0; 426 427 if (!base) 428 return false; 429 430 ret = iwl_trans_read_mem_bytes(trans, base, 431 &err_info, sizeof(err_info)); 432 433 if (ret) 434 return true; 435 436 if (err_info.valid && err_id) 437 *err_id = le32_to_cpu(err_info.err_id); 438 439 return !!err_info.valid; 440 } 441 IWL_EXPORT_SYMBOL(iwl_fwrt_read_err_table); 442