On 1/24/24 10:27 PM, Wang, Qingshun wrote: > When Advisory Non-Fatal errors are raised, both correctable and Maybe you can start with same info about what Advisory Non-FataL errors are and the specification reference. I know that you included it in cover letter. But it is good to include it in commit log. > uncorrectable error statuses will be set. The current kernel code cannot > store both statuses at the same time, thus failing to handle ANFE properly. > In addition, to avoid clearing UEs that are not ANFE by accident, UE Please add some details about the impact of not clearing them. > severity and Device Status also need to be recorded: any fatal UE cannot > be ANFE, and if Fatal/Non-Fatal Error Detected is set in Device Status, do > not take any assumption and let UE handler to clear UE status. > > Store status and mask of both correctable and uncorrectable errors in > aer_err_info. The severity of UEs and the values of the Device Status > register are also recorded, which will be used to determine UEs that should > be handled by the ANFE handler. Refactor the rest of the code to use > cor/uncor_status and cor/uncor_mask fields instead of status and mask > fields. > > Signed-off-by: "Wang, Qingshun" <qingshun.wang@xxxxxxxxxxxxxxx> > --- > drivers/acpi/apei/ghes.c | 10 ++++- > drivers/cxl/core/pci.c | 6 ++- > drivers/pci/pci.h | 8 +++- > drivers/pci/pcie/aer.c | 93 ++++++++++++++++++++++++++-------------- > include/linux/aer.h | 4 +- > include/linux/pci.h | 27 ++++++++++++ > 6 files changed, 111 insertions(+), 37 deletions(-) > > diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c > index 7b7c605166e0..6034039d5cff 100644 > --- a/drivers/acpi/apei/ghes.c > +++ b/drivers/acpi/apei/ghes.c > @@ -593,6 +593,8 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) > > if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && > pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { > + struct pcie_capability_regs *pcie_caps; > + u16 device_status = 0; > unsigned int devfn; > int aer_severity; > u8 *aer_info; > @@ -615,11 +617,17 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) > return; > memcpy(aer_info, pcie_err->aer_info, sizeof(struct aer_capability_regs)); > > + if (pcie_err->validation_bits & CPER_PCIE_VALID_CAPABILITY) { > + pcie_caps = (struct pcie_capability_regs *)pcie_err->capability; > + device_status = pcie_caps->device_status; > + } > + > aer_recover_queue(pcie_err->device_id.segment, > pcie_err->device_id.bus, > devfn, aer_severity, > (struct aer_capability_regs *) > - aer_info); > + aer_info, > + device_status); > } > #endif > } > diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c > index 6c9c8d92f8f7..9111a4415a63 100644 > --- a/drivers/cxl/core/pci.c > +++ b/drivers/cxl/core/pci.c > @@ -903,6 +903,7 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) > struct aer_capability_regs aer_regs; > struct cxl_dport *dport; > struct cxl_port *port; > + u16 device_status; > int severity; > > port = cxl_pci_find_port(pdev, &dport); > @@ -917,7 +918,10 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) > if (!cxl_rch_get_aer_severity(&aer_regs, &severity)) > return; > > - pci_print_aer(pdev, severity, &aer_regs); > + if (pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, &device_status)) > + return; > + > + pci_print_aer(pdev, severity, &aer_regs, device_status); > > if (severity == AER_CORRECTABLE) > cxl_handle_rdport_cor_ras(cxlds, dport); > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h > index 2336a8d1edab..f881a1b42f14 100644 > --- a/drivers/pci/pci.h > +++ b/drivers/pci/pci.h > @@ -407,8 +407,12 @@ struct aer_err_info { > unsigned int __pad2:2; > unsigned int tlp_header_valid:1; > > - unsigned int status; /* COR/UNCOR Error Status */ > - unsigned int mask; /* COR/UNCOR Error Mask */ > + u32 cor_mask; /* COR Error Mask */ > + u32 cor_status; /* COR Error Status */ > + u32 uncor_mask; /* UNCOR Error Mask */ > + u32 uncor_status; /* UNCOR Error Status */ > + u32 uncor_severity; /* UNCOR Error Severity */ > + u16 device_status; > struct aer_header_log_regs tlp; /* TLP Header */ > }; > > diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c > index 05fc30bb5134..6583dcf50977 100644 > --- a/drivers/pci/pcie/aer.c > +++ b/drivers/pci/pcie/aer.c > @@ -615,7 +615,7 @@ const struct attribute_group aer_stats_attr_group = { > static void pci_dev_aer_stats_incr(struct pci_dev *pdev, > struct aer_err_info *info) > { > - unsigned long status = info->status & ~info->mask; > + unsigned long status; > int i, max = -1; > u64 *counter = NULL; > struct aer_stats *aer_stats = pdev->aer_stats; > @@ -625,16 +625,19 @@ static void pci_dev_aer_stats_incr(struct pci_dev *pdev, > > switch (info->severity) { > case AER_CORRECTABLE: > + status = info->cor_status & ~info->cor_mask; > aer_stats->dev_total_cor_errs++; > counter = &aer_stats->dev_cor_errs[0]; > max = AER_MAX_TYPEOF_COR_ERRS; > break; > case AER_NONFATAL: > + status = info->uncor_status & ~info->uncor_mask; > aer_stats->dev_total_nonfatal_errs++; > counter = &aer_stats->dev_nonfatal_errs[0]; > max = AER_MAX_TYPEOF_UNCOR_ERRS; > break; > case AER_FATAL: > + status = info->uncor_status & ~info->uncor_mask; > aer_stats->dev_total_fatal_errs++; > counter = &aer_stats->dev_fatal_errs[0]; > max = AER_MAX_TYPEOF_UNCOR_ERRS; > @@ -674,15 +677,17 @@ static void __print_tlp_header(struct pci_dev *dev, > static void __aer_print_error(struct pci_dev *dev, > struct aer_err_info *info) > { > + unsigned long status; > const char **strings; > - unsigned long status = info->status & ~info->mask; > const char *level, *errmsg; > int i; > > if (info->severity == AER_CORRECTABLE) { > + status = info->cor_status & ~info->cor_mask; > strings = aer_correctable_error_string; > level = KERN_WARNING; > } else { > + status = info->uncor_status & ~info->uncor_mask; > strings = aer_uncorrectable_error_string; > level = KERN_ERR; > } > @@ -700,18 +705,27 @@ static void __aer_print_error(struct pci_dev *dev, > > void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) > { > + u32 status, mask; > int layer, agent; > int id = pci_dev_id(dev); > const char *level; > > - if (!info->status) { > + if (info->severity == AER_CORRECTABLE) { > + status = info->cor_status; > + mask = info->cor_mask; > + } else { > + status = info->uncor_status; > + mask = info->uncor_mask; > + } > + > + if (!status) { > pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", > aer_error_severity_string[info->severity]); > goto out; > } > > - layer = AER_GET_LAYER_ERROR(info->severity, info->status); > - agent = AER_GET_AGENT(info->severity, info->status); > + layer = AER_GET_LAYER_ERROR(info->severity, status); > + agent = AER_GET_AGENT(info->severity, status); > > level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR; > > @@ -720,7 +734,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) > aer_error_layer[layer], aer_agent_string[agent]); > > pci_printk(level, dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", > - dev->vendor, dev->device, info->status, info->mask); > + dev->vendor, dev->device, status, mask); > > __aer_print_error(dev, info); > > @@ -731,7 +745,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) > if (info->id && info->error_dev_num > 1 && info->id == id) > pci_err(dev, " Error of this Agent is reported first\n"); > > - trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask), > + trace_aer_event(dev_name(&dev->dev), (status & ~mask), > info->severity, info->tlp_header_valid, &info->tlp); > } > > @@ -763,7 +777,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer); > #endif > > void pci_print_aer(struct pci_dev *dev, int aer_severity, > - struct aer_capability_regs *aer) > + struct aer_capability_regs *aer, u16 device_status) > { > int layer, agent, tlp_header_valid = 0; > u32 status, mask; > @@ -783,8 +797,12 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, > > memset(&info, 0, sizeof(info)); > info.severity = aer_severity; > - info.status = status; > - info.mask = mask; > + info.cor_status = aer->cor_status; > + info.cor_mask = aer->cor_mask; > + info.uncor_status = aer->uncor_status; > + info.uncor_severity = aer->uncor_severity; > + info.uncor_mask = aer->uncor_mask; > + info.device_status = device_status; > info.first_error = PCI_ERR_CAP_FEP(aer->cap_control); > > pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask); > @@ -996,9 +1014,9 @@ static bool cxl_error_is_native(struct pci_dev *dev) > static bool is_internal_error(struct aer_err_info *info) > { > if (info->severity == AER_CORRECTABLE) > - return info->status & PCI_ERR_COR_INTERNAL; > + return info->cor_status & PCI_ERR_COR_INTERNAL; > > - return info->status & PCI_ERR_UNC_INTN; > + return info->uncor_status & PCI_ERR_UNC_INTN; > } > > static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data) > @@ -1097,7 +1115,7 @@ static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info) > */ > if (aer) > pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS, > - info->status); > + info->cor_status); > if (pcie_aer_is_native(dev)) { > struct pci_driver *pdrv = dev->driver; > > @@ -1128,6 +1146,7 @@ struct aer_recover_entry { > u8 devfn; > u16 domain; > int severity; > + u16 device_status; > struct aer_capability_regs *regs; > }; > > @@ -1148,7 +1167,7 @@ static void aer_recover_work_func(struct work_struct *work) > PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); > continue; > } > - pci_print_aer(pdev, entry.severity, entry.regs); > + pci_print_aer(pdev, entry.severity, entry.regs, entry.device_status); > /* > * Memory for aer_capability_regs(entry.regs) is being allocated from the > * ghes_estatus_pool to protect it from overwriting when multiple sections > @@ -1177,7 +1196,7 @@ static DEFINE_SPINLOCK(aer_recover_ring_lock); > static DECLARE_WORK(aer_recover_work, aer_recover_work_func); > > void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, > - int severity, struct aer_capability_regs *aer_regs) > + int severity, struct aer_capability_regs *aer_regs, u16 device_status) > { > struct aer_recover_entry entry = { > .bus = bus, > @@ -1185,6 +1204,7 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, > .domain = domain, > .severity = severity, > .regs = aer_regs, > + .device_status = device_status, > }; > > if (kfifo_in_spinlocked(&aer_recover_ring, &entry, 1, > @@ -1213,38 +1233,49 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) > int temp; > > /* Must reset in this function */ > - info->status = 0; > + info->cor_status = 0; > + info->uncor_status = 0; > + info->uncor_severity = 0; > info->tlp_header_valid = 0; > > /* The device might not support AER */ > if (!aer) > return 0; > > - if (info->severity == AER_CORRECTABLE) { > + if (info->severity == AER_CORRECTABLE || > + info->severity == AER_NONFATAL || > + type == PCI_EXP_TYPE_ROOT_PORT || > + type == PCI_EXP_TYPE_RC_EC || > + type == PCI_EXP_TYPE_DOWNSTREAM) { It looks like you are reading both uncorrectable and correctable status by default for both NONFATAL and CORRECTABLE errors. Why not do it conditionally only for ANFE errors? > + /* Link is healthy for IO reads */ > pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS, > - &info->status); > + &info->cor_status); > pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, > - &info->mask); > - if (!(info->status & ~info->mask)) > - return 0; > - } else if (type == PCI_EXP_TYPE_ROOT_PORT || > - type == PCI_EXP_TYPE_RC_EC || > - type == PCI_EXP_TYPE_DOWNSTREAM || > - info->severity == AER_NONFATAL) { > - > - /* Link is still healthy for IO reads */ > + &info->cor_mask); > pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, > - &info->status); > + &info->uncor_status); > + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, > + &info->uncor_severity); > pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, > - &info->mask); > - if (!(info->status & ~info->mask)) > + &info->uncor_mask); > + pcie_capability_read_word(dev, PCI_EXP_DEVSTA, > + &info->device_status); > + } else { > + return 1; > + } > + > + if (info->severity == AER_CORRECTABLE) { > + if (!(info->cor_status & ~info->cor_mask)) > + return 0; > + } else { > + if (!(info->uncor_status & ~info->uncor_mask)) > return 0; > > /* Get First Error Pointer */ > pci_read_config_dword(dev, aer + PCI_ERR_CAP, &temp); > info->first_error = PCI_ERR_CAP_FEP(temp); > > - if (info->status & AER_LOG_TLP_MASKS) { > + if (info->uncor_status & AER_LOG_TLP_MASKS) { > info->tlp_header_valid = 1; > pci_read_config_dword(dev, > aer + PCI_ERR_HEADER_LOG, &info->tlp.dw0); > diff --git a/include/linux/aer.h b/include/linux/aer.h > index ae0fae70d4bd..38ac802250ac 100644 > --- a/include/linux/aer.h > +++ b/include/linux/aer.h > @@ -52,9 +52,9 @@ static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; } > #endif > > void pci_print_aer(struct pci_dev *dev, int aer_severity, > - struct aer_capability_regs *aer); > + struct aer_capability_regs *aer, u16 device_status); > int cper_severity_to_aer(int cper_severity); > void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, > - int severity, struct aer_capability_regs *aer_regs); > + int severity, struct aer_capability_regs *aer_regs, u16 device_status); > #endif //_AER_H_ > > diff --git a/include/linux/pci.h b/include/linux/pci.h > index add9368e6314..259812620d4d 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -318,6 +318,33 @@ struct pci_sriov; > struct pci_p2pdma; > struct rcec_ea; > > +struct pcie_capability_regs { > + u8 pcie_cap_id; > + u8 next_cap_ptr; > + u16 pcie_caps; > + u32 device_caps; > + u16 device_control; > + u16 device_status; > + u32 link_caps; > + u16 link_control; > + u16 link_status; > + u32 slot_caps; > + u16 slot_control; > + u16 slot_status; > + u16 root_control; > + u16 root_caps; > + u32 root_status; > + u32 device_caps_2; > + u16 device_control_2; > + u16 device_status_2; > + u32 link_caps_2; > + u16 link_control_2; > + u16 link_status_2; > + u32 slot_caps_2; > + u16 slot_control_2; > + u16 slot_status_2; > +}; > + IIUC, this struct is only used drivers/acpi/apei/ghes.c . Why not define it in that file? > /* The pci_dev structure describes PCI devices */ > struct pci_dev { > struct list_head bus_list; /* Node in per-bus list */ -- Sathyanarayanan Kuppuswamy Linux Kernel Developer