From 24a4a0a5ec25e179f2e567a6e13a9b5c87db1b81 Mon Sep 17 00:00:00 2001 From: Arvind Ram Prakash Date: Mon, 5 Feb 2024 16:19:37 -0600 Subject: [PATCH] fix(gic600): workaround for Part 1 of GIC600 erratum 2384374 GIC600 erratum 2384374 is a Category B erratum. Part 1 is fixed in this patch, and the Part 1 failure mode is described as 'If the packet to be sent is a SET packet, then a higher priority SET may not be sent when it should be until an unblocking event occurs.' This is handled by calling gicv3_apply_errata_wa_2384374() in the ehf_deactivate_priority() path, so that when EHF restores the priority to the original priority, the interrupt packet buffered in the GIC can be sent. gicv3_apply_errata_wa_2384374() is the workaround for the Part 2 of erratum 2384374 which flush packets from the GIC buffer and is being used in this patch. SDEN can be found here: https://developer.arm.com/documentation/sden892601/latest/ Signed-off-by: Arvind Ram Prakash Change-Id: I4bb6dcf86c94125cbc574e0dc5119abe43e84731 --- bl31/ehf.c | 16 +++++++++--- .../platform-interrupt-controller-API.rst | 25 ++++++++++++++++--- drivers/arm/gic/v3/gicv3_main.c | 25 +++++++++++++++++++ include/drivers/arm/gicv3.h | 3 ++- include/plat/common/platform.h | 3 ++- plat/common/plat_gicv3.c | 7 +++++- 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/bl31/ehf.c b/bl31/ehf.c index 5b78ebb13..3a14635c6 100644 --- a/bl31/ehf.c +++ b/bl31/ehf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -203,10 +203,20 @@ void ehf_deactivate_priority(unsigned int priority) * one stashed earlier if there are no more to deactivate. */ cur_pri_idx = get_pe_highest_active_idx(pe_data); - if (cur_pri_idx == EHF_INVALID_IDX) + +#if GIC600_ERRATA_WA_2384374 + if (cur_pri_idx == EHF_INVALID_IDX) { + old_mask = plat_ic_deactivate_priority(pe_data->init_pri_mask); + } else { + old_mask = plat_ic_deactivate_priority(priority); + } +#else + if (cur_pri_idx == EHF_INVALID_IDX) { old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask); - else + } else { old_mask = plat_ic_set_priority_mask(priority); + } +#endif if (old_mask > priority) { ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n", diff --git a/docs/components/platform-interrupt-controller-API.rst b/docs/components/platform-interrupt-controller-API.rst index 4de39d1e5..8cd4bae9f 100644 --- a/docs/components/platform-interrupt-controller-API.rst +++ b/docs/components/platform-interrupt-controller-API.rst @@ -282,9 +282,28 @@ may be signalled to the PE. The API should return the current priority value that it's overwriting. In case of Arm standard platforms using GIC, the implementation of the API -inserts to order memory updates before updating mask, then writes to the GIC -*Priority Mask Register*, and make sure memory updates are visible before -potential trigger due to mask update. +inserts barriers to order memory updates before updating mask, +then writes to the GIC *Priority Mask Register*, and make sure memory updates +are visible before potential trigger due to mask update. + +Function: unsigned int plat_ic_deactivate_priority(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +This API performs the operations of plat_ic_set_priority_mask along with +calling the errata workaround gicv3_apply_errata_wa_2384374(). This is +performed when priority mask is restored to it's older value. This API returns +the current priority value that it's overwriting. + +In case of Arm standard platforms using GIC, the implementation of the API +inserts barriers to order memory updates before updating mask, then writes +to the GIC *Priority Mask Register*, and make sure memory updates +are visible before potential trigger due to mask update, and +applies 2384374 GIC errata workaround to process pending interrupt packets. .. _plat_ic_get_interrupt_id: diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 3190f6615..8ea164ce8 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -1320,6 +1320,31 @@ unsigned int gicv3_set_pmr(unsigned int mask) return old_mask; } +/******************************************************************************* + * This function restores the PMR register to old value and also triggers + * gicv3_apply_errata_wa_2384374() that flushes the GIC buffer allowing any + * pending interrupts to processed. Returns the original PMR. + ******************************************************************************/ +unsigned int gicv3_deactivate_priority(unsigned int mask) +{ + + unsigned int old_mask, proc_num; + uintptr_t gicr_base; + + old_mask = gicv3_set_pmr(mask); + + proc_num = plat_my_core_pos(); + gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; + assert(gicr_base != 0UL); + + /* Add DSB to ensure visibility of System register writes */ + dsb(); + + gicv3_apply_errata_wa_2384374(gicr_base); + + return old_mask; +} + /******************************************************************************* * This function delegates the responsibility of discovering the corresponding * Redistributor frames to each CPU itself. It is a modified version of diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index cf6a7465a..bfda31bbf 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -588,6 +588,7 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num); void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num); unsigned int gicv3_set_pmr(unsigned int mask); +unsigned int gicv3_deactivate_priority(unsigned int mask); void gicv3_get_component_prodid_rev(const uintptr_t gicd_base, unsigned int *gic_prod_id, diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index 4d1b1c17c..2bb23c450 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -136,6 +136,7 @@ void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, void plat_ic_set_interrupt_pending(unsigned int id); void plat_ic_clear_interrupt_pending(unsigned int id); unsigned int plat_ic_set_priority_mask(unsigned int mask); +unsigned int plat_ic_deactivate_priority(unsigned int mask); unsigned int plat_ic_get_interrupt_id(unsigned int raw); /******************************************************************************* diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c index baa70e0ba..d0c7a31e6 100644 --- a/plat/common/plat_gicv3.c +++ b/plat/common/plat_gicv3.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved. * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -344,6 +344,11 @@ unsigned int plat_ic_set_priority_mask(unsigned int mask) return gicv3_set_pmr(mask); } +unsigned int plat_ic_deactivate_priority(unsigned int mask) +{ + return gicv3_deactivate_priority(mask); +} + unsigned int plat_ic_get_interrupt_id(unsigned int raw) { unsigned int id = raw & INT_ID_MASK;