drm/amdgpu/ras: only check bad page for address-based UMC injection

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.

Signed-off-by: Stanley.Yang <Stanley.Yang@amd.com>
Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Stanley.Yang 2026-06-26 20:20:15 +08:00 committed by Alex Deucher
parent a8880289fd
commit bf65973e5f
2 changed files with 72 additions and 19 deletions

View File

@ -596,8 +596,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.",

View File

@ -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;
}
return RAS_CMD__ERROR_ACCESS_DENIED;
}
/* 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);
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);
}
}