[PATCH 023/109] drm/amd/ras: Support querying RAS driver capabilities

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

Support querying RAS driver capabilities:
1. Generate ras block bitmask for HW.
   -- Read ras hw capabilities from registers.
   -- Convert hw ras block bitmask to driver ras block bitmask.
2. Generate ras block bitmask for SW.
3. Add interfaces to query RAS capabilities.

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            | 10 +++++
 drivers/gpu/drm/amd/ras/core/aca.h            |  2 +
 drivers/gpu/drm/amd/ras/core/aca_v1_0.c       | 13 ++++++
 drivers/gpu/drm/amd/ras/core/core.c           | 23 ++++++++++
 drivers/gpu/drm/amd/ras/core/ras.h            |  5 ++-
 drivers/gpu/drm/amd/ras/core/ras_aca_v5_0.c   | 13 ++++++
 drivers/gpu/drm/amd/ras/core/ras_psp.c        | 26 ++++++++++++
 drivers/gpu/drm/amd/ras/core/ras_psp.h        | 25 +++++++++++
 drivers/gpu/drm/amd/ras/core/ras_psp_v13_0.c  | 42 +++++++++++++++++++
 drivers/gpu/drm/amd/ras/core/ras_psp_v15_0.c  | 41 ++++++++++++++++++
 .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c  | 10 ++---
 11 files changed, 204 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/ras/core/aca.c b/drivers/gpu/drm/amd/ras/core/aca.c
index 8bb93ca61b18a..6d7cfef543622 100644
--- a/drivers/gpu/drm/amd/ras/core/aca.c
+++ b/drivers/gpu/drm/amd/ras/core/aca.c
@@ -701,3 +701,13 @@ int ras_aca_parse_bank(struct ras_core_context *ras_core,
 
 	return ret;
 }
+
+u64 ras_aca_get_parser_caps(struct ras_core_context *ras_core)
+{
+	struct ras_aca *ras_aca = &ras_core->ras_aca;
+
+	if (ras_aca->ip_func && ras_aca->ip_func->aca_parse_ras_caps)
+		return ras_aca->ip_func->aca_parse_ras_caps(ras_core);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/amd/ras/core/aca.h b/drivers/gpu/drm/amd/ras/core/aca.h
index a9538e64d7d53..b19b6e7089f28 100644
--- a/drivers/gpu/drm/amd/ras/core/aca.h
+++ b/drivers/gpu/drm/amd/ras/core/aca.h
@@ -145,6 +145,7 @@ struct aca_block {
 struct ras_aca_ip_func {
 	uint32_t block_num;
 	const struct aca_block_info **block_info;
+	u64 (*aca_parse_ras_caps)(struct ras_core_context *ras_core);
 };
 
 struct ras_aca {
@@ -169,4 +170,5 @@ void ras_aca_clear_fatal_flag(struct ras_core_context *ras_core);
 int ras_aca_parse_bank(struct ras_core_context *ras_core,
 				struct aca_bank_reg *bank,
 				struct aca_bank_ecc *ecc);
+u64 ras_aca_get_parser_caps(struct ras_core_context *ras_core);
 #endif
diff --git a/drivers/gpu/drm/amd/ras/core/aca_v1_0.c b/drivers/gpu/drm/amd/ras/core/aca_v1_0.c
index a8b413270de37..c2fba818a4629 100644
--- a/drivers/gpu/drm/amd/ras/core/aca_v1_0.c
+++ b/drivers/gpu/drm/amd/ras/core/aca_v1_0.c
@@ -372,7 +372,20 @@ static const struct aca_block_info *aca_block_info_v1_0[] = {
 	&aca_v1_0_xgmi,
 };
 
+static u64 aca_parse_ras_caps_v1_0(struct ras_core_context *ras_core)
+{
+	u64 parser_supported_mask = 0;
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(aca_block_info_v1_0); i++)
+		parser_supported_mask |=
+			BIT_ULL(aca_block_info_v1_0[i]->ras_block_id);
+
+	return parser_supported_mask;
+}
+
 const struct ras_aca_ip_func ras_aca_func_v1_0 = {
 	.block_num = ARRAY_SIZE(aca_block_info_v1_0),
 	.block_info = aca_block_info_v1_0,
+	.aca_parse_ras_caps = aca_parse_ras_caps_v1_0,
 };
diff --git a/drivers/gpu/drm/amd/ras/core/core.c b/drivers/gpu/drm/amd/ras/core/core.c
index aad95bf3fa180..079032433a916 100644
--- a/drivers/gpu/drm/amd/ras/core/core.c
+++ b/drivers/gpu/drm/amd/ras/core/core.c
@@ -761,3 +761,26 @@ int ras_core_get_eeprom_version(struct ras_core_context *ras_core,
 {
 	return ras_eeprom_get_version(ras_core, version);
 }
+
+uint64_t ras_core_get_ras_caps(struct ras_core_context *ras_core)
+{
+	uint64_t ras_hw_caps,  ras_drv_caps;
+
+	if (!ras_core)
+		return 0;
+
+	ras_hw_caps = ras_psp_get_hw_ras_caps(ras_core);
+	ras_drv_caps = ras_aca_get_parser_caps(ras_core);
+
+	return ras_hw_caps & ras_drv_caps;
+}
+
+bool ras_core_poison_supported(struct ras_core_context *ras_core)
+{
+	if (!ras_core)
+		return false;
+
+	/* For some ASICs, poison flag is detected externally by uniras module. */
+	return ras_core->poison_supported ? true :
+			ras_psp_poison_supported(ras_core);
+}
diff --git a/drivers/gpu/drm/amd/ras/core/ras.h b/drivers/gpu/drm/amd/ras/core/ras.h
index dc590867d82a3..e28d51b1992ef 100644
--- a/drivers/gpu/drm/amd/ras/core/ras.h
+++ b/drivers/gpu/drm/amd/ras/core/ras.h
@@ -103,7 +103,8 @@ enum ras_block_id {
 	RAS_BLOCK_ID__SSBDCI,
 	RAS_BLOCK_ID__UCIE_PCS,
 
-	RAS_BLOCK_ID__LAST
+	RAS_BLOCK_ID__LAST,
+	MAX_SUPPORTED_RAS_BLOCK_ID  = MAX_RAS_BLOCK_MASK_BITS
 };
 
 enum ras_ecc_err_type {
@@ -448,4 +449,6 @@ int ras_core_get_eeprom_version(struct ras_core_context *ras_core,
 	uint32_t *version);
 int ras_core_get_ip_version(struct ras_core_context *ras_core,
 	enum ras_unit_id unit_id, uint32_t *version);
+uint64_t ras_core_get_ras_caps(struct ras_core_context *ras_core);
+bool ras_core_poison_supported(struct ras_core_context *ras_core);
 #endif
diff --git a/drivers/gpu/drm/amd/ras/core/ras_aca_v5_0.c b/drivers/gpu/drm/amd/ras/core/ras_aca_v5_0.c
index 15e72d4b492d0..3074f8c3f3164 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_aca_v5_0.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_aca_v5_0.c
@@ -348,7 +348,20 @@ static const struct aca_block_info *aca_block_info_v5_0[] = {
 	&aca_v5_0_xgmi,
 };
 
+static u64 aca_parse_ras_caps_v5_0(struct ras_core_context *ras_core)
+{
+	u64 parser_supported_mask = 0;
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(aca_block_info_v5_0); i++)
+		parser_supported_mask |=
+			BIT_ULL(aca_block_info_v5_0[i]->ras_block_id);
+
+	return parser_supported_mask;
+}
+
 const struct ras_aca_ip_func ras_aca_func_v5_0 = {
 	.block_num = ARRAY_SIZE(aca_block_info_v5_0),
 	.block_info = aca_block_info_v5_0,
+	.aca_parse_ras_caps = aca_parse_ras_caps_v5_0,
 };
diff --git a/drivers/gpu/drm/amd/ras/core/ras_psp.c b/drivers/gpu/drm/amd/ras/core/ras_psp.c
index 5628b384a7333..da49ee79711d9 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_psp.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_psp.c
@@ -720,6 +720,11 @@ int ras_psp_hw_init(struct ras_core_context *ras_core)
 		psp->ip_func->get_ras_block_maps(ras_core,
 			&psp->blk_maps, &psp->maps_size))
 		return -EINVAL;
+
+	if (psp->ip_func->get_ras_hw_caps &&
+		psp->ip_func->get_ras_hw_caps(ras_core, &psp->ras_hw_caps))
+		return -EINVAL;
+
 	/* After GPU reset, the system RAS PSP status may change.
 	 * therefore, it is necessary to synchronize the system status again.
 	 */
@@ -783,3 +788,24 @@ int ras_psp_get_block_ta_id(struct ras_core_context *ras_core,
 
 	return -RAS_CORE_NOT_SUPPORTED;
 }
+
+bool ras_psp_poison_supported(struct ras_core_context *ras_core)
+{
+	struct ras_psp *psp = &ras_core->ras_psp;
+
+	return psp->ras_hw_caps.poison_supported;
+}
+
+bool ras_psp_flex_mca_enabled(struct ras_core_context *ras_core)
+{
+	struct ras_psp *psp = &ras_core->ras_psp;
+
+	return psp->ras_hw_caps.flex_mca_enabled;
+}
+
+uint64_t ras_psp_get_hw_ras_caps(struct ras_core_context *ras_core)
+{
+	struct ras_psp *psp = &ras_core->ras_psp;
+
+	return psp->ras_hw_caps.features.block_mask;
+}
diff --git a/drivers/gpu/drm/amd/ras/core/ras_psp.h b/drivers/gpu/drm/amd/ras/core/ras_psp.h
index 5265408ddafea..dbc06c85d4aec 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_psp.h
+++ b/drivers/gpu/drm/amd/ras/core/ras_psp.h
@@ -26,6 +26,8 @@
 #include "ras.h"
 #include "ta_if.h"
 
+#define MAX_RAS_BLOCK_MASK_BITS 56
+
 struct ras_core_context;
 struct ras_ta_trigger_error_input;
 struct ras_ta_query_address_input;
@@ -68,11 +70,30 @@ struct ras_block_map {
 	uint32_t ras_id;
 	uint32_t ta_id;
 };
+
+union ras_feature {
+	struct {
+		uint64_t block_mask : MAX_RAS_BLOCK_MASK_BITS;
+		uint64_t rsv: 4;
+		uint64_t tag: 3;
+		uint64_t en : 1;
+	};
+	uint64_t value;
+};
+
+struct ras_hw_caps {
+	bool poison_supported;
+	bool flex_mca_enabled;
+	union ras_feature features;
+};
+
 struct ras_psp_ip_func {
 	uint32_t (*psp_ras_ring_wptr_get)(struct ras_core_context *ras_core);
 	int (*psp_ras_ring_wptr_set)(struct ras_core_context *ras_core, uint32_t wptr);
 	int (*get_ras_block_maps)(struct ras_core_context *ras_core,
 			struct ras_block_map **blk_maps, uint32_t *maps_size);
+	int (*get_ras_hw_caps)(struct ras_core_context *ras_core,
+			struct ras_hw_caps *ras_cap);
 };
 
 struct ras_psp_ring {
@@ -116,6 +137,7 @@ struct ras_psp {
 	uint32_t psp_ip_version;
 	struct ras_block_map *blk_maps;
 	uint32_t maps_size;
+	struct ras_hw_caps ras_hw_caps;
 	struct ras_psp_ring psp_ring;
 	struct ras_psp_ctx  psp_ctx;
 	struct ras_ta_ctx   ta_ctx;
@@ -153,4 +175,7 @@ bool ras_psp_check_supported_cmd(struct ras_core_context *ras_core,
 		enum ras_ta_cmd_id cmd_id);
 int ras_psp_get_block_ta_id(struct ras_core_context *ras_core,
 		uint32_t ras_id, uint32_t *ta_id);
+bool ras_psp_poison_supported(struct ras_core_context *ras_core);
+bool ras_psp_flex_mca_enabled(struct ras_core_context *ras_core);
+uint64_t ras_psp_get_hw_ras_caps(struct ras_core_context *ras_core);
 #endif
diff --git a/drivers/gpu/drm/amd/ras/core/ras_psp_v13_0.c b/drivers/gpu/drm/amd/ras/core/ras_psp_v13_0.c
index 92e617eca8791..49ba57f58878c 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_psp_v13_0.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_psp_v13_0.c
@@ -27,6 +27,9 @@
 
 #define regMP0_SMN_C2PMSG_67                           0x0083
 #define regMP0_SMN_C2PMSG_67_BASE_IDX                  0
+#define regMP0_SMN_C2PMSG_127                          0x00bf
+#define regMP0_SMN_C2PMSG_127_BASE_IDX                 0
+
 static struct ras_block_map   ras_block_maps_v13_0[] = {
 	{RAS_BLOCK_ID__UMC,       RAS_TA_BLOCK__UMC},
 	{RAS_BLOCK_ID__SDMA,      RAS_TA_BLOCK__SDMA},
@@ -73,8 +76,47 @@ static int ras_psp_v13_0_get_ras_block_maps(struct ras_core_context *ras_core,
 
 	return 0;
 }
+
+static int ras_psp_v13_0_get_ras_hw_caps(struct ras_core_context *ras_core,
+				struct ras_hw_caps *ras_cap)
+{
+	uint32_t ras_hw_cap, bit;
+	uint32_t i;
+
+	if (!ras_cap)
+		return -EINVAL;
+
+	ras_hw_cap = RAS_DEV_RREG32_SOC15(ras_core->dev, MP0, 0, regMP0_SMN_C2PMSG_127);
+
+	ras_cap->poison_supported = true;
+	ras_cap->flex_mca_enabled = false;
+
+	ras_cap->features.value = 0;
+	for (bit = 0; bit <= 29; bit++) {
+		if (!(ras_hw_cap & BIT_ULL(bit)))
+			continue;
+
+		for (i = 0; i < ARRAY_SIZE(ras_block_maps_v13_0); i++) {
+			if (ras_block_maps_v13_0[i].ta_id == bit) {
+				if (ras_block_maps_v13_0[i].ras_id < MAX_SUPPORTED_RAS_BLOCK_ID)
+					ras_cap->features.block_mask |=
+						BIT_ULL(ras_block_maps_v13_0[i].ras_id);
+				else
+					RAS_DEV_WARN(ras_core->dev,
+						"RAS block maps v13 error: invalid ras block id %u\n",
+						ras_block_maps_v13_0[i].ras_id);
+
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
 const struct ras_psp_ip_func ras_psp_v13_0 = {
 	.psp_ras_ring_wptr_get = ras_psp_v13_0_ring_wptr_get,
 	.psp_ras_ring_wptr_set = ras_psp_v13_0_ring_wptr_set,
 	.get_ras_block_maps = ras_psp_v13_0_get_ras_block_maps,
+	.get_ras_hw_caps = ras_psp_v13_0_get_ras_hw_caps,
 };
diff --git a/drivers/gpu/drm/amd/ras/core/ras_psp_v15_0.c b/drivers/gpu/drm/amd/ras/core/ras_psp_v15_0.c
index 74f00eec40782..e3cae8c94b28f 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_psp_v15_0.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_psp_v15_0.c
@@ -28,6 +28,8 @@
 
 #define regMPASP_SMN_C2PMSG_67                           0x0083
 #define regMPASP_SMN_C2PMSG_67_BASE_IDX                  1
+#define regMPASP_SMN_C2PMSG_127                          0x00bf
+#define regMPASP_SMN_C2PMSG_127_BASE_IDX                 1
 
 static struct ras_block_map   ras_block_maps_v15_0[] = {
 	{RAS_BLOCK_ID__UMC,         RAS_TA_MPASP_BLOCK__UMC},
@@ -85,8 +87,47 @@ static int ras_psp_v15_0_get_ras_block_maps(struct ras_core_context *ras_core,
 
 	return 0;
 }
+
+static int ras_psp_v15_0_get_ras_hw_caps(struct ras_core_context *ras_core,
+				struct ras_hw_caps *ras_cap)
+{
+	uint32_t ras_hw_cap, bit;
+	uint32_t i;
+
+	if (!ras_cap)
+		return -EINVAL;
+
+	ras_hw_cap = RAS_DEV_RREG32_SOC15(ras_core->dev,
+				MP0, 0, regMPASP_SMN_C2PMSG_127);
+
+	ras_cap->poison_supported = (ras_hw_cap & BIT_ULL(31)) ? true : false;
+	ras_cap->flex_mca_enabled = (ras_hw_cap & BIT_ULL(30)) ? true : false;
+
+	ras_cap->features.value = 0;
+	for (bit = 0; bit <= 29; bit++) {
+		if (!(ras_hw_cap & BIT_ULL(bit)))
+			continue;
+
+		for (i = 0; i < ARRAY_SIZE(ras_block_maps_v15_0); i++) {
+			if (ras_block_maps_v15_0[i].ta_id == bit) {
+				if (ras_block_maps_v15_0[i].ras_id < MAX_SUPPORTED_RAS_BLOCK_ID)
+					ras_cap->features.block_mask |=
+						BIT_ULL(ras_block_maps_v15_0[i].ras_id);
+				else
+					RAS_DEV_WARN(ras_core->dev,
+						"RAS block maps v15 error: invalid ras block id %u\n",
+						ras_block_maps_v15_0[i].ras_id);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
 const struct ras_psp_ip_func ras_psp_v15_0 = {
 	.psp_ras_ring_wptr_get = ras_psp_v15_0_ring_wptr_get,
 	.psp_ras_ring_wptr_set = ras_psp_v15_0_ring_wptr_set,
 	.get_ras_block_maps = ras_psp_v15_0_get_ras_block_maps,
+	.get_ras_hw_caps = ras_psp_v15_0_get_ras_hw_caps,
 };
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c
index 1b23ffffc415c..3b8d61785a897 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c
@@ -269,7 +269,7 @@ static int amdgpu_ras_mgr_get_ras_ta_init_param(struct ras_core_context *ras_cor
 	struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev;
 	uint32_t nps_mode;
 
-	if (amdgpu_ras_is_poison_mode_supported(adev))
+	if (ras_core_poison_supported(ras_core))
 		ras_ta_param->poison_mode_en = 1;
 
 	if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu)
@@ -624,7 +624,7 @@ int amdgpu_ras_mgr_handle_controller_interrupt(struct amdgpu_device *adev, void
 		return -EPERM;
 
 	if (ih_info && (ih_info->block == AMDGPU_RAS_BLOCK__UMC)) {
-		if (ras_mgr->ras_core->poison_supported) {
+		if (ras_core_poison_supported(ras_mgr->ras_core)) {
 			seq_no = amdgpu_ras_mgr_gen_ras_event_seqno(adev, RAS_SEQNO_TYPE_DE);
 			RAS_DEV_INFO(adev,
 				"{%llu} RAS poison is created, no user action is needed.\n",
@@ -632,7 +632,7 @@ int amdgpu_ras_mgr_handle_controller_interrupt(struct amdgpu_device *adev, void
 		}
 
 		ret = amdgpu_ras_process_handle_umc_interrupt(adev, ih_info);
-	} else if (ras_mgr->ras_core->poison_supported) {
+	} else if (ras_core_poison_supported(ras_mgr->ras_core)) {
 		ret = amdgpu_ras_process_handle_unexpected_interrupt(adev, ih_info);
 	} else {
 		RAS_DEV_WARN(adev,
@@ -655,7 +655,7 @@ int amdgpu_ras_mgr_dispatch_interrupt(struct amdgpu_device *adev, struct ras_ih_
 		return 0;
 
 	if (ih_info->block == RAS_BLOCK_ID__UMC) {
-		if (ras_mgr->ras_core->poison_supported) {
+		if (ras_core_poison_supported(ras_mgr->ras_core)) {
 			seq_no = amdgpu_ras_mgr_gen_ras_event_seqno(adev, RAS_SEQNO_TYPE_DE);
 			RAS_DEV_INFO(adev,
 				"{%llu} RAS poison is created, no user action is needed.\n",
@@ -663,7 +663,7 @@ int amdgpu_ras_mgr_dispatch_interrupt(struct amdgpu_device *adev, struct ras_ih_
 		}
 
 		ret = amdgpu_ras_process_handle_umc_interrupt(adev, ih_info);
-	} else if (ras_mgr->ras_core->poison_supported) {
+	} else if (ras_core_poison_supported(ras_mgr->ras_core)) {
 		ret = amdgpu_ras_process_handle_consumption_interrupt(adev, ih_info);
 	} else {
 		RAS_DEV_WARN(adev,
-- 
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.