1*e4efdfcaSRotem Kerem // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2*e4efdfcaSRotem Kerem /*
3*e4efdfcaSRotem Kerem * Copyright (C) 2025 Intel Corporation
4*e4efdfcaSRotem Kerem */
5*e4efdfcaSRotem Kerem
6*e4efdfcaSRotem Kerem #include <linux/pci.h>
7*e4efdfcaSRotem Kerem #include <linux/gfp.h>
8*e4efdfcaSRotem Kerem
9*e4efdfcaSRotem Kerem #include "iwl-io.h"
10*e4efdfcaSRotem Kerem #include "pcie/utils.h"
11*e4efdfcaSRotem Kerem
iwl_trans_pcie_dump_regs(struct iwl_trans * trans,struct pci_dev * pdev)12*e4efdfcaSRotem Kerem void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev)
13*e4efdfcaSRotem Kerem {
14*e4efdfcaSRotem Kerem #define PCI_DUMP_SIZE 352
15*e4efdfcaSRotem Kerem #define PCI_MEM_DUMP_SIZE 64
16*e4efdfcaSRotem Kerem #define PCI_PARENT_DUMP_SIZE 524
17*e4efdfcaSRotem Kerem #define PREFIX_LEN 32
18*e4efdfcaSRotem Kerem
19*e4efdfcaSRotem Kerem static bool pcie_dbg_dumped_once = 0;
20*e4efdfcaSRotem Kerem u32 i, pos, alloc_size, *ptr, *buf;
21*e4efdfcaSRotem Kerem char *prefix;
22*e4efdfcaSRotem Kerem
23*e4efdfcaSRotem Kerem if (pcie_dbg_dumped_once)
24*e4efdfcaSRotem Kerem return;
25*e4efdfcaSRotem Kerem
26*e4efdfcaSRotem Kerem /* Should be a multiple of 4 */
27*e4efdfcaSRotem Kerem BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3);
28*e4efdfcaSRotem Kerem BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3);
29*e4efdfcaSRotem Kerem BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3);
30*e4efdfcaSRotem Kerem
31*e4efdfcaSRotem Kerem /* Alloc a max size buffer */
32*e4efdfcaSRotem Kerem alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
33*e4efdfcaSRotem Kerem alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN);
34*e4efdfcaSRotem Kerem alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN);
35*e4efdfcaSRotem Kerem alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN);
36*e4efdfcaSRotem Kerem
37*e4efdfcaSRotem Kerem buf = kmalloc(alloc_size, GFP_ATOMIC);
38*e4efdfcaSRotem Kerem if (!buf)
39*e4efdfcaSRotem Kerem return;
40*e4efdfcaSRotem Kerem prefix = (char *)buf + alloc_size - PREFIX_LEN;
41*e4efdfcaSRotem Kerem
42*e4efdfcaSRotem Kerem IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n");
43*e4efdfcaSRotem Kerem
44*e4efdfcaSRotem Kerem /* Print wifi device registers */
45*e4efdfcaSRotem Kerem sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
46*e4efdfcaSRotem Kerem IWL_ERR(trans, "iwlwifi device config registers:\n");
47*e4efdfcaSRotem Kerem for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
48*e4efdfcaSRotem Kerem if (pci_read_config_dword(pdev, i, ptr))
49*e4efdfcaSRotem Kerem goto err_read;
50*e4efdfcaSRotem Kerem print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
51*e4efdfcaSRotem Kerem
52*e4efdfcaSRotem Kerem IWL_ERR(trans, "iwlwifi device memory mapped registers:\n");
53*e4efdfcaSRotem Kerem for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++)
54*e4efdfcaSRotem Kerem *ptr = iwl_read32(trans, i);
55*e4efdfcaSRotem Kerem print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
56*e4efdfcaSRotem Kerem
57*e4efdfcaSRotem Kerem pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
58*e4efdfcaSRotem Kerem if (pos) {
59*e4efdfcaSRotem Kerem IWL_ERR(trans, "iwlwifi device AER capability structure:\n");
60*e4efdfcaSRotem Kerem for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++)
61*e4efdfcaSRotem Kerem if (pci_read_config_dword(pdev, pos + i, ptr))
62*e4efdfcaSRotem Kerem goto err_read;
63*e4efdfcaSRotem Kerem print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
64*e4efdfcaSRotem Kerem 32, 4, buf, i, 0);
65*e4efdfcaSRotem Kerem }
66*e4efdfcaSRotem Kerem
67*e4efdfcaSRotem Kerem /* Print parent device registers next */
68*e4efdfcaSRotem Kerem if (!pdev->bus->self)
69*e4efdfcaSRotem Kerem goto out;
70*e4efdfcaSRotem Kerem
71*e4efdfcaSRotem Kerem pdev = pdev->bus->self;
72*e4efdfcaSRotem Kerem sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
73*e4efdfcaSRotem Kerem
74*e4efdfcaSRotem Kerem IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n",
75*e4efdfcaSRotem Kerem pci_name(pdev));
76*e4efdfcaSRotem Kerem for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++)
77*e4efdfcaSRotem Kerem if (pci_read_config_dword(pdev, i, ptr))
78*e4efdfcaSRotem Kerem goto err_read;
79*e4efdfcaSRotem Kerem print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
80*e4efdfcaSRotem Kerem
81*e4efdfcaSRotem Kerem /* Print root port AER registers */
82*e4efdfcaSRotem Kerem pos = 0;
83*e4efdfcaSRotem Kerem pdev = pcie_find_root_port(pdev);
84*e4efdfcaSRotem Kerem if (pdev)
85*e4efdfcaSRotem Kerem pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
86*e4efdfcaSRotem Kerem if (pos) {
87*e4efdfcaSRotem Kerem IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n",
88*e4efdfcaSRotem Kerem pci_name(pdev));
89*e4efdfcaSRotem Kerem sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
90*e4efdfcaSRotem Kerem for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++)
91*e4efdfcaSRotem Kerem if (pci_read_config_dword(pdev, pos + i, ptr))
92*e4efdfcaSRotem Kerem goto err_read;
93*e4efdfcaSRotem Kerem print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32,
94*e4efdfcaSRotem Kerem 4, buf, i, 0);
95*e4efdfcaSRotem Kerem }
96*e4efdfcaSRotem Kerem goto out;
97*e4efdfcaSRotem Kerem
98*e4efdfcaSRotem Kerem err_read:
99*e4efdfcaSRotem Kerem print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
100*e4efdfcaSRotem Kerem IWL_ERR(trans, "Read failed at 0x%X\n", i);
101*e4efdfcaSRotem Kerem out:
102*e4efdfcaSRotem Kerem pcie_dbg_dumped_once = 1;
103*e4efdfcaSRotem Kerem kfree(buf);
104*e4efdfcaSRotem Kerem }
105