UMC error injection on MI300 series is dispatched by the RAS TA using
the injection method; only the "coherent" methods are address based,
the single-shot/persistent/ac-parity ones ignore the address.

The debugfs control path validated the injection address against the
bad page list for every UMC injection. On uniras (SMU v13+) devices the
address is now validated by the ras_mgr inject handler, so the legacy
debugfs bad page check only runs on the legacy RAS path; other ASICs
keep injecting by address.

In the ras_mgr handler an injection is treated as non address-based only
when userspace passes the U64_MAX sentinel address and the method is a
non-address method. In that case the address is cleared to 0 and the bad
page / range validation is skipped; otherwise the injection address is
validated as before.

Changed from V1:
        move address based checking to uniras layer

Changed from V2:
        Check umc injection address setting flag,
        simplify non address based injection judgment


Signed-off-by: Stanley.Yang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c       | 10 ++-
 .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c  | 83 +++++++++++++++----
 2 files changed, 73 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index af48dd2ebd16..f280a312b0a7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -606,8 +606,14 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file 
*f,
                ret = amdgpu_ras_feature_enable(adev, &data.head, 1);
                break;
        case 2:
-               /* umc ce/ue error injection for a bad page is not allowed */
-               if (data.head.block == AMDGPU_RAS_BLOCK__UMC)
+               /*
+                * UMC ce/ue error injection for a bad page is not allowed. For
+                * uniras (SMU v13+) devices the injection address is validated 
by
+                * the ras_mgr inject handler, so only run the legacy bad page
+                * check for the legacy RAS path.
+                */
+               if (data.head.block == AMDGPU_RAS_BLOCK__UMC &&
+                   !amdgpu_uniras_enabled(adev))
                        ret = amdgpu_ras_check_bad_page(adev, 
data.inject.address);
                if (ret == -EINVAL) {
                        dev_warn(adev->dev, "RAS WARN: input address 0x%llx is 
invalid.",
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c 
b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c
index bfbfdffbfbe6..c2285fde8b3c 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c
@@ -82,6 +82,43 @@ static uint64_t local_addr_to_xgmi_global_addr(struct 
ras_core_context *ras_core
        return (addr + xgmi->physical_node_id * xgmi->node_segment_size);
 }
 
+/*
+ * UMC error injection is dispatched by the RAS TA using the injection method
+ * carried in struct ras_cmd_inject_error_req. Only the "coherent" methods
+ * program an explicit injection address and are therefore address-based; the
+ * single-shot, persistent and ac-parity methods ignore the address.
+ *
+ * Keep these values in sync with the RAS TA.
+ */
+enum umc_inject_method {
+       UMC_METHOD_COHERENT             = 0,
+       UMC_METHOD_SINGLE_SHOT          = 1,
+       UMC_METHOD_PERSISTENT           = 2,
+       UMC_METHOD_PERSISTENT_DISABLE   = 3,
+       UMC_METHOD_COHERENT_NO_DETECTION        = 4,
+       UMC_METHOD_COHERENT_WR          = 5,
+       UMC_METHOD_SINGLE_SHOT_WR               = 6,
+       UMC_METHOD_PERSISTENT_WR                = 7,
+       UMC_METHOD_SINGLE_SHOT_CLEAN    = 8,
+};
+
+/*
+ * Return true when @method does not program an explicit injection address.
+ * Only the coherent methods are address-based; every other method ignores the
+ * address, so userspace signals them by setting the address to U64_MAX.
+ */
+static bool amdgpu_ras_mgr_is_non_address_injection(u64 method)
+{
+       switch (method) {
+       case UMC_METHOD_COHERENT:
+       case UMC_METHOD_COHERENT_NO_DETECTION:
+       case UMC_METHOD_COHERENT_WR:
+               return false;
+       default:
+               return true;
+       }
+}
+
 static int amdgpu_ras_inject_error(struct ras_core_context *ras_core,
                        struct ras_cmd_ctx *cmd, void *data)
 {
@@ -91,25 +128,35 @@ static int amdgpu_ras_inject_error(struct ras_core_context 
*ras_core,
        int ret = RAS_CMD__ERROR_GENERIC;
 
        if (req->block_id == RAS_BLOCK_ID__UMC) {
-               if (amdgpu_ras_mgr_check_retired_addr(adev, req->address)) {
-                       RAS_DEV_WARN(ras_core->dev,
-                               "RAS WARN: inject: 0x%llx has already been 
marked as bad!\n",
-                               req->address);
-                       return RAS_CMD__ERROR_ACCESS_DENIED;
-               }
-
-               if ((req->address >= adev->gmc.mc_vram_size &&
-                       adev->gmc.mc_vram_size) ||
-                       (req->address >= RAS_UMC_INJECT_ADDR_LIMIT)) {
-                       RAS_DEV_WARN(adev, "RAS WARN: input address 0x%llx is 
invalid.",
+               /*
+                * Only address-based UMC injections carry an explicit injection
+                * address that has to be validated. A non address-based method
+                * ignores the address, and userspace flags such an injection by
+                * setting the address to U64_MAX. When both the sentinel and 
the
+                * method agree, clear the address so the RAS TA ignores it and
+                * skip the validation; otherwise validate the injection 
address.
+                */
+               if (req->address == U64_MAX && 
amdgpu_ras_mgr_is_non_address_injection(req->method)) {
+                       req->address = 0x0;
+               } else {
+                       if (amdgpu_ras_mgr_check_retired_addr(adev, 
req->address)) {
+                               RAS_DEV_WARN(ras_core->dev,
+                                       "RAS WARN: inject: 0x%llx has already 
been marked as bad!\n",
                                        req->address);
-                       return RAS_CMD__ERROR_INVALID_INPUT_DATA;
-               }
-
-               /* Calculate XGMI relative offset */
-               if (adev->gmc.xgmi.num_physical_nodes > 1 &&
-                       req->block_id != RAS_BLOCK_ID__GFX) {
-                       req->address = local_addr_to_xgmi_global_addr(ras_core, 
req->address);
+                               return RAS_CMD__ERROR_ACCESS_DENIED;
+                       }
+
+                       if ((req->address >= adev->gmc.mc_vram_size &&
+                               adev->gmc.mc_vram_size) ||
+                               (req->address >= RAS_UMC_INJECT_ADDR_LIMIT)) {
+                               RAS_DEV_WARN(adev, "RAS WARN: input address 
0x%llx is invalid.",
+                                               req->address);
+                               return RAS_CMD__ERROR_INVALID_INPUT_DATA;
+                       }
+
+                       /* Calculate XGMI relative offset */
+                       if (adev->gmc.xgmi.num_physical_nodes > 1)
+                               req->address = 
local_addr_to_xgmi_global_addr(ras_core, req->address);
                }
        }
 
-- 
2.43.0

Reply via email to