diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4469e1a77f3c..02ee26ee9206 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -828,6 +828,9 @@ static inline bool pci_dev_binding_disallowed(struct pci_dev *dev) * @tlp_header_valid: Indicates if TLP field contains error information * @status: COR/UNCOR error status * @mask: COR/UNCOR mask + * @anfe_status: Advisory Non-Fatal Errors, i.e. Uncorrectable Errors signaled + * as Correctable Errors (PCIe r7.0 sec 6.2.4.3). Only used if @severity + * is AER_CORRECTABLE and @status has Advisory Non-Fatal Error Status set. * @tlp: Transaction packet information */ struct aer_err_info { @@ -850,6 +853,7 @@ struct aer_err_info { unsigned int status; unsigned int mask; + u32 anfe_status; struct pcie_tlp_log tlp; }; diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index c4fd9c0b2a54..d8dcd238fda1 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -96,6 +96,20 @@ struct aer_info { struct ratelimit_state nonfatal_ratelimit; }; +#define AER_ANFE (PCI_ERR_UNC_UNX_COMP | \ + PCI_ERR_UNC_ATOMEG | \ + PCI_ERR_UNC_DMWR_BLK) + +#define AER_POSSIBLE_ANFE (PCI_ERR_UNC_POISON_TLP | \ + PCI_ERR_UNC_POISON_BLK | \ + PCI_ERR_UNC_ECRC | \ + PCI_ERR_UNC_UNSUP | \ + PCI_ERR_UNC_COMP_TIME | \ + PCI_ERR_UNC_COMP_ABORT | \ + PCI_ERR_UNC_ACSV | \ + PCI_ERR_UNC_TLPPRE | \ + PCI_ERR_UNC_PCRC_CHECK) + #define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ PCI_ERR_UNC_POISON_BLK | \ PCI_ERR_UNC_ECRC| \ @@ -410,6 +424,15 @@ void pci_aer_init(struct pci_dev *dev) n = pcie_cap_has_rtctl(dev) ? 5 : 4; pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n); + /* + * Advisory Non-Fatal Errors are masked by default (PCIe r7.0, sec + * 7.8.4.6). + */ + if (pcie_aer_is_native(dev) && dev->devcap & PCI_EXP_DEVCAP_RBER) + pci_clear_and_set_config_dword(dev, + dev->aer_cap + PCI_ERR_COR_MASK, + PCI_ERR_COR_ADV_NFAT, 0); + pci_aer_clear_status(dev); if (pci_aer_available()) @@ -428,23 +451,38 @@ void pci_aer_exit(struct pci_dev *dev) #define AER_AGENT_REQUESTER 1 #define AER_AGENT_COMPLETER 2 #define AER_AGENT_TRANSMITTER 3 +#define AER_AGENT_COMPONENT 4 +#define AER_AGENT_UNDEF 5 #define AER_AGENT_REQUESTER_MASK(t) ((t == AER_CORRECTABLE) ? \ - 0 : (PCI_ERR_UNC_COMP_TIME|PCI_ERR_UNC_UNSUP)) + 0 : PCI_ERR_UNC_COMP_TIME) #define AER_AGENT_COMPLETER_MASK(t) ((t == AER_CORRECTABLE) ? \ 0 : PCI_ERR_UNC_COMP_ABORT) #define AER_AGENT_TRANSMITTER_MASK(t) ((t == AER_CORRECTABLE) ? \ - (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : 0) + (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : \ + (PCI_ERR_UNC_POISON_BLK|PCI_ERR_UNC_ATOMEG| \ + PCI_ERR_UNC_DMWR_BLK|PCI_ERR_UNC_XLAT_BLK| \ + PCI_ERR_UNC_TLPPRE)) +#define AER_AGENT_COMPONENT_MASK(t) ((t == AER_CORRECTABLE) ? \ + (PCI_ERR_COR_INTERNAL|PCI_ERR_COR_LOG_OVER) : \ + (PCI_ERR_UNC_INTN|PCI_ERR_UNC_SURPDN)) +#define AER_AGENT_UNDEF_MASK(t) ((t == AER_CORRECTABLE) ? \ + PCI_ERR_COR_ADV_NFAT : 0) + #define AER_GET_AGENT(t, e) \ ((e & AER_AGENT_COMPLETER_MASK(t)) ? AER_AGENT_COMPLETER : \ (e & AER_AGENT_REQUESTER_MASK(t)) ? AER_AGENT_REQUESTER : \ (e & AER_AGENT_TRANSMITTER_MASK(t)) ? AER_AGENT_TRANSMITTER : \ + (e & AER_AGENT_COMPONENT_MASK(t)) ? AER_AGENT_COMPONENT : \ + (e & AER_AGENT_UNDEF_MASK(t)) ? AER_AGENT_UNDEF : \ AER_AGENT_RECEIVER) #define AER_PHYSICAL_LAYER_ERROR 0 #define AER_DATA_LINK_LAYER_ERROR 1 #define AER_TRANSACTION_LAYER_ERROR 2 +#define AER_GENERAL_ERROR 3 +#define AER_UNDEF_ERROR 4 #define AER_PHYSICAL_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ PCI_ERR_COR_RCVR : 0) @@ -452,11 +490,17 @@ void pci_aer_exit(struct pci_dev *dev) (PCI_ERR_COR_BAD_TLP| \ PCI_ERR_COR_BAD_DLLP| \ PCI_ERR_COR_REP_ROLL| \ - PCI_ERR_COR_REP_TIMER) : PCI_ERR_UNC_DLP) + PCI_ERR_COR_REP_TIMER) : (PCI_ERR_UNC_DLP|PCI_ERR_UNC_SURPDN)) +#define AER_GENERAL_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ + (PCI_ERR_COR_INTERNAL|PCI_ERR_COR_LOG_OVER) : PCI_ERR_UNC_INTN) +#define AER_UNDEF_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ + PCI_ERR_COR_ADV_NFAT : 0) #define AER_GET_LAYER_ERROR(t, e) \ ((e & AER_PHYSICAL_LAYER_ERROR_MASK(t)) ? AER_PHYSICAL_LAYER_ERROR : \ (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ + (e & AER_GENERAL_ERROR_MASK(t)) ? AER_GENERAL_ERROR : \ + (e & AER_UNDEF_ERROR_MASK(t)) ? AER_UNDEF_ERROR : \ AER_TRANSACTION_LAYER_ERROR) /* @@ -471,7 +515,9 @@ static const char * const aer_error_severity_string[] = { static const char *aer_error_layer[] = { "Physical Layer", "Data Link Layer", - "Transaction Layer" + "Transaction Layer", + "General", + "", }; static const char *aer_correctable_error_string[] = { @@ -545,10 +591,12 @@ static const char *aer_uncorrectable_error_string[] = { }; static const char *aer_agent_string[] = { - "Receiver ID", - "Requester ID", - "Completer ID", - "Transmitter ID" + "Receiver", + "Requester", + "Completer", + "Transmitter", + "Component", + "", }; #define aer_stats_dev_attr(name, stats_array, strings_array, \ @@ -812,6 +860,46 @@ static int aer_ratelimit(struct pci_dev *dev, unsigned int severity) } } +static u32 aer_compute_anfe_status(u16 devsta, u32 uncor_status, + u32 uncor_mask, u32 uncor_severity) +{ + u32 anfe_status; + + /* + * Uncorrectable Errors must be unmasked and have Non-Fatal severity + * to qualify as Advisory Non-Fatal Errors (PCIe r7.0 sec 6.2.4.3). + */ + uncor_status &= ~uncor_mask & ~uncor_severity; + + /* Some Non-Fatal Errors are always Advisory (PCIe r7.0 sec 6.2.7). */ + anfe_status = uncor_status & AER_ANFE; + + /* + * Others may be Advisory at the discretion of the detecting agent. + * That's impossible to discern if the agent signaled ERR_NONFATAL + * in addition to ERR_COR. Assume none are Advisory in that case + * to ensure that the Uncorrectable Error code path is taken. + */ + if (!(devsta & PCI_EXP_DEVSTA_NFED)) + anfe_status |= uncor_status & AER_POSSIBLE_ANFE; + + return anfe_status; +} + +static u32 aer_get_anfe_status(struct pci_dev *dev) +{ + u32 uncor_status, uncor_mask, uncor_severity; + u16 devsta, aer = dev->aer_cap; + + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &uncor_status); + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &uncor_mask); + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, &uncor_severity); + pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &devsta); + + return aer_compute_anfe_status(devsta, uncor_status, uncor_mask, + uncor_severity); +} + static bool tlp_header_logged(u32 status, u32 capctl) { /* Errors for which a header is always logged (PCIe r7.0 sec 6.2.7) */ @@ -830,8 +918,8 @@ static void __aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { const char **strings; unsigned long status = info->status & ~info->mask; + const char *errmsg, *agent, *layer; const char *level = info->level; - const char *errmsg; int i; if (info->severity == AER_CORRECTABLE) @@ -841,10 +929,18 @@ static void __aer_print_error(struct pci_dev *dev, struct aer_err_info *info) for_each_set_bit(i, &status, 32) { errmsg = strings[i]; - if (!errmsg) + agent = aer_agent_string[AER_GET_AGENT(info->severity, BIT(i))]; + layer = aer_error_layer[AER_GET_LAYER_ERROR(info->severity, + BIT(i))]; + if (!errmsg) { errmsg = "Unknown Error Bit"; + agent = ""; + layer = ""; + } - aer_printk(level, dev, " [%2d] %-22s%s\n", i, errmsg, + aer_printk(level, dev, " [%2d] %-17s | %-11s | %-17s%s\n", + i, errmsg, agent, layer, + info->severity != AER_CORRECTABLE && info->first_error == i ? " (First)" : ""); } } @@ -854,18 +950,18 @@ static void aer_print_source(struct pci_dev *dev, struct aer_err_info *info, { u16 source = info->id; - pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d%s\n", + pci_info(dev, "%s%s Error message%s from %04x:%02x:%02x.%d%s\n", info->multi_error_valid ? "Multiple " : "", aer_error_severity_string[info->severity], + info->multi_error_valid ? "s received, first one" : " received", pci_domain_nr(dev->bus), PCI_BUS_NUM(source), PCI_SLOT(source), PCI_FUNC(source), - found ? "" : " (no details found"); + found ? "" : " (no details found)"); } void aer_print_error(struct aer_err_info *info, int i) { struct pci_dev *dev; - int layer, agent, id; const char *level = info->level; const char *bus_type = aer_err_bus(info); @@ -873,39 +969,48 @@ void aer_print_error(struct aer_err_info *info, int i) return; dev = info->dev[i]; - id = pci_dev_id(dev); pci_dev_aer_stats_incr(dev, info); trace_aer_event(pci_name(dev), (info->status & ~info->mask), - info->severity, info->tlp_header_valid, &info->tlp, bus_type); + info->severity, info->tlp_header_valid && + info->severity != AER_CORRECTABLE, &info->tlp, + bus_type); + /* + * For Advisory Non-Fatal Errors, record statistics and tracing + * even if ratelimited + */ if (!info->ratelimit_print[i]) - return; + goto anfe; if (!info->status) { - pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", + pci_err(dev, "%s Bus Error: severity=%s (Inaccessible)\n", bus_type, aer_error_severity_string[info->severity]); - goto out; + return; } - layer = AER_GET_LAYER_ERROR(info->severity, info->status); - agent = AER_GET_AGENT(info->severity, info->status); - - aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n", - bus_type, aer_error_severity_string[info->severity], - aer_error_layer[layer], aer_agent_string[agent]); + aer_printk(level, dev, "%s Bus Error: severity=%s\n", + bus_type, aer_error_severity_string[info->severity]); aer_printk(level, dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", dev->vendor, dev->device, info->status, info->mask); __aer_print_error(dev, info); - if (info->tlp_header_valid) + if (info->tlp_header_valid && info->severity != AER_CORRECTABLE) pcie_print_tlp_log(dev, &info->tlp, level, dev_fmt(" ")); -out: - if (info->id && info->error_dev_num > 1 && info->id == id) - pci_err(dev, " Error of this Agent is reported first\n"); +anfe: + /* Recursive invocation for Advisory Non-Fatal Errors */ + if (info->anfe_status && info->severity == AER_CORRECTABLE) { + info->severity = AER_NONFATAL; + info->status = info->anfe_status; + info->mask = 0; + + aer_print_error(info, i); + + info->severity = AER_CORRECTABLE; + } } #ifdef CONFIG_ACPI_APEI_PCIEAER @@ -923,13 +1028,15 @@ int cper_severity_to_aer(int cper_severity) EXPORT_SYMBOL_GPL(cper_severity_to_aer); #endif -void pci_print_aer(struct pci_dev *dev, int aer_severity, - struct aer_capability_regs *aer) +static void __pci_print_aer(struct pci_dev *dev, int aer_severity, + struct aer_capability_regs *aer, + bool ratelimit_print, const char *level) { - const char *bus_type; - int layer, agent, tlp_header_valid = 0; + const char *bus_type, *sev; + int tlp_header_valid = 0; u32 status, mask; struct aer_err_info info = { + .level = level, .severity = aer_severity, .first_error = PCI_ERR_CAP_FEP(aer->cap_control), }; @@ -937,12 +1044,13 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, if (aer_severity == AER_CORRECTABLE) { status = aer->cor_status; mask = aer->cor_mask; - info.level = KERN_WARNING; + sev = "cor"; } else { status = aer->uncor_status; mask = aer->uncor_mask; - info.level = KERN_ERR; - tlp_header_valid = tlp_header_logged(status, aer->cap_control); + sev = "uncor"; + tlp_header_valid = tlp_header_logged(status & ~mask, + aer->cap_control); } info.status = status; @@ -955,17 +1063,17 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, trace_aer_event(pci_name(dev), (status & ~mask), aer_severity, tlp_header_valid, &aer->header_log, bus_type); - if (!aer_ratelimit(dev, info.severity)) - return; + /* + * For Advisory Non-Fatal Errors, record statistics and tracing + * even if ratelimited + */ + if (!ratelimit_print) + goto anfe; - layer = AER_GET_LAYER_ERROR(aer_severity, status); - agent = AER_GET_AGENT(aer_severity, status); - - aer_printk(info.level, dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", - status, mask); + aer_printk(info.level, dev, + "aer_%s_status: 0x%08x, aer_%s_mask: 0x%08x\n", + sev, status, sev, mask); __aer_print_error(dev, &info); - aer_printk(info.level, dev, "aer_layer=%s, aer_agent=%s\n", - aer_error_layer[layer], aer_agent_string[agent]); if (aer_severity != AER_CORRECTABLE) aer_printk(info.level, dev, "aer_uncor_severity: 0x%08x\n", @@ -974,6 +1082,36 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, if (tlp_header_valid) pcie_print_tlp_log(dev, &aer->header_log, info.level, dev_fmt(" ")); + +anfe: + /* Recursive invocation for Advisory Non-Fatal Errors */ + if (aer_severity == AER_CORRECTABLE && + info.status & ~info.mask & PCI_ERR_COR_ADV_NFAT) { + u32 anfe_status = aer_compute_anfe_status(PCI_EXP_DEVSTA_CED, + aer->uncor_status, + aer->uncor_mask, + aer->uncor_severity); + if (anfe_status) { + aer->uncor_status = anfe_status; + aer->uncor_mask = 0; + __pci_print_aer(dev, AER_NONFATAL, aer, + ratelimit_print, level); + } + } +} + +void pci_print_aer(struct pci_dev *dev, int aer_severity, + struct aer_capability_regs *aer) +{ + /* + * Precalculate ratelimit counter and log level so that Advisory + * Non-Fatal Errors are treated like the accompanying Correctable Error + */ + bool ratelimit_print = aer_ratelimit(dev, aer_severity); + const char *level = aer_severity == AER_CORRECTABLE ? KERN_WARNING + : KERN_ERR; + + __pci_print_aer(dev, aer_severity, aer, ratelimit_print, level); } EXPORT_SYMBOL_GPL(pci_print_aer); @@ -1176,9 +1314,14 @@ static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info) * Correctable error does not need software intervention. * No need to go through error recovery process. */ - if (aer) + if (aer) { pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS, info->status); + if (info->anfe_status) + pci_write_config_dword(dev, + aer + PCI_ERR_UNCOR_STATUS, + info->anfe_status); + } if (pcie_aer_is_native(dev)) { struct pci_driver *pdrv = dev->driver; @@ -1281,6 +1424,27 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, EXPORT_SYMBOL_GPL(aer_recover_queue); #endif +static void aer_get_uncor_info(struct pci_dev *dev, struct aer_err_info *info, + u32 status) +{ + u16 aer = dev->aer_cap; + u32 aercc; + + /* Get First Error Pointer */ + pci_read_config_dword(dev, aer + PCI_ERR_CAP, &aercc); + info->first_error = PCI_ERR_CAP_FEP(aercc); + + /* Get TLP Prefix/Header Log */ + if (tlp_header_logged(status, aercc)) { + info->tlp_header_valid = 1; + pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG, + aer + PCI_ERR_PREFIX_LOG, + aer_tlp_log_len(dev, aercc), + aercc & PCI_ERR_CAP_TLP_LOG_FLIT, + &info->tlp); + } +} + /** * aer_get_device_error_info - read error status from dev and store it to info * @info: pointer to structure to store the error record @@ -1294,7 +1458,6 @@ int aer_get_device_error_info(struct aer_err_info *info, int i) { struct pci_dev *dev; int type, aer; - u32 aercc; if (i >= AER_MAX_MULTI_ERR_DEVICES) return 0; @@ -1305,6 +1468,7 @@ int aer_get_device_error_info(struct aer_err_info *info, int i) /* Must reset in this function */ info->status = 0; + info->anfe_status = 0; info->tlp_header_valid = 0; info->is_cxl = pcie_is_cxl(dev); @@ -1319,6 +1483,10 @@ int aer_get_device_error_info(struct aer_err_info *info, int i) &info->mask); if (!(info->status & ~info->mask)) return 0; + if (info->status & ~info->mask & PCI_ERR_COR_ADV_NFAT) { + info->anfe_status = aer_get_anfe_status(dev); + aer_get_uncor_info(dev, info, info->anfe_status); + } } else if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_DOWNSTREAM || @@ -1332,18 +1500,7 @@ int aer_get_device_error_info(struct aer_err_info *info, int i) if (!(info->status & ~info->mask)) return 0; - /* Get First Error Pointer */ - pci_read_config_dword(dev, aer + PCI_ERR_CAP, &aercc); - info->first_error = PCI_ERR_CAP_FEP(aercc); - - if (tlp_header_logged(info->status, aercc)) { - info->tlp_header_valid = 1; - pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG, - aer + PCI_ERR_PREFIX_LOG, - aer_tlp_log_len(dev, aercc), - aercc & PCI_ERR_CAP_TLP_LOG_FLIT, - &info->tlp); - } + aer_get_uncor_info(dev, info, info->status & ~info->mask); } return 1;