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)
{
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);
}
}