UMC error injection on MI300 series is dispatched by the RAS TA via
the (sub-block, method) pair; 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. Restrict that check to
address-based injections and warn when a non address-based one is
given a non-zero address. Other ASICs keep injecting by address.

Signed-off-by: Stanley.Yang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c       | 94 ++++++++++++++++++-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h       |  3 +
 .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c  |  3 +-
 3 files changed, 97 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index af48dd2ebd16..c563e2d96809 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -485,6 +485,91 @@ static void amdgpu_ras_instance_mask_check(struct 
amdgpu_device *adev,
                        inst_mask, data->inject.instance_mask);
 }
 
+/*
+ * UMC error injection on MI300-class ASICs is dispatched by the RAS TA using
+ * the (sub-block, method) pair passed in struct ta_ras_trigger_error_input as
+ * sub_block_index (enum error_sub_block_umc) and value (enum 
inject_method_umc).
+ * Only the "coherent" methods program an explicit injection address.
+ *
+ * Keep the values below in sync with the RAS TA.
+ */
+enum umc_error_sub_block {
+       UMC_ERROR_CRC                   = 0,
+       UMC_ERROR_SRAM                  = 1,
+       UMC_ERROR_ODECC                 = 2,
+       UMC_ERROR_PARITY_DATA           = 3,
+       UMC_ERROR_PARITY_CMD            = 4,
+};
+
+enum umc_inject_method {
+       UMC_METH_COHERENT               = 0,
+       UMC_METH_SINGLE_SHOT            = 1,
+       UMC_METH_PERSISTENT             = 2,
+       UMC_METH_PERSISTENT_DISABLE     = 3,
+       UMC_METH_COHERENT_NO_DETECTION  = 4,
+       UMC_METH_COHERENT_WR            = 5,
+       UMC_METH_SINGLE_SHOT_WR         = 6,
+       UMC_METH_PERSISTENT_WR          = 7,
+       UMC_METH_SINGLE_SHOT_CLEAN      = 8,
+};
+
+/*
+ * Return true if a UMC error injection using @sub_block (enum 
error_sub_block_umc)
+ * and @method (enum inject_method_umc) is address-based, i.e. it programs an
+ * explicit injection address. On MI300 series the non address-based methods
+ * ignore the address; other ASICs always inject by the given address, so 
return
+ * true there to keep validating it.
+ */
+bool amdgpu_ras_umc_is_address_based(struct amdgpu_device *adev,
+                                    u32 sub_block, u64 method)
+{
+       /*
+        * The (sub-block, method) classification below follows the MI300 RAS
+        * TA injection ABI and does not apply to other ASICs.
+        */
+       switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) {
+       case IP_VERSION(13, 0, 6):
+       case IP_VERSION(13, 0, 12):
+       case IP_VERSION(13, 0, 14):
+               break;
+       default:
+               return true;
+       }
+
+       switch (sub_block) {
+       case UMC_ERROR_CRC:
+               return method == UMC_METH_COHERENT ||
+                      method == UMC_METH_COHERENT_NO_DETECTION ||
+                      method == UMC_METH_COHERENT_WR;
+       case UMC_ERROR_ODECC:
+               return method == UMC_METH_COHERENT;
+       case UMC_ERROR_PARITY_DATA:
+               return method == UMC_METH_COHERENT ||
+                      method == UMC_METH_COHERENT_WR;
+       default:
+               return false;
+       }
+}
+
+/*
+ * Wrapper for the legacy debugfs inject path: classify @data and warn when a
+ * non address-based injection was given a non-zero address (which is ignored).
+ */
+static bool amdgpu_ras_umc_inject_is_address_based(struct amdgpu_device *adev,
+                                                  struct ras_debug_if *data)
+{
+       bool address_based = amdgpu_ras_umc_is_address_based(adev,
+                                       data->head.sub_block_index,
+                                       data->inject.value);
+
+       if (!address_based && data->inject.address)
+               dev_warn(adev->dev,
+                        "RAS WARN: non address based injection, ignore the 
injection address 0x%llx\n",
+                        data->inject.address);
+
+       return address_based;
+}
+
 /**
  * DOC: AMDGPU RAS debugfs control interface
  *
@@ -606,8 +691,13 @@ 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, but
+                * only address-based injections actually use the address, so
+                * limit the bad page check to those.
+                */
+               if (data.head.block == AMDGPU_RAS_BLOCK__UMC &&
+                   amdgpu_ras_umc_inject_is_address_based(adev, &data))
                        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/amdgpu/amdgpu_ras.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
index ad24c7cf8936..69a1600ad1a8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
@@ -917,6 +917,9 @@ int amdgpu_ras_reset_error_status(struct amdgpu_device 
*adev,
 int amdgpu_ras_error_inject(struct amdgpu_device *adev,
                struct ras_inject_if *info);
 
+bool amdgpu_ras_umc_is_address_based(struct amdgpu_device *adev,
+               u32 sub_block, u64 method);
+
 int amdgpu_ras_interrupt_add_handler(struct amdgpu_device *adev,
                struct ras_common_if *head);
 
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..31486ceecc72 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
@@ -90,7 +90,8 @@ static int amdgpu_ras_inject_error(struct ras_core_context 
*ras_core,
                (struct ras_cmd_inject_error_req *)cmd->input_buff_raw;
        int ret = RAS_CMD__ERROR_GENERIC;
 
-       if (req->block_id == RAS_BLOCK_ID__UMC) {
+       if (req->block_id == RAS_BLOCK_ID__UMC &&
+               amdgpu_ras_umc_is_address_based(adev, req->subblock_id, 
req->method)) {
                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",
-- 
2.43.0

Reply via email to