On Sat, Aug 31, 2024, at 07:48, Nick Chan wrote: > From: Konrad Dybcio <konrad.dybcio@xxxxxxxxxxxxxx> > > Starting from the A11 (T8015) SoC, Apple introuced system registers for > fast IPI and UNCORE PMC control. These sysregs do not exist on earlier > A7-A10 SoCs and trying to access them results in an instant crash. > > Restrict sysreg access within the AIC driver to configurations where > use_fast_ipi is true to allow AIC to function properly on A7-A10 SoCs. > As part of the restriction, the IPI-always-ack path in aic_handle_fiq() > has been removed. If the code path were to be reached, the system is > fast IPI capable and one of the fast IPI compatibles should be used > instead. The last part is a bit weird. This is really just a bug in the driver. We either have a system with fastipi and then we can handle it. Or we have a system without fastipi and we shouldn't even try to read SYS_IMP_APL_IPI_SR_EL1. Your first sentence "Restrict sysreg access within the AIC driver to configurations where use_fast_ipi is true to allow AIC to function properly on A7-A10 SoCs." already explains what's going on here. You're fixing a bug where we tried to access SYS_IMP_APL_IPI_SR_EL1 unconditionally. It just didn't matter so far because there's only upstream support for M1+ where SYS_IMP_APL_IPI_SR_EL1 always exist. With a fixed commit message: Reviewed-by: Sven Peter <sven@xxxxxxxxxxxxx> > > Signed-off-by: Konrad Dybcio <konrad.dybcio@xxxxxxxxxxxxxx> > Co-developed-by: Nick Chan <towinchenmi@xxxxxxxxx> > Signed-off-by: Nick Chan <towinchenmi@xxxxxxxxx> > --- > drivers/irqchip/irq-apple-aic.c | 25 ++++++++++++------------- > 1 file changed, 12 insertions(+), 13 deletions(-) > > diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c > index 01a3c79054f5..a6d812afb10d 100644 > --- a/drivers/irqchip/irq-apple-aic.c > +++ b/drivers/irqchip/irq-apple-aic.c > @@ -234,6 +234,7 @@ enum fiq_hwirq { > AIC_NR_FIQ > }; > > +/* True if UNCORE/UNCORE2 and Sn_... IPI registers are present and > used (A11+) */ > static DEFINE_STATIC_KEY_TRUE(use_fast_ipi); > /* True if SYS_IMP_APL_IPI_RR_LOCAL_EL1 exists for local fast IPIs > (M1+) */ > static DEFINE_STATIC_KEY_TRUE(use_local_fast_ipi); > @@ -550,14 +551,9 @@ static void __exception_irq_entry > aic_handle_fiq(struct pt_regs *regs) > * we check for everything here, even things we don't support yet. > */ > > - if (read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) { > - if (static_branch_likely(&use_fast_ipi)) { > - aic_handle_ipi(regs); > - } else { > - pr_err_ratelimited("Fast IPI fired. Acking.\n"); > - write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); > - } > - } > + if (static_branch_likely(&use_fast_ipi) && > + (read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING)) > + aic_handle_ipi(regs); > > if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) > generic_handle_domain_irq(aic_irqc->hw_domain, > @@ -592,8 +588,9 @@ static void __exception_irq_entry > aic_handle_fiq(struct pt_regs *regs) > AIC_FIQ_HWIRQ(irq)); > } > > - if (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == > UPMCR0_IMODE_FIQ && > - (read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) { > + if (static_branch_likely(&use_fast_ipi) && > + (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) > == UPMCR0_IMODE_FIQ) && > + (read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) { > /* Same story with uncore PMCs */ > pr_err_ratelimited("Uncore PMC FIQ fired. Masking.\n"); > sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, > @@ -830,7 +827,8 @@ static int aic_init_cpu(unsigned int cpu) > /* Mask all hard-wired per-CPU IRQ/FIQ sources */ > > /* Pending Fast IPI FIQs */ > - write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); > + if (static_branch_likely(&use_fast_ipi)) > + write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); > > /* Timer FIQs */ > sysreg_clear_set(cntp_ctl_el0, 0, ARCH_TIMER_CTRL_IT_MASK); > @@ -851,8 +849,9 @@ static int aic_init_cpu(unsigned int cpu) > FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_OFF)); > > /* Uncore PMC FIQ */ > - sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, > - FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF)); > + if (static_branch_likely(&use_fast_ipi)) > + sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, > + FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF)); > > /* Commit all of the above */ > isb(); > -- > 2.46.0