CPU RAS CPER records are now written exclusively to the GPU device
with the lowest unique_id across all present amdgpu instances.

This provides a stable, hardware-anchored anchor point that remains
consistent across driver reloads and system reboots, allowing users
to locate CPU RAS error records by looking up the corresponding RAS
CPER file on the GPU with the lowest unique_id.

Signed-off-by: YiPeng Chai <[email protected]>
---
 drivers/gpu/drm/amd/ras/core/ras.h            |  1 +
 .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c  | 54 +++++++++++++++----
 .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c  |  1 +
 3 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/ras/core/ras.h 
b/drivers/gpu/drm/amd/ras/core/ras.h
index 73e3960c7c8e..5f133f3a8277 100644
--- a/drivers/gpu/drm/amd/ras/core/ras.h
+++ b/drivers/gpu/drm/amd/ras/core/ras.h
@@ -249,6 +249,7 @@ struct device_system_info {
        uint32_t device_id;
        uint32_t vendor_id;
        uint32_t socket_id;
+       uint64_t unique_id;
 };
 
 enum gpu_mem_type {
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c 
b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c
index 6bb8bc1b52a9..dc0ce9ca9a85 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c
@@ -31,7 +31,7 @@
 
 static int amdgpu_sys_mce_notifier(struct notifier_block *nb, unsigned long 
val, void *data);
 typedef int (*mce_notifier)(struct amdgpu_device *dev,
-                       unsigned int id, unsigned long val, void *data);
+                       bool is_primary_dev, unsigned long val, void *data);
 struct ras_mce_dev {
        void *dev;
        mce_notifier dev_notifier;
@@ -43,6 +43,7 @@ struct ras_mce_mgr {
        atomic_t ref_count;
        struct notifier_block nb;
        mce_notifier notifier;
+       void *primary_dev;
 };
 
 struct ras_mce_mgr  g_ras_mce_mgr = {
@@ -52,6 +53,24 @@ struct ras_mce_mgr  g_ras_mce_mgr = {
        },
 };
 
+static void *ras_mce_select_primary(struct ras_mce_mgr *mce_mgr)
+{
+       struct amdgpu_device *primary = NULL;
+       struct amdgpu_device *adev;
+       int i;
+
+       for (i = 0; i < atomic_read(&mce_mgr->dev_count); i++) {
+               adev = mce_mgr->devs[i].dev;
+               if (!adev || !adev->pdev)
+                       continue;
+
+               if (!primary || (adev->unique_id < primary->unique_id))
+                       primary = adev;
+       }
+
+       return primary;
+}
+
 static int amdgpu_sys_mce_notifier(struct notifier_block *nb, unsigned long 
val, void *data)
 {
        struct ras_mce_mgr *mce_mgr = container_of(nb, struct ras_mce_mgr, nb);
@@ -61,10 +80,17 @@ static int amdgpu_sys_mce_notifier(struct notifier_block 
*nb, unsigned long val,
        if (!data)
                return NOTIFY_DONE;
 
+       if (!atomic_read(&mce_mgr->dev_count))
+               return NOTIFY_DONE;
+
+       if (!mce_mgr->primary_dev)
+               mce_mgr->primary_dev = ras_mce_select_primary(mce_mgr);
+
        for (i = 0; i < atomic_read(&mce_mgr->dev_count); i++) {
                mce_dev = &mce_mgr->devs[i];
                if (mce_dev->dev && mce_dev->dev_notifier)
-                       mce_dev->dev_notifier(mce_dev->dev, i, val, data);
+                       mce_dev->dev_notifier(mce_dev->dev,
+                               (mce_dev->dev == mce_mgr->primary_dev), val, 
data);
        }
 
        return NOTIFY_DONE;
@@ -110,7 +136,11 @@ static int amdgpu_ras_unregister_mce_notifier(struct 
amdgpu_device *adev)
 
        for (i = 0; i < atomic_read(&mce_mgr->dev_count); i++) {
                mce_dev = &mce_mgr->devs[i];
+
                if (mce_dev->dev == adev) {
+                       if (mce_dev->dev == mce_mgr->primary_dev)
+                               mce_mgr->primary_dev = NULL;
+
                        mce_dev->dev = NULL;
                        mce_dev->dev_notifier = NULL;
                        atomic_dec(&mce_mgr->ref_count);
@@ -141,7 +171,8 @@ static void __fill_mce_to_aca_bank(struct amdgpu_device 
*adev,
        aca_bank->regs[ACA_REG_IDX__SYND] = m->synd;
 }
 
-static int amdgpu_ras_mce_notifier_v1(struct amdgpu_device *adev, unsigned int 
id, struct mce *m)
+static int amdgpu_ras_mce_notifier_v1(struct amdgpu_device *adev,
+               bool is_primary_dev, struct mce *m)
 {
        struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
        struct aca_bank_reg aca_bank = {0};
@@ -178,7 +209,8 @@ static int amdgpu_ras_mce_notifier_v1(struct amdgpu_device 
*adev, unsigned int i
        return ras_mce_add_aca_bank(ras_mgr->ras_core, &aca_bank);
 }
 
-static int amdgpu_ras_mce_notifier_v5(struct amdgpu_device *adev, unsigned int 
id, struct mce *m)
+static int amdgpu_ras_mce_notifier_v5(struct amdgpu_device *adev,
+               bool is_primary_dev, struct mce *m)
 {
        struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
        struct aca_bank_reg aca_bank = {0};
@@ -193,16 +225,16 @@ static int amdgpu_ras_mce_notifier_v5(struct 
amdgpu_device *adev, unsigned int i
        if (ras_mce_check_bank(ras_mgr->ras_core, MCE_BANK_TYPE_GPU, m->bank)) {
                bank_type = MCE_BANK_TYPE_GPU;
        } else if (ras_mce_check_bank(ras_mgr->ras_core, MCE_BANK_TYPE_CPU, 
m->bank)) {
-               /* For CPU bank, only the first registered gpu device needs to 
record bank */
-               if (id)
-                       return 0;
-
                bank_type = MCE_BANK_TYPE_CPU;
        } else {
                RAS_DEV_WARN(adev, "Unsupported mce bank: %u\n",  m->bank);
                return 0;
        }
 
+       /* Only primary gpu device can log cpu ras error */
+       if (bank_type == MCE_BANK_TYPE_CPU && !is_primary_dev)
+               return 0;
+
        __fill_mce_to_aca_bank(adev, bank_type, m, &aca_bank);
 
        if (bank_type == MCE_BANK_TYPE_GPU) {
@@ -223,7 +255,7 @@ static int amdgpu_ras_mce_notifier_v5(struct amdgpu_device 
*adev, unsigned int i
 }
 
 static int amdgpu_ras_mce_notifier(struct amdgpu_device *adev,
-                       unsigned int id, unsigned long val, void *data)
+                       bool is_primary_dev, unsigned long val, void *data)
 {
        struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
        u32 aca_ip_version = 0;
@@ -237,9 +269,9 @@ static int amdgpu_ras_mce_notifier(struct amdgpu_device 
*adev,
 
        switch (aca_ip_version) {
        case IP_VERSION(1, 0, 0):
-               return amdgpu_ras_mce_notifier_v1(adev, id, data);
+               return amdgpu_ras_mce_notifier_v1(adev, is_primary_dev, data);
        case IP_VERSION(5, 0, 0):
-               return amdgpu_ras_mce_notifier_v5(adev, id, data);
+               return amdgpu_ras_mce_notifier_v5(adev, is_primary_dev, data);
        default:
                RAS_DEV_WARN(adev, "Invalid aca ip version:0x%x\n", 
aca_ip_version);
                break;
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c 
b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c
index 291b2a96cbb5..dd8cdc2811f8 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c
@@ -226,6 +226,7 @@ static int amdgpu_ras_sys_get_device_system_info(struct 
ras_core_context *ras_co
        dev_info->device_id = adev->pdev->device;
        dev_info->vendor_id = adev->pdev->vendor;
        dev_info->socket_id = adev->smuio.funcs->get_socket_id(adev);
+       dev_info->unique_id = adev->unique_id;
 
        return 0;
 }
-- 
2.43.0

Reply via email to