diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/pcie/utils.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/pcie/utils.c | 128 | 
1 files changed, 128 insertions, 0 deletions
| diff --git a/sys/contrib/dev/iwlwifi/pcie/utils.c b/sys/contrib/dev/iwlwifi/pcie/utils.c new file mode 100644 index 000000000000..d777e1517cc5 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/pcie/utils.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include <linux/pci.h> +#include <linux/gfp.h> + +#include "iwl-io.h" +#include "pcie/utils.h" + +void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev) +{ +#define PCI_DUMP_SIZE		352 +#define PCI_MEM_DUMP_SIZE	64 +#define PCI_PARENT_DUMP_SIZE	524 +#define PREFIX_LEN		32 + +	static bool pcie_dbg_dumped_once = 0; +	u32 i, pos, alloc_size, *ptr, *buf; +	char *prefix; + +	if (pcie_dbg_dumped_once) +		return; + +	/* Should be a multiple of 4 */ +	BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3); +	BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3); +	BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3); + +	/* Alloc a max size buffer */ +	alloc_size = PCI_ERR_ROOT_ERR_SRC +  4 + PREFIX_LEN; +	alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN); +	alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN); +	alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN); + +	buf = kmalloc(alloc_size, GFP_ATOMIC); +	if (!buf) +		return; +	prefix = (char *)buf + alloc_size - PREFIX_LEN; + +	IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n"); + +	/* Print wifi device registers */ +	sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); +	IWL_ERR(trans, "iwlwifi device config registers:\n"); +	for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++) +		if (pci_read_config_dword(pdev, i, ptr)) +			goto err_read; +#if defined(__linux__) +	print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); +#elif defined(__FreeBSD__) +	iwl_print_hex_dump(NULL, IWL_DL_ANY, prefix, (u8 *)buf, i); +#endif + +	IWL_ERR(trans, "iwlwifi device memory mapped registers:\n"); +	for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++) +		*ptr = iwl_read32(trans, i); +#if defined(__linux__) +	print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); +#elif defined(__FreeBSD__) +	iwl_print_hex_dump(NULL, IWL_DL_ANY, prefix, (u8 *)buf, i); +#endif + +	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); +	if (pos) { +		IWL_ERR(trans, "iwlwifi device AER capability structure:\n"); +		for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++) +			if (pci_read_config_dword(pdev, pos + i, ptr)) +				goto err_read; +#if defined(__linux__) +		print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, +			       32, 4, buf, i, 0); +#elif defined(__FreeBSD__) +		iwl_print_hex_dump(NULL, IWL_DL_ANY, prefix, (u8 *)buf, i); +#endif +	} + +	/* Print parent device registers next */ +	if (!pdev->bus->self) +		goto out; + +	pdev = pdev->bus->self; +	sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); + +	IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n", +		pci_name(pdev)); +	for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++) +		if (pci_read_config_dword(pdev, i, ptr)) +			goto err_read; +#if defined(__linux__) +	print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); +#elif defined(__FreeBSD__) +	iwl_print_hex_dump(NULL, IWL_DL_ANY, prefix, (u8 *)buf, i); +#endif + +	/* Print root port AER registers */ +	pos = 0; +	pdev = pcie_find_root_port(pdev); +	if (pdev) +		pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); +	if (pos) { +		IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n", +			pci_name(pdev)); +		sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); +		for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++) +			if (pci_read_config_dword(pdev, pos + i, ptr)) +				goto err_read; +#if defined(__linux__) +		print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, +			       4, buf, i, 0); +#elif defined(__FreeBSD__) +		iwl_print_hex_dump(NULL, IWL_DL_ANY, prefix, (u8 *)buf, i); +#endif +	} +	goto out; + +err_read: +#if defined(__linux__) +	print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); +#elif defined(__FreeBSD__) +	iwl_print_hex_dump(NULL, IWL_DL_ANY, prefix, (u8 *)buf, i); +#endif +	IWL_ERR(trans, "Read failed at 0x%X\n", i); +out: +	pcie_dbg_dumped_once = 1; +	kfree(buf); +} | 
