The AER driver is now designed to forward CXL protocol errors to the CXL
driver. Update the CXL driver with functionality to dequeue the forwarded
CXL error from the kfifo. Also, update the CXL driver to process the CXL
protocol errors using CXL protocol error handlers.
First, move cxl_rch_handle_error_iter() from aer.c to cxl/core/ras.c.
Remove and drop the cxl_rch_handle_error() in aer.c as it is not needed.
Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
AER service driver. This will begin the CXL protocol error processing
with the call to cxl_handle_prot_error().
Introduce cxl_handle_prot_error() to differntiate between Restricted CXL
Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
RCH errors will be processed with a call to walk the associated Root
Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
so the CXL driver can walk the RCEC's downstream bus, searching for
the RCiEP.
VH correctable error (CE) processing will call the CXL CE handler if
present. VH uncorrectable errors (UCE) will call cxl_do_recovery(),
implemented as a stub for now and to be updated in future patch. Export
pci_aer_clean_fatal_status() and pci_clean_device_status() used to clean up
AER status after handling.
Create cxl_driver::error_handler structure similar to
pci_driver::error_handlers. Add handlers for CE and UCE CXL.io errors. Add
'struct cxl_prot_error_info' as a parameter to the CXL CE and UCE error
handlers.
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
drivers/cxl/core/ras.c | 102 +++++++++++++++++++++++++++++++++++++++-
drivers/cxl/cxl.h | 17 +++++++
drivers/pci/pci.c | 1 +
drivers/pci/pci.h | 6 ---
drivers/pci/pcie/aer.c | 42 +----------------
drivers/pci/pcie/rcec.c | 1 +
include/linux/aer.h | 2 +
include/linux/pci.h | 10 ++++
8 files changed, 133 insertions(+), 48 deletions(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index ecb60a5962de..eca8f11a05d9 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -139,8 +139,108 @@ int cxl_create_prot_err_info(struct pci_dev *_pdev, int severity,
return 0;
}
+EXPORT_SYMBOL_NS_GPL(cxl_create_prot_err_info, "CXL");
-struct work_struct cxl_prot_err_work;
+static void cxl_do_recovery(struct pci_dev *pdev) { }
+
+static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
+{
+ struct cxl_prot_error_info *err_info = data;
+ const struct cxl_error_handlers *err_handler;
+ struct device *dev = err_info->dev;
+ struct cxl_driver *pdrv;
+
+ /*
+ * The capability, status, and control fields in Device 0,
+ * Function 0 DVSEC control the CXL functionality of the
+ * entire device (CXL 3.0, 8.1.3).
+ */
+ if (pdev->devfn != PCI_DEVFN(0, 0))
+ return 0;
+
+ /*
+ * CXL Memory Devices must have the 502h class code set (CXL
+ * 3.0, 8.1.12.1).
+ */
+ if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
+ return 0;
+
+ if (!is_cxl_memdev(dev) || !dev->driver)
+ return 0;
+
+ pdrv = to_cxl_drv(dev->driver);
+ if (!pdrv || !pdrv->err_handler)
+ return 0;
+
+ err_handler = pdrv->err_handler;
+ if (err_info->severity == AER_CORRECTABLE) {
+ if (err_handler->cor_error_detected)
+ err_handler->cor_error_detected(dev, err_info);
+ } else if (err_handler->error_detected) {
+ cxl_do_recovery(pdev);
+ }
+
+ return 0;
+}
+
+static void cxl_handle_prot_error(struct pci_dev *pdev, struct cxl_prot_error_info *err_info)
+{
+ if (!pdev || !err_info)
+ return;
+
+ /*
+ * Internal errors of an RCEC indicate an AER error in an
+ * RCH's downstream port. Check and handle them in the CXL.mem
+ * device driver.
+ */
+ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
+ return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
+
+ if (err_info->severity == AER_CORRECTABLE) {
+ struct device *dev __free(put_device) = get_device(err_info->dev);
+ struct cxl_driver *pdrv;
+ int aer = pdev->aer_cap;
+
+ if (!dev || !dev->driver)
+ return;
+
+ if (aer) {
+ int ras_status;
+
+ pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, &ras_status);
+ pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS,
+ ras_status);
+ }
+
+ pdrv = to_cxl_drv(dev->driver);
+ if (!pdrv || !pdrv->err_handler ||
+ !pdrv->err_handler->cor_error_detected)
+ return;
+
+ pdrv->err_handler->cor_error_detected(dev, err_info);
+ pcie_clear_device_status(pdev);
+ } else {
+ cxl_do_recovery(pdev);
+ }
+}
+
+static void cxl_prot_err_work_fn(struct work_struct *work)
+{
+ struct cxl_prot_err_work_data wd;
+
+ while (cxl_prot_err_kfifo_get(&wd)) {
+ struct cxl_prot_error_info *err_info = &wd.err_info;
+ struct device *dev __free(put_device) = get_device(err_info->dev);
+ struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(err_info->pdev);
+
+ if (!dev || !pdev)
+ continue;
+
+ cxl_handle_prot_error(pdev, err_info);
+ }
+}
+
+static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
int cxl_ras_init(void)
{
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index be8a7dc77719..73cddd2c921e 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -11,6 +11,8 @@
#include <linux/log2.h>
#include <linux/node.h>
#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/aer.h>
extern const struct nvdimm_security_ops *cxl_security_ops;
@@ -786,6 +788,20 @@ static inline int cxl_root_decoder_autoremove(struct device *host,
}
int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
+int cxl_create_prot_err_info(struct pci_dev *pdev, int severity,
+ struct cxl_prot_error_info *err_info);
+
+/* CXL bus error event callbacks */
+struct cxl_error_handlers {
+ /* CXL bus error detected on this device */
+ pci_ers_result_t (*error_detected)(struct device *dev,
+ struct cxl_prot_error_info *err_info);
+
+ /* Allow device driver to record more details of a correctable error */
+ void (*cor_error_detected)(struct device *dev,
+ struct cxl_prot_error_info *err_info);
+};
+
/**
* struct cxl_endpoint_dvsec_info - Cached DVSEC info
* @mem_enabled: cached value of mem_enabled in the DVSEC at init time
@@ -820,6 +836,7 @@ struct cxl_driver {
void (*remove)(struct device *dev);
struct device_driver drv;
int id;
+ const struct cxl_error_handlers *err_handler;
};
#define to_cxl_drv(__drv) container_of_const(__drv, struct cxl_driver, drv)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a1d75f40017e..d80c705d683c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2320,6 +2320,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
}
+EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
#endif
/**
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index eed098c134a6..c32eab22c0b2 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -593,16 +593,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
void pci_rcec_init(struct pci_dev *dev);
void pci_rcec_exit(struct pci_dev *dev);
void pcie_link_rcec(struct pci_dev *rcec);
-void pcie_walk_rcec(struct pci_dev *rcec,
- int (*cb)(struct pci_dev *, void *),
- void *userdata);
#else
static inline void pci_rcec_init(struct pci_dev *dev) { }
static inline void pci_rcec_exit(struct pci_dev *dev) { }
static inline void pcie_link_rcec(struct pci_dev *rcec) { }
-static inline void pcie_walk_rcec(struct pci_dev *rcec,
- int (*cb)(struct pci_dev *, void *),
- void *userdata) { }
#endif
#ifdef CONFIG_PCI_ATS
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index d1df751cfe4b..763ec6aa1a9a 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -288,6 +288,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
if (status)
pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
}
+EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
/**
* pci_aer_raw_clear_status - Clear AER error registers.
@@ -1018,47 +1019,6 @@ static bool is_cxl_error(struct aer_err_info *info)
return is_internal_error(info);
}
-static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
-{
- struct aer_err_info *info = (struct aer_err_info *)data;
- const struct pci_error_handlers *err_handler;
-
- if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
- return 0;
-
- /* protect dev->driver */
- device_lock(&dev->dev);
-
- err_handler = dev->driver ? dev->driver->err_handler : NULL;
- if (!err_handler)
- goto out;
-
- if (info->severity == AER_CORRECTABLE) {
- if (err_handler->cor_error_detected)
- err_handler->cor_error_detected(dev);
- } else if (err_handler->error_detected) {
- if (info->severity == AER_NONFATAL)
- err_handler->error_detected(dev, pci_channel_io_normal);
- else if (info->severity == AER_FATAL)
- err_handler->error_detected(dev, pci_channel_io_frozen);
- }
-out:
- device_unlock(&dev->dev);
- return 0;
-}
-
-static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info)
-{
- /*
- * Internal errors of an RCEC indicate an AER error in an
- * RCH's downstream port. Check and handle them in the CXL.mem
- * device driver.
- */
- if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
- is_internal_error(info))
- pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
-}
-
static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
{
bool *handles_cxl = data;
diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
index d0bcd141ac9c..fb6cf6449a1d 100644
--- a/drivers/pci/pcie/rcec.c
+++ b/drivers/pci/pcie/rcec.c
@@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
walk_rcec(walk_rcec_helper, &rcec_data);
}
+EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
void pci_rcec_init(struct pci_dev *dev)
{
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 761d6f5cd792..8f815f34d447 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -66,12 +66,14 @@ struct cxl_prot_err_work_data {
#if defined(CONFIG_PCIEAER)
int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
+void pci_aer_clear_fatal_status(struct pci_dev *dev);
int pcie_aer_is_native(struct pci_dev *dev);
#else
static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
{
return -EINVAL;
}
+static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index af83230bef1a..56015721be22 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1802,6 +1802,9 @@ extern bool pcie_ports_native;
int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
bool use_lt);
+void pcie_walk_rcec(struct pci_dev *rcec,
+ int (*cb)(struct pci_dev *, void *),
+ void *userdata);
#else
#define pcie_ports_disabled true
#define pcie_ports_native false
@@ -1812,8 +1815,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
{
return -EOPNOTSUPP;
}
+
+static inline void pcie_walk_rcec(struct pci_dev *rcec,
+ int (*cb)(struct pci_dev *, void *),
+ void *userdata) { }
+
#endif
+void pcie_clear_device_status(struct pci_dev *dev);
+
#define PCIE_LINK_STATE_L0S (BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
#define PCIE_LINK_STATE_L1 BIT(2) /* L1 state */
#define PCIE_LINK_STATE_L1_1 BIT(3) /* ASPM L1.1 state */
--
2.34.1
On Wed, 26 Mar 2025 20:47:06 -0500
Terry Bowman <terry.bowman@amd.com> wrote:
> The AER driver is now designed to forward CXL protocol errors to the CXL
> driver. Update the CXL driver with functionality to dequeue the forwarded
> CXL error from the kfifo. Also, update the CXL driver to process the CXL
> protocol errors using CXL protocol error handlers.
>
> First, move cxl_rch_handle_error_iter() from aer.c to cxl/core/ras.c.
> Remove and drop the cxl_rch_handle_error() in aer.c as it is not needed.
>
> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
> AER service driver. This will begin the CXL protocol error processing
> with the call to cxl_handle_prot_error().
>
> Introduce cxl_handle_prot_error() to differntiate between Restricted CXL
> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
> RCH errors will be processed with a call to walk the associated Root
> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
> so the CXL driver can walk the RCEC's downstream bus, searching for
> the RCiEP.
>
> VH correctable error (CE) processing will call the CXL CE handler if
> present. VH uncorrectable errors (UCE) will call cxl_do_recovery(),
> implemented as a stub for now and to be updated in future patch. Export
> pci_aer_clean_fatal_status() and pci_clean_device_status() used to clean up
> AER status after handling.
>
> Create cxl_driver::error_handler structure similar to
> pci_driver::error_handlers. Add handlers for CE and UCE CXL.io errors. Add
> 'struct cxl_prot_error_info' as a parameter to the CXL CE and UCE error
> handlers.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
> drivers/cxl/core/ras.c | 102 +++++++++++++++++++++++++++++++++++++++-
> drivers/cxl/cxl.h | 17 +++++++
> drivers/pci/pci.c | 1 +
> drivers/pci/pci.h | 6 ---
> drivers/pci/pcie/aer.c | 42 +----------------
> drivers/pci/pcie/rcec.c | 1 +
> include/linux/aer.h | 2 +
> include/linux/pci.h | 10 ++++
> 8 files changed, 133 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index ecb60a5962de..eca8f11a05d9 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -139,8 +139,108 @@ int cxl_create_prot_err_info(struct pci_dev *_pdev, int severity,
>
> return 0;
> }
> +EXPORT_SYMBOL_NS_GPL(cxl_create_prot_err_info, "CXL");
>
> -struct work_struct cxl_prot_err_work;
> +static void cxl_do_recovery(struct pci_dev *pdev) { }
> +
> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> +{
> + struct cxl_prot_error_info *err_info = data;
> + const struct cxl_error_handlers *err_handler;
> + struct device *dev = err_info->dev;
> + struct cxl_driver *pdrv;
> +
> + /*
> + * The capability, status, and control fields in Device 0,
> + * Function 0 DVSEC control the CXL functionality of the
> + * entire device (CXL 3.0, 8.1.3).
> + */
> + if (pdev->devfn != PCI_DEVFN(0, 0))
> + return 0;
> +
> + /*
> + * CXL Memory Devices must have the 502h class code set (CXL
> + * 3.0, 8.1.12.1).
> + */
> + if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> + return 0;
> +
> + if (!is_cxl_memdev(dev) || !dev->driver)
> + return 0;
> +
> + pdrv = to_cxl_drv(dev->driver);
> + if (!pdrv || !pdrv->err_handler)
> + return 0;
> +
> + err_handler = pdrv->err_handler;
> + if (err_info->severity == AER_CORRECTABLE) {
> + if (err_handler->cor_error_detected)
> + err_handler->cor_error_detected(dev, err_info);
> + } else if (err_handler->error_detected) {
> + cxl_do_recovery(pdev);
> + }
> +
> + return 0;
> +}
> +
> +static void cxl_handle_prot_error(struct pci_dev *pdev, struct cxl_prot_error_info *err_info)
> +{
> + if (!pdev || !err_info)
Are these real potential conditions? If so can we have a comment on why.
If this is defensive only, do we need it?
Looks like the caller below checked pdev already.
> + return;
> +
> + /*
> + * Internal errors of an RCEC indicate an AER error in an
> + * RCH's downstream port. Check and handle them in the CXL.mem
> + * device driver.
> + */
> + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
> + return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
> +
> + if (err_info->severity == AER_CORRECTABLE) {
> + struct device *dev __free(put_device) = get_device(err_info->dev);
Similar question around lifetimes. The caller already got this. Why again?
> + struct cxl_driver *pdrv;
calling a cxl driver pdrv seems odd. cdrv maybe?
> + int aer = pdev->aer_cap;
> +
> + if (!dev || !dev->driver)
> + return;
> +
> + if (aer) {
> + int ras_status;
> +
> + pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, &ras_status);
If we get multiple bits set in this register, can this wipe out ones we haven't noticed
anywhere else in the handling? Bad tlp etc. Maybe we need to ensure this only clears
the internal error bit?
> + pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS,
> + ras_status);
> + }
> +
> + pdrv = to_cxl_drv(dev->driver);
> + if (!pdrv || !pdrv->err_handler ||
> + !pdrv->err_handler->cor_error_detected)
> + return;
> +
> + pdrv->err_handler->cor_error_detected(dev, err_info);
> + pcie_clear_device_status(pdev);
> + } else {
> + cxl_do_recovery(pdev);
> + }
> +}
> +
> +static void cxl_prot_err_work_fn(struct work_struct *work)
> +{
> + struct cxl_prot_err_work_data wd;
> +
> + while (cxl_prot_err_kfifo_get(&wd)) {
> + struct cxl_prot_error_info *err_info = &wd.err_info;
> + struct device *dev __free(put_device) = get_device(err_info->dev);
> + struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(err_info->pdev);
> +
> + if (!dev || !pdev)
> + continue;
> +
> + cxl_handle_prot_error(pdev, err_info);
> + }
> +}
> +
> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
Ah! Here it is... I think this can be in patch 3. With a stub of the function
(which is what the patch 3 description claims is there).
>
Jonathan
On 4/23/2025 11:28 AM, Jonathan Cameron wrote:
> On Wed, 26 Mar 2025 20:47:06 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
>
>> The AER driver is now designed to forward CXL protocol errors to the CXL
>> driver. Update the CXL driver with functionality to dequeue the forwarded
>> CXL error from the kfifo. Also, update the CXL driver to process the CXL
>> protocol errors using CXL protocol error handlers.
>>
>> First, move cxl_rch_handle_error_iter() from aer.c to cxl/core/ras.c.
>> Remove and drop the cxl_rch_handle_error() in aer.c as it is not needed.
>>
>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>> AER service driver. This will begin the CXL protocol error processing
>> with the call to cxl_handle_prot_error().
>>
>> Introduce cxl_handle_prot_error() to differntiate between Restricted CXL
>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>> RCH errors will be processed with a call to walk the associated Root
>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>> so the CXL driver can walk the RCEC's downstream bus, searching for
>> the RCiEP.
>>
>> VH correctable error (CE) processing will call the CXL CE handler if
>> present. VH uncorrectable errors (UCE) will call cxl_do_recovery(),
>> implemented as a stub for now and to be updated in future patch. Export
>> pci_aer_clean_fatal_status() and pci_clean_device_status() used to clean up
>> AER status after handling.
>>
>> Create cxl_driver::error_handler structure similar to
>> pci_driver::error_handlers. Add handlers for CE and UCE CXL.io errors. Add
>> 'struct cxl_prot_error_info' as a parameter to the CXL CE and UCE error
>> handlers.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>> drivers/cxl/core/ras.c | 102 +++++++++++++++++++++++++++++++++++++++-
>> drivers/cxl/cxl.h | 17 +++++++
>> drivers/pci/pci.c | 1 +
>> drivers/pci/pci.h | 6 ---
>> drivers/pci/pcie/aer.c | 42 +----------------
>> drivers/pci/pcie/rcec.c | 1 +
>> include/linux/aer.h | 2 +
>> include/linux/pci.h | 10 ++++
>> 8 files changed, 133 insertions(+), 48 deletions(-)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index ecb60a5962de..eca8f11a05d9 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -139,8 +139,108 @@ int cxl_create_prot_err_info(struct pci_dev *_pdev, int severity,
>>
>> return 0;
>> }
>> +EXPORT_SYMBOL_NS_GPL(cxl_create_prot_err_info, "CXL");
>>
>> -struct work_struct cxl_prot_err_work;
>> +static void cxl_do_recovery(struct pci_dev *pdev) { }
>> +
>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> +{
>> + struct cxl_prot_error_info *err_info = data;
>> + const struct cxl_error_handlers *err_handler;
>> + struct device *dev = err_info->dev;
>> + struct cxl_driver *pdrv;
>> +
>> + /*
>> + * The capability, status, and control fields in Device 0,
>> + * Function 0 DVSEC control the CXL functionality of the
>> + * entire device (CXL 3.0, 8.1.3).
>> + */
>> + if (pdev->devfn != PCI_DEVFN(0, 0))
>> + return 0;
>> +
>> + /*
>> + * CXL Memory Devices must have the 502h class code set (CXL
>> + * 3.0, 8.1.12.1).
>> + */
>> + if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>> + return 0;
>> +
>> + if (!is_cxl_memdev(dev) || !dev->driver)
>> + return 0;
>> +
>> + pdrv = to_cxl_drv(dev->driver);
>> + if (!pdrv || !pdrv->err_handler)
>> + return 0;
>> +
>> + err_handler = pdrv->err_handler;
>> + if (err_info->severity == AER_CORRECTABLE) {
>> + if (err_handler->cor_error_detected)
>> + err_handler->cor_error_detected(dev, err_info);
>> + } else if (err_handler->error_detected) {
>> + cxl_do_recovery(pdev);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void cxl_handle_prot_error(struct pci_dev *pdev, struct cxl_prot_error_info *err_info)
>> +{
>> + if (!pdev || !err_info)
> Are these real potential conditions? If so can we have a comment on why.
> If this is defensive only, do we need it?
> Looks like the caller below checked pdev already.
Yes, these checks can be removed.
>> + return;
>> +
>> + /*
>> + * Internal errors of an RCEC indicate an AER error in an
>> + * RCH's downstream port. Check and handle them in the CXL.mem
>> + * device driver.
>> + */
>> + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>> + return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>> +
>> + if (err_info->severity == AER_CORRECTABLE) {
>> + struct device *dev __free(put_device) = get_device(err_info->dev);
> Similar question around lifetimes. The caller already got this. Why again?
Not necessary. I'll remove.
>> + struct cxl_driver *pdrv;
> calling a cxl driver pdrv seems odd. cdrv maybe?
Ok. I'll rename cdrv.
>> + int aer = pdev->aer_cap;
>> +
>> + if (!dev || !dev->driver)
>> + return;
>> +
>> + if (aer) {
>> + int ras_status;
>> +
>> + pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, &ras_status);
> If we get multiple bits set in this register, can this wipe out ones we haven't noticed
> anywhere else in the handling? Bad tlp etc. Maybe we need to ensure this only clears
> the internal error bit?
Good point. I'll fix. I'm going to rename 'ras_status' to 'aer_status' as well.
>> + pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS,
>> + ras_status);
>> + }
>> +
>> + pdrv = to_cxl_drv(dev->driver);
>> + if (!pdrv || !pdrv->err_handler ||
>> + !pdrv->err_handler->cor_error_detected)
>> + return;
>> +
>> + pdrv->err_handler->cor_error_detected(dev, err_info);
>> + pcie_clear_device_status(pdev);
>> + } else {
>> + cxl_do_recovery(pdev);
>> + }
>> +}
>> +
>> +static void cxl_prot_err_work_fn(struct work_struct *work)
>> +{
>> + struct cxl_prot_err_work_data wd;
>> +
>> + while (cxl_prot_err_kfifo_get(&wd)) {
>> + struct cxl_prot_error_info *err_info = &wd.err_info;
>> + struct device *dev __free(put_device) = get_device(err_info->dev);
>> + struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(err_info->pdev);
>> +
>> + if (!dev || !pdev)
>> + continue;
>> +
>> + cxl_handle_prot_error(pdev, err_info);
>> + }
>> +}
>> +
>> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
> Ah! Here it is... I think this can be in patch 3. With a stub of the function
> (which is what the patch 3 description claims is there).
I'll move it.
>>
> Jonathan
>
-Terry
Hi Terry,
kernel test robot noticed the following build errors:
[auto build test ERROR on aae0594a7053c60b82621136257c8b648c67b512]
url: https://github.com/intel-lab-lkp/linux/commits/Terry-Bowman/PCI-CXL-Introduce-PCIe-helper-function-pcie_is_cxl/20250327-095738
base: aae0594a7053c60b82621136257c8b648c67b512
patch link: https://lore.kernel.org/r/20250327014717.2988633-6-terry.bowman%40amd.com
patch subject: [PATCH v8 05/16] PCI/AER: CXL driver dequeues CXL error forwarded from AER service driver
config: loongarch-randconfig-001-20250327 (https://download.01.org/0day-ci/archive/20250327/202503271234.IKMoGynt-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250327/202503271234.IKMoGynt-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202503271234.IKMoGynt-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/cxl/core/ras.c: In function 'cxl_handle_prot_error':
>> drivers/cxl/core/ras.c:202:33: error: 'struct pci_dev' has no member named 'aer_cap'; did you mean 'ats_cap'?
202 | int aer = pdev->aer_cap;
| ^~~~~~~
| ats_cap
vim +202 drivers/cxl/core/ras.c
185
186 static void cxl_handle_prot_error(struct pci_dev *pdev, struct cxl_prot_error_info *err_info)
187 {
188 if (!pdev || !err_info)
189 return;
190
191 /*
192 * Internal errors of an RCEC indicate an AER error in an
193 * RCH's downstream port. Check and handle them in the CXL.mem
194 * device driver.
195 */
196 if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
197 return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
198
199 if (err_info->severity == AER_CORRECTABLE) {
200 struct device *dev __free(put_device) = get_device(err_info->dev);
201 struct cxl_driver *pdrv;
> 202 int aer = pdev->aer_cap;
203
204 if (!dev || !dev->driver)
205 return;
206
207 if (aer) {
208 int ras_status;
209
210 pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, &ras_status);
211 pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS,
212 ras_status);
213 }
214
215 pdrv = to_cxl_drv(dev->driver);
216 if (!pdrv || !pdrv->err_handler ||
217 !pdrv->err_handler->cor_error_detected)
218 return;
219
220 pdrv->err_handler->cor_error_detected(dev, err_info);
221 pcie_clear_device_status(pdev);
222 } else {
223 cxl_do_recovery(pdev);
224 }
225 }
226
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.