1 /******************************************************************************
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
8 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program;
24 * The full GNU General Public License is included in this distribution
25 * in the file called COPYING.
27 * Contact Information:
28 * Intel Linux Wireless <linuxwifi@intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
33 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
34 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
35 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
42 * * Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * * Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in
46 * the documentation and/or other materials provided with the
48 * * Neither the name Intel Corporation nor the names of its
49 * contributors may be used to endorse or promote products derived
50 * from this software without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
58 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
62 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 *****************************************************************************/
65 #include <linux/devcoredump.h>
73 #define RADIO_REG_MAX_READ 0x2ad
74 static void iwl_mvm_read_radio_reg(struct iwl_mvm
*mvm
,
75 struct iwl_fw_error_dump_data
**dump_data
)
77 u8
*pos
= (void *)(*dump_data
)->data
;
81 if (!iwl_trans_grab_nic_access(mvm
->trans
, &flags
))
84 (*dump_data
)->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_RADIO_REG
);
85 (*dump_data
)->len
= cpu_to_le32(RADIO_REG_MAX_READ
);
87 for (i
= 0; i
< RADIO_REG_MAX_READ
; i
++) {
88 u32 rd_cmd
= RADIO_RSP_RD_CMD
;
90 rd_cmd
|= i
<< RADIO_RSP_ADDR_POS
;
91 iwl_write_prph_no_grab(mvm
->trans
, RSP_RADIO_CMD
, rd_cmd
);
92 *pos
= (u8
)iwl_read_prph_no_grab(mvm
->trans
, RSP_RADIO_RDDAT
);
97 *dump_data
= iwl_fw_error_next_data(*dump_data
);
99 iwl_trans_release_nic_access(mvm
->trans
, &flags
);
102 static void iwl_mvm_dump_rxf(struct iwl_mvm
*mvm
,
103 struct iwl_fw_error_dump_data
**dump_data
,
104 int size
, u32 offset
, int fifo_num
)
106 struct iwl_fw_error_dump_fifo
*fifo_hdr
;
111 fifo_hdr
= (void *)(*dump_data
)->data
;
112 fifo_data
= (void *)fifo_hdr
->data
;
115 /* No need to try to read the data if the length is 0 */
119 /* Add a TLV for the RXF */
120 (*dump_data
)->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_RXF
);
121 (*dump_data
)->len
= cpu_to_le32(fifo_len
+ sizeof(*fifo_hdr
));
123 fifo_hdr
->fifo_num
= cpu_to_le32(fifo_num
);
124 fifo_hdr
->available_bytes
=
125 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
126 RXF_RD_D_SPACE
+ offset
));
128 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
129 RXF_RD_WR_PTR
+ offset
));
131 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
132 RXF_RD_RD_PTR
+ offset
));
133 fifo_hdr
->fence_ptr
=
134 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
135 RXF_RD_FENCE_PTR
+ offset
));
136 fifo_hdr
->fence_mode
=
137 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
138 RXF_SET_FENCE_MODE
+ offset
));
141 iwl_trans_write_prph(mvm
->trans
, RXF_SET_FENCE_MODE
+ offset
, 0x1);
142 /* Set fence pointer to the same place like WR pointer */
143 iwl_trans_write_prph(mvm
->trans
, RXF_LD_WR2FENCE
+ offset
, 0x1);
144 /* Set fence offset */
145 iwl_trans_write_prph(mvm
->trans
,
146 RXF_LD_FENCE_OFFSET_ADDR
+ offset
, 0x0);
149 fifo_len
/= sizeof(u32
); /* Size in DWORDS */
150 for (i
= 0; i
< fifo_len
; i
++)
151 fifo_data
[i
] = iwl_trans_read_prph(mvm
->trans
,
152 RXF_FIFO_RD_FENCE_INC
+
154 *dump_data
= iwl_fw_error_next_data(*dump_data
);
157 static void iwl_mvm_dump_txf(struct iwl_mvm
*mvm
,
158 struct iwl_fw_error_dump_data
**dump_data
,
159 int size
, u32 offset
, int fifo_num
)
161 struct iwl_fw_error_dump_fifo
*fifo_hdr
;
166 fifo_hdr
= (void *)(*dump_data
)->data
;
167 fifo_data
= (void *)fifo_hdr
->data
;
170 /* No need to try to read the data if the length is 0 */
174 /* Add a TLV for the FIFO */
175 (*dump_data
)->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_TXF
);
176 (*dump_data
)->len
= cpu_to_le32(fifo_len
+ sizeof(*fifo_hdr
));
178 fifo_hdr
->fifo_num
= cpu_to_le32(fifo_num
);
179 fifo_hdr
->available_bytes
=
180 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
181 TXF_FIFO_ITEM_CNT
+ offset
));
183 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
184 TXF_WR_PTR
+ offset
));
186 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
187 TXF_RD_PTR
+ offset
));
188 fifo_hdr
->fence_ptr
=
189 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
190 TXF_FENCE_PTR
+ offset
));
191 fifo_hdr
->fence_mode
=
192 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
193 TXF_LOCK_FENCE
+ offset
));
195 /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
196 iwl_trans_write_prph(mvm
->trans
, TXF_READ_MODIFY_ADDR
+ offset
,
197 TXF_WR_PTR
+ offset
);
199 /* Dummy-read to advance the read pointer to the head */
200 iwl_trans_read_prph(mvm
->trans
, TXF_READ_MODIFY_DATA
+ offset
);
203 fifo_len
/= sizeof(u32
); /* Size in DWORDS */
204 for (i
= 0; i
< fifo_len
; i
++)
205 fifo_data
[i
] = iwl_trans_read_prph(mvm
->trans
,
206 TXF_READ_MODIFY_DATA
+
208 *dump_data
= iwl_fw_error_next_data(*dump_data
);
211 static void iwl_mvm_dump_fifos(struct iwl_mvm
*mvm
,
212 struct iwl_fw_error_dump_data
**dump_data
)
214 struct iwl_fw_error_dump_fifo
*fifo_hdr
;
215 struct iwl_mvm_shared_mem_cfg
*cfg
= &mvm
->smem_cfg
;
221 if (!iwl_trans_grab_nic_access(mvm
->trans
, &flags
))
225 iwl_mvm_dump_rxf(mvm
, dump_data
, cfg
->lmac
[0].rxfifo1_size
, 0, 0);
227 iwl_mvm_dump_rxf(mvm
, dump_data
, cfg
->rxfifo2_size
,
228 RXF_DIFF_FROM_PREV
, 1);
229 /* Pull LMAC2 RXF1 */
230 if (mvm
->smem_cfg
.num_lmacs
> 1)
231 iwl_mvm_dump_rxf(mvm
, dump_data
, cfg
->lmac
[1].rxfifo1_size
,
232 LMAC2_PRPH_OFFSET
, 2);
234 /* Pull TXF data from LMAC1 */
235 for (i
= 0; i
< mvm
->smem_cfg
.num_txfifo_entries
; i
++) {
236 /* Mark the number of TXF we're pulling now */
237 iwl_trans_write_prph(mvm
->trans
, TXF_LARC_NUM
, i
);
238 iwl_mvm_dump_txf(mvm
, dump_data
, cfg
->lmac
[0].txfifo_size
[i
],
242 /* Pull TXF data from LMAC2 */
243 if (mvm
->smem_cfg
.num_lmacs
> 1) {
244 for (i
= 0; i
< mvm
->smem_cfg
.num_txfifo_entries
; i
++) {
245 /* Mark the number of TXF we're pulling now */
246 iwl_trans_write_prph(mvm
->trans
,
247 TXF_LARC_NUM
+ LMAC2_PRPH_OFFSET
,
249 iwl_mvm_dump_txf(mvm
, dump_data
,
250 cfg
->lmac
[1].txfifo_size
[i
],
252 i
+ cfg
->num_txfifo_entries
);
256 if (fw_has_capa(&mvm
->fw
->ucode_capa
,
257 IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG
)) {
258 /* Pull UMAC internal TXF data from all TXFs */
260 i
< ARRAY_SIZE(mvm
->smem_cfg
.internal_txfifo_size
);
262 fifo_hdr
= (void *)(*dump_data
)->data
;
263 fifo_data
= (void *)fifo_hdr
->data
;
264 fifo_len
= mvm
->smem_cfg
.internal_txfifo_size
[i
];
266 /* No need to try to read the data if the length is 0 */
270 /* Add a TLV for the internal FIFOs */
272 cpu_to_le32(IWL_FW_ERROR_DUMP_INTERNAL_TXF
);
274 cpu_to_le32(fifo_len
+ sizeof(*fifo_hdr
));
276 fifo_hdr
->fifo_num
= cpu_to_le32(i
);
278 /* Mark the number of TXF we're pulling now */
279 iwl_trans_write_prph(mvm
->trans
, TXF_CPU2_NUM
, i
+
280 mvm
->smem_cfg
.num_txfifo_entries
);
282 fifo_hdr
->available_bytes
=
283 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
284 TXF_CPU2_FIFO_ITEM_CNT
));
286 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
289 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
291 fifo_hdr
->fence_ptr
=
292 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
293 TXF_CPU2_FENCE_PTR
));
294 fifo_hdr
->fence_mode
=
295 cpu_to_le32(iwl_trans_read_prph(mvm
->trans
,
296 TXF_CPU2_LOCK_FENCE
));
298 /* Set TXF_CPU2_READ_MODIFY_ADDR to TXF_CPU2_WR_PTR */
299 iwl_trans_write_prph(mvm
->trans
,
300 TXF_CPU2_READ_MODIFY_ADDR
,
303 /* Dummy-read to advance the read pointer to head */
304 iwl_trans_read_prph(mvm
->trans
,
305 TXF_CPU2_READ_MODIFY_DATA
);
308 fifo_len
/= sizeof(u32
); /* Size in DWORDS */
309 for (j
= 0; j
< fifo_len
; j
++)
311 iwl_trans_read_prph(mvm
->trans
,
312 TXF_CPU2_READ_MODIFY_DATA
);
313 *dump_data
= iwl_fw_error_next_data(*dump_data
);
317 iwl_trans_release_nic_access(mvm
->trans
, &flags
);
320 void iwl_mvm_free_fw_dump_desc(struct iwl_mvm
*mvm
)
322 if (mvm
->fw_dump_desc
== &iwl_mvm_dump_desc_assert
)
325 kfree(mvm
->fw_dump_desc
);
326 mvm
->fw_dump_desc
= NULL
;
329 #define IWL8260_ICCM_OFFSET 0x44000 /* Only for B-step */
330 #define IWL8260_ICCM_LEN 0xC000 /* Only for B-step */
332 struct iwl_prph_range
{
336 static const struct iwl_prph_range iwl_prph_dump_addr_comm
[] = {
337 { .start
= 0x00a00000, .end
= 0x00a00000 },
338 { .start
= 0x00a0000c, .end
= 0x00a00024 },
339 { .start
= 0x00a0002c, .end
= 0x00a0003c },
340 { .start
= 0x00a00410, .end
= 0x00a00418 },
341 { .start
= 0x00a00420, .end
= 0x00a00420 },
342 { .start
= 0x00a00428, .end
= 0x00a00428 },
343 { .start
= 0x00a00430, .end
= 0x00a0043c },
344 { .start
= 0x00a00444, .end
= 0x00a00444 },
345 { .start
= 0x00a004c0, .end
= 0x00a004cc },
346 { .start
= 0x00a004d8, .end
= 0x00a004d8 },
347 { .start
= 0x00a004e0, .end
= 0x00a004f0 },
348 { .start
= 0x00a00840, .end
= 0x00a00840 },
349 { .start
= 0x00a00850, .end
= 0x00a00858 },
350 { .start
= 0x00a01004, .end
= 0x00a01008 },
351 { .start
= 0x00a01010, .end
= 0x00a01010 },
352 { .start
= 0x00a01018, .end
= 0x00a01018 },
353 { .start
= 0x00a01024, .end
= 0x00a01024 },
354 { .start
= 0x00a0102c, .end
= 0x00a01034 },
355 { .start
= 0x00a0103c, .end
= 0x00a01040 },
356 { .start
= 0x00a01048, .end
= 0x00a01094 },
357 { .start
= 0x00a01c00, .end
= 0x00a01c20 },
358 { .start
= 0x00a01c58, .end
= 0x00a01c58 },
359 { .start
= 0x00a01c7c, .end
= 0x00a01c7c },
360 { .start
= 0x00a01c28, .end
= 0x00a01c54 },
361 { .start
= 0x00a01c5c, .end
= 0x00a01c5c },
362 { .start
= 0x00a01c60, .end
= 0x00a01cdc },
363 { .start
= 0x00a01ce0, .end
= 0x00a01d0c },
364 { .start
= 0x00a01d18, .end
= 0x00a01d20 },
365 { .start
= 0x00a01d2c, .end
= 0x00a01d30 },
366 { .start
= 0x00a01d40, .end
= 0x00a01d5c },
367 { .start
= 0x00a01d80, .end
= 0x00a01d80 },
368 { .start
= 0x00a01d98, .end
= 0x00a01d9c },
369 { .start
= 0x00a01da8, .end
= 0x00a01da8 },
370 { .start
= 0x00a01db8, .end
= 0x00a01df4 },
371 { .start
= 0x00a01dc0, .end
= 0x00a01dfc },
372 { .start
= 0x00a01e00, .end
= 0x00a01e2c },
373 { .start
= 0x00a01e40, .end
= 0x00a01e60 },
374 { .start
= 0x00a01e68, .end
= 0x00a01e6c },
375 { .start
= 0x00a01e74, .end
= 0x00a01e74 },
376 { .start
= 0x00a01e84, .end
= 0x00a01e90 },
377 { .start
= 0x00a01e9c, .end
= 0x00a01ec4 },
378 { .start
= 0x00a01ed0, .end
= 0x00a01ee0 },
379 { .start
= 0x00a01f00, .end
= 0x00a01f1c },
380 { .start
= 0x00a01f44, .end
= 0x00a01ffc },
381 { .start
= 0x00a02000, .end
= 0x00a02048 },
382 { .start
= 0x00a02068, .end
= 0x00a020f0 },
383 { .start
= 0x00a02100, .end
= 0x00a02118 },
384 { .start
= 0x00a02140, .end
= 0x00a0214c },
385 { .start
= 0x00a02168, .end
= 0x00a0218c },
386 { .start
= 0x00a021c0, .end
= 0x00a021c0 },
387 { .start
= 0x00a02400, .end
= 0x00a02410 },
388 { .start
= 0x00a02418, .end
= 0x00a02420 },
389 { .start
= 0x00a02428, .end
= 0x00a0242c },
390 { .start
= 0x00a02434, .end
= 0x00a02434 },
391 { .start
= 0x00a02440, .end
= 0x00a02460 },
392 { .start
= 0x00a02468, .end
= 0x00a024b0 },
393 { .start
= 0x00a024c8, .end
= 0x00a024cc },
394 { .start
= 0x00a02500, .end
= 0x00a02504 },
395 { .start
= 0x00a0250c, .end
= 0x00a02510 },
396 { .start
= 0x00a02540, .end
= 0x00a02554 },
397 { .start
= 0x00a02580, .end
= 0x00a025f4 },
398 { .start
= 0x00a02600, .end
= 0x00a0260c },
399 { .start
= 0x00a02648, .end
= 0x00a02650 },
400 { .start
= 0x00a02680, .end
= 0x00a02680 },
401 { .start
= 0x00a026c0, .end
= 0x00a026d0 },
402 { .start
= 0x00a02700, .end
= 0x00a0270c },
403 { .start
= 0x00a02804, .end
= 0x00a02804 },
404 { .start
= 0x00a02818, .end
= 0x00a0281c },
405 { .start
= 0x00a02c00, .end
= 0x00a02db4 },
406 { .start
= 0x00a02df4, .end
= 0x00a02fb0 },
407 { .start
= 0x00a03000, .end
= 0x00a03014 },
408 { .start
= 0x00a0301c, .end
= 0x00a0302c },
409 { .start
= 0x00a03034, .end
= 0x00a03038 },
410 { .start
= 0x00a03040, .end
= 0x00a03048 },
411 { .start
= 0x00a03060, .end
= 0x00a03068 },
412 { .start
= 0x00a03070, .end
= 0x00a03074 },
413 { .start
= 0x00a0307c, .end
= 0x00a0307c },
414 { .start
= 0x00a03080, .end
= 0x00a03084 },
415 { .start
= 0x00a0308c, .end
= 0x00a03090 },
416 { .start
= 0x00a03098, .end
= 0x00a03098 },
417 { .start
= 0x00a030a0, .end
= 0x00a030a0 },
418 { .start
= 0x00a030a8, .end
= 0x00a030b4 },
419 { .start
= 0x00a030bc, .end
= 0x00a030bc },
420 { .start
= 0x00a030c0, .end
= 0x00a0312c },
421 { .start
= 0x00a03c00, .end
= 0x00a03c5c },
422 { .start
= 0x00a04400, .end
= 0x00a04454 },
423 { .start
= 0x00a04460, .end
= 0x00a04474 },
424 { .start
= 0x00a044c0, .end
= 0x00a044ec },
425 { .start
= 0x00a04500, .end
= 0x00a04504 },
426 { .start
= 0x00a04510, .end
= 0x00a04538 },
427 { .start
= 0x00a04540, .end
= 0x00a04548 },
428 { .start
= 0x00a04560, .end
= 0x00a0457c },
429 { .start
= 0x00a04590, .end
= 0x00a04598 },
430 { .start
= 0x00a045c0, .end
= 0x00a045f4 },
433 static const struct iwl_prph_range iwl_prph_dump_addr_9000
[] = {
434 { .start
= 0x00a05c00, .end
= 0x00a05c18 },
435 { .start
= 0x00a05400, .end
= 0x00a056e8 },
436 { .start
= 0x00a08000, .end
= 0x00a098bc },
437 { .start
= 0x00a02400, .end
= 0x00a02758 },
440 static void _iwl_read_prph_block(struct iwl_trans
*trans
, u32 start
,
441 u32 len_bytes
, __le32
*data
)
445 for (i
= 0; i
< len_bytes
; i
+= 4)
446 *data
++ = cpu_to_le32(iwl_read_prph_no_grab(trans
, start
+ i
));
449 static bool iwl_read_prph_block(struct iwl_trans
*trans
, u32 start
,
450 u32 len_bytes
, __le32
*data
)
453 bool success
= false;
455 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
457 _iwl_read_prph_block(trans
, start
, len_bytes
, data
);
458 iwl_trans_release_nic_access(trans
, &flags
);
464 static void iwl_dump_prph(struct iwl_trans
*trans
,
465 struct iwl_fw_error_dump_data
**data
,
466 const struct iwl_prph_range
*iwl_prph_dump_addr
,
469 struct iwl_fw_error_dump_prph
*prph
;
473 if (!iwl_trans_grab_nic_access(trans
, &flags
))
476 for (i
= 0; i
< range_len
; i
++) {
477 /* The range includes both boundaries */
478 int num_bytes_in_chunk
= iwl_prph_dump_addr
[i
].end
-
479 iwl_prph_dump_addr
[i
].start
+ 4;
481 (*data
)->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH
);
482 (*data
)->len
= cpu_to_le32(sizeof(*prph
) +
484 prph
= (void *)(*data
)->data
;
485 prph
->prph_start
= cpu_to_le32(iwl_prph_dump_addr
[i
].start
);
487 _iwl_read_prph_block(trans
, iwl_prph_dump_addr
[i
].start
,
488 /* our range is inclusive, hence + 4 */
489 iwl_prph_dump_addr
[i
].end
-
490 iwl_prph_dump_addr
[i
].start
+ 4,
493 *data
= iwl_fw_error_next_data(*data
);
496 iwl_trans_release_nic_access(trans
, &flags
);
500 * alloc_sgtable - allocates scallerlist table in the given size,
501 * fills it with pages and returns it
502 * @size: the size (in bytes) of the table
504 static struct scatterlist
*alloc_sgtable(int size
)
506 int alloc_size
, nents
, i
;
507 struct page
*new_page
;
508 struct scatterlist
*iter
;
509 struct scatterlist
*table
;
511 nents
= DIV_ROUND_UP(size
, PAGE_SIZE
);
512 table
= kcalloc(nents
, sizeof(*table
), GFP_KERNEL
);
515 sg_init_table(table
, nents
);
517 for_each_sg(table
, iter
, sg_nents(table
), i
) {
518 new_page
= alloc_page(GFP_KERNEL
);
520 /* release all previous allocated pages in the table */
522 for_each_sg(table
, iter
, sg_nents(table
), i
) {
523 new_page
= sg_page(iter
);
525 __free_page(new_page
);
529 alloc_size
= min_t(int, size
, PAGE_SIZE
);
531 sg_set_page(iter
, new_page
, alloc_size
, 0);
536 void iwl_mvm_fw_error_dump(struct iwl_mvm
*mvm
)
538 struct iwl_fw_error_dump_file
*dump_file
;
539 struct iwl_fw_error_dump_data
*dump_data
;
540 struct iwl_fw_error_dump_info
*dump_info
;
541 struct iwl_fw_error_dump_mem
*dump_mem
;
542 struct iwl_fw_error_dump_trigger_desc
*dump_trig
;
543 struct iwl_mvm_dump_ptrs
*fw_error_dump
;
544 struct scatterlist
*sg_dump_data
;
545 u32 sram_len
, sram_ofs
;
546 const struct iwl_fw_dbg_mem_seg_tlv
*fw_dbg_mem
= mvm
->fw
->dbg_mem_tlv
;
547 u32 file_len
, fifo_data_len
= 0, prph_len
= 0, radio_len
= 0;
548 u32 smem_len
= mvm
->fw
->n_dbg_mem_tlv
? 0 : mvm
->cfg
->smem_len
;
549 u32 sram2_len
= mvm
->fw
->n_dbg_mem_tlv
? 0 : mvm
->cfg
->dccm2_len
;
550 bool monitor_dump_only
= false;
553 if (!IWL_MVM_COLLECT_FW_ERR_DUMP
&&
554 !mvm
->trans
->dbg_dest_tlv
)
557 lockdep_assert_held(&mvm
->mutex
);
559 /* there's no point in fw dump if the bus is dead */
560 if (test_bit(STATUS_TRANS_DEAD
, &mvm
->trans
->status
)) {
561 IWL_ERR(mvm
, "Skip fw error dump since bus is dead\n");
565 if (mvm
->fw_dump_trig
&&
566 mvm
->fw_dump_trig
->mode
& IWL_FW_DBG_TRIGGER_MONITOR_ONLY
)
567 monitor_dump_only
= true;
569 fw_error_dump
= kzalloc(sizeof(*fw_error_dump
), GFP_KERNEL
);
573 /* SRAM - include stack CCM if driver knows the values for it */
574 if (!mvm
->cfg
->dccm_offset
|| !mvm
->cfg
->dccm_len
) {
575 const struct fw_img
*img
;
577 img
= &mvm
->fw
->img
[mvm
->cur_ucode
];
578 sram_ofs
= img
->sec
[IWL_UCODE_SECTION_DATA
].offset
;
579 sram_len
= img
->sec
[IWL_UCODE_SECTION_DATA
].len
;
581 sram_ofs
= mvm
->cfg
->dccm_offset
;
582 sram_len
= mvm
->cfg
->dccm_len
;
585 /* reading RXF/TXF sizes */
586 if (test_bit(STATUS_FW_ERROR
, &mvm
->trans
->status
)) {
587 struct iwl_mvm_shared_mem_cfg
*mem_cfg
= &mvm
->smem_cfg
;
591 /* Count RXF2 size */
592 if (mem_cfg
->rxfifo2_size
) {
593 /* Add header info */
594 fifo_data_len
+= mem_cfg
->rxfifo2_size
+
596 sizeof(struct iwl_fw_error_dump_fifo
);
599 /* Count RXF1 sizes */
600 for (i
= 0; i
< mem_cfg
->num_lmacs
; i
++) {
601 if (!mem_cfg
->lmac
[i
].rxfifo1_size
)
604 /* Add header info */
605 fifo_data_len
+= mem_cfg
->lmac
[i
].rxfifo1_size
+
607 sizeof(struct iwl_fw_error_dump_fifo
);
610 /* Count TXF sizes */
611 for (i
= 0; i
< mem_cfg
->num_lmacs
; i
++) {
614 for (j
= 0; j
< mem_cfg
->num_txfifo_entries
; j
++) {
615 if (!mem_cfg
->lmac
[i
].txfifo_size
[j
])
618 /* Add header info */
620 mem_cfg
->lmac
[i
].txfifo_size
[j
] +
622 sizeof(struct iwl_fw_error_dump_fifo
);
626 if (fw_has_capa(&mvm
->fw
->ucode_capa
,
627 IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG
)) {
629 i
< ARRAY_SIZE(mem_cfg
->internal_txfifo_size
);
631 if (!mem_cfg
->internal_txfifo_size
[i
])
634 /* Add header info */
636 mem_cfg
->internal_txfifo_size
[i
] +
638 sizeof(struct iwl_fw_error_dump_fifo
);
642 /* Make room for PRPH registers */
643 for (i
= 0; i
< ARRAY_SIZE(iwl_prph_dump_addr_comm
); i
++) {
644 /* The range includes both boundaries */
645 int num_bytes_in_chunk
=
646 iwl_prph_dump_addr_comm
[i
].end
-
647 iwl_prph_dump_addr_comm
[i
].start
+ 4;
649 prph_len
+= sizeof(*dump_data
) +
650 sizeof(struct iwl_fw_error_dump_prph
) +
654 if (mvm
->cfg
->mq_rx_supported
) {
656 ARRAY_SIZE(iwl_prph_dump_addr_9000
); i
++) {
657 /* The range includes both boundaries */
658 int num_bytes_in_chunk
=
659 iwl_prph_dump_addr_9000
[i
].end
-
660 iwl_prph_dump_addr_9000
[i
].start
+ 4;
662 prph_len
+= sizeof(*dump_data
) +
663 sizeof(struct iwl_fw_error_dump_prph
) +
668 if (mvm
->cfg
->device_family
== IWL_DEVICE_FAMILY_7000
)
669 radio_len
= sizeof(*dump_data
) + RADIO_REG_MAX_READ
;
672 file_len
= sizeof(*dump_file
) +
673 sizeof(*dump_data
) * 2 +
679 /* Make room for the SMEM, if it exists */
681 file_len
+= sizeof(*dump_data
) + sizeof(*dump_mem
) + smem_len
;
683 /* Make room for the secondary SRAM, if it exists */
685 file_len
+= sizeof(*dump_data
) + sizeof(*dump_mem
) + sram2_len
;
687 /* Make room for MEM segments */
688 for (i
= 0; i
< mvm
->fw
->n_dbg_mem_tlv
; i
++) {
689 file_len
+= sizeof(*dump_data
) + sizeof(*dump_mem
) +
690 le32_to_cpu(fw_dbg_mem
[i
].len
);
693 /* Make room for fw's virtual image pages, if it exists */
694 if (mvm
->fw
->img
[mvm
->cur_ucode
].paging_mem_size
&&
695 mvm
->fw_paging_db
[0].fw_paging_block
)
696 file_len
+= mvm
->num_of_paging_blk
*
697 (sizeof(*dump_data
) +
698 sizeof(struct iwl_fw_error_dump_paging
) +
701 /* If we only want a monitor dump, reset the file length */
702 if (monitor_dump_only
) {
703 file_len
= sizeof(*dump_file
) + sizeof(*dump_data
) +
708 * In 8000 HW family B-step include the ICCM (which resides separately)
710 if (mvm
->cfg
->device_family
== IWL_DEVICE_FAMILY_8000
&&
711 CSR_HW_REV_STEP(mvm
->trans
->hw_rev
) == SILICON_B_STEP
)
712 file_len
+= sizeof(*dump_data
) + sizeof(*dump_mem
) +
715 if (mvm
->fw_dump_desc
)
716 file_len
+= sizeof(*dump_data
) + sizeof(*dump_trig
) +
717 mvm
->fw_dump_desc
->len
;
719 if (!mvm
->fw
->n_dbg_mem_tlv
)
720 file_len
+= sram_len
+ sizeof(*dump_mem
);
722 dump_file
= vzalloc(file_len
);
724 kfree(fw_error_dump
);
728 fw_error_dump
->op_mode_ptr
= dump_file
;
730 dump_file
->barker
= cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER
);
731 dump_data
= (void *)dump_file
->data
;
733 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO
);
734 dump_data
->len
= cpu_to_le32(sizeof(*dump_info
));
735 dump_info
= (void *)dump_data
->data
;
736 dump_info
->device_family
=
737 mvm
->cfg
->device_family
== IWL_DEVICE_FAMILY_7000
?
738 cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7
) :
739 cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8
);
740 dump_info
->hw_step
= cpu_to_le32(CSR_HW_REV_STEP(mvm
->trans
->hw_rev
));
741 memcpy(dump_info
->fw_human_readable
, mvm
->fw
->human_readable
,
742 sizeof(dump_info
->fw_human_readable
));
743 strncpy(dump_info
->dev_human_readable
, mvm
->cfg
->name
,
744 sizeof(dump_info
->dev_human_readable
));
745 strncpy(dump_info
->bus_human_readable
, mvm
->dev
->bus
->name
,
746 sizeof(dump_info
->bus_human_readable
));
748 dump_data
= iwl_fw_error_next_data(dump_data
);
749 /* We only dump the FIFOs if the FW is in error state */
750 if (test_bit(STATUS_FW_ERROR
, &mvm
->trans
->status
)) {
751 iwl_mvm_dump_fifos(mvm
, &dump_data
);
753 iwl_mvm_read_radio_reg(mvm
, &dump_data
);
756 if (mvm
->fw_dump_desc
) {
757 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO
);
758 dump_data
->len
= cpu_to_le32(sizeof(*dump_trig
) +
759 mvm
->fw_dump_desc
->len
);
760 dump_trig
= (void *)dump_data
->data
;
761 memcpy(dump_trig
, &mvm
->fw_dump_desc
->trig_desc
,
762 sizeof(*dump_trig
) + mvm
->fw_dump_desc
->len
);
764 dump_data
= iwl_fw_error_next_data(dump_data
);
767 /* In case we only want monitor dump, skip to dump trasport data */
768 if (monitor_dump_only
)
769 goto dump_trans_data
;
771 if (!mvm
->fw
->n_dbg_mem_tlv
) {
772 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM
);
773 dump_data
->len
= cpu_to_le32(sram_len
+ sizeof(*dump_mem
));
774 dump_mem
= (void *)dump_data
->data
;
775 dump_mem
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM
);
776 dump_mem
->offset
= cpu_to_le32(sram_ofs
);
777 iwl_trans_read_mem_bytes(mvm
->trans
, sram_ofs
, dump_mem
->data
,
779 dump_data
= iwl_fw_error_next_data(dump_data
);
782 for (i
= 0; i
< mvm
->fw
->n_dbg_mem_tlv
; i
++) {
783 u32 len
= le32_to_cpu(fw_dbg_mem
[i
].len
);
784 u32 ofs
= le32_to_cpu(fw_dbg_mem
[i
].ofs
);
787 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM
);
788 dump_data
->len
= cpu_to_le32(len
+ sizeof(*dump_mem
));
789 dump_mem
= (void *)dump_data
->data
;
790 dump_mem
->type
= fw_dbg_mem
[i
].data_type
;
791 dump_mem
->offset
= cpu_to_le32(ofs
);
793 switch (dump_mem
->type
& cpu_to_le32(FW_DBG_MEM_TYPE_MASK
)) {
794 case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR
):
795 iwl_trans_read_mem_bytes(mvm
->trans
, ofs
,
800 case cpu_to_le32(FW_DBG_MEM_TYPE_PRPH
):
801 success
= iwl_read_prph_block(mvm
->trans
, ofs
, len
,
802 (void *)dump_mem
->data
);
806 * shouldn't get here, we ignored this kind
807 * of TLV earlier during the TLV parsing?!
814 dump_data
= iwl_fw_error_next_data(dump_data
);
818 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM
);
819 dump_data
->len
= cpu_to_le32(smem_len
+ sizeof(*dump_mem
));
820 dump_mem
= (void *)dump_data
->data
;
821 dump_mem
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM
);
822 dump_mem
->offset
= cpu_to_le32(mvm
->cfg
->smem_offset
);
823 iwl_trans_read_mem_bytes(mvm
->trans
, mvm
->cfg
->smem_offset
,
824 dump_mem
->data
, smem_len
);
825 dump_data
= iwl_fw_error_next_data(dump_data
);
829 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM
);
830 dump_data
->len
= cpu_to_le32(sram2_len
+ sizeof(*dump_mem
));
831 dump_mem
= (void *)dump_data
->data
;
832 dump_mem
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM
);
833 dump_mem
->offset
= cpu_to_le32(mvm
->cfg
->dccm2_offset
);
834 iwl_trans_read_mem_bytes(mvm
->trans
, mvm
->cfg
->dccm2_offset
,
835 dump_mem
->data
, sram2_len
);
836 dump_data
= iwl_fw_error_next_data(dump_data
);
839 if (mvm
->cfg
->device_family
== IWL_DEVICE_FAMILY_8000
&&
840 CSR_HW_REV_STEP(mvm
->trans
->hw_rev
) == SILICON_B_STEP
) {
841 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM
);
842 dump_data
->len
= cpu_to_le32(IWL8260_ICCM_LEN
+
844 dump_mem
= (void *)dump_data
->data
;
845 dump_mem
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM
);
846 dump_mem
->offset
= cpu_to_le32(IWL8260_ICCM_OFFSET
);
847 iwl_trans_read_mem_bytes(mvm
->trans
, IWL8260_ICCM_OFFSET
,
848 dump_mem
->data
, IWL8260_ICCM_LEN
);
849 dump_data
= iwl_fw_error_next_data(dump_data
);
852 /* Dump fw's virtual image */
853 if (mvm
->fw
->img
[mvm
->cur_ucode
].paging_mem_size
&&
854 mvm
->fw_paging_db
[0].fw_paging_block
) {
855 for (i
= 1; i
< mvm
->num_of_paging_blk
+ 1; i
++) {
856 struct iwl_fw_error_dump_paging
*paging
;
858 mvm
->fw_paging_db
[i
].fw_paging_block
;
859 dma_addr_t addr
= mvm
->fw_paging_db
[i
].fw_paging_phys
;
861 dump_data
->type
= cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING
);
862 dump_data
->len
= cpu_to_le32(sizeof(*paging
) +
864 paging
= (void *)dump_data
->data
;
865 paging
->index
= cpu_to_le32(i
);
866 dma_sync_single_for_cpu(mvm
->trans
->dev
, addr
,
869 memcpy(paging
->data
, page_address(pages
),
871 dump_data
= iwl_fw_error_next_data(dump_data
);
876 iwl_dump_prph(mvm
->trans
, &dump_data
,
877 iwl_prph_dump_addr_comm
,
878 ARRAY_SIZE(iwl_prph_dump_addr_comm
));
880 if (mvm
->cfg
->mq_rx_supported
)
881 iwl_dump_prph(mvm
->trans
, &dump_data
,
882 iwl_prph_dump_addr_9000
,
883 ARRAY_SIZE(iwl_prph_dump_addr_9000
));
887 fw_error_dump
->trans_ptr
= iwl_trans_dump_data(mvm
->trans
,
889 fw_error_dump
->op_mode_len
= file_len
;
890 if (fw_error_dump
->trans_ptr
)
891 file_len
+= fw_error_dump
->trans_ptr
->len
;
892 dump_file
->file_len
= cpu_to_le32(file_len
);
894 sg_dump_data
= alloc_sgtable(file_len
);
896 sg_pcopy_from_buffer(sg_dump_data
,
897 sg_nents(sg_dump_data
),
898 fw_error_dump
->op_mode_ptr
,
899 fw_error_dump
->op_mode_len
, 0);
900 if (fw_error_dump
->trans_ptr
)
901 sg_pcopy_from_buffer(sg_dump_data
,
902 sg_nents(sg_dump_data
),
903 fw_error_dump
->trans_ptr
->data
,
904 fw_error_dump
->trans_ptr
->len
,
905 fw_error_dump
->op_mode_len
);
906 dev_coredumpsg(mvm
->trans
->dev
, sg_dump_data
, file_len
,
909 vfree(fw_error_dump
->op_mode_ptr
);
910 vfree(fw_error_dump
->trans_ptr
);
911 kfree(fw_error_dump
);
914 iwl_mvm_free_fw_dump_desc(mvm
);
915 mvm
->fw_dump_trig
= NULL
;
916 clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG
, &mvm
->status
);
919 const struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert
= {
921 .type
= cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT
),
925 int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm
*mvm
,
926 const struct iwl_mvm_dump_desc
*desc
,
927 const struct iwl_fw_dbg_trigger_tlv
*trigger
)
929 unsigned int delay
= 0;
932 delay
= msecs_to_jiffies(le32_to_cpu(trigger
->stop_delay
));
934 if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG
, &mvm
->status
))
937 if (WARN_ON(mvm
->fw_dump_desc
))
938 iwl_mvm_free_fw_dump_desc(mvm
);
940 IWL_WARN(mvm
, "Collecting data: trigger %d fired.\n",
941 le32_to_cpu(desc
->trig_desc
.type
));
943 mvm
->fw_dump_desc
= desc
;
944 mvm
->fw_dump_trig
= trigger
;
946 queue_delayed_work(system_wq
, &mvm
->fw_dump_wk
, delay
);
951 int iwl_mvm_fw_dbg_collect(struct iwl_mvm
*mvm
, enum iwl_fw_dbg_trigger trig
,
952 const char *str
, size_t len
,
953 const struct iwl_fw_dbg_trigger_tlv
*trigger
)
955 struct iwl_mvm_dump_desc
*desc
;
957 desc
= kzalloc(sizeof(*desc
) + len
, GFP_ATOMIC
);
962 desc
->trig_desc
.type
= cpu_to_le32(trig
);
963 memcpy(desc
->trig_desc
.data
, str
, len
);
965 return iwl_mvm_fw_dbg_collect_desc(mvm
, desc
, trigger
);
968 int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm
*mvm
,
969 struct iwl_fw_dbg_trigger_tlv
*trigger
,
970 const char *fmt
, ...)
972 u16 occurrences
= le16_to_cpu(trigger
->occurrences
);
982 buf
[sizeof(buf
) - 1] = '\0';
985 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
988 /* check for truncation */
989 if (WARN_ON_ONCE(buf
[sizeof(buf
) - 1]))
990 buf
[sizeof(buf
) - 1] = '\0';
992 len
= strlen(buf
) + 1;
995 ret
= iwl_mvm_fw_dbg_collect(mvm
, le32_to_cpu(trigger
->id
), buf
, len
,
1001 trigger
->occurrences
= cpu_to_le16(occurrences
- 1);
1005 static inline void iwl_mvm_restart_early_start(struct iwl_mvm
*mvm
)
1007 if (mvm
->cfg
->device_family
== IWL_DEVICE_FAMILY_7000
)
1008 iwl_clear_bits_prph(mvm
->trans
, MON_BUFF_SAMPLE_CTL
, 0x100);
1010 iwl_write_prph(mvm
->trans
, DBGC_IN_SAMPLE
, 1);
1013 int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm
*mvm
, u8 conf_id
)
1019 if (WARN_ONCE(conf_id
>= ARRAY_SIZE(mvm
->fw
->dbg_conf_tlv
),
1020 "Invalid configuration %d\n", conf_id
))
1023 /* EARLY START - firmware's configuration is hard coded */
1024 if ((!mvm
->fw
->dbg_conf_tlv
[conf_id
] ||
1025 !mvm
->fw
->dbg_conf_tlv
[conf_id
]->num_of_hcmds
) &&
1026 conf_id
== FW_DBG_START_FROM_ALIVE
) {
1027 iwl_mvm_restart_early_start(mvm
);
1031 if (!mvm
->fw
->dbg_conf_tlv
[conf_id
])
1034 if (mvm
->fw_dbg_conf
!= FW_DBG_INVALID
)
1035 IWL_WARN(mvm
, "FW already configured (%d) - re-configuring\n",
1038 /* Send all HCMDs for configuring the FW debug */
1039 ptr
= (void *)&mvm
->fw
->dbg_conf_tlv
[conf_id
]->hcmd
;
1040 for (i
= 0; i
< mvm
->fw
->dbg_conf_tlv
[conf_id
]->num_of_hcmds
; i
++) {
1041 struct iwl_fw_dbg_conf_hcmd
*cmd
= (void *)ptr
;
1043 ret
= iwl_mvm_send_cmd_pdu(mvm
, cmd
->id
, 0,
1044 le16_to_cpu(cmd
->len
), cmd
->data
);
1048 ptr
+= sizeof(*cmd
);
1049 ptr
+= le16_to_cpu(cmd
->len
);
1052 mvm
->fw_dbg_conf
= conf_id
;