diff options
-rw-r--r-- | drivers/acpi/prmt.c | 24 | ||||
-rw-r--r-- | drivers/edac/synopsys_edac.c | 35 | ||||
-rw-r--r-- | drivers/ras/amd/atl/Kconfig | 4 | ||||
-rw-r--r-- | drivers/ras/amd/atl/Makefile | 2 | ||||
-rw-r--r-- | drivers/ras/amd/atl/internal.h | 10 | ||||
-rw-r--r-- | drivers/ras/amd/atl/prm.c | 57 | ||||
-rw-r--r-- | drivers/ras/amd/atl/umc.c | 5 | ||||
-rw-r--r-- | include/linux/prmt.h | 5 |
8 files changed, 141 insertions, 1 deletions
diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c index c78453c74ef5..1cfaa5957ac4 100644 --- a/drivers/acpi/prmt.c +++ b/drivers/acpi/prmt.c @@ -214,6 +214,30 @@ static struct prm_handler_info *find_prm_handler(const guid_t *guid) #define UPDATE_LOCK_ALREADY_HELD 4 #define UPDATE_UNLOCK_WITHOUT_LOCK 5 +int acpi_call_prm_handler(guid_t handler_guid, void *param_buffer) +{ + struct prm_handler_info *handler = find_prm_handler(&handler_guid); + struct prm_module_info *module = find_prm_module(&handler_guid); + struct prm_context_buffer context; + efi_status_t status; + + if (!module || !handler) + return -ENODEV; + + memset(&context, 0, sizeof(context)); + ACPI_COPY_NAMESEG(context.signature, "PRMC"); + context.identifier = handler->guid; + context.static_data_buffer = handler->static_data_buffer_addr; + context.mmio_ranges = module->mmio_info; + + status = efi_call_acpi_prm_handler(handler->handler_addr, + (u64)param_buffer, + &context); + + return efi_status_to_err(status); +} +EXPORT_SYMBOL_GPL(acpi_call_prm_handler); + /* * This is the PlatformRtMechanism opregion space handler. * @function: indicates the read/write. In fact as the PlatformRtMechanism diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index ea7a9a342dd3..d7416166fd8a 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/spinlock.h> +#include <linux/sizes.h> #include <linux/interrupt.h> #include <linux/of.h> @@ -337,6 +338,7 @@ struct synps_edac_priv { * @get_mtype: Get mtype. * @get_dtype: Get dtype. * @get_ecc_state: Get ECC state. + * @get_mem_info: Get EDAC memory info * @quirks: To differentiate IPs. */ struct synps_platform_data { @@ -344,6 +346,9 @@ struct synps_platform_data { enum mem_type (*get_mtype)(const void __iomem *base); enum dev_type (*get_dtype)(const void __iomem *base); bool (*get_ecc_state)(void __iomem *base); +#ifdef CONFIG_EDAC_DEBUG + u64 (*get_mem_info)(struct synps_edac_priv *priv); +#endif int quirks; }; @@ -402,6 +407,25 @@ out: return 0; } +#ifdef CONFIG_EDAC_DEBUG +/** + * zynqmp_get_mem_info - Get the current memory info. + * @priv: DDR memory controller private instance data. + * + * Return: host interface address. + */ +static u64 zynqmp_get_mem_info(struct synps_edac_priv *priv) +{ + u64 hif_addr = 0, linear_addr; + + linear_addr = priv->poison_addr; + if (linear_addr >= SZ_32G) + linear_addr = linear_addr - SZ_32G + SZ_2G; + hif_addr = linear_addr >> 3; + return hif_addr; +} +#endif + /** * zynqmp_get_error_info - Get the current ECC error info. * @priv: DDR memory controller private instance data. @@ -922,6 +946,9 @@ static const struct synps_platform_data zynqmp_edac_def = { .get_mtype = zynqmp_get_mtype, .get_dtype = zynqmp_get_dtype, .get_ecc_state = zynqmp_get_ecc_state, +#ifdef CONFIG_EDAC_DEBUG + .get_mem_info = zynqmp_get_mem_info, +#endif .quirks = (DDR_ECC_INTR_SUPPORT #ifdef CONFIG_EDAC_DEBUG | DDR_ECC_DATA_POISON_SUPPORT @@ -975,10 +1002,16 @@ MODULE_DEVICE_TABLE(of, synps_edac_match); static void ddr_poison_setup(struct synps_edac_priv *priv) { int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval; + const struct synps_platform_data *p_data; int index; ulong hif_addr = 0; - hif_addr = priv->poison_addr >> 3; + p_data = priv->p_data; + + if (p_data->get_mem_info) + hif_addr = p_data->get_mem_info(priv); + else + hif_addr = priv->poison_addr >> 3; for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) { if (priv->row_shift[index]) diff --git a/drivers/ras/amd/atl/Kconfig b/drivers/ras/amd/atl/Kconfig index df49c23e7f62..551680073e43 100644 --- a/drivers/ras/amd/atl/Kconfig +++ b/drivers/ras/amd/atl/Kconfig @@ -19,3 +19,7 @@ config AMD_ATL Enable this option if using DRAM ECC on Zen-based systems and OS-based error handling. + +config AMD_ATL_PRM + depends on AMD_ATL && ACPI_PRMT + def_bool y diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile index 4acd5f05bd9c..b56892c0c0d9 100644 --- a/drivers/ras/amd/atl/Makefile +++ b/drivers/ras/amd/atl/Makefile @@ -15,4 +15,6 @@ amd_atl-y += map.o amd_atl-y += system.o amd_atl-y += umc.o +amd_atl-$(CONFIG_AMD_ATL_PRM) += prm.o + obj-$(CONFIG_AMD_ATL) += amd_atl.o diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index 9de5d53d0568..143d04c779a8 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -282,6 +282,16 @@ unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err); u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr); u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr); +#ifdef CONFIG_AMD_ATL_PRM +unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, unsigned long addr); +#else +static inline unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, + unsigned long addr) +{ + return -ENODEV; +} +#endif + /* * Make a gap in @data that is @num_bits long starting at @bit_num. * e.g. data = 11111111'b diff --git a/drivers/ras/amd/atl/prm.c b/drivers/ras/amd/atl/prm.c new file mode 100644 index 000000000000..0931a20d213b --- /dev/null +++ b/drivers/ras/amd/atl/prm.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Address Translation Library + * + * prm.c : Plumbing code for ACPI Platform Runtime Mechanism (PRM) + * + * Information on AMD PRM modules and handlers including the GUIDs and buffer + * structures used here are defined in the AMD ACPI Porting Guide in the + * chapter "Platform Runtime Mechanism Table (PRMT)" + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: John Allen <[email protected]> + */ + +#include "internal.h" + +#include <linux/prmt.h> + +/* + * PRM parameter buffer - normalized to system physical address, as described + * in the "PRM Parameter Buffer" section of the AMD ACPI Porting Guide. + */ +struct norm_to_sys_param_buf { + u64 norm_addr; + u8 socket; + u64 bank_id; + void *out_buf; +} __packed; + +static const guid_t norm_to_sys_guid = GUID_INIT(0xE7180659, 0xA65D, 0x451D, + 0x92, 0xCD, 0x2B, 0x56, 0xF1, + 0x2B, 0xEB, 0xA6); + +unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 bank_id, unsigned long addr) +{ + struct norm_to_sys_param_buf p_buf; + unsigned long ret_addr; + int ret; + + p_buf.norm_addr = addr; + p_buf.socket = socket_id; + p_buf.bank_id = bank_id; + p_buf.out_buf = &ret_addr; + + ret = acpi_call_prm_handler(norm_to_sys_guid, &p_buf); + if (!ret) + return ret_addr; + + if (ret == -ENODEV) + pr_debug("PRM module/handler not available\n"); + else + pr_notice_once("PRM address translation failed\n"); + + return ret; +} diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c index a1b4accf7b96..dc8aa12f63c8 100644 --- a/drivers/ras/amd/atl/umc.c +++ b/drivers/ras/amd/atl/umc.c @@ -401,9 +401,14 @@ unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err) u8 coh_st_inst_id = get_coh_st_inst_id(err); unsigned long addr = get_addr(err->addr); u8 die_id = get_die_id(err); + unsigned long ret_addr; pr_debug("socket_id=0x%x die_id=0x%x coh_st_inst_id=0x%x addr=0x%016lx", socket_id, die_id, coh_st_inst_id, addr); + ret_addr = prm_umc_norm_to_sys_addr(socket_id, err->ipid, addr); + if (!IS_ERR_VALUE(ret_addr)) + return ret_addr; + return norm_to_sys_addr(socket_id, die_id, coh_st_inst_id, addr); } diff --git a/include/linux/prmt.h b/include/linux/prmt.h index 24da8364b919..9c094294403f 100644 --- a/include/linux/prmt.h +++ b/include/linux/prmt.h @@ -2,6 +2,11 @@ #ifdef CONFIG_ACPI_PRMT void init_prmt(void); +int acpi_call_prm_handler(guid_t handler_guid, void *param_buffer); #else static inline void init_prmt(void) { } +static inline int acpi_call_prm_handler(guid_t handler_guid, void *param_buffer) +{ + return -EOPNOTSUPP; +} #endif |