Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/gic-v3: Fix rk3399 workaround when secure interrupts are enabled

Christoph reports that their rk3399 system dies since commit 773c05f417fa1
("irqchip/gic-v3: Work around insecure GIC integrations").

It appears that some rk3399 have secure payloads, and that the firmware
sets SCR_EL3.FIQ==1. Obivously, disabling security in that configuration
leads to even more problems.

Revisit the workaround by:

- making it rk3399 specific
- checking whether Group-0 is available, which is a good proxy
for SCR_EL3.FIQ being 0
- either apply the workaround if Group-0 is available, or disable
pseudo-NMIs if not

Note that this doesn't mean that the secure side is able to receive
interrupts, as all interrupts are made non-secure anyway.

Clearly, nobody ever tested secure interrupts on this platform.

Fixes: 773c05f417fa1 ("irqchip/gic-v3: Work around insecure GIC integrations")
Reported-by: Christoph Fritz <chf.fritz@googlemail.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Christoph Fritz <chf.fritz@googlemail.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/all/20250215185241.3768218-1-maz@kernel.org
Closes: https://lore.kernel.org/r/b1266652fb64857246e8babdf268d0df8f0c36d9.camel@googlemail.com

authored by

Marc Zyngier and committed by
Thomas Gleixner
4cb77793 0ad2507d

+38 -11
+38 -11
drivers/irqchip/irq-gic-v3.c
··· 44 44 #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) 45 45 #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) 46 46 #define FLAGS_WORKAROUND_ASR_ERRATUM_8601001 (1ULL << 2) 47 + #define FLAGS_WORKAROUND_INSECURE (1ULL << 3) 47 48 48 49 #define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) 49 50 ··· 83 82 #define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer)) 84 83 #define GIC_LINE_NR min(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U) 85 84 #define GIC_ESPI_NR GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer) 85 + 86 + static bool nmi_support_forbidden; 86 87 87 88 /* 88 89 * There are 16 SGIs, though we only actually use 8 in Linux. The other 8 SGIs ··· 166 163 { 167 164 bool ds; 168 165 166 + cpus_have_group0 = gic_has_group0(); 167 + 169 168 ds = gic_dist_security_disabled(); 170 - if (!ds) { 171 - u32 val; 169 + if ((gic_data.flags & FLAGS_WORKAROUND_INSECURE) && !ds) { 170 + if (cpus_have_group0) { 171 + u32 val; 172 172 173 - val = readl_relaxed(gic_data.dist_base + GICD_CTLR); 174 - val |= GICD_CTLR_DS; 175 - writel_relaxed(val, gic_data.dist_base + GICD_CTLR); 173 + val = readl_relaxed(gic_data.dist_base + GICD_CTLR); 174 + val |= GICD_CTLR_DS; 175 + writel_relaxed(val, gic_data.dist_base + GICD_CTLR); 176 176 177 - ds = gic_dist_security_disabled(); 178 - if (ds) 179 - pr_warn("Broken GIC integration, security disabled"); 177 + ds = gic_dist_security_disabled(); 178 + if (ds) 179 + pr_warn("Broken GIC integration, security disabled\n"); 180 + } else { 181 + pr_warn("Broken GIC integration, pNMI forbidden\n"); 182 + nmi_support_forbidden = true; 183 + } 180 184 } 181 185 182 186 cpus_have_security_disabled = ds; 183 - cpus_have_group0 = gic_has_group0(); 184 187 185 188 /* 186 189 * How priority values are used by the GIC depends on two things: ··· 218 209 * be in the non-secure range, we program the non-secure values into 219 210 * the distributor to match the PMR values we want. 220 211 */ 221 - if (cpus_have_group0 & !cpus_have_security_disabled) { 212 + if (cpus_have_group0 && !cpus_have_security_disabled) { 222 213 dist_prio_irq = __gicv3_prio_to_ns(dist_prio_irq); 223 214 dist_prio_nmi = __gicv3_prio_to_ns(dist_prio_nmi); 224 215 } ··· 1931 1922 return true; 1932 1923 } 1933 1924 1925 + static bool gic_enable_quirk_rk3399(void *data) 1926 + { 1927 + struct gic_chip_data *d = data; 1928 + 1929 + if (of_machine_is_compatible("rockchip,rk3399")) { 1930 + d->flags |= FLAGS_WORKAROUND_INSECURE; 1931 + return true; 1932 + } 1933 + 1934 + return false; 1935 + } 1936 + 1934 1937 static bool rd_set_non_coherent(void *data) 1935 1938 { 1936 1939 struct gic_chip_data *d = data; ··· 2018 1997 .init = rd_set_non_coherent, 2019 1998 }, 2020 1999 { 2000 + .desc = "GICv3: Insecure RK3399 integration", 2001 + .iidr = 0x0000043b, 2002 + .mask = 0xff000fff, 2003 + .init = gic_enable_quirk_rk3399, 2004 + }, 2005 + { 2021 2006 } 2022 2007 }; 2023 2008 ··· 2031 2004 { 2032 2005 int i; 2033 2006 2034 - if (!gic_prio_masking_enabled()) 2007 + if (!gic_prio_masking_enabled() || nmi_support_forbidden) 2035 2008 return; 2036 2009 2037 2010 rdist_nmi_refs = kcalloc(gic_data.ppi_nr + SGI_NR,