--- zzzz-none-000/linux-5.4.213/drivers/pci/pcie/aer.c 2022-09-15 10:04:56.000000000 +0000 +++ miami-7690-761/linux-5.4.213/drivers/pci/pcie/aer.c 2024-05-29 11:19:59.000000000 +0000 @@ -448,9 +448,43 @@ return 0; } +static void pci_aer_panic_dump_sw(struct pci_dev *dev, const char *event); +static void pci_aer_panic_dump_regs(struct pci_dev *dev, const char *event); + +static int pci_aer_panic_notify_sw(struct notifier_block *self, + unsigned long event, void *data) +{ + struct pci_dev *dev = container_of(self, struct pci_dev, aer_panic_sw); + + pci_aer_panic_dump_sw(dev, "panic"); + + return NOTIFY_OK; +} + +static int pci_aer_panic_notify_regs(struct notifier_block *self, + unsigned long event, void *data) +{ + struct pci_dev *dev = container_of(self, struct pci_dev, aer_panic_regs); + + pci_aer_panic_dump_regs(dev, "panic"); + + return NOTIFY_OK; +} + void pci_aer_init(struct pci_dev *dev) { dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + dev->aer_panic_sw = (struct notifier_block) { + .notifier_call = pci_aer_panic_notify_sw, + .priority = 201, + }; + dev->aer_panic_regs = (struct notifier_block) { + .notifier_call = pci_aer_panic_notify_regs, + .priority = 200, + }; + atomic_notifier_chain_register(&panic_notifier_list, &dev->aer_panic_sw); + atomic_notifier_chain_register(&panic_notifier_list, &dev->aer_panic_regs); + pci_aer_panic_dump_regs(dev, "init"); if (dev->aer_cap) dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL); @@ -460,6 +494,13 @@ void pci_aer_exit(struct pci_dev *dev) { + atomic_notifier_chain_unregister(&panic_notifier_list, + &dev->aer_panic_sw); + atomic_notifier_chain_unregister(&panic_notifier_list, + &dev->aer_panic_regs); + pci_aer_panic_dump_sw(dev, "exit"); + pci_aer_panic_dump_regs(dev, "exit"); + kfree(dev->aer_stats); dev->aer_stats = NULL; } @@ -707,6 +748,84 @@ } } +static void pci_aer_panic_dump_sw_type(struct pci_dev *dev, const char *name, + const u64 *count, u64 total, + const char **strings, size_t strings_len) +{ + size_t i; + + if (!total) + return; + + pci_err(dev, " %s:\n", name); + + for (i = 0; i < strings_len; ++i) { + if (!count[i]) + continue; + + if (strings[i]) + pci_err(dev, " %s: %llu\n", strings[i], count[i]); + else + pci_err(dev, " %s_BIT[%zu]: %llu\n", name, i, count[i]); + } + + pci_err(dev, " total: %llu\n", total); +} + +static void pci_aer_panic_dump_sw(struct pci_dev *dev, const char *event) +{ + if (dev->aer_stats) { + pci_err(dev, " Error History (hidden if 0):\n"); + + pci_aer_panic_dump_sw_type(dev, "ERR_COR", + dev->aer_stats->dev_cor_errs, + dev->aer_stats->dev_total_cor_errs, + aer_correctable_error_string, + ARRAY_SIZE(aer_correctable_error_string)); + pci_aer_panic_dump_sw_type(dev, "ERR_FATAL", + dev->aer_stats->dev_fatal_errs, + dev->aer_stats->dev_total_fatal_errs, + aer_uncorrectable_error_string, + ARRAY_SIZE(aer_uncorrectable_error_string)); + pci_aer_panic_dump_sw_type(dev, "ERR_NONFATAL", + dev->aer_stats->dev_nonfatal_errs, + dev->aer_stats->dev_total_nonfatal_errs, + aer_uncorrectable_error_string, + ARRAY_SIZE(aer_uncorrectable_error_string)); + } +} + +static void pci_aer_panic_dump_regs(struct pci_dev *dev, const char *event) +{ + u32 correctable_error_status; + u32 uncorrectable_error_status; + u32 reg32; + u16 reg16; + + if (!dev->aer_cap) { + pci_info(dev, "On %s: Could not find AER capability\n", event); + return; + } + + pci_info(dev, "On %s: Found AER capability@0x%X\n", event, dev->aer_cap); + + pci_read_config_dword(dev, dev->aer_cap + PCI_ERR_CAP, ®32); + pci_info(dev, " ECRC_GENC = %d\n", !!(reg32 & PCI_ERR_CAP_ECRC_GENC)); + pci_info(dev, " ECRC_CHKC = %d\n", !!(reg32 & PCI_ERR_CAP_ECRC_CHKC)); + + pcie_capability_read_word(dev, PCI_EXP_DEVCTL, ®16); + pci_info(dev, " CERE = %d\n", !!(reg16 & PCI_EXP_DEVCTL_CERE)); + pci_info(dev, " NFERE = %d\n", !!(reg16 & PCI_EXP_DEVCTL_NFERE)); + pci_info(dev, " FERE = %d\n", !!(reg16 & PCI_EXP_DEVCTL_FERE)); + pci_info(dev, " URRE = %d\n", !!(reg16 & PCI_EXP_DEVCTL_URRE)); + + pci_read_config_dword(dev, dev->aer_cap + PCI_ERR_COR_STATUS, &correctable_error_status); + pci_read_config_dword(dev, dev->aer_cap + PCI_ERR_UNCOR_STATUS, &uncorrectable_error_status); + + pci_err(dev, " Correctable Error Status: 0x%X\n", correctable_error_status); + pci_err(dev, " Uncorrectable Error Status: 0x%X\n", uncorrectable_error_status); +} + static void __print_tlp_header(struct pci_dev *dev, struct aer_header_log_regs *t) {