From: YiPeng Chai <[email protected]>

Add address translation interface for umc_v15_0.

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/Makefile        |   1 +
 drivers/gpu/drm/amd/ras/core/ras_umc.c       |   4 +-
 drivers/gpu/drm/amd/ras/core/ras_umc.h       |   2 +
 drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c | 220 +++++++++++++++++++
 drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.h |  69 ++++++
 5 files changed, 295 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c
 create mode 100644 drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.h

diff --git a/drivers/gpu/drm/amd/ras/core/Makefile 
b/drivers/gpu/drm/amd/ras/core/Makefile
index 980ae48b1ab8e..def5fbb2a49e6 100644
--- a/drivers/gpu/drm/amd/ras/core/Makefile
+++ b/drivers/gpu/drm/amd/ras/core/Makefile
@@ -30,6 +30,7 @@ RAS_CORE_FILES = core.o \
                        eeprom.o \
                        ras_umc.o \
                        ras_umc_v12_0.o \
+                       ras_umc_v15_0.o \
                        cmd.o \
                        ras_gfx.o \
                        ras_gfx_v9_0.o \
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc.c 
b/drivers/gpu/drm/amd/ras/core/ras_umc.c
index 32203e85ef14b..d78b111b87852 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc.c
@@ -24,6 +24,7 @@
 #include "ras.h"
 #include "ras_umc.h"
 #include "ras_umc_v12_0.h"
+#include "ras_umc_v15_0.h"
 
 #define MAX_ECC_NUM_PER_RETIREMENT  16
 
@@ -72,8 +73,9 @@ static const struct ras_umc_ip_func *ras_umc_get_ip_func(
        switch (ip_version) {
        case IP_VERSION(12, 0, 0):
        case IP_VERSION(12, 5, 0):
-       case IP_VERSION(15, 0, 0):
                return &ras_umc_func_v12_0;
+       case IP_VERSION(15, 0, 0):
+               return &ras_umc_func_v15_0;
        default:
                RAS_DEV_ERR(ras_core->dev,
                        "UMC ip version(0x%x) is not supported!\n", ip_version);
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc.h 
b/drivers/gpu/drm/amd/ras/core/ras_umc.h
index 5b7b497503927..725f74740ead9 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc.h
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc.h
@@ -128,6 +128,8 @@ struct ras_umc_ip_func {
        int (*eeprom_record_to_nps_pages)(struct ras_core_context *ras_core,
                        struct eeprom_umc_record *record, uint32_t nps,
                        uint64_t *pfns, uint32_t num);
+       int (*eeprom_record_to_nps_record)(struct ras_core_context *ras_core,
+                       struct eeprom_umc_record *record, uint32_t nps);
        int (*bank_to_soc_pa)(struct ras_core_context *ras_core,
                        struct umc_bank_addr bank_addr, uint64_t *soc_pa);
        int (*soc_pa_to_bank)(struct ras_core_context *ras_core,
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c 
b/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c
new file mode 100644
index 0000000000000..0f3182b14dae9
--- /dev/null
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "ras.h"
+#include "ras_umc.h"
+#include "core_status.h"
+#include "ras_umc_v15_0.h"
+
+static void __get_nps_pa_flip_bits(struct ras_core_context *ras_core,
+                       enum umc_memory_partition_mode nps,
+                       struct umc_flip_bits *flip_bits)
+{
+
+}
+
+static uint64_t  convert_nps_pa_to_row_pa(struct ras_core_context *ras_core,
+               uint64_t pa, enum umc_memory_partition_mode nps, bool 
zero_pfn_ok)
+{
+       struct umc_flip_bits flip_bits = {0};
+       uint64_t row_pa;
+       int i;
+
+       __get_nps_pa_flip_bits(ras_core, nps, &flip_bits);
+
+       row_pa = pa;
+       /* clear loop bits in soc physical address */
+       for (i = 0; i < flip_bits.bit_num; i++)
+               row_pa &= ~BIT_ULL(flip_bits.flip_bits_in_pa[i]);
+
+       if (!zero_pfn_ok && !RAS_ADDR_TO_PFN(row_pa))
+               row_pa |= BIT_ULL(flip_bits.flip_bits_in_pa[2]);
+
+       return row_pa;
+}
+
+static int lookup_bad_pages_in_a_row(struct ras_core_context *ras_core,
+               struct eeprom_umc_record *record, uint32_t nps,
+               uint64_t *pfns, uint32_t num,
+               uint64_t seq_no, bool dump)
+{
+       return 0;
+}
+
+static int umc_v15_convert_ma_to_pa(struct ras_core_context *ras_core,
+                       struct umc_mca_addr *addr_in, struct umc_phy_addr 
*addr_out,
+                       uint32_t nps)
+{
+
+       return 0;
+}
+
+static int convert_ma_to_pa(struct ras_core_context *ras_core,
+                       struct umc_mca_addr *addr_in, struct umc_phy_addr 
*addr_out,
+                       uint32_t nps)
+{
+       int ret;
+
+       if (ras_psp_check_supported_cmd(ras_core, RAS_TA_CMD_ID__QUERY_ADDRESS))
+               ret = ras_umc_psp_ma2pa(ras_core,
+                               addr_in, addr_out, nps);
+       else
+               ret = umc_v15_convert_ma_to_pa(ras_core,
+                               addr_in, addr_out, nps);
+
+       return ret;
+}
+
+static int convert_bank_to_nps_addr(struct ras_core_context *ras_core,
+                       struct ras_bank_ecc *bank, struct umc_phy_addr 
*pa_addr, uint32_t nps)
+{
+       struct umc_mca_addr addr_in;
+       struct umc_phy_addr addr_out;
+       int ret;
+
+       memset(&addr_in, 0, sizeof(addr_in));
+       memset(&addr_out, 0, sizeof(addr_out));
+
+       addr_in.err_addr = ACA_ADDR_2_ERR_ADDR(bank->addr);
+       addr_in.ch_inst = ACA_IPID_2_UMC_CH(bank->ipid);
+       addr_in.umc_inst = ACA_IPID_2_UMC_INST(bank->ipid);
+       addr_in.node_inst = ACA_IPID_2_DIE_ID(bank->ipid);
+       addr_in.socket_id = ACA_IPID_2_SOCKET_ID(bank->ipid);
+
+       ret = convert_ma_to_pa(ras_core, &addr_in, &addr_out, nps);
+       if (!ret) {
+               pa_addr->pa =
+                       convert_nps_pa_to_row_pa(ras_core, addr_out.pa, nps, 
false);
+               pa_addr->channel_idx = addr_out.channel_idx;
+               pa_addr->bank = addr_out.bank;
+       }
+
+       return ret;
+}
+
+static int umc_v15_0_bank_to_eeprom_record(struct ras_core_context *ras_core,
+               struct ras_bank_ecc *bank, struct eeprom_umc_record *record)
+{
+       struct umc_phy_addr nps_addr;
+       int ret;
+
+       memset(&nps_addr, 0, sizeof(nps_addr));
+
+       ret = convert_bank_to_nps_addr(ras_core, bank,
+                       &nps_addr, bank->nps);
+       if (ret)
+               return ret;
+
+       ras_umc_fill_eeprom_record(ras_core,
+               ACA_ADDR_2_ERR_ADDR(bank->addr), 
ACA_IPID_2_UMC_INST(bank->ipid),
+               &nps_addr, bank->nps, record);
+
+       /* If the bank being converted already has a timestamp,
+        * then use the bank's timestamp.
+        */
+       if (bank->timestamp)
+               record->ts = bank->timestamp;
+
+       lookup_bad_pages_in_a_row(ras_core, record,
+               bank->nps, NULL, 0, bank->seq_no, true);
+
+       return 0;
+}
+
+static int convert_eeprom_record_to_nps_addr(struct ras_core_context *ras_core,
+                       struct eeprom_umc_record *record, uint64_t *pa, 
uint32_t nps)
+{
+       struct device_system_info dev_info = {0};
+       struct umc_mca_addr addr_in;
+       struct umc_phy_addr addr_out;
+       int ret;
+
+       memset(&addr_in, 0, sizeof(addr_in));
+       memset(&addr_out, 0, sizeof(addr_out));
+
+       ras_core_get_device_system_info(ras_core, &dev_info);
+
+       addr_in.err_addr = record->address;
+       addr_in.ch_inst = record->mem_channel;
+       addr_in.umc_inst = record->mcumc_id;
+       addr_in.node_inst = UMC_INV_AID_NODE;
+       addr_in.socket_id = dev_info.socket_id;
+
+       ret = convert_ma_to_pa(ras_core, &addr_in, &addr_out, nps);
+       if (ret)
+               return ret;
+
+       *pa = convert_nps_pa_to_row_pa(ras_core, addr_out.pa, nps, false);
+
+       return 0;
+}
+
+static int umc_v15_0_eeprom_record_to_nps_record(struct ras_core_context 
*ras_core,
+                               struct eeprom_umc_record *record, uint32_t nps)
+{
+       uint64_t pa = 0;
+       int ret = 0;
+
+       if (nps == EEPROM_RECORD_UMC_NPS_MODE(record)) {
+               record->cur_nps_retired_row_pfn = 
EEPROM_RECORD_UMC_ADDR_PFN(record);
+       } else {
+               ret = convert_eeprom_record_to_nps_addr(ras_core,
+                               record, &pa, nps);
+               if (!ret)
+                       record->cur_nps_retired_row_pfn = RAS_ADDR_TO_PFN(pa);
+       }
+
+       record->cur_nps = nps;
+
+       return ret;
+}
+
+static int umc_v15_0_eeprom_record_to_nps_pages(struct ras_core_context 
*ras_core,
+                       struct eeprom_umc_record *record, uint32_t nps,
+                       uint64_t *pfns, uint32_t num)
+{
+       return lookup_bad_pages_in_a_row(ras_core,
+                               record, nps, pfns, num, 0, false);
+}
+
+static int umc_v15_0_soc_pa_to_bank(struct ras_core_context *ras_core,
+                       uint64_t soc_pa,
+                       struct umc_bank_addr *bank_addr)
+{
+       return 0;
+}
+
+static int umc_v15_0_bank_to_soc_pa(struct ras_core_context *ras_core,
+                       struct umc_bank_addr bank_addr,
+                       uint64_t *soc_pa)
+{
+       return 0;
+}
+
+const struct ras_umc_ip_func ras_umc_func_v15_0 = {
+       .bank_to_eeprom_record = umc_v15_0_bank_to_eeprom_record,
+       .eeprom_record_to_nps_record = umc_v15_0_eeprom_record_to_nps_record,
+       .eeprom_record_to_nps_pages = umc_v15_0_eeprom_record_to_nps_pages,
+       .bank_to_soc_pa = umc_v15_0_bank_to_soc_pa,
+       .soc_pa_to_bank = umc_v15_0_soc_pa_to_bank,
+};
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.h 
b/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.h
new file mode 100644
index 0000000000000..5c3a79a48ec00
--- /dev/null
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RAS_UMC_V15_0_H__
+#define __RAS_UMC_V15_0_H__
+#include "ras.h"
+
+/* MCA_UMC_UMC0_MCUMC_ADDRT0 */
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr__SHIFT                0x0
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved__SHIFT                 0x38
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr_MASK                  
0x00FFFFFFFFFFFFFFL
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved_MASK                   
0xFF00000000000000L
+
+/* MCMP1_IPIDT0 */
+#define MCMP1_IPIDT0__InstanceIdLo__SHIFT                          0x0
+#define MCMP1_IPIDT0__HardwareID__SHIFT                            0x20
+#define MCMP1_IPIDT0__InstanceIdHi__SHIFT                          0x2c
+#define MCMP1_IPIDT0__McaType__SHIFT                               0x30
+
+#define MCMP1_IPIDT0__InstanceIdLo_MASK                            
0x00000000FFFFFFFFL
+#define MCMP1_IPIDT0__HardwareID_MASK                              
0x00000FFF00000000L
+#define MCMP1_IPIDT0__InstanceIdHi_MASK                            
0x0000F00000000000L
+#define MCMP1_IPIDT0__McaType_MASK                                 
0xFFFF000000000000L
+
+#define ACA_IPID_HI_2_UMC_AID(_ipid_hi) (((_ipid_hi) >> 2) & 0x3)
+#define ACA_IPID_LO_2_UMC_CH(_ipid_lo)  \
+       (((((_ipid_lo) >> 20) & 0x1) * 4) + (((_ipid_lo) >> 12) & 0xF))
+#define ACA_IPID_LO_2_UMC_INST(_ipid_lo) (((_ipid_lo) >> 21) & 0x7)
+
+#define ACA_IPID_2_DIE_ID(ipid)  ((REG_GET_FIELD(ipid, MCMP1_IPIDT0, 
InstanceIdHi) >> 2) & 0x03)
+#define ACA_IPID_2_UMC_CH(ipid) \
+       (ACA_IPID_LO_2_UMC_CH(REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdLo)))
+
+#define ACA_IPID_2_UMC_INST(ipid) \
+       (ACA_IPID_LO_2_UMC_INST(REG_GET_FIELD(ipid, MCMP1_IPIDT0, 
InstanceIdLo)))
+
+#define ACA_IPID_2_SOCKET_ID(ipid) \
+       (((REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdLo) & 0x1) << 2) | \
+        (REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdHi) & 0x03))
+
+#define ACA_ADDR_2_ERR_ADDR(addr) \
+       REG_GET_FIELD(addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr)
+
+/* invalid node instance value */
+#define UMC_INV_AID_NODE 0xffff
+
+extern const struct ras_umc_ip_func ras_umc_func_v15_0;
+
+#endif
-- 
2.55.0

Reply via email to