Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
0004  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
0005  * Copyright (C) 2015-2017 Intel Deutschland GmbH
0006  */
0007 #include <linux/devcoredump.h>
0008 #include "iwl-drv.h"
0009 #include "runtime.h"
0010 #include "dbg.h"
0011 #include "debugfs.h"
0012 #include "iwl-io.h"
0013 #include "iwl-prph.h"
0014 #include "iwl-csr.h"
0015 #include "pnvm.h"
0016 
0017 /*
0018  * Note: This structure is read from the device with IO accesses,
0019  * and the reading already does the endian conversion. As it is
0020  * read with u32-sized accesses, any members with a different size
0021  * need to be ordered correctly though!
0022  */
0023 struct iwl_error_event_table {
0024     u32 valid;      /* (nonzero) valid, (0) log is empty */
0025     u32 error_id;       /* type of error */
0026     u32 trm_hw_status0; /* TRM HW status */
0027     u32 trm_hw_status1; /* TRM HW status */
0028     u32 blink2;     /* branch link */
0029     u32 ilink1;     /* interrupt link */
0030     u32 ilink2;     /* interrupt link */
0031     u32 data1;      /* error-specific data */
0032     u32 data2;      /* error-specific data */
0033     u32 data3;      /* error-specific data */
0034     u32 bcon_time;      /* beacon timer */
0035     u32 tsf_low;        /* network timestamp function timer */
0036     u32 tsf_hi;     /* network timestamp function timer */
0037     u32 gp1;        /* GP1 timer register */
0038     u32 gp2;        /* GP2 timer register */
0039     u32 fw_rev_type;    /* firmware revision type */
0040     u32 major;      /* uCode version major */
0041     u32 minor;      /* uCode version minor */
0042     u32 hw_ver;     /* HW Silicon version */
0043     u32 brd_ver;        /* HW board version */
0044     u32 log_pc;     /* log program counter */
0045     u32 frame_ptr;      /* frame pointer */
0046     u32 stack_ptr;      /* stack pointer */
0047     u32 hcmd;       /* last host command header */
0048     u32 isr0;       /* isr status register LMPM_NIC_ISR0:
0049                  * rxtx_flag */
0050     u32 isr1;       /* isr status register LMPM_NIC_ISR1:
0051                  * host_flag */
0052     u32 isr2;       /* isr status register LMPM_NIC_ISR2:
0053                  * enc_flag */
0054     u32 isr3;       /* isr status register LMPM_NIC_ISR3:
0055                  * time_flag */
0056     u32 isr4;       /* isr status register LMPM_NIC_ISR4:
0057                  * wico interrupt */
0058     u32 last_cmd_id;    /* last HCMD id handled by the firmware */
0059     u32 wait_event;     /* wait event() caller address */
0060     u32 l2p_control;    /* L2pControlField */
0061     u32 l2p_duration;   /* L2pDurationField */
0062     u32 l2p_mhvalid;    /* L2pMhValidBits */
0063     u32 l2p_addr_match; /* L2pAddrMatchStat */
0064     u32 lmpm_pmg_sel;   /* indicate which clocks are turned on
0065                  * (LMPM_PMG_SEL) */
0066     u32 u_timestamp;    /* indicate when the date and time of the
0067                  * compilation */
0068     u32 flow_handler;   /* FH read/write pointers, RX credit */
0069 } __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;
0070 
0071 /*
0072  * UMAC error struct - relevant starting from family 8000 chip.
0073  * Note: This structure is read from the device with IO accesses,
0074  * and the reading already does the endian conversion. As it is
0075  * read with u32-sized accesses, any members with a different size
0076  * need to be ordered correctly though!
0077  */
0078 struct iwl_umac_error_event_table {
0079     u32 valid;      /* (nonzero) valid, (0) log is empty */
0080     u32 error_id;       /* type of error */
0081     u32 blink1;     /* branch link */
0082     u32 blink2;     /* branch link */
0083     u32 ilink1;     /* interrupt link */
0084     u32 ilink2;     /* interrupt link */
0085     u32 data1;      /* error-specific data */
0086     u32 data2;      /* error-specific data */
0087     u32 data3;      /* error-specific data */
0088     u32 umac_major;
0089     u32 umac_minor;
0090     u32 frame_pointer;  /* core register 27*/
0091     u32 stack_pointer;  /* core register 28 */
0092     u32 cmd_header;     /* latest host cmd sent to UMAC */
0093     u32 nic_isr_pref;   /* ISR status register */
0094 } __packed;
0095 
0096 #define ERROR_START_OFFSET  (1 * sizeof(u32))
0097 #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
0098 
0099 static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt)
0100 {
0101     struct iwl_trans *trans = fwrt->trans;
0102     struct iwl_umac_error_event_table table = {};
0103     u32 base = fwrt->trans->dbg.umac_error_event_table;
0104     char pnvm_name[MAX_PNVM_NAME];
0105 
0106     if (!base &&
0107         !(fwrt->trans->dbg.error_event_table_tlv_status &
0108           IWL_ERROR_EVENT_TABLE_UMAC))
0109         return;
0110 
0111     iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
0112 
0113     if (table.valid)
0114         fwrt->dump.umac_err_id = table.error_id;
0115 
0116     if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
0117         IWL_ERR(trans, "Start IWL Error Log Dump:\n");
0118         IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
0119             fwrt->trans->status, table.valid);
0120     }
0121 
0122     if ((table.error_id & ~FW_SYSASSERT_CPU_MASK) ==
0123         FW_SYSASSERT_PNVM_MISSING) {
0124         iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name));
0125         IWL_ERR(fwrt, "PNVM data is missing, please install %s\n",
0126             pnvm_name);
0127     }
0128 
0129     IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id,
0130         iwl_fw_lookup_assert_desc(table.error_id));
0131     IWL_ERR(fwrt, "0x%08X | umac branchlink1\n", table.blink1);
0132     IWL_ERR(fwrt, "0x%08X | umac branchlink2\n", table.blink2);
0133     IWL_ERR(fwrt, "0x%08X | umac interruptlink1\n", table.ilink1);
0134     IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2);
0135     IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1);
0136     IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2);
0137     IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3);
0138     IWL_ERR(fwrt, "0x%08X | umac major\n", table.umac_major);
0139     IWL_ERR(fwrt, "0x%08X | umac minor\n", table.umac_minor);
0140     IWL_ERR(fwrt, "0x%08X | frame pointer\n", table.frame_pointer);
0141     IWL_ERR(fwrt, "0x%08X | stack pointer\n", table.stack_pointer);
0142     IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header);
0143     IWL_ERR(fwrt, "0x%08X | isr status reg\n", table.nic_isr_pref);
0144 }
0145 
0146 static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num)
0147 {
0148     struct iwl_trans *trans = fwrt->trans;
0149     struct iwl_error_event_table table = {};
0150     u32 val, base = fwrt->trans->dbg.lmac_error_event_table[lmac_num];
0151 
0152     if (fwrt->cur_fw_img == IWL_UCODE_INIT) {
0153         if (!base)
0154             base = fwrt->fw->init_errlog_ptr;
0155     } else {
0156         if (!base)
0157             base = fwrt->fw->inst_errlog_ptr;
0158     }
0159 
0160     if (base < 0x400000) {
0161         IWL_ERR(fwrt,
0162             "Not valid error log pointer 0x%08X for %s uCode\n",
0163             base,
0164             (fwrt->cur_fw_img == IWL_UCODE_INIT)
0165             ? "Init" : "RT");
0166         return;
0167     }
0168 
0169     /* check if there is a HW error */
0170     val = iwl_trans_read_mem32(trans, base);
0171     if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) {
0172         int err;
0173 
0174         IWL_ERR(trans, "HW error, resetting before reading\n");
0175 
0176         /* reset the device */
0177         err = iwl_trans_sw_reset(trans, true);
0178         if (err)
0179             return;
0180 
0181         err = iwl_finish_nic_init(trans);
0182         if (err)
0183             return;
0184     }
0185 
0186     iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
0187 
0188     if (table.valid)
0189         fwrt->dump.lmac_err_id[lmac_num] = table.error_id;
0190 
0191     if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
0192         IWL_ERR(trans, "Start IWL Error Log Dump:\n");
0193         IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
0194             fwrt->trans->status, table.valid);
0195     }
0196 
0197     /* Do not change this output - scripts rely on it */
0198 
0199     IWL_ERR(fwrt, "Loaded firmware version: %s\n", fwrt->fw->fw_version);
0200 
0201     IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id,
0202         iwl_fw_lookup_assert_desc(table.error_id));
0203     IWL_ERR(fwrt, "0x%08X | trm_hw_status0\n", table.trm_hw_status0);
0204     IWL_ERR(fwrt, "0x%08X | trm_hw_status1\n", table.trm_hw_status1);
0205     IWL_ERR(fwrt, "0x%08X | branchlink2\n", table.blink2);
0206     IWL_ERR(fwrt, "0x%08X | interruptlink1\n", table.ilink1);
0207     IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2);
0208     IWL_ERR(fwrt, "0x%08X | data1\n", table.data1);
0209     IWL_ERR(fwrt, "0x%08X | data2\n", table.data2);
0210     IWL_ERR(fwrt, "0x%08X | data3\n", table.data3);
0211     IWL_ERR(fwrt, "0x%08X | beacon time\n", table.bcon_time);
0212     IWL_ERR(fwrt, "0x%08X | tsf low\n", table.tsf_low);
0213     IWL_ERR(fwrt, "0x%08X | tsf hi\n", table.tsf_hi);
0214     IWL_ERR(fwrt, "0x%08X | time gp1\n", table.gp1);
0215     IWL_ERR(fwrt, "0x%08X | time gp2\n", table.gp2);
0216     IWL_ERR(fwrt, "0x%08X | uCode revision type\n", table.fw_rev_type);
0217     IWL_ERR(fwrt, "0x%08X | uCode version major\n", table.major);
0218     IWL_ERR(fwrt, "0x%08X | uCode version minor\n", table.minor);
0219     IWL_ERR(fwrt, "0x%08X | hw version\n", table.hw_ver);
0220     IWL_ERR(fwrt, "0x%08X | board version\n", table.brd_ver);
0221     IWL_ERR(fwrt, "0x%08X | hcmd\n", table.hcmd);
0222     IWL_ERR(fwrt, "0x%08X | isr0\n", table.isr0);
0223     IWL_ERR(fwrt, "0x%08X | isr1\n", table.isr1);
0224     IWL_ERR(fwrt, "0x%08X | isr2\n", table.isr2);
0225     IWL_ERR(fwrt, "0x%08X | isr3\n", table.isr3);
0226     IWL_ERR(fwrt, "0x%08X | isr4\n", table.isr4);
0227     IWL_ERR(fwrt, "0x%08X | last cmd Id\n", table.last_cmd_id);
0228     IWL_ERR(fwrt, "0x%08X | wait_event\n", table.wait_event);
0229     IWL_ERR(fwrt, "0x%08X | l2p_control\n", table.l2p_control);
0230     IWL_ERR(fwrt, "0x%08X | l2p_duration\n", table.l2p_duration);
0231     IWL_ERR(fwrt, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
0232     IWL_ERR(fwrt, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
0233     IWL_ERR(fwrt, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
0234     IWL_ERR(fwrt, "0x%08X | timestamp\n", table.u_timestamp);
0235     IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler);
0236 }
0237 
0238 /*
0239  * TCM error struct.
0240  * Note: This structure is read from the device with IO accesses,
0241  * and the reading already does the endian conversion. As it is
0242  * read with u32-sized accesses, any members with a different size
0243  * need to be ordered correctly though!
0244  */
0245 struct iwl_tcm_error_event_table {
0246     u32 valid;
0247     u32 error_id;
0248     u32 blink2;
0249     u32 ilink1;
0250     u32 ilink2;
0251     u32 data1, data2, data3;
0252     u32 logpc;
0253     u32 frame_pointer;
0254     u32 stack_pointer;
0255     u32 msgid;
0256     u32 isr;
0257     u32 hw_status[5];
0258     u32 sw_status[1];
0259     u32 reserved[4];
0260 } __packed; /* TCM_LOG_ERROR_TABLE_API_S_VER_1 */
0261 
0262 static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt, int idx)
0263 {
0264     struct iwl_trans *trans = fwrt->trans;
0265     struct iwl_tcm_error_event_table table = {};
0266     u32 base = fwrt->trans->dbg.tcm_error_event_table[idx];
0267     int i;
0268     u32 flag = idx ? IWL_ERROR_EVENT_TABLE_TCM2 :
0269              IWL_ERROR_EVENT_TABLE_TCM1;
0270 
0271     if (!base || !(fwrt->trans->dbg.error_event_table_tlv_status & flag))
0272         return;
0273 
0274     iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
0275 
0276     IWL_ERR(fwrt, "TCM%d status:\n", idx + 1);
0277     IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id);
0278     IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2);
0279     IWL_ERR(fwrt, "0x%08X | tcm interruptlink1\n", table.ilink1);
0280     IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2);
0281     IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1);
0282     IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2);
0283     IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3);
0284     IWL_ERR(fwrt, "0x%08X | tcm log PC\n", table.logpc);
0285     IWL_ERR(fwrt, "0x%08X | tcm frame pointer\n", table.frame_pointer);
0286     IWL_ERR(fwrt, "0x%08X | tcm stack pointer\n", table.stack_pointer);
0287     IWL_ERR(fwrt, "0x%08X | tcm msg ID\n", table.msgid);
0288     IWL_ERR(fwrt, "0x%08X | tcm ISR status\n", table.isr);
0289     for (i = 0; i < ARRAY_SIZE(table.hw_status); i++)
0290         IWL_ERR(fwrt, "0x%08X | tcm HW status[%d]\n",
0291             table.hw_status[i], i);
0292     for (i = 0; i < ARRAY_SIZE(table.sw_status); i++)
0293         IWL_ERR(fwrt, "0x%08X | tcm SW status[%d]\n",
0294             table.sw_status[i], i);
0295 }
0296 
0297 /*
0298  * RCM error struct.
0299  * Note: This structure is read from the device with IO accesses,
0300  * and the reading already does the endian conversion. As it is
0301  * read with u32-sized accesses, any members with a different size
0302  * need to be ordered correctly though!
0303  */
0304 struct iwl_rcm_error_event_table {
0305     u32 valid;
0306     u32 error_id;
0307     u32 blink2;
0308     u32 ilink1;
0309     u32 ilink2;
0310     u32 data1, data2, data3;
0311     u32 logpc;
0312     u32 frame_pointer;
0313     u32 stack_pointer;
0314     u32 msgid;
0315     u32 isr;
0316     u32 frame_hw_status;
0317     u32 mbx_lmac_to_rcm_req;
0318     u32 mbx_rcm_to_lmac_req;
0319     u32 mh_ctl;
0320     u32 mh_addr1_lo;
0321     u32 mh_info;
0322     u32 mh_err;
0323     u32 reserved[3];
0324 } __packed; /* RCM_LOG_ERROR_TABLE_API_S_VER_1 */
0325 
0326 static void iwl_fwrt_dump_rcm_error_log(struct iwl_fw_runtime *fwrt, int idx)
0327 {
0328     struct iwl_trans *trans = fwrt->trans;
0329     struct iwl_rcm_error_event_table table = {};
0330     u32 base = fwrt->trans->dbg.rcm_error_event_table[idx];
0331     u32 flag = idx ? IWL_ERROR_EVENT_TABLE_RCM2 :
0332              IWL_ERROR_EVENT_TABLE_RCM1;
0333 
0334     if (!base || !(fwrt->trans->dbg.error_event_table_tlv_status & flag))
0335         return;
0336 
0337     iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
0338 
0339     IWL_ERR(fwrt, "RCM%d status:\n", idx + 1);
0340     IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id);
0341     IWL_ERR(fwrt, "0x%08X | rcm branchlink2\n", table.blink2);
0342     IWL_ERR(fwrt, "0x%08X | rcm interruptlink1\n", table.ilink1);
0343     IWL_ERR(fwrt, "0x%08X | rcm interruptlink2\n", table.ilink2);
0344     IWL_ERR(fwrt, "0x%08X | rcm data1\n", table.data1);
0345     IWL_ERR(fwrt, "0x%08X | rcm data2\n", table.data2);
0346     IWL_ERR(fwrt, "0x%08X | rcm data3\n", table.data3);
0347     IWL_ERR(fwrt, "0x%08X | rcm log PC\n", table.logpc);
0348     IWL_ERR(fwrt, "0x%08X | rcm frame pointer\n", table.frame_pointer);
0349     IWL_ERR(fwrt, "0x%08X | rcm stack pointer\n", table.stack_pointer);
0350     IWL_ERR(fwrt, "0x%08X | rcm msg ID\n", table.msgid);
0351     IWL_ERR(fwrt, "0x%08X | rcm ISR status\n", table.isr);
0352     IWL_ERR(fwrt, "0x%08X | frame HW status\n", table.frame_hw_status);
0353     IWL_ERR(fwrt, "0x%08X | LMAC-to-RCM request mbox\n",
0354         table.mbx_lmac_to_rcm_req);
0355     IWL_ERR(fwrt, "0x%08X | RCM-to-LMAC request mbox\n",
0356         table.mbx_rcm_to_lmac_req);
0357     IWL_ERR(fwrt, "0x%08X | MAC header control\n", table.mh_ctl);
0358     IWL_ERR(fwrt, "0x%08X | MAC header addr1 low\n", table.mh_addr1_lo);
0359     IWL_ERR(fwrt, "0x%08X | MAC header info\n", table.mh_info);
0360     IWL_ERR(fwrt, "0x%08X | MAC header error\n", table.mh_err);
0361 }
0362 
0363 static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)
0364 {
0365     struct iwl_trans *trans = fwrt->trans;
0366     u32 error, data1;
0367 
0368     if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
0369         error = UMAG_SB_CPU_2_STATUS;
0370         data1 = UMAG_SB_CPU_1_STATUS;
0371     } else if (fwrt->trans->trans_cfg->device_family >=
0372            IWL_DEVICE_FAMILY_8000) {
0373         error = SB_CPU_2_STATUS;
0374         data1 = SB_CPU_1_STATUS;
0375     } else {
0376         return;
0377     }
0378 
0379     error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS);
0380 
0381     IWL_ERR(trans, "IML/ROM dump:\n");
0382 
0383     if (error & 0xFFFF0000)
0384         IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16);
0385 
0386     IWL_ERR(fwrt, "0x%08X | IML/ROM error/state\n", error);
0387     IWL_ERR(fwrt, "0x%08X | IML/ROM data1\n",
0388         iwl_read_umac_prph(trans, data1));
0389 
0390     if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000)
0391         IWL_ERR(fwrt, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n",
0392             iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG));
0393 }
0394 
0395 #define FSEQ_REG(x) { .addr = (x), .str = #x, }
0396 
0397 static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt)
0398 {
0399     struct iwl_trans *trans = fwrt->trans;
0400     int i;
0401     struct {
0402         u32 addr;
0403         const char *str;
0404     } fseq_regs[] = {
0405         FSEQ_REG(FSEQ_ERROR_CODE),
0406         FSEQ_REG(FSEQ_TOP_INIT_VERSION),
0407         FSEQ_REG(FSEQ_CNVIO_INIT_VERSION),
0408         FSEQ_REG(FSEQ_OTP_VERSION),
0409         FSEQ_REG(FSEQ_TOP_CONTENT_VERSION),
0410         FSEQ_REG(FSEQ_ALIVE_TOKEN),
0411         FSEQ_REG(FSEQ_CNVI_ID),
0412         FSEQ_REG(FSEQ_CNVR_ID),
0413         FSEQ_REG(CNVI_AUX_MISC_CHIP),
0414         FSEQ_REG(CNVR_AUX_MISC_CHIP),
0415         FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM),
0416         FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR),
0417     };
0418 
0419     if (!iwl_trans_grab_nic_access(trans))
0420         return;
0421 
0422     IWL_ERR(fwrt, "Fseq Registers:\n");
0423 
0424     for (i = 0; i < ARRAY_SIZE(fseq_regs); i++)
0425         IWL_ERR(fwrt, "0x%08X | %s\n",
0426             iwl_read_prph_no_grab(trans, fseq_regs[i].addr),
0427             fseq_regs[i].str);
0428 
0429     iwl_trans_release_nic_access(trans);
0430 }
0431 
0432 void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
0433 {
0434     if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) {
0435         IWL_ERR(fwrt,
0436             "DEVICE_ENABLED bit is not set. Aborting dump.\n");
0437         return;
0438     }
0439 
0440     iwl_fwrt_dump_lmac_error_log(fwrt, 0);
0441     if (fwrt->trans->dbg.lmac_error_event_table[1])
0442         iwl_fwrt_dump_lmac_error_log(fwrt, 1);
0443     iwl_fwrt_dump_umac_error_log(fwrt);
0444     iwl_fwrt_dump_tcm_error_log(fwrt, 0);
0445     iwl_fwrt_dump_rcm_error_log(fwrt, 0);
0446     iwl_fwrt_dump_tcm_error_log(fwrt, 1);
0447     iwl_fwrt_dump_rcm_error_log(fwrt, 1);
0448     iwl_fwrt_dump_iml_error_log(fwrt);
0449     iwl_fwrt_dump_fseq_regs(fwrt);
0450 
0451     if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) {
0452         u32 scratch = iwl_read32(fwrt->trans, CSR_FUNC_SCRATCH);
0453 
0454         IWL_ERR(fwrt, "Function Scratch status:\n");
0455         IWL_ERR(fwrt, "0x%08X | Func Scratch\n", scratch);
0456     }
0457 }
0458 IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs);