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