[PATCH v2 4/4] irqchip/gicv3: Add workaround for FUJITSU-MONAKA erratum E#030003

From: Tomohiro Misono

Date: Fri Oct 16 2026 - 06:14:57 EST


From: Kohei Enju <enju.kohei@xxxxxxxxxxx>

On affected FUJITSU-MONAKA CPUs, the erratum may occur when an SGI is
generated by writing to ICC_SGI0R_EL1, ICC_SGI1R_EL1, or ICC_ASGI1R_EL1,
if the operation races with CPU interface processing triggered by the
arrival of a higher-priority interrupt, an update to a pending
interrupt, or a transition of the PE to the Sleep state. When the
erratum occurs, the SGI is lost and the system register write does not
complete, causing the issuing core to hang.

Guest accesses to these registers are not affected by this erratum, as
they are trapped to EL2 and handled without issuing the affected system
register write.

Work around the erratum by writing 1 to the bit corresponding to the
target SGI INTID in GICR_ISPENDR0 of each target PE's GIC Redistributor,
instead of writing to the affected system registers.

Accessing a target PE's GICR_ISPENDR0 requires its Redistributor base to
have been discovered. Affected platforms conform to SBBR, which requires
PSCI for secondary CPU boot. They therefore do not use the ACPI Parking
protocol, which sends an IPI before the secondary CPU has initialized
its Redistributor. With PSCI, a secondary CPU discovers its
Redistributor before becoming an IPI target.

Signed-off-by: Kohei Enju <enju.kohei@xxxxxxxxxxx>
---
Changes in v2:
- Clarify the erratum description and document that virtual accesses are
unaffected.
- Remove the gic_send_sgi_via_rdist() helper.
- Remove the write-count rationale.
- Use the CPU MIDR instead of the SoC ID for filtering.

Note that I have left the dsb(st) after the GICR_ISPENDR0 writes
unchanged, pending clarification of the required completion point. If
the writes must be observed by a specific component before
gic_ipi_send_mask() returns, I will use the appropriate mechanism to
provide that guarantee.
---
---
Documentation/arch/arm64/silicon-errata.rst | 2 ++
drivers/irqchip/irq-gic-v3.c | 32 +++++++++++++++++++++++++++++
2 files changed, 34 insertions(+)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index 0efb24ec01b4c..ee957494a5513 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -379,6 +379,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Fujitsu | MONAKA | E#030002 | FUJITSU_ERRATUM_030002 |
+----------------+-----------------+-----------------+-----------------------------+
+| Fujitsu | MONAKA GICv3/v4 | E#030003 | N/A |
++----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| ASR | ASR8601 | #8601001 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 6e1fa5b247fc4..125940442d77a 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -80,6 +80,8 @@ static DEFINE_STATIC_KEY_FALSE(gic_nvidia_t241_erratum);

static DEFINE_STATIC_KEY_FALSE(gic_arm64_2941627_erratum);

+static DEFINE_STATIC_KEY_FALSE(gic_fujitsu_030003_erratum);
+
static struct gic_chip_data gic_data __read_mostly;
static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);

@@ -238,6 +240,9 @@ static DEFINE_PER_CPU(bool, has_rss);
#define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist))
#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
#define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K)
+#define gic_data_rdist_cpu(cpu) (per_cpu_ptr(gic_data.rdists.rdist, cpu))
+#define gic_data_rdist_rd_base_cpu(cpu) (gic_data_rdist_cpu(cpu)->rd_base)
+#define gic_data_rdist_sgi_base_cpu(cpu) (gic_data_rdist_rd_base_cpu(cpu) + SZ_64K)

/* Our default, arbitrary priority value. Linux only uses one anyway. */
#define DEFAULT_PMR_VALUE 0xf0
@@ -1386,6 +1391,17 @@ static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
*/
dsb(ishst);

+ if (static_branch_unlikely(&gic_fujitsu_030003_erratum)) {
+ for_each_cpu(cpu, mask) {
+ void __iomem *base = gic_data_rdist_sgi_base_cpu(cpu);
+
+ writel_relaxed(BIT(d->hwirq), base + GICR_ISPENDR0);
+ }
+
+ dsb(st);
+ return;
+ }
+
for_each_cpu(cpu, mask) {
u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(gic_cpu_to_affinity(cpu));
u16 tlist;
@@ -1871,6 +1887,16 @@ static bool gic_enable_quirk_rk3399(void *data)
return false;
}

+static bool gic_enable_quirk_fujitsu_030003(void *data)
+{
+ if (read_cpuid_implementor() != ARM_CPU_IMP_FUJITSU ||
+ read_cpuid_part_number() != FUJITSU_CPU_PART_MONAKA)
+ return false;
+
+ static_branch_enable(&gic_fujitsu_030003_erratum);
+ return true;
+}
+
static bool rd_set_non_coherent(void *data)
{
struct gic_chip_data *d = data;
@@ -1951,6 +1977,12 @@ static const struct gic_quirk gic_quirks[] = {
.mask = 0xff000fff,
.init = gic_enable_quirk_rk3399,
},
+ {
+ .desc = "GICv3: Fujitsu erratum 030003",
+ .iidr = 0x0403043b,
+ .mask = 0xffffffff,
+ .init = gic_enable_quirk_fujitsu_030003,
+ },
{
}
};

--
2.43.0