The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/iwlwifi/fw/dbg.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
    2 /*
    3  * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
    4  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
    5  * Copyright (C) 2015-2017 Intel Deutschland GmbH
    6  */
    7 #include <linux/devcoredump.h>
    8 #if defined(__FreeBSD__)
    9 #include <linux/delay.h>
   10 #endif
   11 #include "iwl-drv.h"
   12 #include "runtime.h"
   13 #include "dbg.h"
   14 #include "debugfs.h"
   15 #include "iwl-io.h"
   16 #include "iwl-prph.h"
   17 #include "iwl-csr.h"
   18 #include "iwl-fh.h"
   19 /**
   20  * struct iwl_fw_dump_ptrs - set of pointers needed for the fw-error-dump
   21  *
   22  * @fwrt_ptr: pointer to the buffer coming from fwrt
   23  * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the
   24  *      transport's data.
   25  * @trans_len: length of the valid data in trans_ptr
   26  * @fwrt_len: length of the valid data in fwrt_ptr
   27  */
   28 struct iwl_fw_dump_ptrs {
   29         struct iwl_trans_dump_data *trans_ptr;
   30         void *fwrt_ptr;
   31         u32 fwrt_len;
   32 };
   33 
   34 #define RADIO_REG_MAX_READ 0x2ad
   35 static void iwl_read_radio_regs(struct iwl_fw_runtime *fwrt,
   36                                 struct iwl_fw_error_dump_data **dump_data)
   37 {
   38         u8 *pos = (void *)(*dump_data)->data;
   39         int i;
   40 
   41         IWL_DEBUG_INFO(fwrt, "WRT radio registers dump\n");
   42 
   43         if (!iwl_trans_grab_nic_access(fwrt->trans))
   44                 return;
   45 
   46         (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RADIO_REG);
   47         (*dump_data)->len = cpu_to_le32(RADIO_REG_MAX_READ);
   48 
   49         for (i = 0; i < RADIO_REG_MAX_READ; i++) {
   50                 u32 rd_cmd = RADIO_RSP_RD_CMD;
   51 
   52                 rd_cmd |= i << RADIO_RSP_ADDR_POS;
   53                 iwl_write_prph_no_grab(fwrt->trans, RSP_RADIO_CMD, rd_cmd);
   54                 *pos = (u8)iwl_read_prph_no_grab(fwrt->trans, RSP_RADIO_RDDAT);
   55 
   56                 pos++;
   57         }
   58 
   59         *dump_data = iwl_fw_error_next_data(*dump_data);
   60 
   61         iwl_trans_release_nic_access(fwrt->trans);
   62 }
   63 
   64 static void iwl_fwrt_dump_rxf(struct iwl_fw_runtime *fwrt,
   65                               struct iwl_fw_error_dump_data **dump_data,
   66                               int size, u32 offset, int fifo_num)
   67 {
   68         struct iwl_fw_error_dump_fifo *fifo_hdr;
   69         u32 *fifo_data;
   70         u32 fifo_len;
   71         int i;
   72 
   73         fifo_hdr = (void *)(*dump_data)->data;
   74         fifo_data = (void *)fifo_hdr->data;
   75         fifo_len = size;
   76 
   77         /* No need to try to read the data if the length is 0 */
   78         if (fifo_len == 0)
   79                 return;
   80 
   81         /* Add a TLV for the RXF */
   82         (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
   83         (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
   84 
   85         fifo_hdr->fifo_num = cpu_to_le32(fifo_num);
   86         fifo_hdr->available_bytes =
   87                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
   88                                                 RXF_RD_D_SPACE + offset));
   89         fifo_hdr->wr_ptr =
   90                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
   91                                                 RXF_RD_WR_PTR + offset));
   92         fifo_hdr->rd_ptr =
   93                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
   94                                                 RXF_RD_RD_PTR + offset));
   95         fifo_hdr->fence_ptr =
   96                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
   97                                                 RXF_RD_FENCE_PTR + offset));
   98         fifo_hdr->fence_mode =
   99                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  100                                                 RXF_SET_FENCE_MODE + offset));
  101 
  102         /* Lock fence */
  103         iwl_trans_write_prph(fwrt->trans, RXF_SET_FENCE_MODE + offset, 0x1);
  104         /* Set fence pointer to the same place like WR pointer */
  105         iwl_trans_write_prph(fwrt->trans, RXF_LD_WR2FENCE + offset, 0x1);
  106         /* Set fence offset */
  107         iwl_trans_write_prph(fwrt->trans,
  108                              RXF_LD_FENCE_OFFSET_ADDR + offset, 0x0);
  109 
  110         /* Read FIFO */
  111         fifo_len /= sizeof(u32); /* Size in DWORDS */
  112         for (i = 0; i < fifo_len; i++)
  113                 fifo_data[i] = iwl_trans_read_prph(fwrt->trans,
  114                                                  RXF_FIFO_RD_FENCE_INC +
  115                                                  offset);
  116         *dump_data = iwl_fw_error_next_data(*dump_data);
  117 }
  118 
  119 static void iwl_fwrt_dump_txf(struct iwl_fw_runtime *fwrt,
  120                               struct iwl_fw_error_dump_data **dump_data,
  121                               int size, u32 offset, int fifo_num)
  122 {
  123         struct iwl_fw_error_dump_fifo *fifo_hdr;
  124         u32 *fifo_data;
  125         u32 fifo_len;
  126         int i;
  127 
  128         fifo_hdr = (void *)(*dump_data)->data;
  129         fifo_data = (void *)fifo_hdr->data;
  130         fifo_len = size;
  131 
  132         /* No need to try to read the data if the length is 0 */
  133         if (fifo_len == 0)
  134                 return;
  135 
  136         /* Add a TLV for the FIFO */
  137         (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF);
  138         (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
  139 
  140         fifo_hdr->fifo_num = cpu_to_le32(fifo_num);
  141         fifo_hdr->available_bytes =
  142                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  143                                                 TXF_FIFO_ITEM_CNT + offset));
  144         fifo_hdr->wr_ptr =
  145                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  146                                                 TXF_WR_PTR + offset));
  147         fifo_hdr->rd_ptr =
  148                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  149                                                 TXF_RD_PTR + offset));
  150         fifo_hdr->fence_ptr =
  151                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  152                                                 TXF_FENCE_PTR + offset));
  153         fifo_hdr->fence_mode =
  154                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  155                                                 TXF_LOCK_FENCE + offset));
  156 
  157         /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
  158         iwl_trans_write_prph(fwrt->trans, TXF_READ_MODIFY_ADDR + offset,
  159                              TXF_WR_PTR + offset);
  160 
  161         /* Dummy-read to advance the read pointer to the head */
  162         iwl_trans_read_prph(fwrt->trans, TXF_READ_MODIFY_DATA + offset);
  163 
  164         /* Read FIFO */
  165         for (i = 0; i < fifo_len / sizeof(u32); i++)
  166                 fifo_data[i] = iwl_trans_read_prph(fwrt->trans,
  167                                                   TXF_READ_MODIFY_DATA +
  168                                                   offset);
  169 
  170         if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf)
  171                 fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx,
  172                                              fifo_data, fifo_len);
  173 
  174         *dump_data = iwl_fw_error_next_data(*dump_data);
  175 }
  176 
  177 static void iwl_fw_dump_rxf(struct iwl_fw_runtime *fwrt,
  178                             struct iwl_fw_error_dump_data **dump_data)
  179 {
  180         struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
  181 
  182         IWL_DEBUG_INFO(fwrt, "WRT RX FIFO dump\n");
  183 
  184         if (!iwl_trans_grab_nic_access(fwrt->trans))
  185                 return;
  186 
  187         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF)) {
  188                 /* Pull RXF1 */
  189                 iwl_fwrt_dump_rxf(fwrt, dump_data,
  190                                   cfg->lmac[0].rxfifo1_size, 0, 0);
  191                 /* Pull RXF2 */
  192                 iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->rxfifo2_size,
  193                                   RXF_DIFF_FROM_PREV +
  194                                   fwrt->trans->trans_cfg->umac_prph_offset, 1);
  195                 /* Pull LMAC2 RXF1 */
  196                 if (fwrt->smem_cfg.num_lmacs > 1)
  197                         iwl_fwrt_dump_rxf(fwrt, dump_data,
  198                                           cfg->lmac[1].rxfifo1_size,
  199                                           LMAC2_PRPH_OFFSET, 2);
  200         }
  201 
  202         iwl_trans_release_nic_access(fwrt->trans);
  203 }
  204 
  205 static void iwl_fw_dump_txf(struct iwl_fw_runtime *fwrt,
  206                             struct iwl_fw_error_dump_data **dump_data)
  207 {
  208         struct iwl_fw_error_dump_fifo *fifo_hdr;
  209         struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
  210         u32 *fifo_data;
  211         u32 fifo_len;
  212         int i, j;
  213 
  214         IWL_DEBUG_INFO(fwrt, "WRT TX FIFO dump\n");
  215 
  216         if (!iwl_trans_grab_nic_access(fwrt->trans))
  217                 return;
  218 
  219         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF)) {
  220                 /* Pull TXF data from LMAC1 */
  221                 for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) {
  222                         /* Mark the number of TXF we're pulling now */
  223                         iwl_trans_write_prph(fwrt->trans, TXF_LARC_NUM, i);
  224                         iwl_fwrt_dump_txf(fwrt, dump_data,
  225                                           cfg->lmac[0].txfifo_size[i], 0, i);
  226                 }
  227 
  228                 /* Pull TXF data from LMAC2 */
  229                 if (fwrt->smem_cfg.num_lmacs > 1) {
  230                         for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries;
  231                              i++) {
  232                                 /* Mark the number of TXF we're pulling now */
  233                                 iwl_trans_write_prph(fwrt->trans,
  234                                                      TXF_LARC_NUM +
  235                                                      LMAC2_PRPH_OFFSET, i);
  236                                 iwl_fwrt_dump_txf(fwrt, dump_data,
  237                                                   cfg->lmac[1].txfifo_size[i],
  238                                                   LMAC2_PRPH_OFFSET,
  239                                                   i + cfg->num_txfifo_entries);
  240                         }
  241                 }
  242         }
  243 
  244         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
  245             fw_has_capa(&fwrt->fw->ucode_capa,
  246                         IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
  247                 /* Pull UMAC internal TXF data from all TXFs */
  248                 for (i = 0;
  249                      i < ARRAY_SIZE(fwrt->smem_cfg.internal_txfifo_size);
  250                      i++) {
  251                         fifo_hdr = (void *)(*dump_data)->data;
  252                         fifo_data = (void *)fifo_hdr->data;
  253                         fifo_len = fwrt->smem_cfg.internal_txfifo_size[i];
  254 
  255                         /* No need to try to read the data if the length is 0 */
  256                         if (fifo_len == 0)
  257                                 continue;
  258 
  259                         /* Add a TLV for the internal FIFOs */
  260                         (*dump_data)->type =
  261                                 cpu_to_le32(IWL_FW_ERROR_DUMP_INTERNAL_TXF);
  262                         (*dump_data)->len =
  263                                 cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
  264 
  265                         fifo_hdr->fifo_num = cpu_to_le32(i);
  266 
  267                         /* Mark the number of TXF we're pulling now */
  268                         iwl_trans_write_prph(fwrt->trans, TXF_CPU2_NUM, i +
  269                                 fwrt->smem_cfg.num_txfifo_entries);
  270 
  271                         fifo_hdr->available_bytes =
  272                                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  273                                                                 TXF_CPU2_FIFO_ITEM_CNT));
  274                         fifo_hdr->wr_ptr =
  275                                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  276                                                                 TXF_CPU2_WR_PTR));
  277                         fifo_hdr->rd_ptr =
  278                                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  279                                                                 TXF_CPU2_RD_PTR));
  280                         fifo_hdr->fence_ptr =
  281                                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  282                                                                 TXF_CPU2_FENCE_PTR));
  283                         fifo_hdr->fence_mode =
  284                                 cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
  285                                                                 TXF_CPU2_LOCK_FENCE));
  286 
  287                         /* Set TXF_CPU2_READ_MODIFY_ADDR to TXF_CPU2_WR_PTR */
  288                         iwl_trans_write_prph(fwrt->trans,
  289                                              TXF_CPU2_READ_MODIFY_ADDR,
  290                                              TXF_CPU2_WR_PTR);
  291 
  292                         /* Dummy-read to advance the read pointer to head */
  293                         iwl_trans_read_prph(fwrt->trans,
  294                                             TXF_CPU2_READ_MODIFY_DATA);
  295 
  296                         /* Read FIFO */
  297                         fifo_len /= sizeof(u32); /* Size in DWORDS */
  298                         for (j = 0; j < fifo_len; j++)
  299                                 fifo_data[j] =
  300                                         iwl_trans_read_prph(fwrt->trans,
  301                                                             TXF_CPU2_READ_MODIFY_DATA);
  302                         *dump_data = iwl_fw_error_next_data(*dump_data);
  303                 }
  304         }
  305 
  306         iwl_trans_release_nic_access(fwrt->trans);
  307 }
  308 
  309 struct iwl_prph_range {
  310         u32 start, end;
  311 };
  312 
  313 static const struct iwl_prph_range iwl_prph_dump_addr_comm[] = {
  314         { .start = 0x00a00000, .end = 0x00a00000 },
  315         { .start = 0x00a0000c, .end = 0x00a00024 },
  316         { .start = 0x00a0002c, .end = 0x00a0003c },
  317         { .start = 0x00a00410, .end = 0x00a00418 },
  318         { .start = 0x00a00420, .end = 0x00a00420 },
  319         { .start = 0x00a00428, .end = 0x00a00428 },
  320         { .start = 0x00a00430, .end = 0x00a0043c },
  321         { .start = 0x00a00444, .end = 0x00a00444 },
  322         { .start = 0x00a004c0, .end = 0x00a004cc },
  323         { .start = 0x00a004d8, .end = 0x00a004d8 },
  324         { .start = 0x00a004e0, .end = 0x00a004f0 },
  325         { .start = 0x00a00840, .end = 0x00a00840 },
  326         { .start = 0x00a00850, .end = 0x00a00858 },
  327         { .start = 0x00a01004, .end = 0x00a01008 },
  328         { .start = 0x00a01010, .end = 0x00a01010 },
  329         { .start = 0x00a01018, .end = 0x00a01018 },
  330         { .start = 0x00a01024, .end = 0x00a01024 },
  331         { .start = 0x00a0102c, .end = 0x00a01034 },
  332         { .start = 0x00a0103c, .end = 0x00a01040 },
  333         { .start = 0x00a01048, .end = 0x00a01094 },
  334         { .start = 0x00a01c00, .end = 0x00a01c20 },
  335         { .start = 0x00a01c58, .end = 0x00a01c58 },
  336         { .start = 0x00a01c7c, .end = 0x00a01c7c },
  337         { .start = 0x00a01c28, .end = 0x00a01c54 },
  338         { .start = 0x00a01c5c, .end = 0x00a01c5c },
  339         { .start = 0x00a01c60, .end = 0x00a01cdc },
  340         { .start = 0x00a01ce0, .end = 0x00a01d0c },
  341         { .start = 0x00a01d18, .end = 0x00a01d20 },
  342         { .start = 0x00a01d2c, .end = 0x00a01d30 },
  343         { .start = 0x00a01d40, .end = 0x00a01d5c },
  344         { .start = 0x00a01d80, .end = 0x00a01d80 },
  345         { .start = 0x00a01d98, .end = 0x00a01d9c },
  346         { .start = 0x00a01da8, .end = 0x00a01da8 },
  347         { .start = 0x00a01db8, .end = 0x00a01df4 },
  348         { .start = 0x00a01dc0, .end = 0x00a01dfc },
  349         { .start = 0x00a01e00, .end = 0x00a01e2c },
  350         { .start = 0x00a01e40, .end = 0x00a01e60 },
  351         { .start = 0x00a01e68, .end = 0x00a01e6c },
  352         { .start = 0x00a01e74, .end = 0x00a01e74 },
  353         { .start = 0x00a01e84, .end = 0x00a01e90 },
  354         { .start = 0x00a01e9c, .end = 0x00a01ec4 },
  355         { .start = 0x00a01ed0, .end = 0x00a01ee0 },
  356         { .start = 0x00a01f00, .end = 0x00a01f1c },
  357         { .start = 0x00a01f44, .end = 0x00a01ffc },
  358         { .start = 0x00a02000, .end = 0x00a02048 },
  359         { .start = 0x00a02068, .end = 0x00a020f0 },
  360         { .start = 0x00a02100, .end = 0x00a02118 },
  361         { .start = 0x00a02140, .end = 0x00a0214c },
  362         { .start = 0x00a02168, .end = 0x00a0218c },
  363         { .start = 0x00a021c0, .end = 0x00a021c0 },
  364         { .start = 0x00a02400, .end = 0x00a02410 },
  365         { .start = 0x00a02418, .end = 0x00a02420 },
  366         { .start = 0x00a02428, .end = 0x00a0242c },
  367         { .start = 0x00a02434, .end = 0x00a02434 },
  368         { .start = 0x00a02440, .end = 0x00a02460 },
  369         { .start = 0x00a02468, .end = 0x00a024b0 },
  370         { .start = 0x00a024c8, .end = 0x00a024cc },
  371         { .start = 0x00a02500, .end = 0x00a02504 },
  372         { .start = 0x00a0250c, .end = 0x00a02510 },
  373         { .start = 0x00a02540, .end = 0x00a02554 },
  374         { .start = 0x00a02580, .end = 0x00a025f4 },
  375         { .start = 0x00a02600, .end = 0x00a0260c },
  376         { .start = 0x00a02648, .end = 0x00a02650 },
  377         { .start = 0x00a02680, .end = 0x00a02680 },
  378         { .start = 0x00a026c0, .end = 0x00a026d0 },
  379         { .start = 0x00a02700, .end = 0x00a0270c },
  380         { .start = 0x00a02804, .end = 0x00a02804 },
  381         { .start = 0x00a02818, .end = 0x00a0281c },
  382         { .start = 0x00a02c00, .end = 0x00a02db4 },
  383         { .start = 0x00a02df4, .end = 0x00a02fb0 },
  384         { .start = 0x00a03000, .end = 0x00a03014 },
  385         { .start = 0x00a0301c, .end = 0x00a0302c },
  386         { .start = 0x00a03034, .end = 0x00a03038 },
  387         { .start = 0x00a03040, .end = 0x00a03048 },
  388         { .start = 0x00a03060, .end = 0x00a03068 },
  389         { .start = 0x00a03070, .end = 0x00a03074 },
  390         { .start = 0x00a0307c, .end = 0x00a0307c },
  391         { .start = 0x00a03080, .end = 0x00a03084 },
  392         { .start = 0x00a0308c, .end = 0x00a03090 },
  393         { .start = 0x00a03098, .end = 0x00a03098 },
  394         { .start = 0x00a030a0, .end = 0x00a030a0 },
  395         { .start = 0x00a030a8, .end = 0x00a030b4 },
  396         { .start = 0x00a030bc, .end = 0x00a030bc },
  397         { .start = 0x00a030c0, .end = 0x00a0312c },
  398         { .start = 0x00a03c00, .end = 0x00a03c5c },
  399         { .start = 0x00a04400, .end = 0x00a04454 },
  400         { .start = 0x00a04460, .end = 0x00a04474 },
  401         { .start = 0x00a044c0, .end = 0x00a044ec },
  402         { .start = 0x00a04500, .end = 0x00a04504 },
  403         { .start = 0x00a04510, .end = 0x00a04538 },
  404         { .start = 0x00a04540, .end = 0x00a04548 },
  405         { .start = 0x00a04560, .end = 0x00a0457c },
  406         { .start = 0x00a04590, .end = 0x00a04598 },
  407         { .start = 0x00a045c0, .end = 0x00a045f4 },
  408 };
  409 
  410 static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
  411         { .start = 0x00a05c00, .end = 0x00a05c18 },
  412         { .start = 0x00a05400, .end = 0x00a056e8 },
  413         { .start = 0x00a08000, .end = 0x00a098bc },
  414         { .start = 0x00a02400, .end = 0x00a02758 },
  415         { .start = 0x00a04764, .end = 0x00a0476c },
  416         { .start = 0x00a04770, .end = 0x00a04774 },
  417         { .start = 0x00a04620, .end = 0x00a04624 },
  418 };
  419 
  420 static const struct iwl_prph_range iwl_prph_dump_addr_22000[] = {
  421         { .start = 0x00a00000, .end = 0x00a00000 },
  422         { .start = 0x00a0000c, .end = 0x00a00024 },
  423         { .start = 0x00a0002c, .end = 0x00a00034 },
  424         { .start = 0x00a0003c, .end = 0x00a0003c },
  425         { .start = 0x00a00410, .end = 0x00a00418 },
  426         { .start = 0x00a00420, .end = 0x00a00420 },
  427         { .start = 0x00a00428, .end = 0x00a00428 },
  428         { .start = 0x00a00430, .end = 0x00a0043c },
  429         { .start = 0x00a00444, .end = 0x00a00444 },
  430         { .start = 0x00a00840, .end = 0x00a00840 },
  431         { .start = 0x00a00850, .end = 0x00a00858 },
  432         { .start = 0x00a01004, .end = 0x00a01008 },
  433         { .start = 0x00a01010, .end = 0x00a01010 },
  434         { .start = 0x00a01018, .end = 0x00a01018 },
  435         { .start = 0x00a01024, .end = 0x00a01024 },
  436         { .start = 0x00a0102c, .end = 0x00a01034 },
  437         { .start = 0x00a0103c, .end = 0x00a01040 },
  438         { .start = 0x00a01048, .end = 0x00a01050 },
  439         { .start = 0x00a01058, .end = 0x00a01058 },
  440         { .start = 0x00a01060, .end = 0x00a01070 },
  441         { .start = 0x00a0108c, .end = 0x00a0108c },
  442         { .start = 0x00a01c20, .end = 0x00a01c28 },
  443         { .start = 0x00a01d10, .end = 0x00a01d10 },
  444         { .start = 0x00a01e28, .end = 0x00a01e2c },
  445         { .start = 0x00a01e60, .end = 0x00a01e60 },
  446         { .start = 0x00a01e80, .end = 0x00a01e80 },
  447         { .start = 0x00a01ea0, .end = 0x00a01ea0 },
  448         { .start = 0x00a02000, .end = 0x00a0201c },
  449         { .start = 0x00a02024, .end = 0x00a02024 },
  450         { .start = 0x00a02040, .end = 0x00a02048 },
  451         { .start = 0x00a020c0, .end = 0x00a020e0 },
  452         { .start = 0x00a02400, .end = 0x00a02404 },
  453         { .start = 0x00a0240c, .end = 0x00a02414 },
  454         { .start = 0x00a0241c, .end = 0x00a0243c },
  455         { .start = 0x00a02448, .end = 0x00a024bc },
  456         { .start = 0x00a024c4, .end = 0x00a024cc },
  457         { .start = 0x00a02508, .end = 0x00a02508 },
  458         { .start = 0x00a02510, .end = 0x00a02514 },
  459         { .start = 0x00a0251c, .end = 0x00a0251c },
  460         { .start = 0x00a0252c, .end = 0x00a0255c },
  461         { .start = 0x00a02564, .end = 0x00a025a0 },
  462         { .start = 0x00a025a8, .end = 0x00a025b4 },
  463         { .start = 0x00a025c0, .end = 0x00a025c0 },
  464         { .start = 0x00a025e8, .end = 0x00a025f4 },
  465         { .start = 0x00a02c08, .end = 0x00a02c18 },
  466         { .start = 0x00a02c2c, .end = 0x00a02c38 },
  467         { .start = 0x00a02c68, .end = 0x00a02c78 },
  468         { .start = 0x00a03000, .end = 0x00a03000 },
  469         { .start = 0x00a03010, .end = 0x00a03014 },
  470         { .start = 0x00a0301c, .end = 0x00a0302c },
  471         { .start = 0x00a03034, .end = 0x00a03038 },
  472         { .start = 0x00a03040, .end = 0x00a03044 },
  473         { .start = 0x00a03060, .end = 0x00a03068 },
  474         { .start = 0x00a03070, .end = 0x00a03070 },
  475         { .start = 0x00a0307c, .end = 0x00a03084 },
  476         { .start = 0x00a0308c, .end = 0x00a03090 },
  477         { .start = 0x00a03098, .end = 0x00a03098 },
  478         { .start = 0x00a030a0, .end = 0x00a030a0 },
  479         { .start = 0x00a030a8, .end = 0x00a030b4 },
  480         { .start = 0x00a030bc, .end = 0x00a030c0 },
  481         { .start = 0x00a030c8, .end = 0x00a030f4 },
  482         { .start = 0x00a03100, .end = 0x00a0312c },
  483         { .start = 0x00a03c00, .end = 0x00a03c5c },
  484         { .start = 0x00a04400, .end = 0x00a04454 },
  485         { .start = 0x00a04460, .end = 0x00a04474 },
  486         { .start = 0x00a044c0, .end = 0x00a044ec },
  487         { .start = 0x00a04500, .end = 0x00a04504 },
  488         { .start = 0x00a04510, .end = 0x00a04538 },
  489         { .start = 0x00a04540, .end = 0x00a04548 },
  490         { .start = 0x00a04560, .end = 0x00a04560 },
  491         { .start = 0x00a04570, .end = 0x00a0457c },
  492         { .start = 0x00a04590, .end = 0x00a04590 },
  493         { .start = 0x00a04598, .end = 0x00a04598 },
  494         { .start = 0x00a045c0, .end = 0x00a045f4 },
  495         { .start = 0x00a05c18, .end = 0x00a05c1c },
  496         { .start = 0x00a0c000, .end = 0x00a0c018 },
  497         { .start = 0x00a0c020, .end = 0x00a0c028 },
  498         { .start = 0x00a0c038, .end = 0x00a0c094 },
  499         { .start = 0x00a0c0c0, .end = 0x00a0c104 },
  500         { .start = 0x00a0c10c, .end = 0x00a0c118 },
  501         { .start = 0x00a0c150, .end = 0x00a0c174 },
  502         { .start = 0x00a0c17c, .end = 0x00a0c188 },
  503         { .start = 0x00a0c190, .end = 0x00a0c198 },
  504         { .start = 0x00a0c1a0, .end = 0x00a0c1a8 },
  505         { .start = 0x00a0c1b0, .end = 0x00a0c1b8 },
  506 };
  507 
  508 static const struct iwl_prph_range iwl_prph_dump_addr_ax210[] = {
  509         { .start = 0x00d03c00, .end = 0x00d03c64 },
  510         { .start = 0x00d05c18, .end = 0x00d05c1c },
  511         { .start = 0x00d0c000, .end = 0x00d0c174 },
  512 };
  513 
  514 static void iwl_read_prph_block(struct iwl_trans *trans, u32 start,
  515                                 u32 len_bytes, __le32 *data)
  516 {
  517         u32 i;
  518 
  519         for (i = 0; i < len_bytes; i += 4)
  520                 *data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i));
  521 }
  522 
  523 static void iwl_dump_prph(struct iwl_fw_runtime *fwrt,
  524                           const struct iwl_prph_range *iwl_prph_dump_addr,
  525                           u32 range_len, void *ptr)
  526 {
  527         struct iwl_fw_error_dump_prph *prph;
  528         struct iwl_trans *trans = fwrt->trans;
  529         struct iwl_fw_error_dump_data **data =
  530                 (struct iwl_fw_error_dump_data **)ptr;
  531         u32 i;
  532 
  533         if (!data)
  534                 return;
  535 
  536         IWL_DEBUG_INFO(trans, "WRT PRPH dump\n");
  537 
  538         if (!iwl_trans_grab_nic_access(trans))
  539                 return;
  540 
  541         for (i = 0; i < range_len; i++) {
  542                 /* The range includes both boundaries */
  543                 int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
  544                          iwl_prph_dump_addr[i].start + 4;
  545 
  546                 (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
  547                 (*data)->len = cpu_to_le32(sizeof(*prph) +
  548                                         num_bytes_in_chunk);
  549                 prph = (void *)(*data)->data;
  550                 prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
  551 
  552                 iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start,
  553                                     /* our range is inclusive, hence + 4 */
  554                                     iwl_prph_dump_addr[i].end -
  555                                     iwl_prph_dump_addr[i].start + 4,
  556                                     (void *)prph->data);
  557 
  558                 *data = iwl_fw_error_next_data(*data);
  559         }
  560 
  561         iwl_trans_release_nic_access(trans);
  562 }
  563 
  564 /*
  565  * alloc_sgtable - allocates scallerlist table in the given size,
  566  * fills it with pages and returns it
  567  * @size: the size (in bytes) of the table
  568 */
  569 static struct scatterlist *alloc_sgtable(int size)
  570 {
  571         int alloc_size, nents, i;
  572         struct page *new_page;
  573         struct scatterlist *iter;
  574         struct scatterlist *table;
  575 
  576         nents = DIV_ROUND_UP(size, PAGE_SIZE);
  577         table = kcalloc(nents, sizeof(*table), GFP_KERNEL);
  578         if (!table)
  579                 return NULL;
  580         sg_init_table(table, nents);
  581         iter = table;
  582         for_each_sg(table, iter, sg_nents(table), i) {
  583                 new_page = alloc_page(GFP_KERNEL);
  584                 if (!new_page) {
  585                         /* release all previous allocated pages in the table */
  586                         iter = table;
  587                         for_each_sg(table, iter, sg_nents(table), i) {
  588                                 new_page = sg_page(iter);
  589                                 if (new_page)
  590                                         __free_page(new_page);
  591                         }
  592                         kfree(table);
  593                         return NULL;
  594                 }
  595                 alloc_size = min_t(int, size, PAGE_SIZE);
  596                 size -= PAGE_SIZE;
  597                 sg_set_page(iter, new_page, alloc_size, 0);
  598         }
  599         return table;
  600 }
  601 
  602 static void iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt,
  603                                 const struct iwl_prph_range *iwl_prph_dump_addr,
  604                                 u32 range_len, void *ptr)
  605 {
  606         u32 *prph_len = (u32 *)ptr;
  607         int i, num_bytes_in_chunk;
  608 
  609         if (!prph_len)
  610                 return;
  611 
  612         for (i = 0; i < range_len; i++) {
  613                 /* The range includes both boundaries */
  614                 num_bytes_in_chunk =
  615                         iwl_prph_dump_addr[i].end -
  616                         iwl_prph_dump_addr[i].start + 4;
  617 
  618                 *prph_len += sizeof(struct iwl_fw_error_dump_data) +
  619                         sizeof(struct iwl_fw_error_dump_prph) +
  620                         num_bytes_in_chunk;
  621         }
  622 }
  623 
  624 static void iwl_fw_prph_handler(struct iwl_fw_runtime *fwrt, void *ptr,
  625                                 void (*handler)(struct iwl_fw_runtime *,
  626                                                 const struct iwl_prph_range *,
  627                                                 u32, void *))
  628 {
  629         u32 range_len;
  630 
  631         if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
  632                 range_len = ARRAY_SIZE(iwl_prph_dump_addr_ax210);
  633                 handler(fwrt, iwl_prph_dump_addr_ax210, range_len, ptr);
  634         } else if (fwrt->trans->trans_cfg->device_family >=
  635                    IWL_DEVICE_FAMILY_22000) {
  636                 range_len = ARRAY_SIZE(iwl_prph_dump_addr_22000);
  637                 handler(fwrt, iwl_prph_dump_addr_22000, range_len, ptr);
  638         } else {
  639                 range_len = ARRAY_SIZE(iwl_prph_dump_addr_comm);
  640                 handler(fwrt, iwl_prph_dump_addr_comm, range_len, ptr);
  641 
  642                 if (fwrt->trans->trans_cfg->mq_rx_supported) {
  643                         range_len = ARRAY_SIZE(iwl_prph_dump_addr_9000);
  644                         handler(fwrt, iwl_prph_dump_addr_9000, range_len, ptr);
  645                 }
  646         }
  647 }
  648 
  649 static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt,
  650                             struct iwl_fw_error_dump_data **dump_data,
  651                             u32 len, u32 ofs, u32 type)
  652 {
  653         struct iwl_fw_error_dump_mem *dump_mem;
  654 
  655         if (!len)
  656                 return;
  657 
  658         (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
  659         (*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem));
  660         dump_mem = (void *)(*dump_data)->data;
  661         dump_mem->type = cpu_to_le32(type);
  662         dump_mem->offset = cpu_to_le32(ofs);
  663         iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len);
  664         *dump_data = iwl_fw_error_next_data(*dump_data);
  665 
  666         if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
  667                 fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx, ofs,
  668                                              dump_mem->data, len);
  669 
  670         IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
  671 }
  672 
  673 #define ADD_LEN(len, item_len, const_len) \
  674         do {size_t item = item_len; len += (!!item) * const_len + item; } \
  675         while (0)
  676 
  677 static int iwl_fw_rxf_len(struct iwl_fw_runtime *fwrt,
  678                           struct iwl_fwrt_shared_mem_cfg *mem_cfg)
  679 {
  680         size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
  681                          sizeof(struct iwl_fw_error_dump_fifo);
  682         u32 fifo_len = 0;
  683         int i;
  684 
  685         if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF))
  686                 return 0;
  687 
  688         /* Count RXF2 size */
  689         ADD_LEN(fifo_len, mem_cfg->rxfifo2_size, hdr_len);
  690 
  691         /* Count RXF1 sizes */
  692         if (WARN_ON(mem_cfg->num_lmacs > MAX_NUM_LMAC))
  693                 mem_cfg->num_lmacs = MAX_NUM_LMAC;
  694 
  695         for (i = 0; i < mem_cfg->num_lmacs; i++)
  696                 ADD_LEN(fifo_len, mem_cfg->lmac[i].rxfifo1_size, hdr_len);
  697 
  698         return fifo_len;
  699 }
  700 
  701 static int iwl_fw_txf_len(struct iwl_fw_runtime *fwrt,
  702                           struct iwl_fwrt_shared_mem_cfg *mem_cfg)
  703 {
  704         size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
  705                          sizeof(struct iwl_fw_error_dump_fifo);
  706         u32 fifo_len = 0;
  707         int i;
  708 
  709         if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF))
  710                 goto dump_internal_txf;
  711 
  712         /* Count TXF sizes */
  713         if (WARN_ON(mem_cfg->num_lmacs > MAX_NUM_LMAC))
  714                 mem_cfg->num_lmacs = MAX_NUM_LMAC;
  715 
  716         for (i = 0; i < mem_cfg->num_lmacs; i++) {
  717                 int j;
  718 
  719                 for (j = 0; j < mem_cfg->num_txfifo_entries; j++)
  720                         ADD_LEN(fifo_len, mem_cfg->lmac[i].txfifo_size[j],
  721                                 hdr_len);
  722         }
  723 
  724 dump_internal_txf:
  725         if (!(iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
  726               fw_has_capa(&fwrt->fw->ucode_capa,
  727                           IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)))
  728                 goto out;
  729 
  730         for (i = 0; i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); i++)
  731                 ADD_LEN(fifo_len, mem_cfg->internal_txfifo_size[i], hdr_len);
  732 
  733 out:
  734         return fifo_len;
  735 }
  736 
  737 static void iwl_dump_paging(struct iwl_fw_runtime *fwrt,
  738                             struct iwl_fw_error_dump_data **data)
  739 {
  740         int i;
  741 
  742         IWL_DEBUG_INFO(fwrt, "WRT paging dump\n");
  743         for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) {
  744                 struct iwl_fw_error_dump_paging *paging;
  745                 struct page *pages =
  746                         fwrt->fw_paging_db[i].fw_paging_block;
  747                 dma_addr_t addr = fwrt->fw_paging_db[i].fw_paging_phys;
  748 
  749                 (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
  750                 (*data)->len = cpu_to_le32(sizeof(*paging) +
  751                                              PAGING_BLOCK_SIZE);
  752                 paging =  (void *)(*data)->data;
  753                 paging->index = cpu_to_le32(i);
  754                 dma_sync_single_for_cpu(fwrt->trans->dev, addr,
  755                                         PAGING_BLOCK_SIZE,
  756                                         DMA_BIDIRECTIONAL);
  757                 memcpy(paging->data, page_address(pages),
  758                        PAGING_BLOCK_SIZE);
  759                 dma_sync_single_for_device(fwrt->trans->dev, addr,
  760                                            PAGING_BLOCK_SIZE,
  761                                            DMA_BIDIRECTIONAL);
  762                 (*data) = iwl_fw_error_next_data(*data);
  763 
  764                 if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
  765                         fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx,
  766                                                      fwrt->fw_paging_db[i].fw_offs,
  767                                                      paging->data,
  768                                                      PAGING_BLOCK_SIZE);
  769         }
  770 }
  771 
  772 static struct iwl_fw_error_dump_file *
  773 iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt,
  774                        struct iwl_fw_dump_ptrs *fw_error_dump,
  775                        struct iwl_fwrt_dump_data *data)
  776 {
  777         struct iwl_fw_error_dump_file *dump_file;
  778         struct iwl_fw_error_dump_data *dump_data;
  779         struct iwl_fw_error_dump_info *dump_info;
  780         struct iwl_fw_error_dump_smem_cfg *dump_smem_cfg;
  781         struct iwl_fw_error_dump_trigger_desc *dump_trig;
  782         u32 sram_len, sram_ofs;
  783         const struct iwl_fw_dbg_mem_seg_tlv *fw_mem = fwrt->fw->dbg.mem_tlv;
  784         struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg;
  785         u32 file_len, fifo_len = 0, prph_len = 0, radio_len = 0;
  786         u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len;
  787         u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ?
  788                                 0 : fwrt->trans->cfg->dccm2_len;
  789         int i;
  790 
  791         /* SRAM - include stack CCM if driver knows the values for it */
  792         if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) {
  793                 const struct fw_img *img;
  794 
  795                 if (fwrt->cur_fw_img >= IWL_UCODE_TYPE_MAX)
  796                         return NULL;
  797                 img = &fwrt->fw->img[fwrt->cur_fw_img];
  798                 sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
  799                 sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
  800         } else {
  801                 sram_ofs = fwrt->trans->cfg->dccm_offset;
  802                 sram_len = fwrt->trans->cfg->dccm_len;
  803         }
  804 
  805         /* reading RXF/TXF sizes */
  806         if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
  807                 fifo_len = iwl_fw_rxf_len(fwrt, mem_cfg);
  808                 fifo_len += iwl_fw_txf_len(fwrt, mem_cfg);
  809 
  810                 /* Make room for PRPH registers */
  811                 if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PRPH))
  812                         iwl_fw_prph_handler(fwrt, &prph_len,
  813                                             iwl_fw_get_prph_len);
  814 
  815                 if (fwrt->trans->trans_cfg->device_family ==
  816                     IWL_DEVICE_FAMILY_7000 &&
  817                     iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RADIO_REG))
  818                         radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
  819         }
  820 
  821         file_len = sizeof(*dump_file) + fifo_len + prph_len + radio_len;
  822 
  823         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO))
  824                 file_len += sizeof(*dump_data) + sizeof(*dump_info);
  825         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG))
  826                 file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg);
  827 
  828         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) {
  829                 size_t hdr_len = sizeof(*dump_data) +
  830                                  sizeof(struct iwl_fw_error_dump_mem);
  831 
  832                 /* Dump SRAM only if no mem_tlvs */
  833                 if (!fwrt->fw->dbg.n_mem_tlv)
  834                         ADD_LEN(file_len, sram_len, hdr_len);
  835 
  836                 /* Make room for all mem types that exist */
  837                 ADD_LEN(file_len, smem_len, hdr_len);
  838                 ADD_LEN(file_len, sram2_len, hdr_len);
  839 
  840                 for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++)
  841                         ADD_LEN(file_len, le32_to_cpu(fw_mem[i].len), hdr_len);
  842         }
  843 
  844         /* Make room for fw's virtual image pages, if it exists */
  845         if (iwl_fw_dbg_is_paging_enabled(fwrt))
  846                 file_len += fwrt->num_of_paging_blk *
  847                         (sizeof(*dump_data) +
  848                          sizeof(struct iwl_fw_error_dump_paging) +
  849                          PAGING_BLOCK_SIZE);
  850 
  851         if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) {
  852                 file_len += sizeof(*dump_data) +
  853                         fwrt->trans->cfg->d3_debug_data_length * 2;
  854         }
  855 
  856         /* If we only want a monitor dump, reset the file length */
  857         if (data->monitor_only) {
  858                 file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 +
  859                            sizeof(*dump_info) + sizeof(*dump_smem_cfg);
  860         }
  861 
  862         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) &&
  863             data->desc)
  864                 file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
  865                         data->desc->len;
  866 
  867         dump_file = vzalloc(file_len);
  868         if (!dump_file)
  869                 return NULL;
  870 
  871         fw_error_dump->fwrt_ptr = dump_file;
  872 
  873         dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
  874         dump_data = (void *)dump_file->data;
  875 
  876         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
  877                 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
  878                 dump_data->len = cpu_to_le32(sizeof(*dump_info));
  879                 dump_info = (void *)dump_data->data;
  880                 dump_info->hw_type =
  881                         cpu_to_le32(CSR_HW_REV_TYPE(fwrt->trans->hw_rev));
  882                 dump_info->hw_step =
  883                         cpu_to_le32(fwrt->trans->hw_rev_step);
  884                 memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable,
  885                        sizeof(dump_info->fw_human_readable));
  886                 strncpy(dump_info->dev_human_readable, fwrt->trans->name,
  887                         sizeof(dump_info->dev_human_readable) - 1);
  888 #if defined(__linux__)
  889                 strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name,
  890                         sizeof(dump_info->bus_human_readable) - 1);
  891 #elif defined(__FreeBSD__)      /* XXX TODO */
  892                 strncpy(dump_info->bus_human_readable, "<bus>",
  893                         sizeof(dump_info->bus_human_readable) - 1);
  894 #endif
  895                 dump_info->num_of_lmacs = fwrt->smem_cfg.num_lmacs;
  896                 dump_info->lmac_err_id[0] =
  897                         cpu_to_le32(fwrt->dump.lmac_err_id[0]);
  898                 if (fwrt->smem_cfg.num_lmacs > 1)
  899                         dump_info->lmac_err_id[1] =
  900                                 cpu_to_le32(fwrt->dump.lmac_err_id[1]);
  901                 dump_info->umac_err_id = cpu_to_le32(fwrt->dump.umac_err_id);
  902 
  903                 dump_data = iwl_fw_error_next_data(dump_data);
  904         }
  905 
  906         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG)) {
  907                 /* Dump shared memory configuration */
  908                 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG);
  909                 dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg));
  910                 dump_smem_cfg = (void *)dump_data->data;
  911                 dump_smem_cfg->num_lmacs = cpu_to_le32(mem_cfg->num_lmacs);
  912                 dump_smem_cfg->num_txfifo_entries =
  913                         cpu_to_le32(mem_cfg->num_txfifo_entries);
  914                 for (i = 0; i < MAX_NUM_LMAC; i++) {
  915                         int j;
  916                         u32 *txf_size = mem_cfg->lmac[i].txfifo_size;
  917 
  918                         for (j = 0; j < TX_FIFO_MAX_NUM; j++)
  919                                 dump_smem_cfg->lmac[i].txfifo_size[j] =
  920                                         cpu_to_le32(txf_size[j]);
  921                         dump_smem_cfg->lmac[i].rxfifo1_size =
  922                                 cpu_to_le32(mem_cfg->lmac[i].rxfifo1_size);
  923                 }
  924                 dump_smem_cfg->rxfifo2_size =
  925                         cpu_to_le32(mem_cfg->rxfifo2_size);
  926                 dump_smem_cfg->internal_txfifo_addr =
  927                         cpu_to_le32(mem_cfg->internal_txfifo_addr);
  928                 for (i = 0; i < TX_FIFO_INTERNAL_MAX_NUM; i++) {
  929                         dump_smem_cfg->internal_txfifo_size[i] =
  930                                 cpu_to_le32(mem_cfg->internal_txfifo_size[i]);
  931                 }
  932 
  933                 dump_data = iwl_fw_error_next_data(dump_data);
  934         }
  935 
  936         /* We only dump the FIFOs if the FW is in error state */
  937         if (fifo_len) {
  938                 iwl_fw_dump_rxf(fwrt, &dump_data);
  939                 iwl_fw_dump_txf(fwrt, &dump_data);
  940         }
  941 
  942         if (radio_len)
  943                 iwl_read_radio_regs(fwrt, &dump_data);
  944 
  945         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) &&
  946             data->desc) {
  947                 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
  948                 dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
  949                                              data->desc->len);
  950                 dump_trig = (void *)dump_data->data;
  951                 memcpy(dump_trig, &data->desc->trig_desc,
  952                        sizeof(*dump_trig) + data->desc->len);
  953 
  954                 dump_data = iwl_fw_error_next_data(dump_data);
  955         }
  956 
  957         /* In case we only want monitor dump, skip to dump trasport data */
  958         if (data->monitor_only)
  959                 goto out;
  960 
  961         if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) {
  962                 const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem =
  963                         fwrt->fw->dbg.mem_tlv;
  964 
  965                 if (!fwrt->fw->dbg.n_mem_tlv)
  966                         iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs,
  967                                         IWL_FW_ERROR_DUMP_MEM_SRAM);
  968 
  969                 for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) {
  970                         u32 len = le32_to_cpu(fw_dbg_mem[i].len);
  971                         u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
  972 
  973                         iwl_fw_dump_mem(fwrt, &dump_data, len, ofs,
  974                                         le32_to_cpu(fw_dbg_mem[i].data_type));
  975                 }
  976 
  977                 iwl_fw_dump_mem(fwrt, &dump_data, smem_len,
  978                                 fwrt->trans->cfg->smem_offset,
  979                                 IWL_FW_ERROR_DUMP_MEM_SMEM);
  980 
  981                 iwl_fw_dump_mem(fwrt, &dump_data, sram2_len,
  982                                 fwrt->trans->cfg->dccm2_offset,
  983                                 IWL_FW_ERROR_DUMP_MEM_SRAM);
  984         }
  985 
  986         if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) {
  987                 u32 addr = fwrt->trans->cfg->d3_debug_data_base_addr;
  988                 size_t data_size = fwrt->trans->cfg->d3_debug_data_length;
  989 
  990                 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
  991                 dump_data->len = cpu_to_le32(data_size * 2);
  992 
  993                 memcpy(dump_data->data, fwrt->dump.d3_debug_data, data_size);
  994 
  995                 kfree(fwrt->dump.d3_debug_data);
  996                 fwrt->dump.d3_debug_data = NULL;
  997 
  998                 iwl_trans_read_mem_bytes(fwrt->trans, addr,
  999                                          dump_data->data + data_size,
 1000                                          data_size);
 1001 
 1002                 if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
 1003                         fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx, addr,
 1004                                                      dump_data->data + data_size,
 1005                                                      data_size);
 1006 
 1007                 dump_data = iwl_fw_error_next_data(dump_data);
 1008         }
 1009 
 1010         /* Dump fw's virtual image */
 1011         if (iwl_fw_dbg_is_paging_enabled(fwrt))
 1012                 iwl_dump_paging(fwrt, &dump_data);
 1013 
 1014         if (prph_len)
 1015                 iwl_fw_prph_handler(fwrt, &dump_data, iwl_dump_prph);
 1016 
 1017 out:
 1018         dump_file->file_len = cpu_to_le32(file_len);
 1019         return dump_file;
 1020 }
 1021 
 1022 /**
 1023  * struct iwl_dump_ini_region_data - region data
 1024  * @reg_tlv: region TLV
 1025  * @dump_data: dump data
 1026  */
 1027 struct iwl_dump_ini_region_data {
 1028         struct iwl_ucode_tlv *reg_tlv;
 1029         struct iwl_fwrt_dump_data *dump_data;
 1030 };
 1031 
 1032 static int
 1033 iwl_dump_ini_prph_mac_iter(struct iwl_fw_runtime *fwrt,
 1034                            struct iwl_dump_ini_region_data *reg_data,
 1035                            void *range_ptr, u32 range_len, int idx)
 1036 {
 1037         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1038         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1039         __le32 *val = range->data;
 1040         u32 prph_val;
 1041         u32 addr = le32_to_cpu(reg->addrs[idx]) +
 1042                    le32_to_cpu(reg->dev_addr.offset);
 1043         int i;
 1044 
 1045         range->internal_base_addr = cpu_to_le32(addr);
 1046         range->range_data_size = reg->dev_addr.size;
 1047         for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) {
 1048                 prph_val = iwl_read_prph(fwrt->trans, addr + i);
 1049                 if (prph_val == 0x5a5a5a5a)
 1050                         return -EBUSY;
 1051                 *val++ = cpu_to_le32(prph_val);
 1052         }
 1053 
 1054         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1055 }
 1056 
 1057 static int
 1058 iwl_dump_ini_prph_phy_iter(struct iwl_fw_runtime *fwrt,
 1059                            struct iwl_dump_ini_region_data *reg_data,
 1060                            void *range_ptr, u32 range_len, int idx)
 1061 {
 1062         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1063         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1064         __le32 *val = range->data;
 1065         u32 indirect_wr_addr = WMAL_INDRCT_RD_CMD1;
 1066         u32 indirect_rd_addr = WMAL_MRSPF_1;
 1067         u32 prph_val;
 1068         u32 addr = le32_to_cpu(reg->addrs[idx]);
 1069         u32 dphy_state;
 1070         u32 dphy_addr;
 1071         int i;
 1072 
 1073         range->internal_base_addr = cpu_to_le32(addr);
 1074         range->range_data_size = reg->dev_addr.size;
 1075 
 1076         if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
 1077                 indirect_wr_addr = WMAL_INDRCT_CMD1;
 1078 
 1079         indirect_wr_addr += le32_to_cpu(reg->dev_addr.offset);
 1080         indirect_rd_addr += le32_to_cpu(reg->dev_addr.offset);
 1081 
 1082         if (!iwl_trans_grab_nic_access(fwrt->trans))
 1083                 return -EBUSY;
 1084 
 1085         dphy_addr = (reg->dev_addr.offset) ? WFPM_LMAC2_PS_CTL_RW :
 1086                                              WFPM_LMAC1_PS_CTL_RW;
 1087         dphy_state = iwl_read_umac_prph_no_grab(fwrt->trans, dphy_addr);
 1088 
 1089         for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) {
 1090                 if (dphy_state == HBUS_TIMEOUT ||
 1091                     (dphy_state & WFPM_PS_CTL_RW_PHYRF_PD_FSM_CURSTATE_MSK) !=
 1092                     WFPM_PHYRF_STATE_ON) {
 1093                         *val++ = cpu_to_le32(WFPM_DPHY_OFF);
 1094                         continue;
 1095                 }
 1096 
 1097                 iwl_write_prph_no_grab(fwrt->trans, indirect_wr_addr,
 1098                                        WMAL_INDRCT_CMD(addr + i));
 1099                 prph_val = iwl_read_prph_no_grab(fwrt->trans,
 1100                                                  indirect_rd_addr);
 1101                 *val++ = cpu_to_le32(prph_val);
 1102         }
 1103 
 1104         iwl_trans_release_nic_access(fwrt->trans);
 1105         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1106 }
 1107 
 1108 static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt,
 1109                                  struct iwl_dump_ini_region_data *reg_data,
 1110                                  void *range_ptr, u32 range_len, int idx)
 1111 {
 1112         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1113         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1114         __le32 *val = range->data;
 1115         u32 addr = le32_to_cpu(reg->addrs[idx]) +
 1116                    le32_to_cpu(reg->dev_addr.offset);
 1117         int i;
 1118 
 1119         range->internal_base_addr = cpu_to_le32(addr);
 1120         range->range_data_size = reg->dev_addr.size;
 1121         for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4)
 1122                 *val++ = cpu_to_le32(iwl_trans_read32(fwrt->trans, addr + i));
 1123 
 1124         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1125 }
 1126 
 1127 static int iwl_dump_ini_config_iter(struct iwl_fw_runtime *fwrt,
 1128                                     struct iwl_dump_ini_region_data *reg_data,
 1129                                     void *range_ptr, u32 range_len, int idx)
 1130 {
 1131         struct iwl_trans *trans = fwrt->trans;
 1132         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1133         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1134         __le32 *val = range->data;
 1135         u32 addr = le32_to_cpu(reg->addrs[idx]) +
 1136                    le32_to_cpu(reg->dev_addr.offset);
 1137         int i;
 1138 
 1139         /* we shouldn't get here if the trans doesn't have read_config32 */
 1140         if (WARN_ON_ONCE(!trans->ops->read_config32))
 1141                 return -EOPNOTSUPP;
 1142 
 1143         range->internal_base_addr = cpu_to_le32(addr);
 1144         range->range_data_size = reg->dev_addr.size;
 1145         for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) {
 1146                 int ret;
 1147                 u32 tmp;
 1148 
 1149                 ret = trans->ops->read_config32(trans, addr + i, &tmp);
 1150                 if (ret < 0)
 1151                         return ret;
 1152 
 1153                 *val++ = cpu_to_le32(tmp);
 1154         }
 1155 
 1156         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1157 }
 1158 
 1159 static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt,
 1160                                      struct iwl_dump_ini_region_data *reg_data,
 1161                                      void *range_ptr, u32 range_len, int idx)
 1162 {
 1163         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1164         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1165         u32 addr = le32_to_cpu(reg->addrs[idx]) +
 1166                    le32_to_cpu(reg->dev_addr.offset);
 1167 
 1168         range->internal_base_addr = cpu_to_le32(addr);
 1169         range->range_data_size = reg->dev_addr.size;
 1170         iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
 1171                                  le32_to_cpu(reg->dev_addr.size));
 1172 
 1173         if (reg->sub_type == IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM &&
 1174             fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf)
 1175                 fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx,
 1176                                              range->data,
 1177                                              le32_to_cpu(reg->dev_addr.size));
 1178 
 1179         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1180 }
 1181 
 1182 static int _iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt,
 1183                                      void *range_ptr, u32 range_len, int idx)
 1184 {
 1185         struct page *page = fwrt->fw_paging_db[idx].fw_paging_block;
 1186         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1187         dma_addr_t addr = fwrt->fw_paging_db[idx].fw_paging_phys;
 1188         u32 page_size = fwrt->fw_paging_db[idx].fw_paging_size;
 1189 
 1190         range->page_num = cpu_to_le32(idx);
 1191         range->range_data_size = cpu_to_le32(page_size);
 1192         dma_sync_single_for_cpu(fwrt->trans->dev, addr, page_size,
 1193                                 DMA_BIDIRECTIONAL);
 1194         memcpy(range->data, page_address(page), page_size);
 1195         dma_sync_single_for_device(fwrt->trans->dev, addr, page_size,
 1196                                    DMA_BIDIRECTIONAL);
 1197 
 1198         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1199 }
 1200 
 1201 static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt,
 1202                                     struct iwl_dump_ini_region_data *reg_data,
 1203                                     void *range_ptr, u32 range_len, int idx)
 1204 {
 1205         struct iwl_fw_ini_error_dump_range *range;
 1206         u32 page_size;
 1207 
 1208         /* all paged index start from 1 to skip CSS section */
 1209         idx++;
 1210 
 1211         if (!fwrt->trans->trans_cfg->gen2)
 1212                 return _iwl_dump_ini_paging_iter(fwrt, range_ptr, range_len, idx);
 1213 
 1214         range = range_ptr;
 1215         page_size = fwrt->trans->init_dram.paging[idx].size;
 1216 
 1217         range->page_num = cpu_to_le32(idx);
 1218         range->range_data_size = cpu_to_le32(page_size);
 1219         memcpy(range->data, fwrt->trans->init_dram.paging[idx].block,
 1220                page_size);
 1221 
 1222         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1223 }
 1224 
 1225 static int
 1226 iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
 1227                            struct iwl_dump_ini_region_data *reg_data,
 1228                            void *range_ptr, u32 range_len, int idx)
 1229 {
 1230         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1231         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1232         struct iwl_dram_data *frag;
 1233         u32 alloc_id = le32_to_cpu(reg->dram_alloc_id);
 1234 
 1235         frag = &fwrt->trans->dbg.fw_mon_ini[alloc_id].frags[idx];
 1236 
 1237         range->dram_base_addr = cpu_to_le64(frag->physical);
 1238         range->range_data_size = cpu_to_le32(frag->size);
 1239 
 1240         memcpy(range->data, frag->block, frag->size);
 1241 
 1242         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1243 }
 1244 
 1245 static int iwl_dump_ini_mon_smem_iter(struct iwl_fw_runtime *fwrt,
 1246                                       struct iwl_dump_ini_region_data *reg_data,
 1247                                       void *range_ptr, u32 range_len, int idx)
 1248 {
 1249         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1250         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1251         u32 addr = le32_to_cpu(reg->internal_buffer.base_addr);
 1252 
 1253         range->internal_base_addr = cpu_to_le32(addr);
 1254         range->range_data_size = reg->internal_buffer.size;
 1255         iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
 1256                                  le32_to_cpu(reg->internal_buffer.size));
 1257 
 1258         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1259 }
 1260 
 1261 static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt,
 1262                              struct iwl_dump_ini_region_data *reg_data, int idx)
 1263 {
 1264         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1265         struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data;
 1266         struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
 1267         int txf_num = cfg->num_txfifo_entries;
 1268         int int_txf_num = ARRAY_SIZE(cfg->internal_txfifo_size);
 1269         u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid[0]);
 1270 
 1271         if (!idx) {
 1272                 if (le32_to_cpu(reg->fifos.offset) && cfg->num_lmacs == 1) {
 1273                         IWL_ERR(fwrt, "WRT: Invalid lmac offset 0x%x\n",
 1274                                 le32_to_cpu(reg->fifos.offset));
 1275                         return false;
 1276                 }
 1277 
 1278                 iter->internal_txf = 0;
 1279                 iter->fifo_size = 0;
 1280                 iter->fifo = -1;
 1281                 if (le32_to_cpu(reg->fifos.offset))
 1282                         iter->lmac = 1;
 1283                 else
 1284                         iter->lmac = 0;
 1285         }
 1286 
 1287         if (!iter->internal_txf) {
 1288                 for (iter->fifo++; iter->fifo < txf_num; iter->fifo++) {
 1289                         iter->fifo_size =
 1290                                 cfg->lmac[iter->lmac].txfifo_size[iter->fifo];
 1291                         if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo)))
 1292                                 return true;
 1293                 }
 1294                 iter->fifo--;
 1295         }
 1296 
 1297         iter->internal_txf = 1;
 1298 
 1299         if (!fw_has_capa(&fwrt->fw->ucode_capa,
 1300                          IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))
 1301                 return false;
 1302 
 1303         for (iter->fifo++; iter->fifo < int_txf_num + txf_num; iter->fifo++) {
 1304                 iter->fifo_size =
 1305                         cfg->internal_txfifo_size[iter->fifo - txf_num];
 1306                 if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo)))
 1307                         return true;
 1308         }
 1309 
 1310         return false;
 1311 }
 1312 
 1313 static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
 1314                                  struct iwl_dump_ini_region_data *reg_data,
 1315                                  void *range_ptr, u32 range_len, int idx)
 1316 {
 1317         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1318         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1319         struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data;
 1320         struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
 1321         u32 offs = le32_to_cpu(reg->fifos.offset), addr;
 1322         u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
 1323         u32 registers_size = registers_num * sizeof(*reg_dump);
 1324         __le32 *data;
 1325         int i;
 1326 
 1327         if (!iwl_ini_txf_iter(fwrt, reg_data, idx))
 1328                 return -EIO;
 1329 
 1330         if (!iwl_trans_grab_nic_access(fwrt->trans))
 1331                 return -EBUSY;
 1332 
 1333         range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo);
 1334         range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num);
 1335         range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size);
 1336 
 1337         iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo);
 1338 
 1339         /*
 1340          * read txf registers. for each register, write to the dump the
 1341          * register address and its value
 1342          */
 1343         for (i = 0; i < registers_num; i++) {
 1344                 addr = le32_to_cpu(reg->addrs[i]) + offs;
 1345 
 1346                 reg_dump->addr = cpu_to_le32(addr);
 1347                 reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans,
 1348                                                                    addr));
 1349 
 1350                 reg_dump++;
 1351         }
 1352 
 1353         if (reg->fifos.hdr_only) {
 1354                 range->range_data_size = cpu_to_le32(registers_size);
 1355                 goto out;
 1356         }
 1357 
 1358         /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
 1359         iwl_write_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_ADDR + offs,
 1360                                TXF_WR_PTR + offs);
 1361 
 1362         /* Dummy-read to advance the read pointer to the head */
 1363         iwl_read_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_DATA + offs);
 1364 
 1365         /* Read FIFO */
 1366         addr = TXF_READ_MODIFY_DATA + offs;
 1367         data = (void *)reg_dump;
 1368         for (i = 0; i < iter->fifo_size; i += sizeof(*data))
 1369                 *data++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr));
 1370 
 1371         if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf)
 1372                 fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx,
 1373                                              reg_dump, iter->fifo_size);
 1374 
 1375 out:
 1376         iwl_trans_release_nic_access(fwrt->trans);
 1377 
 1378         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1379 }
 1380 
 1381 struct iwl_ini_rxf_data {
 1382         u32 fifo_num;
 1383         u32 size;
 1384         u32 offset;
 1385 };
 1386 
 1387 static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt,
 1388                                  struct iwl_dump_ini_region_data *reg_data,
 1389                                  struct iwl_ini_rxf_data *data)
 1390 {
 1391         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1392         u32 fid1 = le32_to_cpu(reg->fifos.fid[0]);
 1393         u32 fid2 = le32_to_cpu(reg->fifos.fid[1]);
 1394         u8 fifo_idx;
 1395 
 1396         if (!data)
 1397                 return;
 1398 
 1399         /* make sure only one bit is set in only one fid */
 1400         if (WARN_ONCE(hweight_long(fid1) + hweight_long(fid2) != 1,
 1401                       "fid1=%x, fid2=%x\n", fid1, fid2))
 1402                 return;
 1403 
 1404         memset(data, 0, sizeof(*data));
 1405 
 1406         if (fid1) {
 1407                 fifo_idx = ffs(fid1) - 1;
 1408                 if (WARN_ONCE(fifo_idx >= MAX_NUM_LMAC, "fifo_idx=%d\n",
 1409                               fifo_idx))
 1410                         return;
 1411 
 1412                 data->size = fwrt->smem_cfg.lmac[fifo_idx].rxfifo1_size;
 1413                 data->fifo_num = fifo_idx;
 1414         } else {
 1415                 u8 max_idx;
 1416 
 1417                 fifo_idx = ffs(fid2) - 1;
 1418                 if (iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
 1419                                             SHARED_MEM_CFG_CMD, 0) <= 3)
 1420                         max_idx = 0;
 1421                 else
 1422                         max_idx = 1;
 1423 
 1424                 if (WARN_ONCE(fifo_idx > max_idx,
 1425                               "invalid umac fifo idx %d", fifo_idx))
 1426                         return;
 1427 
 1428                 /* use bit 31 to distinguish between umac and lmac rxf while
 1429                  * parsing the dump
 1430                  */
 1431                 data->fifo_num = fifo_idx | IWL_RXF_UMAC_BIT;
 1432 
 1433                 switch (fifo_idx) {
 1434                 case 0:
 1435                         data->size = fwrt->smem_cfg.rxfifo2_size;
 1436                         data->offset = iwl_umac_prph(fwrt->trans,
 1437                                                      RXF_DIFF_FROM_PREV);
 1438                         break;
 1439                 case 1:
 1440                         data->size = fwrt->smem_cfg.rxfifo2_control_size;
 1441                         data->offset = iwl_umac_prph(fwrt->trans,
 1442                                                      RXF2C_DIFF_FROM_PREV);
 1443                         break;
 1444                 }
 1445         }
 1446 }
 1447 
 1448 static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
 1449                                  struct iwl_dump_ini_region_data *reg_data,
 1450                                  void *range_ptr, u32 range_len, int idx)
 1451 {
 1452         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1453         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1454         struct iwl_ini_rxf_data rxf_data;
 1455         struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
 1456         u32 offs = le32_to_cpu(reg->fifos.offset), addr;
 1457         u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
 1458         u32 registers_size = registers_num * sizeof(*reg_dump);
 1459         __le32 *data;
 1460         int i;
 1461 
 1462         iwl_ini_get_rxf_data(fwrt, reg_data, &rxf_data);
 1463         if (!rxf_data.size)
 1464                 return -EIO;
 1465 
 1466         if (!iwl_trans_grab_nic_access(fwrt->trans))
 1467                 return -EBUSY;
 1468 
 1469         range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num);
 1470         range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num);
 1471         range->range_data_size = cpu_to_le32(rxf_data.size + registers_size);
 1472 
 1473         /*
 1474          * read rxf registers. for each register, write to the dump the
 1475          * register address and its value
 1476          */
 1477         for (i = 0; i < registers_num; i++) {
 1478                 addr = le32_to_cpu(reg->addrs[i]) + offs;
 1479 
 1480                 reg_dump->addr = cpu_to_le32(addr);
 1481                 reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans,
 1482                                                                    addr));
 1483 
 1484                 reg_dump++;
 1485         }
 1486 
 1487         if (reg->fifos.hdr_only) {
 1488                 range->range_data_size = cpu_to_le32(registers_size);
 1489                 goto out;
 1490         }
 1491 
 1492         offs = rxf_data.offset;
 1493 
 1494         /* Lock fence */
 1495         iwl_write_prph_no_grab(fwrt->trans, RXF_SET_FENCE_MODE + offs, 0x1);
 1496         /* Set fence pointer to the same place like WR pointer */
 1497         iwl_write_prph_no_grab(fwrt->trans, RXF_LD_WR2FENCE + offs, 0x1);
 1498         /* Set fence offset */
 1499         iwl_write_prph_no_grab(fwrt->trans, RXF_LD_FENCE_OFFSET_ADDR + offs,
 1500                                0x0);
 1501 
 1502         /* Read FIFO */
 1503         addr =  RXF_FIFO_RD_FENCE_INC + offs;
 1504         data = (void *)reg_dump;
 1505         for (i = 0; i < rxf_data.size; i += sizeof(*data))
 1506                 *data++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr));
 1507 
 1508 out:
 1509         iwl_trans_release_nic_access(fwrt->trans);
 1510 
 1511         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1512 }
 1513 
 1514 static int
 1515 iwl_dump_ini_err_table_iter(struct iwl_fw_runtime *fwrt,
 1516                             struct iwl_dump_ini_region_data *reg_data,
 1517                             void *range_ptr, u32 range_len, int idx)
 1518 {
 1519         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1520         struct iwl_fw_ini_region_err_table *err_table = &reg->err_table;
 1521         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1522         u32 addr = le32_to_cpu(err_table->base_addr) +
 1523                    le32_to_cpu(err_table->offset);
 1524 
 1525         range->internal_base_addr = cpu_to_le32(addr);
 1526         range->range_data_size = err_table->size;
 1527         iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
 1528                                  le32_to_cpu(err_table->size));
 1529 
 1530         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1531 }
 1532 
 1533 static int
 1534 iwl_dump_ini_special_mem_iter(struct iwl_fw_runtime *fwrt,
 1535                               struct iwl_dump_ini_region_data *reg_data,
 1536                               void *range_ptr, u32 range_len, int idx)
 1537 {
 1538         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1539         struct iwl_fw_ini_region_special_device_memory *special_mem =
 1540                 &reg->special_mem;
 1541 
 1542         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1543         u32 addr = le32_to_cpu(special_mem->base_addr) +
 1544                    le32_to_cpu(special_mem->offset);
 1545 
 1546         range->internal_base_addr = cpu_to_le32(addr);
 1547         range->range_data_size = special_mem->size;
 1548         iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
 1549                                  le32_to_cpu(special_mem->size));
 1550 
 1551         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1552 }
 1553 
 1554 static int
 1555 iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt,
 1556                             struct iwl_dump_ini_region_data *reg_data,
 1557                             void *range_ptr, u32 range_len, int idx)
 1558 {
 1559         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1560         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1561         __le32 *val = range->data;
 1562         u32 prph_data;
 1563         int i;
 1564 
 1565         if (!iwl_trans_grab_nic_access(fwrt->trans))
 1566                 return -EBUSY;
 1567 
 1568         range->range_data_size = reg->dev_addr.size;
 1569         for (i = 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) {
 1570                 prph_data = iwl_read_prph_no_grab(fwrt->trans, (i % 2) ?
 1571                                           DBGI_SRAM_TARGET_ACCESS_RDATA_MSB :
 1572                                           DBGI_SRAM_TARGET_ACCESS_RDATA_LSB);
 1573                 if (prph_data == 0x5a5a5a5a) {
 1574                         iwl_trans_release_nic_access(fwrt->trans);
 1575                         return -EBUSY;
 1576                 }
 1577                 *val++ = cpu_to_le32(prph_data);
 1578         }
 1579         iwl_trans_release_nic_access(fwrt->trans);
 1580         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1581 }
 1582 
 1583 static int iwl_dump_ini_fw_pkt_iter(struct iwl_fw_runtime *fwrt,
 1584                                     struct iwl_dump_ini_region_data *reg_data,
 1585                                     void *range_ptr, u32 range_len, int idx)
 1586 {
 1587         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1588         struct iwl_rx_packet *pkt = reg_data->dump_data->fw_pkt;
 1589         u32 pkt_len;
 1590 
 1591         if (!pkt)
 1592                 return -EIO;
 1593 
 1594         pkt_len = iwl_rx_packet_payload_len(pkt);
 1595 
 1596         memcpy(&range->fw_pkt_hdr, &pkt->hdr, sizeof(range->fw_pkt_hdr));
 1597         range->range_data_size = cpu_to_le32(pkt_len);
 1598 
 1599         memcpy(range->data, pkt->data, pkt_len);
 1600 
 1601         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1602 }
 1603 
 1604 static int iwl_dump_ini_imr_iter(struct iwl_fw_runtime *fwrt,
 1605                                  struct iwl_dump_ini_region_data *reg_data,
 1606                                  void *range_ptr, u32 range_len, int idx)
 1607 {
 1608         /* read the IMR memory and DMA it to SRAM */
 1609         struct iwl_fw_ini_error_dump_range *range = range_ptr;
 1610         u64 imr_curr_addr = fwrt->trans->dbg.imr_data.imr_curr_addr;
 1611         u32 imr_rem_bytes = fwrt->trans->dbg.imr_data.imr2sram_remainbyte;
 1612         u32 sram_addr = fwrt->trans->dbg.imr_data.sram_addr;
 1613         u32 sram_size = fwrt->trans->dbg.imr_data.sram_size;
 1614         u32 size_to_dump = (imr_rem_bytes > sram_size) ? sram_size : imr_rem_bytes;
 1615 
 1616         range->range_data_size = cpu_to_le32(size_to_dump);
 1617         if (iwl_trans_write_imr_mem(fwrt->trans, sram_addr,
 1618                                     imr_curr_addr, size_to_dump)) {
 1619                 IWL_ERR(fwrt, "WRT_DEBUG: IMR Memory transfer failed\n");
 1620                 return -1;
 1621         }
 1622 
 1623         fwrt->trans->dbg.imr_data.imr_curr_addr = imr_curr_addr + size_to_dump;
 1624         fwrt->trans->dbg.imr_data.imr2sram_remainbyte -= size_to_dump;
 1625 
 1626         iwl_trans_read_mem_bytes(fwrt->trans, sram_addr, range->data,
 1627                                  size_to_dump);
 1628         return sizeof(*range) + le32_to_cpu(range->range_data_size);
 1629 }
 1630 
 1631 static void *
 1632 iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt,
 1633                              struct iwl_dump_ini_region_data *reg_data,
 1634                              void *data, u32 data_len)
 1635 {
 1636         struct iwl_fw_ini_error_dump *dump = data;
 1637 
 1638         dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
 1639 
 1640         return dump->data;
 1641 }
 1642 
 1643 /**
 1644  * mask_apply_and_normalize - applies mask on val and normalize the result
 1645  *
 1646  * The normalization is based on the first set bit in the mask
 1647  *
 1648  * @val: value
 1649  * @mask: mask to apply and to normalize with
 1650  */
 1651 static u32 mask_apply_and_normalize(u32 val, u32 mask)
 1652 {
 1653         return (val & mask) >> (ffs(mask) - 1);
 1654 }
 1655 
 1656 static __le32 iwl_get_mon_reg(struct iwl_fw_runtime *fwrt, u32 alloc_id,
 1657                               const struct iwl_fw_mon_reg *reg_info)
 1658 {
 1659         u32 val, offs;
 1660 
 1661         /* The header addresses of DBGCi is calculate as follows:
 1662          * DBGC1 address + (0x100 * i)
 1663          */
 1664         offs = (alloc_id - IWL_FW_INI_ALLOCATION_ID_DBGC1) * 0x100;
 1665 
 1666         if (!reg_info || !reg_info->addr || !reg_info->mask)
 1667                 return 0;
 1668 
 1669         val = iwl_read_prph_no_grab(fwrt->trans, reg_info->addr + offs);
 1670 
 1671         return cpu_to_le32(mask_apply_and_normalize(val, reg_info->mask));
 1672 }
 1673 
 1674 static void *
 1675 iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt,
 1676                              struct iwl_dump_ini_region_data *reg_data,
 1677                              struct iwl_fw_ini_monitor_dump *data,
 1678                              const struct iwl_fw_mon_regs *addrs)
 1679 {
 1680         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1681         u32 alloc_id = le32_to_cpu(reg->dram_alloc_id);
 1682 
 1683         if (!iwl_trans_grab_nic_access(fwrt->trans)) {
 1684                 IWL_ERR(fwrt, "Failed to get monitor header\n");
 1685                 return NULL;
 1686         }
 1687 
 1688         data->write_ptr = iwl_get_mon_reg(fwrt, alloc_id,
 1689                                           &addrs->write_ptr);
 1690         if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
 1691                 u32 wrt_ptr = le32_to_cpu(data->write_ptr);
 1692 
 1693                 data->write_ptr = cpu_to_le32(wrt_ptr >> 2);
 1694         }
 1695         data->cycle_cnt = iwl_get_mon_reg(fwrt, alloc_id,
 1696                                           &addrs->cycle_cnt);
 1697         data->cur_frag = iwl_get_mon_reg(fwrt, alloc_id,
 1698                                          &addrs->cur_frag);
 1699 
 1700         iwl_trans_release_nic_access(fwrt->trans);
 1701 
 1702         data->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
 1703 
 1704         return data->data;
 1705 }
 1706 
 1707 static void *
 1708 iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt,
 1709                                   struct iwl_dump_ini_region_data *reg_data,
 1710                                   void *data, u32 data_len)
 1711 {
 1712         struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;
 1713 
 1714         return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump,
 1715                                             &fwrt->trans->cfg->mon_dram_regs);
 1716 }
 1717 
 1718 static void *
 1719 iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt,
 1720                                   struct iwl_dump_ini_region_data *reg_data,
 1721                                   void *data, u32 data_len)
 1722 {
 1723         struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;
 1724 
 1725         return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump,
 1726                                             &fwrt->trans->cfg->mon_smem_regs);
 1727 }
 1728 
 1729 static void *
 1730 iwl_dump_ini_mon_dbgi_fill_header(struct iwl_fw_runtime *fwrt,
 1731                                   struct iwl_dump_ini_region_data *reg_data,
 1732                                   void *data, u32 data_len)
 1733 {
 1734         struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;
 1735 
 1736         return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump,
 1737                                             &fwrt->trans->cfg->mon_dbgi_regs);
 1738 }
 1739 
 1740 static void *
 1741 iwl_dump_ini_err_table_fill_header(struct iwl_fw_runtime *fwrt,
 1742                                    struct iwl_dump_ini_region_data *reg_data,
 1743                                    void *data, u32 data_len)
 1744 {
 1745         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1746         struct iwl_fw_ini_err_table_dump *dump = data;
 1747 
 1748         dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
 1749         dump->version = reg->err_table.version;
 1750 
 1751         return dump->data;
 1752 }
 1753 
 1754 static void *
 1755 iwl_dump_ini_special_mem_fill_header(struct iwl_fw_runtime *fwrt,
 1756                                      struct iwl_dump_ini_region_data *reg_data,
 1757                                      void *data, u32 data_len)
 1758 {
 1759         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1760         struct iwl_fw_ini_special_device_memory *dump = data;
 1761 
 1762         dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
 1763         dump->type = reg->special_mem.type;
 1764         dump->version = reg->special_mem.version;
 1765 
 1766         return dump->data;
 1767 }
 1768 
 1769 static void *
 1770 iwl_dump_ini_imr_fill_header(struct iwl_fw_runtime *fwrt,
 1771                              struct iwl_dump_ini_region_data *reg_data,
 1772                              void *data, u32 data_len)
 1773 {
 1774         struct iwl_fw_ini_error_dump *dump = data;
 1775 
 1776         dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
 1777 
 1778         return dump->data;
 1779 }
 1780 
 1781 static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt,
 1782                                    struct iwl_dump_ini_region_data *reg_data)
 1783 {
 1784         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1785 
 1786         return iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
 1787 }
 1788 
 1789 static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt,
 1790                                       struct iwl_dump_ini_region_data *reg_data)
 1791 {
 1792         if (fwrt->trans->trans_cfg->gen2) {
 1793                 if (fwrt->trans->init_dram.paging_cnt)
 1794                         return fwrt->trans->init_dram.paging_cnt - 1;
 1795                 else
 1796                         return 0;
 1797         }
 1798 
 1799         return fwrt->num_of_paging_blk;
 1800 }
 1801 
 1802 static u32
 1803 iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt,
 1804                              struct iwl_dump_ini_region_data *reg_data)
 1805 {
 1806         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1807         struct iwl_fw_mon *fw_mon;
 1808         u32 ranges = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id);
 1809         int i;
 1810 
 1811         fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
 1812 
 1813         for (i = 0; i < fw_mon->num_frags; i++) {
 1814                 if (!fw_mon->frags[i].size)
 1815                         break;
 1816 
 1817                 ranges++;
 1818         }
 1819 
 1820         return ranges;
 1821 }
 1822 
 1823 static u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt,
 1824                                    struct iwl_dump_ini_region_data *reg_data)
 1825 {
 1826         u32 num_of_fifos = 0;
 1827 
 1828         while (iwl_ini_txf_iter(fwrt, reg_data, num_of_fifos))
 1829                 num_of_fifos++;
 1830 
 1831         return num_of_fifos;
 1832 }
 1833 
 1834 static u32 iwl_dump_ini_single_range(struct iwl_fw_runtime *fwrt,
 1835                                      struct iwl_dump_ini_region_data *reg_data)
 1836 {
 1837         return 1;
 1838 }
 1839 
 1840 static u32 iwl_dump_ini_imr_ranges(struct iwl_fw_runtime *fwrt,
 1841                                    struct iwl_dump_ini_region_data *reg_data)
 1842 {
 1843         /* range is total number of pages need to copied from
 1844          *IMR memory to SRAM and later from SRAM to DRAM
 1845          */
 1846         u32 imr_enable = fwrt->trans->dbg.imr_data.imr_enable;
 1847         u32 imr_size = fwrt->trans->dbg.imr_data.imr_size;
 1848         u32 sram_size = fwrt->trans->dbg.imr_data.sram_size;
 1849 
 1850         if (imr_enable == 0 || imr_size == 0 || sram_size == 0) {
 1851                 IWL_DEBUG_INFO(fwrt,
 1852                                "WRT: Invalid imr data enable: %d, imr_size: %d, sram_size: %d\n",
 1853                                imr_enable, imr_size, sram_size);
 1854                 return 0;
 1855         }
 1856 
 1857         return((imr_size % sram_size) ? (imr_size / sram_size + 1) : (imr_size / sram_size));
 1858 }
 1859 
 1860 static u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt,
 1861                                      struct iwl_dump_ini_region_data *reg_data)
 1862 {
 1863         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1864         u32 size = le32_to_cpu(reg->dev_addr.size);
 1865         u32 ranges = iwl_dump_ini_mem_ranges(fwrt, reg_data);
 1866 
 1867         if (!size || !ranges)
 1868                 return 0;
 1869 
 1870         return sizeof(struct iwl_fw_ini_error_dump) + ranges *
 1871                 (size + sizeof(struct iwl_fw_ini_error_dump_range));
 1872 }
 1873 
 1874 static u32
 1875 iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt,
 1876                              struct iwl_dump_ini_region_data *reg_data)
 1877 {
 1878         int i;
 1879         u32 range_header_len = sizeof(struct iwl_fw_ini_error_dump_range);
 1880         u32 size = sizeof(struct iwl_fw_ini_error_dump);
 1881 
 1882         /* start from 1 to skip CSS section */
 1883         for (i = 1; i <= iwl_dump_ini_paging_ranges(fwrt, reg_data); i++) {
 1884                 size += range_header_len;
 1885                 if (fwrt->trans->trans_cfg->gen2)
 1886                         size += fwrt->trans->init_dram.paging[i].size;
 1887                 else
 1888                         size += fwrt->fw_paging_db[i].fw_paging_size;
 1889         }
 1890 
 1891         return size;
 1892 }
 1893 
 1894 static u32
 1895 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
 1896                                struct iwl_dump_ini_region_data *reg_data)
 1897 {
 1898         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1899         struct iwl_fw_mon *fw_mon;
 1900         u32 size = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id);
 1901         int i;
 1902 
 1903         fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
 1904 
 1905         for (i = 0; i < fw_mon->num_frags; i++) {
 1906                 struct iwl_dram_data *frag = &fw_mon->frags[i];
 1907 
 1908                 if (!frag->size)
 1909                         break;
 1910 
 1911                 size += sizeof(struct iwl_fw_ini_error_dump_range) + frag->size;
 1912         }
 1913 
 1914         if (size)
 1915                 size += sizeof(struct iwl_fw_ini_monitor_dump);
 1916 
 1917         return size;
 1918 }
 1919 
 1920 static u32
 1921 iwl_dump_ini_mon_smem_get_size(struct iwl_fw_runtime *fwrt,
 1922                                struct iwl_dump_ini_region_data *reg_data)
 1923 {
 1924         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1925         u32 size;
 1926 
 1927         size = le32_to_cpu(reg->internal_buffer.size);
 1928         if (!size)
 1929                 return 0;
 1930 
 1931         size += sizeof(struct iwl_fw_ini_monitor_dump) +
 1932                 sizeof(struct iwl_fw_ini_error_dump_range);
 1933 
 1934         return size;
 1935 }
 1936 
 1937 static u32 iwl_dump_ini_mon_dbgi_get_size(struct iwl_fw_runtime *fwrt,
 1938                                           struct iwl_dump_ini_region_data *reg_data)
 1939 {
 1940         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1941         u32 size = le32_to_cpu(reg->dev_addr.size);
 1942         u32 ranges = iwl_dump_ini_mem_ranges(fwrt, reg_data);
 1943 
 1944         if (!size || !ranges)
 1945                 return 0;
 1946 
 1947         return sizeof(struct iwl_fw_ini_monitor_dump) + ranges *
 1948                 (size + sizeof(struct iwl_fw_ini_error_dump_range));
 1949 }
 1950 
 1951 static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
 1952                                      struct iwl_dump_ini_region_data *reg_data)
 1953 {
 1954         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1955         struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data;
 1956         u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
 1957         u32 size = 0;
 1958         u32 fifo_hdr = sizeof(struct iwl_fw_ini_error_dump_range) +
 1959                        registers_num *
 1960                        sizeof(struct iwl_fw_ini_error_dump_register);
 1961 
 1962         while (iwl_ini_txf_iter(fwrt, reg_data, size)) {
 1963                 size += fifo_hdr;
 1964                 if (!reg->fifos.hdr_only)
 1965                         size += iter->fifo_size;
 1966         }
 1967 
 1968         if (!size)
 1969                 return 0;
 1970 
 1971         return size + sizeof(struct iwl_fw_ini_error_dump);
 1972 }
 1973 
 1974 static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt,
 1975                                      struct iwl_dump_ini_region_data *reg_data)
 1976 {
 1977         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1978         struct iwl_ini_rxf_data rx_data;
 1979         u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
 1980         u32 size = sizeof(struct iwl_fw_ini_error_dump) +
 1981                 sizeof(struct iwl_fw_ini_error_dump_range) +
 1982                 registers_num * sizeof(struct iwl_fw_ini_error_dump_register);
 1983 
 1984         if (reg->fifos.hdr_only)
 1985                 return size;
 1986 
 1987         iwl_ini_get_rxf_data(fwrt, reg_data, &rx_data);
 1988         size += rx_data.size;
 1989 
 1990         return size;
 1991 }
 1992 
 1993 static u32
 1994 iwl_dump_ini_err_table_get_size(struct iwl_fw_runtime *fwrt,
 1995                                 struct iwl_dump_ini_region_data *reg_data)
 1996 {
 1997         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 1998         u32 size = le32_to_cpu(reg->err_table.size);
 1999 
 2000         if (size)
 2001                 size += sizeof(struct iwl_fw_ini_err_table_dump) +
 2002                         sizeof(struct iwl_fw_ini_error_dump_range);
 2003 
 2004         return size;
 2005 }
 2006 
 2007 static u32
 2008 iwl_dump_ini_special_mem_get_size(struct iwl_fw_runtime *fwrt,
 2009                                   struct iwl_dump_ini_region_data *reg_data)
 2010 {
 2011         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 2012         u32 size = le32_to_cpu(reg->special_mem.size);
 2013 
 2014         if (size)
 2015                 size += sizeof(struct iwl_fw_ini_special_device_memory) +
 2016                         sizeof(struct iwl_fw_ini_error_dump_range);
 2017 
 2018         return size;
 2019 }
 2020 
 2021 static u32
 2022 iwl_dump_ini_fw_pkt_get_size(struct iwl_fw_runtime *fwrt,
 2023                              struct iwl_dump_ini_region_data *reg_data)
 2024 {
 2025         u32 size = 0;
 2026 
 2027         if (!reg_data->dump_data->fw_pkt)
 2028                 return 0;
 2029 
 2030         size += iwl_rx_packet_payload_len(reg_data->dump_data->fw_pkt);
 2031         if (size)
 2032                 size += sizeof(struct iwl_fw_ini_error_dump) +
 2033                         sizeof(struct iwl_fw_ini_error_dump_range);
 2034 
 2035         return size;
 2036 }
 2037 
 2038 static u32
 2039 iwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt,
 2040                           struct iwl_dump_ini_region_data *reg_data)
 2041 {
 2042         u32 size = 0;
 2043         u32 ranges = 0;
 2044         u32 imr_enable = fwrt->trans->dbg.imr_data.imr_enable;
 2045         u32 imr_size = fwrt->trans->dbg.imr_data.imr_size;
 2046         u32 sram_size = fwrt->trans->dbg.imr_data.sram_size;
 2047 
 2048         if (imr_enable == 0 || imr_size == 0 || sram_size == 0) {
 2049                 IWL_DEBUG_INFO(fwrt,
 2050                                "WRT: Invalid imr data enable: %d, imr_size: %d, sram_size: %d\n",
 2051                                imr_enable, imr_size, sram_size);
 2052                 return size;
 2053         }
 2054         size = imr_size;
 2055         ranges = iwl_dump_ini_imr_ranges(fwrt, reg_data);
 2056         if (!size && !ranges) {
 2057                 IWL_ERR(fwrt, "WRT: imr_size :=%d, ranges :=%d\n", size, ranges);
 2058                 return 0;
 2059         }
 2060         size += sizeof(struct iwl_fw_ini_error_dump) +
 2061                 ranges * sizeof(struct iwl_fw_ini_error_dump_range);
 2062         return size;
 2063 }
 2064 
 2065 /**
 2066  * struct iwl_dump_ini_mem_ops - ini memory dump operations
 2067  * @get_num_of_ranges: returns the number of memory ranges in the region.
 2068  * @get_size: returns the total size of the region.
 2069  * @fill_mem_hdr: fills region type specific headers and returns pointer to
 2070  *      the first range or NULL if failed to fill headers.
 2071  * @fill_range: copies a given memory range into the dump.
 2072  *      Returns the size of the range or negative error value otherwise.
 2073  */
 2074 struct iwl_dump_ini_mem_ops {
 2075         u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt,
 2076                                  struct iwl_dump_ini_region_data *reg_data);
 2077         u32 (*get_size)(struct iwl_fw_runtime *fwrt,
 2078                         struct iwl_dump_ini_region_data *reg_data);
 2079         void *(*fill_mem_hdr)(struct iwl_fw_runtime *fwrt,
 2080                               struct iwl_dump_ini_region_data *reg_data,
 2081                               void *data, u32 data_len);
 2082         int (*fill_range)(struct iwl_fw_runtime *fwrt,
 2083                           struct iwl_dump_ini_region_data *reg_data,
 2084                           void *range, u32 range_len, int idx);
 2085 };
 2086 
 2087 /**
 2088  * iwl_dump_ini_mem
 2089  *
 2090  * Creates a dump tlv and copy a memory region into it.
 2091  * Returns the size of the current dump tlv or 0 if failed
 2092  *
 2093  * @fwrt: fw runtime struct
 2094  * @list: list to add the dump tlv to
 2095  * @reg_data: memory region
 2096  * @ops: memory dump operations
 2097  */
 2098 static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list,
 2099                             struct iwl_dump_ini_region_data *reg_data,
 2100                             const struct iwl_dump_ini_mem_ops *ops)
 2101 {
 2102         struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
 2103         struct iwl_fw_ini_dump_entry *entry;
 2104         struct iwl_fw_ini_error_dump_data *tlv;
 2105         struct iwl_fw_ini_error_dump_header *header;
 2106         u32 type = reg->type;
 2107         u32 id = le32_get_bits(reg->id, IWL_FW_INI_REGION_ID_MASK);
 2108         u32 num_of_ranges, i, size;
 2109         u8 *range;
 2110         u32 free_size;
 2111         u64 header_size;
 2112         u32 dump_policy = IWL_FW_INI_DUMP_VERBOSE;
 2113 
 2114         IWL_DEBUG_FW(fwrt, "WRT: Collecting region: dump type=%d, id=%d, type=%d\n",
 2115                      dump_policy, id, type);
 2116 
 2117         if (le32_to_cpu(reg->hdr.version) >= 2) {
 2118                 u32 dp = le32_get_bits(reg->id,
 2119                                        IWL_FW_INI_REGION_DUMP_POLICY_MASK);
 2120 
 2121                 if (dump_policy == IWL_FW_INI_DUMP_VERBOSE &&
 2122                     !(dp & IWL_FW_INI_DEBUG_DUMP_POLICY_NO_LIMIT)) {
 2123                         IWL_DEBUG_FW(fwrt,
 2124                                      "WRT: no dump - type %d and policy mismatch=%d\n",
 2125                                      dump_policy, dp);
 2126                         return 0;
 2127                 } else if (dump_policy == IWL_FW_INI_DUMP_MEDIUM &&
 2128                            !(dp & IWL_FW_IWL_DEBUG_DUMP_POLICY_MAX_LIMIT_5MB)) {
 2129                         IWL_DEBUG_FW(fwrt,
 2130                                      "WRT: no dump - type %d and policy mismatch=%d\n",
 2131                                      dump_policy, dp);
 2132                         return 0;
 2133                 } else if (dump_policy == IWL_FW_INI_DUMP_BRIEF &&
 2134                            !(dp & IWL_FW_INI_DEBUG_DUMP_POLICY_MAX_LIMIT_600KB)) {
 2135                         IWL_DEBUG_FW(fwrt,
 2136                                      "WRT: no dump - type %d and policy mismatch=%d\n",
 2137                                      dump_policy, dp);
 2138                         return 0;
 2139                 }
 2140         }
 2141 
 2142         if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr ||
 2143             !ops->fill_range) {
 2144                 IWL_DEBUG_FW(fwrt, "WRT: no ops for collecting data\n");
 2145                 return 0;
 2146         }
 2147 
 2148         size = ops->get_size(fwrt, reg_data);
 2149 
 2150         if (size < sizeof(*header)) {
 2151                 IWL_DEBUG_FW(fwrt, "WRT: size didn't include space for header\n");
 2152                 return 0;
 2153         }
 2154 
 2155         entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + size);
 2156         if (!entry)
 2157                 return 0;
 2158 
 2159         entry->size = sizeof(*tlv) + size;
 2160 
 2161         tlv = (void *)entry->data;
 2162         tlv->type = reg->type;
 2163         tlv->sub_type = reg->sub_type;
 2164         tlv->sub_type_ver = reg->sub_type_ver;
 2165         tlv->reserved = reg->reserved;
 2166         tlv->len = cpu_to_le32(size);
 2167 
 2168         num_of_ranges = ops->get_num_of_ranges(fwrt, reg_data);
 2169 
 2170         header = (void *)tlv->data;
 2171         header->region_id = cpu_to_le32(id);
 2172         header->num_of_ranges = cpu_to_le32(num_of_ranges);
 2173         header->name_len = cpu_to_le32(IWL_FW_INI_MAX_NAME);
 2174         memcpy(header->name, reg->name, IWL_FW_INI_MAX_NAME);
 2175 
 2176         free_size = size;
 2177         range = ops->fill_mem_hdr(fwrt, reg_data, header, free_size);
 2178         if (!range) {
 2179                 IWL_ERR(fwrt,
 2180                         "WRT: Failed to fill region header: id=%d, type=%d\n",
 2181                         id, type);
 2182                 goto out_err;
 2183         }
 2184 
 2185         header_size = range - (u8 *)header;
 2186 
 2187         if (WARN(header_size > free_size,
 2188 #if defined(__linux__)
 2189                  "header size %llu > free_size %d",
 2190                  header_size, free_size)) {
 2191 #elif defined(__FreeBSD__)
 2192                  "header size %ju > free_size %d",
 2193                  (uintmax_t)header_size, free_size)) {
 2194 #endif
 2195                 IWL_ERR(fwrt,
 2196                         "WRT: fill_mem_hdr used more than given free_size\n");
 2197                 goto out_err;
 2198         }
 2199 
 2200         free_size -= header_size;
 2201 
 2202         for (i = 0; i < num_of_ranges; i++) {
 2203                 int range_size = ops->fill_range(fwrt, reg_data, range,
 2204                                                  free_size, i);
 2205 
 2206                 if (range_size < 0) {
 2207                         IWL_ERR(fwrt,
 2208                                 "WRT: Failed to dump region: id=%d, type=%d\n",
 2209                                 id, type);
 2210                         goto out_err;
 2211                 }
 2212 
 2213                 if (WARN(range_size > free_size, "range_size %d > free_size %d",
 2214                          range_size, free_size)) {
 2215                         IWL_ERR(fwrt,
 2216                                 "WRT: fill_raged used more than given free_size\n");
 2217                         goto out_err;
 2218                 }
 2219 
 2220                 free_size -= range_size;
 2221                 range = range + range_size;
 2222         }
 2223 
 2224         list_add_tail(&entry->list, list);
 2225 
 2226         return entry->size;
 2227 
 2228 out_err:
 2229         vfree(entry);
 2230 
 2231         return 0;
 2232 }
 2233 
 2234 static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt,
 2235                              struct iwl_fw_ini_trigger_tlv *trigger,
 2236                              struct list_head *list)
 2237 {
 2238         struct iwl_fw_ini_dump_entry *entry;
 2239         struct iwl_fw_error_dump_data *tlv;
 2240         struct iwl_fw_ini_dump_info *dump;
 2241         struct iwl_dbg_tlv_node *node;
 2242         struct iwl_fw_ini_dump_cfg_name *cfg_name;
 2243         u32 size = sizeof(*tlv) + sizeof(*dump);
 2244         u32 num_of_cfg_names = 0;
 2245         u32 hw_type;
 2246 
 2247         list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) {
 2248                 size += sizeof(*cfg_name);
 2249                 num_of_cfg_names++;
 2250         }
 2251 
 2252         entry = vzalloc(sizeof(*entry) + size);
 2253         if (!entry)
 2254                 return 0;
 2255 
 2256         entry->size = size;
 2257 
 2258         tlv = (void *)entry->data;
 2259         tlv->type = cpu_to_le32(IWL_INI_DUMP_INFO_TYPE);
 2260         tlv->len = cpu_to_le32(size - sizeof(*tlv));
 2261 
 2262         dump = (void *)tlv->data;
 2263 
 2264         dump->version = cpu_to_le32(IWL_INI_DUMP_VER);
 2265         dump->time_point = trigger->time_point;
 2266         dump->trigger_reason = trigger->trigger_reason;
 2267         dump->external_cfg_state =
 2268                 cpu_to_le32(fwrt->trans->dbg.external_ini_cfg);
 2269 
 2270         dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type);
 2271         dump->ver_subtype = cpu_to_le32(fwrt->dump.fw_ver.subtype);
 2272 
 2273         dump->hw_step = cpu_to_le32(fwrt->trans->hw_rev_step);
 2274 
 2275         /*
 2276          * Several HWs all have type == 0x42, so we'll override this value
 2277          * according to the detected HW
 2278          */
 2279         hw_type = CSR_HW_REV_TYPE(fwrt->trans->hw_rev);
 2280         if (hw_type == IWL_AX210_HW_TYPE) {
 2281                 u32 prph_val = iwl_read_umac_prph(fwrt->trans, WFPM_OTP_CFG1_ADDR);
 2282                 u32 is_jacket = !!(prph_val & WFPM_OTP_CFG1_IS_JACKET_BIT);
 2283                 u32 is_cdb = !!(prph_val & WFPM_OTP_CFG1_IS_CDB_BIT);
 2284                 u32 masked_bits = is_jacket | (is_cdb << 1);
 2285 
 2286                 /*
 2287                  * The HW type depends on certain bits in this case, so add
 2288                  * these bits to the HW type. We won't have collisions since we
 2289                  * add these bits after the highest possible bit in the mask.
 2290                  */
 2291                 hw_type |= masked_bits << IWL_AX210_HW_TYPE_ADDITION_SHIFT;
 2292         }
 2293         dump->hw_type = cpu_to_le32(hw_type);
 2294 
 2295         dump->rf_id_flavor =
 2296                 cpu_to_le32(CSR_HW_RFID_FLAVOR(fwrt->trans->hw_rf_id));
 2297         dump->rf_id_dash = cpu_to_le32(CSR_HW_RFID_DASH(fwrt->trans->hw_rf_id));
 2298         dump->rf_id_step = cpu_to_le32(CSR_HW_RFID_STEP(fwrt->trans->hw_rf_id));
 2299         dump->rf_id_type = cpu_to_le32(CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id));
 2300 
 2301         dump->lmac_major = cpu_to_le32(fwrt->dump.fw_ver.lmac_major);
 2302         dump->lmac_minor = cpu_to_le32(fwrt->dump.fw_ver.lmac_minor);
 2303         dump->umac_major = cpu_to_le32(fwrt->dump.fw_ver.umac_major);
 2304         dump->umac_minor = cpu_to_le32(fwrt->dump.fw_ver.umac_minor);
 2305 
 2306         dump->fw_mon_mode = cpu_to_le32(fwrt->trans->dbg.ini_dest);
 2307         dump->regions_mask = trigger->regions_mask &
 2308                              ~cpu_to_le64(fwrt->trans->dbg.unsupported_region_msk);
 2309 
 2310         dump->build_tag_len = cpu_to_le32(sizeof(dump->build_tag));
 2311         memcpy(dump->build_tag, fwrt->fw->human_readable,
 2312                sizeof(dump->build_tag));
 2313 
 2314         cfg_name = dump->cfg_names;
 2315         dump->num_of_cfg_names = cpu_to_le32(num_of_cfg_names);
 2316         list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) {
 2317                 struct iwl_fw_ini_debug_info_tlv *debug_info =
 2318                         (void *)node->tlv.data;
 2319 
 2320                 cfg_name->image_type = debug_info->image_type;
 2321                 cfg_name->cfg_name_len =
 2322                         cpu_to_le32(IWL_FW_INI_MAX_CFG_NAME);
 2323                 memcpy(cfg_name->cfg_name, debug_info->debug_cfg_name,
 2324                        sizeof(cfg_name->cfg_name));
 2325                 cfg_name++;
 2326         }
 2327 
 2328         /* add dump info TLV to the beginning of the list since it needs to be
 2329          * the first TLV in the dump
 2330          */
 2331         list_add(&entry->list, list);
 2332 
 2333         return entry->size;
 2334 }
 2335 
 2336 static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
 2337         [IWL_FW_INI_REGION_INVALID] = {},
 2338         [IWL_FW_INI_REGION_INTERNAL_BUFFER] = {
 2339                 .get_num_of_ranges = iwl_dump_ini_single_range,
 2340                 .get_size = iwl_dump_ini_mon_smem_get_size,
 2341                 .fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header,
 2342                 .fill_range = iwl_dump_ini_mon_smem_iter,
 2343         },
 2344         [IWL_FW_INI_REGION_DRAM_BUFFER] = {
 2345                 .get_num_of_ranges = iwl_dump_ini_mon_dram_ranges,
 2346                 .get_size = iwl_dump_ini_mon_dram_get_size,
 2347                 .fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header,
 2348                 .fill_range = iwl_dump_ini_mon_dram_iter,
 2349         },
 2350         [IWL_FW_INI_REGION_TXF] = {
 2351                 .get_num_of_ranges = iwl_dump_ini_txf_ranges,
 2352                 .get_size = iwl_dump_ini_txf_get_size,
 2353                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2354                 .fill_range = iwl_dump_ini_txf_iter,
 2355         },
 2356         [IWL_FW_INI_REGION_RXF] = {
 2357                 .get_num_of_ranges = iwl_dump_ini_single_range,
 2358                 .get_size = iwl_dump_ini_rxf_get_size,
 2359                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2360                 .fill_range = iwl_dump_ini_rxf_iter,
 2361         },
 2362         [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = {
 2363                 .get_num_of_ranges = iwl_dump_ini_single_range,
 2364                 .get_size = iwl_dump_ini_err_table_get_size,
 2365                 .fill_mem_hdr = iwl_dump_ini_err_table_fill_header,
 2366                 .fill_range = iwl_dump_ini_err_table_iter,
 2367         },
 2368         [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = {
 2369                 .get_num_of_ranges = iwl_dump_ini_single_range,
 2370                 .get_size = iwl_dump_ini_err_table_get_size,
 2371                 .fill_mem_hdr = iwl_dump_ini_err_table_fill_header,
 2372                 .fill_range = iwl_dump_ini_err_table_iter,
 2373         },
 2374         [IWL_FW_INI_REGION_RSP_OR_NOTIF] = {
 2375                 .get_num_of_ranges = iwl_dump_ini_single_range,
 2376                 .get_size = iwl_dump_ini_fw_pkt_get_size,
 2377                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2378                 .fill_range = iwl_dump_ini_fw_pkt_iter,
 2379         },
 2380         [IWL_FW_INI_REGION_DEVICE_MEMORY] = {
 2381                 .get_num_of_ranges = iwl_dump_ini_mem_ranges,
 2382                 .get_size = iwl_dump_ini_mem_get_size,
 2383                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2384                 .fill_range = iwl_dump_ini_dev_mem_iter,
 2385         },
 2386         [IWL_FW_INI_REGION_PERIPHERY_MAC] = {
 2387                 .get_num_of_ranges = iwl_dump_ini_mem_ranges,
 2388                 .get_size = iwl_dump_ini_mem_get_size,
 2389                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2390                 .fill_range = iwl_dump_ini_prph_mac_iter,
 2391         },
 2392         [IWL_FW_INI_REGION_PERIPHERY_PHY] = {
 2393                 .get_num_of_ranges = iwl_dump_ini_mem_ranges,
 2394                 .get_size = iwl_dump_ini_mem_get_size,
 2395                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2396                 .fill_range = iwl_dump_ini_prph_phy_iter,
 2397         },
 2398         [IWL_FW_INI_REGION_PERIPHERY_AUX] = {},
 2399         [IWL_FW_INI_REGION_PAGING] = {
 2400                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2401                 .get_num_of_ranges = iwl_dump_ini_paging_ranges,
 2402                 .get_size = iwl_dump_ini_paging_get_size,
 2403                 .fill_range = iwl_dump_ini_paging_iter,
 2404         },
 2405         [IWL_FW_INI_REGION_CSR] = {
 2406                 .get_num_of_ranges = iwl_dump_ini_mem_ranges,
 2407                 .get_size = iwl_dump_ini_mem_get_size,
 2408                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2409                 .fill_range = iwl_dump_ini_csr_iter,
 2410         },
 2411         [IWL_FW_INI_REGION_DRAM_IMR] = {
 2412                 .get_num_of_ranges = iwl_dump_ini_imr_ranges,
 2413                 .get_size = iwl_dump_ini_imr_get_size,
 2414                 .fill_mem_hdr = iwl_dump_ini_imr_fill_header,
 2415                 .fill_range = iwl_dump_ini_imr_iter,
 2416         },
 2417         [IWL_FW_INI_REGION_PCI_IOSF_CONFIG] = {
 2418                 .get_num_of_ranges = iwl_dump_ini_mem_ranges,
 2419                 .get_size = iwl_dump_ini_mem_get_size,
 2420                 .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
 2421                 .fill_range = iwl_dump_ini_config_iter,
 2422         },
 2423         [IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY] = {
 2424                 .get_num_of_ranges = iwl_dump_ini_single_range,
 2425                 .get_size = iwl_dump_ini_special_mem_get_size,
 2426                 .fill_mem_hdr = iwl_dump_ini_special_mem_fill_header,
 2427                 .fill_range = iwl_dump_ini_special_mem_iter,
 2428         },
 2429         [IWL_FW_INI_REGION_DBGI_SRAM] = {
 2430                 .get_num_of_ranges = iwl_dump_ini_mem_ranges,
 2431                 .get_size = iwl_dump_ini_mon_dbgi_get_size,
 2432                 .fill_mem_hdr = iwl_dump_ini_mon_dbgi_fill_header,
 2433                 .fill_range = iwl_dump_ini_dbgi_sram_iter,
 2434         },
 2435 };
 2436 
 2437 static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt,
 2438                                 struct iwl_fwrt_dump_data *dump_data,
 2439                                 struct list_head *list)
 2440 {
 2441         struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig;
 2442         enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trigger->time_point);
 2443         struct iwl_dump_ini_region_data reg_data = {
 2444                 .dump_data = dump_data,
 2445         };
 2446         struct iwl_dump_ini_region_data imr_reg_data = {
 2447                 .dump_data = dump_data,
 2448         };
 2449         int i;
 2450         u32 size = 0;
 2451         u64 regions_mask = le64_to_cpu(trigger->regions_mask) &
 2452                            ~(fwrt->trans->dbg.unsupported_region_msk);
 2453 
 2454         BUILD_BUG_ON(sizeof(trigger->regions_mask) != sizeof(regions_mask));
 2455         BUILD_BUG_ON((sizeof(trigger->regions_mask) * BITS_PER_BYTE) <
 2456                      ARRAY_SIZE(fwrt->trans->dbg.active_regions));
 2457 
 2458         for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.active_regions); i++) {
 2459                 u32 reg_type;
 2460                 struct iwl_fw_ini_region_tlv *reg;
 2461 
 2462                 if (!(BIT_ULL(i) & regions_mask))
 2463                         continue;
 2464 
 2465                 reg_data.reg_tlv = fwrt->trans->dbg.active_regions[i];
 2466                 if (!reg_data.reg_tlv) {
 2467                         IWL_WARN(fwrt,
 2468                                  "WRT: Unassigned region id %d, skipping\n", i);
 2469                         continue;
 2470                 }
 2471 
 2472                 reg = (void *)reg_data.reg_tlv->data;
 2473                 reg_type = reg->type;
 2474                 if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops))
 2475                         continue;
 2476 
 2477                 if (reg_type == IWL_FW_INI_REGION_PERIPHERY_PHY &&
 2478                     tp_id != IWL_FW_INI_TIME_POINT_FW_ASSERT) {
 2479                         IWL_WARN(fwrt,
 2480                                  "WRT: trying to collect phy prph at time point: %d, skipping\n",
 2481                                  tp_id);
 2482                         continue;
 2483                 }
 2484                 /*
 2485                  * DRAM_IMR can be collected only for FW/HW error timepoint
 2486                  * when fw is not alive. In addition, it must be collected
 2487                  * lastly as it overwrites SRAM that can possibly contain
 2488                  * debug data which also need to be collected.
 2489                  */
 2490                 if (reg_type == IWL_FW_INI_REGION_DRAM_IMR) {
 2491                         if (tp_id == IWL_FW_INI_TIME_POINT_FW_ASSERT ||
 2492                             tp_id == IWL_FW_INI_TIME_POINT_FW_HW_ERROR)
 2493                                 imr_reg_data.reg_tlv = fwrt->trans->dbg.active_regions[i];
 2494                         else
 2495                                 IWL_INFO(fwrt,
 2496                                          "WRT: trying to collect DRAM_IMR at time point: %d, skipping\n",
 2497                                          tp_id);
 2498                 /* continue to next region */
 2499                         continue;
 2500                 }
 2501 
 2502 
 2503                 size += iwl_dump_ini_mem(fwrt, list, &reg_data,
 2504                                          &iwl_dump_ini_region_ops[reg_type]);
 2505         }
 2506         /* collect DRAM_IMR region in the last */
 2507         if (imr_reg_data.reg_tlv)
 2508                 size += iwl_dump_ini_mem(fwrt, list, &reg_data,
 2509                                          &iwl_dump_ini_region_ops[IWL_FW_INI_REGION_DRAM_IMR]);
 2510 
 2511         if (size)
 2512                 size += iwl_dump_ini_info(fwrt, trigger, list);
 2513 
 2514         return size;
 2515 }
 2516 
 2517 static bool iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt,
 2518                                   struct iwl_fw_ini_trigger_tlv *trig)
 2519 {
 2520         enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point);
 2521         u32 usec = le32_to_cpu(trig->ignore_consec);
 2522 
 2523         if (!iwl_trans_dbg_ini_valid(fwrt->trans) ||
 2524             tp_id == IWL_FW_INI_TIME_POINT_INVALID ||
 2525             tp_id >= IWL_FW_INI_TIME_POINT_NUM ||
 2526             iwl_fw_dbg_no_trig_window(fwrt, tp_id, usec))
 2527                 return false;
 2528 
 2529         return true;
 2530 }
 2531 
 2532 static u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt,
 2533                                  struct iwl_fwrt_dump_data *dump_data,
 2534                                  struct list_head *list)
 2535 {
 2536         struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig;
 2537         struct iwl_fw_ini_dump_entry *entry;
 2538         struct iwl_fw_ini_dump_file_hdr *hdr;
 2539         u32 size;
 2540 
 2541         if (!trigger || !iwl_fw_ini_trigger_on(fwrt, trigger) ||
 2542             !le64_to_cpu(trigger->regions_mask))
 2543                 return 0;
 2544 
 2545         entry = vzalloc(sizeof(*entry) + sizeof(*hdr));
 2546         if (!entry)
 2547                 return 0;
 2548 
 2549         entry->size = sizeof(*hdr);
 2550 
 2551         size = iwl_dump_ini_trigger(fwrt, dump_data, list);
 2552         if (!size) {
 2553                 vfree(entry);
 2554                 return 0;
 2555         }
 2556 
 2557         hdr = (void *)entry->data;
 2558         hdr->barker = cpu_to_le32(IWL_FW_INI_ERROR_DUMP_BARKER);
 2559         hdr->file_len = cpu_to_le32(size + entry->size);
 2560 
 2561         list_add(&entry->list, list);
 2562 
 2563         return le32_to_cpu(hdr->file_len);
 2564 }
 2565 
 2566 static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt,
 2567                                          const struct iwl_fw_dump_desc *desc)
 2568 {
 2569         if (desc && desc != &iwl_dump_desc_assert)
 2570                 kfree(desc);
 2571 
 2572         fwrt->dump.lmac_err_id[0] = 0;
 2573         if (fwrt->smem_cfg.num_lmacs > 1)
 2574                 fwrt->dump.lmac_err_id[1] = 0;
 2575         fwrt->dump.umac_err_id = 0;
 2576 }
 2577 
 2578 static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
 2579                               struct iwl_fwrt_dump_data *dump_data)
 2580 {
 2581         struct iwl_fw_dump_ptrs fw_error_dump = {};
 2582         struct iwl_fw_error_dump_file *dump_file;
 2583         struct scatterlist *sg_dump_data;
 2584         u32 file_len;
 2585         u32 dump_mask = fwrt->fw->dbg.dump_mask;
 2586 
 2587         dump_file = iwl_fw_error_dump_file(fwrt, &fw_error_dump, dump_data);
 2588         if (!dump_file)
 2589                 return;
 2590 
 2591         if (dump_data->monitor_only)
 2592                 dump_mask &= BIT(IWL_FW_ERROR_DUMP_FW_MONITOR);
 2593 
 2594         fw_error_dump.trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask,
 2595                                                       fwrt->sanitize_ops,
 2596                                                       fwrt->sanitize_ctx);
 2597         file_len = le32_to_cpu(dump_file->file_len);
 2598         fw_error_dump.fwrt_len = file_len;
 2599 
 2600         if (fw_error_dump.trans_ptr) {
 2601                 file_len += fw_error_dump.trans_ptr->len;
 2602                 dump_file->file_len = cpu_to_le32(file_len);
 2603         }
 2604 
 2605         sg_dump_data = alloc_sgtable(file_len);
 2606         if (sg_dump_data) {
 2607                 sg_pcopy_from_buffer(sg_dump_data,
 2608                                      sg_nents(sg_dump_data),
 2609                                      fw_error_dump.fwrt_ptr,
 2610                                      fw_error_dump.fwrt_len, 0);
 2611                 if (fw_error_dump.trans_ptr)
 2612                         sg_pcopy_from_buffer(sg_dump_data,
 2613                                              sg_nents(sg_dump_data),
 2614                                              fw_error_dump.trans_ptr->data,
 2615                                              fw_error_dump.trans_ptr->len,
 2616                                              fw_error_dump.fwrt_len);
 2617                 dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len,
 2618                                GFP_KERNEL);
 2619         }
 2620         vfree(fw_error_dump.fwrt_ptr);
 2621         vfree(fw_error_dump.trans_ptr);
 2622 }
 2623 
 2624 static void iwl_dump_ini_list_free(struct list_head *list)
 2625 {
 2626         while (!list_empty(list)) {
 2627                 struct iwl_fw_ini_dump_entry *entry =
 2628                         list_entry(list->next, typeof(*entry), list);
 2629 
 2630                 list_del(&entry->list);
 2631                 vfree(entry);
 2632         }
 2633 }
 2634 
 2635 static void iwl_fw_error_dump_data_free(struct iwl_fwrt_dump_data *dump_data)
 2636 {
 2637         dump_data->trig = NULL;
 2638         kfree(dump_data->fw_pkt);
 2639         dump_data->fw_pkt = NULL;
 2640 }
 2641 
 2642 static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt,
 2643                                   struct iwl_fwrt_dump_data *dump_data)
 2644 {
 2645 #if defined(__linux__)
 2646         LIST_HEAD(dump_list);
 2647 #elif defined(__FreeBSD__)
 2648         LINUX_LIST_HEAD(dump_list);
 2649 #endif
 2650         struct scatterlist *sg_dump_data;
 2651         u32 file_len = iwl_dump_ini_file_gen(fwrt, dump_data, &dump_list);
 2652 
 2653         if (!file_len)
 2654                 return;
 2655 
 2656         sg_dump_data = alloc_sgtable(file_len);
 2657         if (sg_dump_data) {
 2658                 struct iwl_fw_ini_dump_entry *entry;
 2659                 int sg_entries = sg_nents(sg_dump_data);
 2660                 u32 offs = 0;
 2661 
 2662                 list_for_each_entry(entry, &dump_list, list) {
 2663                         sg_pcopy_from_buffer(sg_dump_data, sg_entries,
 2664                                              entry->data, entry->size, offs);
 2665                         offs += entry->size;
 2666                 }
 2667                 dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len,
 2668                                GFP_KERNEL);
 2669         }
 2670         iwl_dump_ini_list_free(&dump_list);
 2671 }
 2672 
 2673 const struct iwl_fw_dump_desc iwl_dump_desc_assert = {
 2674         .trig_desc = {
 2675                 .type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT),
 2676         },
 2677 };
 2678 IWL_EXPORT_SYMBOL(iwl_dump_desc_assert);
 2679 
 2680 int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
 2681                             const struct iwl_fw_dump_desc *desc,
 2682                             bool monitor_only,
 2683                             unsigned int delay)
 2684 {
 2685         struct iwl_fwrt_wk_data *wk_data;
 2686         unsigned long idx;
 2687 
 2688         if (iwl_trans_dbg_ini_valid(fwrt->trans)) {
 2689                 iwl_fw_free_dump_desc(fwrt, desc);
 2690                 return 0;
 2691         }
 2692 
 2693         /*
 2694          * Check there is an available worker.
 2695          * ffz return value is undefined if no zero exists,
 2696          * so check against ~0UL first.
 2697          */
 2698         if (fwrt->dump.active_wks == ~0UL)
 2699                 return -EBUSY;
 2700 
 2701         idx = ffz(fwrt->dump.active_wks);
 2702 
 2703         if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM ||
 2704             test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks))
 2705                 return -EBUSY;
 2706 
 2707         wk_data = &fwrt->dump.wks[idx];
 2708 
 2709         if (WARN_ON(wk_data->dump_data.desc))
 2710                 iwl_fw_free_dump_desc(fwrt, wk_data->dump_data.desc);
 2711 
 2712         wk_data->dump_data.desc = desc;
 2713         wk_data->dump_data.monitor_only = monitor_only;
 2714 
 2715         IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n",
 2716                  le32_to_cpu(desc->trig_desc.type));
 2717 
 2718         schedule_delayed_work(&wk_data->wk, usecs_to_jiffies(delay));
 2719 
 2720         return 0;
 2721 }
 2722 IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc);
 2723 
 2724 int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
 2725                              enum iwl_fw_dbg_trigger trig_type)
 2726 {
 2727         if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status))
 2728                 return -EIO;
 2729 
 2730         if (iwl_trans_dbg_ini_valid(fwrt->trans)) {
 2731                 if (trig_type != FW_DBG_TRIGGER_ALIVE_TIMEOUT &&
 2732                     trig_type != FW_DBG_TRIGGER_DRIVER)
 2733                         return -EIO;
 2734 
 2735                 iwl_dbg_tlv_time_point(fwrt,
 2736                                        IWL_FW_INI_TIME_POINT_HOST_ALIVE_TIMEOUT,
 2737                                        NULL);
 2738         } else {
 2739                 struct iwl_fw_dump_desc *iwl_dump_error_desc;
 2740                 int ret;
 2741 
 2742                 iwl_dump_error_desc =
 2743                         kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL);
 2744 
 2745                 if (!iwl_dump_error_desc)
 2746                         return -ENOMEM;
 2747 
 2748                 iwl_dump_error_desc->trig_desc.type = cpu_to_le32(trig_type);
 2749                 iwl_dump_error_desc->len = 0;
 2750 
 2751                 ret = iwl_fw_dbg_collect_desc(fwrt, iwl_dump_error_desc,
 2752                                               false, 0);
 2753                 if (ret) {
 2754                         kfree(iwl_dump_error_desc);
 2755                         return ret;
 2756                 }
 2757         }
 2758 
 2759         iwl_trans_sync_nmi(fwrt->trans);
 2760 
 2761         return 0;
 2762 }
 2763 IWL_EXPORT_SYMBOL(iwl_fw_dbg_error_collect);
 2764 
 2765 int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
 2766                        enum iwl_fw_dbg_trigger trig,
 2767                        const char *str, size_t len,
 2768                        struct iwl_fw_dbg_trigger_tlv *trigger)
 2769 {
 2770         struct iwl_fw_dump_desc *desc;
 2771         unsigned int delay = 0;
 2772         bool monitor_only = false;
 2773 
 2774         if (trigger) {
 2775                 u16 occurrences = le16_to_cpu(trigger->occurrences) - 1;
 2776 
 2777                 if (!le16_to_cpu(trigger->occurrences))
 2778                         return 0;
 2779 
 2780                 if (trigger->flags & IWL_FW_DBG_FORCE_RESTART) {
 2781                         IWL_WARN(fwrt, "Force restart: trigger %d fired.\n",
 2782                                  trig);
 2783                         iwl_force_nmi(fwrt->trans);
 2784                         return 0;
 2785                 }
 2786 
 2787                 trigger->occurrences = cpu_to_le16(occurrences);
 2788                 monitor_only = trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY;
 2789 
 2790                 /* convert msec to usec */
 2791                 delay = le32_to_cpu(trigger->stop_delay) * USEC_PER_MSEC;
 2792         }
 2793 
 2794         desc = kzalloc(struct_size(desc, trig_desc.data, len), GFP_ATOMIC);
 2795         if (!desc)
 2796                 return -ENOMEM;
 2797 
 2798 
 2799         desc->len = len;
 2800         desc->trig_desc.type = cpu_to_le32(trig);
 2801         memcpy(desc->trig_desc.data, str, len);
 2802 
 2803         return iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay);
 2804 }
 2805 IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect);
 2806 
 2807 int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
 2808                             struct iwl_fw_dbg_trigger_tlv *trigger,
 2809                             const char *fmt, ...)
 2810 {
 2811         int ret, len = 0;
 2812         char buf[64];
 2813 
 2814         if (iwl_trans_dbg_ini_valid(fwrt->trans))
 2815                 return 0;
 2816 
 2817         if (fmt) {
 2818                 va_list ap;
 2819 
 2820                 buf[sizeof(buf) - 1] = '\0';
 2821 
 2822                 va_start(ap, fmt);
 2823                 vsnprintf(buf, sizeof(buf), fmt, ap);
 2824                 va_end(ap);
 2825 
 2826                 /* check for truncation */
 2827                 if (WARN_ON_ONCE(buf[sizeof(buf) - 1]))
 2828                         buf[sizeof(buf) - 1] = '\0';
 2829 
 2830                 len = strlen(buf) + 1;
 2831         }
 2832 
 2833         ret = iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len,
 2834                                  trigger);
 2835 
 2836         if (ret)
 2837                 return ret;
 2838 
 2839         return 0;
 2840 }
 2841 IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig);
 2842 
 2843 int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id)
 2844 {
 2845         u8 *ptr;
 2846         int ret;
 2847         int i;
 2848 
 2849         if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg.conf_tlv),
 2850                       "Invalid configuration %d\n", conf_id))
 2851                 return -EINVAL;
 2852 
 2853         /* EARLY START - firmware's configuration is hard coded */
 2854         if ((!fwrt->fw->dbg.conf_tlv[conf_id] ||
 2855              !fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds) &&
 2856             conf_id == FW_DBG_START_FROM_ALIVE)
 2857                 return 0;
 2858 
 2859         if (!fwrt->fw->dbg.conf_tlv[conf_id])
 2860                 return -EINVAL;
 2861 
 2862         if (fwrt->dump.conf != FW_DBG_INVALID)
 2863                 IWL_INFO(fwrt, "FW already configured (%d) - re-configuring\n",
 2864                          fwrt->dump.conf);
 2865 
 2866         /* Send all HCMDs for configuring the FW debug */
 2867         ptr = (void *)&fwrt->fw->dbg.conf_tlv[conf_id]->hcmd;
 2868         for (i = 0; i < fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds; i++) {
 2869                 struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr;
 2870                 struct iwl_host_cmd hcmd = {
 2871                         .id = cmd->id,
 2872                         .len = { le16_to_cpu(cmd->len), },
 2873                         .data = { cmd->data, },
 2874                 };
 2875 
 2876                 ret = iwl_trans_send_cmd(fwrt->trans, &hcmd);
 2877                 if (ret)
 2878                         return ret;
 2879 
 2880                 ptr += sizeof(*cmd);
 2881                 ptr += le16_to_cpu(cmd->len);
 2882         }
 2883 
 2884         fwrt->dump.conf = conf_id;
 2885 
 2886         return 0;
 2887 }
 2888 IWL_EXPORT_SYMBOL(iwl_fw_start_dbg_conf);
 2889 
 2890 void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt,
 2891                                     u32 timepoint,
 2892                                     u32 timepoint_data)
 2893 {
 2894         struct iwl_dbg_dump_complete_cmd hcmd_data;
 2895         struct iwl_host_cmd hcmd = {
 2896                 .id = WIDE_ID(DEBUG_GROUP, FW_DUMP_COMPLETE_CMD),
 2897                 .data[0] = &hcmd_data,
 2898                 .len[0] = sizeof(hcmd_data),
 2899         };
 2900 
 2901         if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status))
 2902                 return;
 2903 
 2904         if (fw_has_capa(&fwrt->fw->ucode_capa,
 2905                         IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT)) {
 2906                 hcmd_data.tp = cpu_to_le32(timepoint);
 2907                 hcmd_data.tp_data = cpu_to_le32(timepoint_data);
 2908                 iwl_trans_send_cmd(fwrt->trans, &hcmd);
 2909         }
 2910 }
 2911 
 2912 /* this function assumes dump_start was called beforehand and dump_end will be
 2913  * called afterwards
 2914  */
 2915 static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx)
 2916 {
 2917         struct iwl_fw_dbg_params params = {0};
 2918         struct iwl_fwrt_dump_data *dump_data =
 2919                 &fwrt->dump.wks[wk_idx].dump_data;
 2920         u32 policy;
 2921         u32 time_point;
 2922         if (!test_bit(wk_idx, &fwrt->dump.active_wks))
 2923                 return;
 2924 
 2925         if (!dump_data->trig) {
 2926                 IWL_ERR(fwrt, "dump trigger data is not set\n");
 2927                 goto out;
 2928         }
 2929 
 2930         if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) {
 2931                 IWL_ERR(fwrt, "Device is not enabled - cannot dump error\n");
 2932                 goto out;
 2933         }
 2934 
 2935         /* there's no point in fw dump if the bus is dead */
 2936         if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
 2937                 IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
 2938                 goto out;
 2939         }
 2940 
 2941         iwl_fw_dbg_stop_restart_recording(fwrt, &params, true);
 2942 
 2943         IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection start\n");
 2944         if (iwl_trans_dbg_ini_valid(fwrt->trans))
 2945                 iwl_fw_error_ini_dump(fwrt, &fwrt->dump.wks[wk_idx].dump_data);
 2946         else
 2947                 iwl_fw_error_dump(fwrt, &fwrt->dump.wks[wk_idx].dump_data);
 2948         IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection done\n");
 2949 
 2950         iwl_fw_dbg_stop_restart_recording(fwrt, &params, false);
 2951 
 2952         policy = le32_to_cpu(dump_data->trig->apply_policy);
 2953         time_point = le32_to_cpu(dump_data->trig->time_point);
 2954 
 2955         if (policy & IWL_FW_INI_APPLY_POLICY_DUMP_COMPLETE_CMD) {
 2956                 IWL_DEBUG_FW_INFO(fwrt, "WRT: sending dump complete\n");
 2957                 iwl_send_dbg_dump_complete_cmd(fwrt, time_point, 0);
 2958         }
 2959         if (fwrt->trans->dbg.last_tp_resetfw == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY)
 2960                 iwl_force_nmi(fwrt->trans);
 2961 
 2962 out:
 2963         if (iwl_trans_dbg_ini_valid(fwrt->trans)) {
 2964                 iwl_fw_error_dump_data_free(dump_data);
 2965         } else {
 2966                 iwl_fw_free_dump_desc(fwrt, dump_data->desc);
 2967                 dump_data->desc = NULL;
 2968         }
 2969 
 2970         clear_bit(wk_idx, &fwrt->dump.active_wks);
 2971 }
 2972 
 2973 int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
 2974                            struct iwl_fwrt_dump_data *dump_data,
 2975                            bool sync)
 2976 {
 2977         struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig;
 2978         enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point);
 2979         u32 occur, delay;
 2980         unsigned long idx;
 2981 
 2982         if (!iwl_fw_ini_trigger_on(fwrt, trig)) {
 2983                 IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n",
 2984                          tp_id);
 2985                 return -EINVAL;
 2986         }
 2987 
 2988         delay = le32_to_cpu(trig->dump_delay);
 2989         occur = le32_to_cpu(trig->occurrences);
 2990         if (!occur)
 2991                 return 0;
 2992 
 2993         trig->occurrences = cpu_to_le32(--occur);
 2994 
 2995         /* Check there is an available worker.
 2996          * ffz return value is undefined if no zero exists,
 2997          * so check against ~0UL first.
 2998          */
 2999         if (fwrt->dump.active_wks == ~0UL)
 3000                 return -EBUSY;
 3001 
 3002         idx = ffz(fwrt->dump.active_wks);
 3003 
 3004         if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM ||
 3005             test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks))
 3006                 return -EBUSY;
 3007 
 3008         fwrt->dump.wks[idx].dump_data = *dump_data;
 3009 
 3010         if (sync)
 3011                 delay = 0;
 3012 
 3013         IWL_WARN(fwrt,
 3014                  "WRT: Collecting data: ini trigger %d fired (delay=%dms).\n",
 3015                  tp_id, (u32)(delay / USEC_PER_MSEC));
 3016 
 3017         if (sync)
 3018                 iwl_fw_dbg_collect_sync(fwrt, idx);
 3019         else
 3020                 schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay));
 3021 
 3022         return 0;
 3023 }
 3024 
 3025 void iwl_fw_error_dump_wk(struct work_struct *work)
 3026 {
 3027         struct iwl_fwrt_wk_data *wks =
 3028                 container_of(work, typeof(*wks), wk.work);
 3029         struct iwl_fw_runtime *fwrt =
 3030                 container_of(wks, typeof(*fwrt), dump.wks[wks->idx]);
 3031 
 3032         /* assumes the op mode mutex is locked in dump_start since
 3033          * iwl_fw_dbg_collect_sync can't run in parallel
 3034          */
 3035         if (fwrt->ops && fwrt->ops->dump_start)
 3036                 fwrt->ops->dump_start(fwrt->ops_ctx);
 3037 
 3038         iwl_fw_dbg_collect_sync(fwrt, wks->idx);
 3039 
 3040         if (fwrt->ops && fwrt->ops->dump_end)
 3041                 fwrt->ops->dump_end(fwrt->ops_ctx);
 3042 }
 3043 
 3044 void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
 3045 {
 3046         const struct iwl_cfg *cfg = fwrt->trans->cfg;
 3047 
 3048         if (!iwl_fw_dbg_is_d3_debug_enabled(fwrt))
 3049                 return;
 3050 
 3051         if (!fwrt->dump.d3_debug_data) {
 3052                 fwrt->dump.d3_debug_data = kmalloc(cfg->d3_debug_data_length,
 3053                                                    GFP_KERNEL);
 3054                 if (!fwrt->dump.d3_debug_data) {
 3055                         IWL_ERR(fwrt,
 3056                                 "failed to allocate memory for D3 debug data\n");
 3057                         return;
 3058                 }
 3059         }
 3060 
 3061         /* if the buffer holds previous debug data it is overwritten */
 3062         iwl_trans_read_mem_bytes(fwrt->trans, cfg->d3_debug_data_base_addr,
 3063                                  fwrt->dump.d3_debug_data,
 3064                                  cfg->d3_debug_data_length);
 3065 
 3066         if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
 3067                 fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx,
 3068                                              cfg->d3_debug_data_base_addr,
 3069                                              fwrt->dump.d3_debug_data,
 3070                                              cfg->d3_debug_data_length);
 3071 }
 3072 IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);
 3073 
 3074 void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt)
 3075 {
 3076         int i;
 3077 
 3078         iwl_dbg_tlv_del_timers(fwrt->trans);
 3079         for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++)
 3080                 iwl_fw_dbg_collect_sync(fwrt, i);
 3081 
 3082         iwl_fw_dbg_stop_restart_recording(fwrt, NULL, true);
 3083 }
 3084 IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_sync);
 3085 
 3086 static int iwl_fw_dbg_suspend_resume_hcmd(struct iwl_trans *trans, bool suspend)
 3087 {
 3088         struct iwl_dbg_suspend_resume_cmd cmd = {
 3089                 .operation = suspend ?
 3090                         cpu_to_le32(DBGC_SUSPEND_CMD) :
 3091                         cpu_to_le32(DBGC_RESUME_CMD),
 3092         };
 3093         struct iwl_host_cmd hcmd = {
 3094                 .id = WIDE_ID(DEBUG_GROUP, DBGC_SUSPEND_RESUME),
 3095                 .data[0] = &cmd,
 3096                 .len[0] = sizeof(cmd),
 3097         };
 3098 
 3099         return iwl_trans_send_cmd(trans, &hcmd);
 3100 }
 3101 
 3102 static void iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
 3103                                       struct iwl_fw_dbg_params *params)
 3104 {
 3105         if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) {
 3106                 iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
 3107                 return;
 3108         }
 3109 
 3110         if (params) {
 3111                 params->in_sample = iwl_read_umac_prph(trans, DBGC_IN_SAMPLE);
 3112                 params->out_ctrl = iwl_read_umac_prph(trans, DBGC_OUT_CTRL);
 3113         }
 3114 
 3115         iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, 0);
 3116         /* wait for the DBGC to finish writing the internal buffer to DRAM to
 3117          * avoid halting the HW while writing
 3118          */
 3119         usleep_range(700, 1000);
 3120         iwl_write_umac_prph(trans, DBGC_OUT_CTRL, 0);
 3121 }
 3122 
 3123 static int iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
 3124                                         struct iwl_fw_dbg_params *params)
 3125 {
 3126         if (!params)
 3127                 return -EIO;
 3128 
 3129         if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) {
 3130                 iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
 3131                 iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
 3132                 iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
 3133         } else {
 3134                 iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, params->in_sample);
 3135                 iwl_write_umac_prph(trans, DBGC_OUT_CTRL, params->out_ctrl);
 3136         }
 3137 
 3138         return 0;
 3139 }
 3140 
 3141 void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
 3142                                        struct iwl_fw_dbg_params *params,
 3143                                        bool stop)
 3144 {
 3145         int ret __maybe_unused = 0;
 3146 
 3147         if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status))
 3148                 return;
 3149 
 3150         if (fw_has_capa(&fwrt->fw->ucode_capa,
 3151                         IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP))
 3152                 ret = iwl_fw_dbg_suspend_resume_hcmd(fwrt->trans, stop);
 3153         else if (stop)
 3154                 iwl_fw_dbg_stop_recording(fwrt->trans, params);
 3155         else
 3156                 ret = iwl_fw_dbg_restart_recording(fwrt->trans, params);
 3157 #ifdef CONFIG_IWLWIFI_DEBUGFS
 3158         if (!ret) {
 3159                 if (stop)
 3160                         fwrt->trans->dbg.rec_on = false;
 3161                 else
 3162                         iwl_fw_set_dbg_rec_on(fwrt);
 3163         }
 3164 #endif
 3165 }
 3166 IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_restart_recording);

Cache object: 40e5fc36099b3aae90f0cc70ec3c179c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.