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 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