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 <arvind.ramprakash@arm.com>
Change-Id: I4bb6dcf86c94125cbc574e0dc5119abe43e84731
This commit is contained in:
Arvind Ram Prakash 2024-02-05 16:19:37 -06:00
parent 0cda4adae7
commit 24a4a0a5ec
6 changed files with 70 additions and 9 deletions

View File

@ -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",

View File

@ -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:

View File

@ -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

View File

@ -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,

View File

@ -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);
/*******************************************************************************

View File

@ -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;