[PATCH 019/109] drm/amd/ras: Handling ras mce notification event

Alex Deucher <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: YiPeng Chai <[email protected]>

Handling ras mce notification event.

Signed-off-by: YiPeng Chai <[email protected]>
Reviewed-by: Hawking Zhang <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/ras/core/aca.c            |   9 +-
 .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c  | 103 ++++++++++++++++++
 2 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/ras/core/aca.c b/drivers/gpu/drm/amd/ras/core/aca.c
index be4af1522685b..e6110e02c38e9 100644
--- a/drivers/gpu/drm/amd/ras/core/aca.c
+++ b/drivers/gpu/drm/amd/ras/core/aca.c
@@ -390,7 +390,10 @@ static int aca_banks_update(struct ras_core_context *ras_core,
 	if (!count)
 		goto out;
 
-	batch_tag = ras_log_ring_create_batch_tag(ras_core);
+	/* Only one MCE error is logged for each batch */
+	if (ecc_type != RAS_ERR_TYPE__MCE)
+		batch_tag = ras_log_ring_create_batch_tag(ras_core);
+
 	for (i = 0; i < count; i++) {
 		memset(&bank, 0, sizeof(bank));
 		ret = aca_dump_bank(ras_core, ecc_type, i, &bank);
@@ -415,7 +418,9 @@ static int aca_banks_update(struct ras_core_context *ras_core,
 		if (ret)
 			break;
 	}
-	ras_log_ring_destroy_batch_tag(ras_core, batch_tag);
+
+	if (batch_tag)
+		ras_log_ring_destroy_batch_tag(ras_core, batch_tag);
 
 	if (!ret)
 		ras_core_event_notify(ras_core,
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c
index 991cf39195eea..795085beb1986 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mce.c
@@ -124,9 +124,112 @@ static int amdgpu_ras_unregister_mce_notifier(struct amdgpu_device *adev)
 	return 0;
 }
 
+static void __fill_mce_to_aca_bank(struct amdgpu_device *adev,
+	enum mce_bank_type bank_type, struct mce *m, struct aca_bank_reg *aca_bank)
+{
+	aca_bank->timestamp = m->time;
+	aca_bank->bank_type = bank_type;
+	aca_bank->ecc_type = RAS_ERR_TYPE__MCE;
+	aca_bank->regs[ACA_REG_IDX__STATUS] = m->status;
+	aca_bank->regs[ACA_REG_IDX__ADDR] = m->addr;
+	aca_bank->regs[ACA_REG_IDX__MISC0] = m->misc;
+	aca_bank->regs[ACA_REG_IDX__IPID] = m->ipid;
+	aca_bank->regs[ACA_REG_IDX__SYND] = m->synd;
+}
+
+static int amdgpu_ras_mce_notifier_v1(struct amdgpu_device *adev, unsigned int id, struct mce *m)
+{
+	struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
+	struct aca_bank_reg aca_bank = {0};
+	struct aca_bank_ecc err = {0};
+
+	/*
+	 * If the error was generated in UMC_V2, which belongs to GPU UMCs,
+	 * and error occurred in DramECC (Extended error code = 0) then only
+	 * process the error, else bail out.
+	 */
+	#ifdef HAVE_SMCA_UMC_V2
+	if (!((smca_get_bank_type(m->extcpu, m->bank) == SMCA_UMC_V2) &&
+			(XEC(m->status, 0x3f) == 0x0)))
+		return 0;
+	#endif
+
+	if (!adev->smuio.funcs || !adev->smuio.funcs->get_socket_id)
+		return 0;
+
+	__fill_mce_to_aca_bank(adev, MCE_BANK_TYPE_GPU, m, &aca_bank);
+
+	if (ras_aca_parse_bank(ras_mgr->ras_core, &aca_bank, &err))
+		return -EINVAL;
+
+	/* GPU device only record bank data that matches its own socket id.*/
+	if (adev->smuio.funcs->get_socket_id(adev) != err.bank_info.socket_id)
+		return 0;
+
+	return ras_mce_add_aca_bank(ras_mgr->ras_core, &aca_bank);
+}
+
+static int amdgpu_ras_mce_notifier_v5(struct amdgpu_device *adev, unsigned int id, struct mce *m)
+{
+	struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
+	struct aca_bank_reg aca_bank = {0};
+	struct aca_bank_ecc err = {0};
+	enum mce_bank_type bank_type;
+
+	if (!adev->smuio.funcs || !adev->smuio.funcs->get_socket_id) {
+		RAS_DEV_WARN(adev, "No interface to obtain current device socket ID!\n");
+		return 0;
+	}
+
+	if (ras_mce_check_bank(ras_mgr->ras_core, MCE_BANK_TYPE_GPU, m->bank)) {
+		bank_type = MCE_BANK_TYPE_GPU;
+	/* For CPU bank, only the first registered gpu device needs to record bank */
+	} else if (ras_mce_check_bank(ras_mgr->ras_core, MCE_BANK_TYPE_CPU, m->bank) &&
+			!id) {
+		bank_type = MCE_BANK_TYPE_CPU;
+	} else {
+		RAS_DEV_WARN(adev, "Unsupported mce bank: %u\n",  m->bank);
+		return 0;
+	}
+
+	__fill_mce_to_aca_bank(adev, bank_type, m, &aca_bank);
+
+	if (bank_type == MCE_BANK_TYPE_GPU) {
+
+		if (ras_aca_parse_bank(ras_mgr->ras_core, &aca_bank, &err))
+			return -EINVAL;
+
+		/* GPU device only record bank data that matches its own socket id.*/
+		if (adev->smuio.funcs->get_socket_id(adev) != err.bank_info.socket_id)
+			return 0;
+	}
+
+	return ras_mce_add_aca_bank(ras_mgr->ras_core, &aca_bank);
+}
+
 static int amdgpu_ras_mce_notifier(struct amdgpu_device *adev,
 			unsigned int id, unsigned long val, void *data)
 {
+	struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
+	u32 aca_ip_version = 0;
+
+	if (!data || !ras_mgr)
+		return 0;
+
+	if (ras_core_get_ip_version(ras_mgr->ras_core,
+				RAS_UNIT_ID_ACA, &aca_ip_version))
+		return 0;
+
+	switch (aca_ip_version) {
+	case IP_VERSION(1, 0, 0):
+		return amdgpu_ras_mce_notifier_v1(adev, id, data);
+	case IP_VERSION(5, 0, 0):
+		return amdgpu_ras_mce_notifier_v5(adev, id, data);
+	default:
+		RAS_DEV_WARN(adev, "Invalid aca ip version:0x%x\n", aca_ip_version);
+		break;
+	}
+
 	return 0;
 }
 
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.