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