Merge changes from topic "RAS_REFACTORING" into integration

* changes:
  feat(board/rdn2): enable base element RAM RAS support on RD-N2 platform
  feat(plat/arm): add memory map entry for CPER memory region
  feat(plat/arm): firmware first error handling support for base RAMs
  feat(plat/arm): update common platform RAS implementation
  feat(plat/sgi): remove RAS setup call from common code
  refactor(plat/sgi): deprecate DMC-620 RAS support
  fix(plat/common): register PLAT_SP_PRI only if not already registered
  fix(plat/sgi): update PLAT_SP_PRI macro definition
  fix(plat/arm): add RAS_FFH_SUPPORT check for RAS EHF priority
This commit is contained in:
Manish Pandey 2023-06-23 15:18:26 +02:00 committed by TrustedFirmware Code Review
commit 6b6cefbf7b
17 changed files with 359 additions and 207 deletions

View file

@ -775,7 +775,9 @@ MEASURED_BOOT
#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
/* Priority levels for ARM platforms */
#if RAS_FFH_SUPPORT
#define PLAT_RAS_PRI 0x10
#endif
#define PLAT_SDEI_CRITICAL_PRI 0x60
#define PLAT_SDEI_NORMAL_PRI 0x70

View file

@ -8,7 +8,7 @@
#define PLATFORM_DEF_H
#include <lib/utils_def.h>
#include <sgi_sdei.h>
#include <sgi_soc_platform_def_v2.h>
#if (CSS_SGI_PLATFORM_VARIANT == 1)

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef RDN2_RAS_H
#define RDN2_RAS_H
#include <sgi_ras.h>
extern struct plat_sgi_ras_config ras_config;
#endif /* RDN2_RAS_H */

View file

@ -69,6 +69,12 @@ BL31_SOURCES += drivers/arm/gic/v3/gic600_multichip.c
BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
endif
ifeq (${RAS_FFH_SUPPORT},1)
BL31_SOURCES += ${RDN2_BASE}/rdn2_ras.c \
${CSS_ENT_BASE}/ras/sgi_ras_common.c \
${CSS_ENT_BASE}/ras/sgi_ras_sram.c
endif
# Add the FDT_SOURCES and options for Dynamic Config
FDT_SOURCES += ${RDN2_BASE}/fdts/${PLAT}_fw_config.dts \
${RDN2_BASE}/fdts/${PLAT}_tb_fw_config.dts

View file

@ -8,6 +8,7 @@
#include <drivers/arm/gic600_multichip.h>
#include <plat/arm/common/plat_arm.h>
#include <plat/common/platform.h>
#include <rdn2_ras.h>
#include <sgi_soc_platform_def_v2.h>
#include <sgi_plat.h>
@ -134,5 +135,9 @@ void bl31_platform_setup(void)
#endif
sgi_bl31_common_platform_setup();
#if RAS_FFH_SUPPORT
sgi_ras_platform_setup(&ras_config);
#endif
}
#endif /* IMAGE_BL31 */

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <sgi_ras.h>
#include <sgi_sdei.h>
struct sgi_ras_ev_map plat_ras_map[] = {
/* Non Secure base RAM ECC CE interrupt */
{SGI_SDEI_DS_EVENT_0, NS_RAM_ECC_CE_INT, SGI_RAS_INTR_TYPE_SPI},
/* Non Secure base RAM ECC UE interrupt */
{SGI_SDEI_DS_EVENT_0, NS_RAM_ECC_UE_INT, SGI_RAS_INTR_TYPE_SPI},
};
/* RAS error record list definition, used by the common RAS framework. */
struct err_record_info plat_err_records[] = {
/* Base element RAM Non-secure error record. */
ERR_RECORD_MEMMAP_V1(SOC_NS_RAM_ERR_REC_BASE, 4, NULL,
&sgi_ras_sram_intr_handler, 0),
};
/* RAS error interrupt list definition, used by the common RAS framework. */
struct ras_interrupt plat_ras_interrupts[] = {
{
.intr_number = NS_RAM_ECC_CE_INT,
.err_record = &plat_err_records[0],
}, {
.intr_number = NS_RAM_ECC_UE_INT,
.err_record = &plat_err_records[0],
},
};
/* Registers the RAS error record list with common RAS framework. */
REGISTER_ERR_RECORD_INFO(plat_err_records);
/* Registers the RAS error interrupt info list with common RAS framework. */
REGISTER_RAS_INTERRUPTS(plat_ras_interrupts);
/* Platform RAS handling config data definition */
struct plat_sgi_ras_config ras_config = {
plat_ras_map,
ARRAY_SIZE(plat_ras_map)
};

View file

@ -8,8 +8,16 @@
#include <plat/arm/common/plat_arm.h>
#include <platform_def.h>
#define RDN2_TZC_CPER_REGION \
{CSS_SGI_SP_CPER_BUF_BASE, (CSS_SGI_SP_CPER_BUF_BASE + \
CSS_SGI_SP_CPER_BUF_SIZE) - 1, TZC_REGION_S_NONE, \
PLAT_ARM_TZC_NS_DEV_ACCESS}
static const arm_tzc_regions_info_t tzc_regions[] = {
ARM_TZC_REGIONS_DEF,
#if RAS_FFH_SUPPORT
RDN2_TZC_CPER_REGION,
#endif
{}
};

View file

@ -204,7 +204,11 @@
SOC_CSS_DEVICE_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
#if RAS_FFH_SUPPORT
#define PLAT_SP_PRI PLAT_RAS_PRI
#else
#define PLAT_SP_PRI 0x10
#endif
#if SPM_MM && RAS_FFH_SUPPORT
/*

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -7,15 +7,57 @@
#ifndef SGI_RAS_H
#define SGI_RAS_H
#include <lib/extensions/ras.h>
#include <plat/common/platform.h>
/*
* Mapping the RAS interrupt with SDEI event number and the event
* id used with Standalone MM code
* Interrupt type supported.
* - SGI_RAS_INTR_TYPE_SPI: Denotes a SPI interrupt
* - SGI_RAS_INTR_TYPE_PPI: Denotes a PPI interrupt
*/
#define SGI_RAS_INTR_TYPE_SPI 0
#define SGI_RAS_INTR_TYPE_PPI 1
/*
* MM Communicate information structure. Required to generate MM Communicate
* payload to be shared with Standalone MM.
*/
typedef struct mm_communicate_header {
struct efi_guid header_guid;
size_t message_len;
uint8_t data[1];
} mm_communicate_header_t;
/* RAS error info data structure. */
struct sgi_ras_ev_map {
int sdei_ev_num; /* SDEI Event number */
int intr; /* Physical intr number */
int intr_type; /* Interrupt Type (SPI or PPI)*/
};
int sgi_ras_intr_handler_setup(void);
/* RAS config data structure. Must be defined by each platform. */
struct plat_sgi_ras_config {
struct sgi_ras_ev_map *ev_map;
int ev_map_size;
};
/*
* Find event map for a given interrupt number. On success, returns pointer
* to the event map. On error, returns NULL.
*/
struct sgi_ras_ev_map *sgi_find_ras_event_map_by_intr(uint32_t intr_num);
/*
* Initialization function for the framework.
*
* Registers RAS config provided by the platform and then configures and
* enables interrupt for each registered error. On success, return 0.
*/
int sgi_ras_platform_setup(struct plat_sgi_ras_config *config);
/* Base element RAM RAS interrupt handler function. */
int sgi_ras_sram_intr_handler(const struct err_record_info *err_rec,
int probe_data,
const struct err_handler_data *const data);
#endif /* SGI_RAS_H */

View file

@ -58,6 +58,11 @@
#define END_KEY_BASE (SOC_KEYS_BASE + 0x0044)
#define END_KEY_SIZE U(32)
/* Base Element RAM error definitions */
#define SOC_NS_RAM_ERR_REC_BASE UL(0x2A4C0000)
#define NS_RAM_ECC_CE_INT U(87)
#define NS_RAM_ECC_UE_INT U(88)
#define SOC_PLATFORM_PERIPH_MAP_DEVICE MAP_REGION_FLAT( \
SOC_PLATFORM_PERIPH_BASE, \
SOC_PLATFORM_PERIPH_SIZE, \

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <bl31/interrupt_mgmt.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <sgi_ras.h>
static struct plat_sgi_ras_config *sgi_ras_config;
/*
* Find event map for a given interrupt number. On success, returns pointer to
* the event map. On error, returns NULL.
*/
struct sgi_ras_ev_map *sgi_find_ras_event_map_by_intr(uint32_t intr_num)
{
struct sgi_ras_ev_map *map;
int size;
int i;
if (sgi_ras_config == NULL) {
ERROR("RAS config is NULL\n");
return NULL;
}
map = sgi_ras_config->ev_map;
size = sgi_ras_config->ev_map_size;
for (i = 0; i < size; i++) {
if (map->intr == intr_num)
return map;
map++;
}
return NULL;
}
/*
* Programs GIC registers and configures interrupt ID's as Group0 EL3
* interrupts. Current support is to register PPI and SPI interrupts.
*/
static void sgi_ras_intr_configure(int intr, int intr_type)
{
plat_ic_set_interrupt_type(intr, INTR_TYPE_EL3);
plat_ic_set_interrupt_priority(intr, PLAT_RAS_PRI);
plat_ic_clear_interrupt_pending(intr);
/* Routing mode option available only for SPI interrupts */
if (intr_type == SGI_RAS_INTR_TYPE_SPI) {
plat_ic_set_spi_routing(intr, INTR_ROUTING_MODE_ANY,
(u_register_t)read_mpidr_el1());
}
plat_ic_enable_interrupt(intr);
}
/*
* Initialization function for the framework.
*
* Registers RAS config provided by the platform and then configures and
* enables interrupt for each registered error. On success, return 0.
*/
int sgi_ras_platform_setup(struct plat_sgi_ras_config *config)
{
struct sgi_ras_ev_map *map;
int size;
int i;
/* Check if parameter is valid. */
if (config == NULL) {
ERROR("SGI: Failed to register RAS config\n");
return -1;
}
/*
* Maintain a reference to the platform RAS config data for later
* use.
*/
sgi_ras_config = config;
map = sgi_ras_config->ev_map;
size = sgi_ras_config->ev_map_size;
for (i = 0; i < size; i++) {
sgi_ras_intr_configure(map->intr, map->intr_type);
map++;
}
INFO("SGI: Platform RAS setup successful\n");
return 0;
}

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <bl31/interrupt_mgmt.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <plat/common/platform.h>
#include <services/sdei.h>
#include <services/spm_mm_svc.h>
#include <platform_def.h>
#include <sgi_ras.h>
/* Base Element RAM Error Record offsets. */
#define ERRSTATUS U(0)
#define ERRCODE U(8)
#define ERRADDR U(12)
/*
* Base Element RAM error information data structure communicated as part of MM
* Communication data payload.
*/
typedef struct sgi_sram_err_info {
uint32_t err_status;
uint32_t err_code;
uint32_t err_addr;
} sgi_sram_err_info_t;
/*
* MM Communicate message header GUID to indicate the payload is intended for
* base element RAM MM driver.
*/
struct efi_guid sram_ecc_event_guid = {
0x7312db4f, 0xd0c4, 0x4fb5,
{ 0x81, 0x2c, 0xb7, 0x4b, 0xc6, 0xc4, 0xa9, 0x38 }
};
/* Base element RAM RAS error interrupt handler */
int sgi_ras_sram_intr_handler(const struct err_record_info *err_rec,
int probe_data,
const struct err_handler_data *const data)
{
struct sgi_ras_ev_map *ras_map;
mm_communicate_header_t *header;
sgi_sram_err_info_t sram_info;
uintptr_t base_addr;
uint32_t clear_status, intr;
int ret;
cm_el1_sysregs_context_save(NON_SECURE);
intr = data->interrupt;
INFO("SGI: Base element RAM interrupt [%d] handler\n", intr);
/* Determine error record base address to read. */
base_addr = 0;
if (intr == NS_RAM_ECC_CE_INT || intr == NS_RAM_ECC_UE_INT) {
base_addr = SOC_NS_RAM_ERR_REC_BASE;
}
sram_info.err_status = mmio_read_32(base_addr + ERRSTATUS);
sram_info.err_code = mmio_read_32(base_addr + ERRCODE);
sram_info.err_addr = mmio_read_32(base_addr + ERRADDR);
/* Clear the interrupt. */
clear_status = mmio_read_32(base_addr + ERRSTATUS);
mmio_write_32((base_addr + ERRSTATUS), clear_status);
/*
* Prepare the MM Communication buffer to pass the base element RAM
* error information to Secure Partition.
*/
header = (void *)PLAT_SPM_BUF_BASE;
memset(header, 0, sizeof(*header));
memcpy(&header->data, &sram_info, sizeof(sram_info));
header->message_len = sizeof(sram_info);
memcpy(&header->header_guid, (void *)&sram_ecc_event_guid,
sizeof(struct efi_guid));
spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0,
plat_my_core_pos());
plat_ic_end_of_interrupt(intr);
/*
* Find if this is a RAS interrupt. There must be an event against
* this interrupt
*/
ras_map = sgi_find_ras_event_map_by_intr(intr);
if (ras_map == NULL) {
ERROR("SGI: RAS error info for interrupt id: %d not found\n",
intr);
return -1;
}
/* Dispatch the event to the SDEI client */
ret = sdei_dispatch_event(ras_map->sdei_ev_num);
if (ret != 0) {
/*
* sdei_dispatch_event() may return failing result in some
* cases, for example kernel may not have registered a handler
* or RAS event may happen early during boot. We restore the NS
* context when sdei_dispatch_event() returns failing result.
*/
ERROR("SDEI dispatch failed: %d", ret);
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
}
return ret;
}

View file

@ -54,10 +54,6 @@ BL31_SOURCES += ${INTERCONNECT_SOURCES} \
${CSS_ENT_BASE}/sgi_bl31_setup.c \
${CSS_ENT_BASE}/sgi_topology.c
ifeq (${RAS_FFH_SUPPORT},1)
BL31_SOURCES += ${CSS_ENT_BASE}/sgi_ras.c
endif
ifneq (${RESET_TO_BL31},0)
$(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \
Please set RESET_TO_BL31 to 0.")

View file

@ -106,10 +106,6 @@ void sgi_bl31_common_platform_setup(void)
{
arm_bl31_platform_setup();
#if RAS_FFH_SUPPORT
sgi_ras_intr_handler_setup();
#endif
/* Configure the warm reboot SGI for primary core */
css_setup_cpu_pwr_down_intr();

View file

@ -87,6 +87,9 @@ const mmap_region_t plat_arm_secure_partition_mmap[] = {
SOC_PLATFORM_PERIPH_MAP_DEVICE_USER,
ARM_SP_IMAGE_MMAP,
ARM_SP_IMAGE_NS_BUF_MMAP,
#if RAS_FFH_SUPPORT
CSS_SGI_SP_CPER_BUF_MMAP,
#endif
ARM_SP_IMAGE_RW_MMAP,
ARM_SPM_BUF_EL0_MMAP,
{0}

View file

@ -1,194 +0,0 @@
/*
* Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <bl31/interrupt_mgmt.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/extensions/ras.h>
#include <plat/arm/common/arm_spm_def.h>
#include <plat/common/platform.h>
#include <services/sdei.h>
#include <services/spm_mm_svc.h>
#include <sgi_ras.h>
static int sgi_ras_intr_handler(const struct err_record_info *err_rec,
int probe_data,
const struct err_handler_data *const data);
typedef struct mm_communicate_header {
struct efi_guid header_guid;
size_t message_len;
uint8_t data[8];
} mm_communicate_header_t;
/*
* GUID to indicate that the MM communication message is intended for DMC-620
* MM driver.
*/
const struct efi_guid dmc620_ecc_event_guid = {
0x5ef0afd5, 0xe01a, 0x4c30,
{0x86, 0x19, 0x45, 0x46, 0x26, 0x91, 0x80, 0x98}
};
struct sgi_ras_ev_map sgi575_ras_map[] = {
/* DMC 0 error ECC error interrupt*/
{SGI_SDEI_DS_EVENT_0, 35},
/* DMC 1 error ECC error interrupt*/
{SGI_SDEI_DS_EVENT_1, 39},
};
#define SGI575_RAS_MAP_SIZE ARRAY_SIZE(sgi575_ras_map)
struct err_record_info sgi_err_records[] = {
{
/* DMC 0 error record info */
.handler = &sgi_ras_intr_handler,
.aux_data = (void *)0,
}, {
/* DMC 1 error record info */
.handler = &sgi_ras_intr_handler,
.aux_data = (void *)1,
},
};
struct ras_interrupt sgi_ras_interrupts[] = {
{
.intr_number = 35,
.err_record = &sgi_err_records[0],
}, {
.intr_number = 39,
.err_record = &sgi_err_records[1],
}
};
REGISTER_ERR_RECORD_INFO(sgi_err_records);
REGISTER_RAS_INTERRUPTS(sgi_ras_interrupts);
static struct sgi_ras_ev_map *plat_sgi_get_ras_ev_map(void)
{
return sgi575_ras_map;
}
static int plat_sgi_get_ras_ev_map_size(void)
{
return SGI575_RAS_MAP_SIZE;
}
/*
* Find event mapping for a given interrupt number: On success, returns pointer
* to the event mapping. On error, returns NULL.
*/
static struct sgi_ras_ev_map *find_ras_event_map_by_intr(uint32_t intr_num)
{
struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map();
int i;
int size = plat_sgi_get_ras_ev_map_size();
for (i = 0; i < size; i++) {
if (map->intr == intr_num)
return map;
map++;
}
return NULL;
}
static void sgi_ras_intr_configure(int intr)
{
plat_ic_set_interrupt_type(intr, INTR_TYPE_EL3);
plat_ic_set_interrupt_priority(intr, PLAT_RAS_PRI);
plat_ic_clear_interrupt_pending(intr);
plat_ic_set_spi_routing(intr, INTR_ROUTING_MODE_ANY,
(u_register_t)read_mpidr_el1());
plat_ic_enable_interrupt(intr);
}
static int sgi_ras_intr_handler(const struct err_record_info *err_rec,
int probe_data,
const struct err_handler_data *const data)
{
struct sgi_ras_ev_map *ras_map;
mm_communicate_header_t *header;
uint32_t intr;
int ret;
cm_el1_sysregs_context_save(NON_SECURE);
intr = data->interrupt;
/*
* Find if this is a RAS interrupt. There must be an event against
* this interrupt
*/
ras_map = find_ras_event_map_by_intr(intr);
assert(ras_map != NULL);
/*
* Populate the MM_COMMUNICATE payload to share the
* event info with StandaloneMM code. This allows us to use
* MM_COMMUNICATE as a common entry mechanism into S-EL0. The
* header data will be parsed in StandaloneMM to process the
* corresponding event.
*
* TBD - Currently, the buffer allocated by SPM for communication
* between EL3 and S-EL0 is being used(PLAT_SPM_BUF_BASE). But this
* should happen via a dynamic mem allocation, which should be
* managed by SPM -- the individual platforms then call the mem
* alloc api to get memory for the payload.
*/
header = (void *) PLAT_SPM_BUF_BASE;
memset(header, 0, sizeof(*header));
memcpy(&header->data, &err_rec->aux_data, sizeof(err_rec->aux_data));
header->message_len = sizeof(err_rec->aux_data);
memcpy(&header->header_guid, (void *) &dmc620_ecc_event_guid,
sizeof(const struct efi_guid));
spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0,
plat_my_core_pos());
/*
* Do an EOI of the RAS interrupt. This allows the
* sdei event to be dispatched at the SDEI event's
* priority.
*/
plat_ic_end_of_interrupt(intr);
/* Dispatch the event to the SDEI client */
ret = sdei_dispatch_event(ras_map->sdei_ev_num);
if (ret != 0) {
/*
* sdei_dispatch_event() may return failing result in some cases,
* for example kernel may not have registered a handler or RAS event
* may happen early during boot. We restore the NS context when
* sdei_dispatch_event() returns failing result.
*/
ERROR("SDEI dispatch failed: %d", ret);
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
}
return ret;
}
int sgi_ras_intr_handler_setup(void)
{
int i;
struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map();
int size = plat_sgi_get_ras_ev_map_size();
for (i = 0; i < size; i++) {
sgi_ras_intr_configure(map->intr);
map++;
}
INFO("SGI: RAS Interrupt Handler successfully registered\n");
return 0;
}

View file

@ -24,9 +24,17 @@ ehf_pri_desc_t plat_exceptions[] = {
/* Normal priority SDEI */
EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
#endif
#if SPM_MM
#if RAS_FFH_SUPPORT
#if (PLAT_SP_PRI != PLAT_RAS_PRI)
EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI),
#endif
#else
EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI),
#endif
#endif
/* Platform specific exceptions description */
#ifdef PLAT_EHF_DESC
PLAT_EHF_DESC,