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

Reply via email to