Module Name: src Committed By: martin Date: Sat Feb 22 12:27:48 UTC 2025
Modified Files: src/sys/arch/powerpc/pic [netbsd-10]: intr.c picvar.h Log Message: Pull up following revision(s) (requested by jmcneill in ticket #1056): sys/arch/powerpc/pic/intr.c: revision 1.35 sys/arch/powerpc/pic/intr.c: revision 1.36 sys/arch/powerpc/pic/intr.c: revision 1.37 sys/arch/powerpc/pic/picvar.h: revision 1.14 powerpc: Fix ci_ipending corruption with cascaded pics A cascaded pic will register pic_handle_intr as its interrupt handler, but interrupt handlers are called with MSR[EE] = 1. This breaks assumptions in pic callbacks and can result in eg. corrupt ci_ipending due to a read/modify/write of the field with nested interrupts. Fix this by always clearing MSR[EE] at the top of pic_handle_intr. powerpc: Mask interrupts after returning from handler. Now that we are explicitly masking interrupts on entry of pic_handle_intr, we need to disable (instead of store) interrupts after calling intr_deliver. powerpc: Don't enable interrupts before calling cascaded intr handler. Before calling a normal interrupt handler, the pic code adjusts cpl and enables interrupts. Don't do this with interrupt sources that feed cascaded pics as the resulting handler will do it anyway, and it can result in multiple interrupts firing on the parent pic just to service a single interrupt on the child. To generate a diff of this commit: cvs rdiff -u -r1.34 -r1.34.4.1 src/sys/arch/powerpc/pic/intr.c cvs rdiff -u -r1.13 -r1.13.16.1 src/sys/arch/powerpc/pic/picvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/powerpc/pic/intr.c diff -u src/sys/arch/powerpc/pic/intr.c:1.34 src/sys/arch/powerpc/pic/intr.c:1.34.4.1 --- src/sys/arch/powerpc/pic/intr.c:1.34 Wed Feb 16 23:49:27 2022 +++ src/sys/arch/powerpc/pic/intr.c Sat Feb 22 12:27:48 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: intr.c,v 1.34 2022/02/16 23:49:27 riastradh Exp $ */ +/* $NetBSD: intr.c,v 1.34.4.1 2025/02/22 12:27:48 martin Exp $ */ /*- * Copyright (c) 2007 Michael Lorenz @@ -29,7 +29,7 @@ #define __INTR_PRIVATE #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.34 2022/02/16 23:49:27 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.34.4.1 2025/02/22 12:27:48 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_interrupt.h" @@ -180,10 +180,12 @@ intr_establish_xname(int hwirq, int type hwirq, type); struct intr_source * const is = &intrsources[virq]; + const bool cascaded = ih_fun == pic_handle_intr; switch (is->is_type) { case IST_NONE: is->is_type = type; + is->is_cascaded = cascaded; break; case IST_EDGE_FALLING: case IST_EDGE_RISING: @@ -193,10 +195,15 @@ intr_establish_xname(int hwirq, int type break; /* FALLTHROUGH */ case IST_PULSE: - if (type != IST_NONE) + if (type != IST_NONE) { panic("intr_establish: can't share %s with %s", intr_typename(is->is_type), intr_typename(type)); + } + if (cascaded != is->is_cascaded) { + panic("intr_establish: can't share cascaded with " + "non-cascaded interrupt"); + } break; } if (is->is_hand == NULL) { @@ -519,11 +526,15 @@ again: struct intr_source * const is = &intrsources[virq]; struct pic_ops * const pic = is->is_pic; - splraise(is->is_ipl); - mtmsr(emsr); + if (!is->is_cascaded) { + splraise(is->is_ipl); + mtmsr(emsr); + } intr_deliver(is, virq); - mtmsr(dmsr); - ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ + if (!is->is_cascaded) { + mtmsr(dmsr); + ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ + } pic->pic_reenable_irq(pic, is->is_hwirq - pic->pic_intrbase, is->is_type); @@ -560,13 +571,17 @@ pic_handle_intr(void *cookie) struct cpu_info *ci = curcpu(); int picirq; - picirq = pic->pic_get_irq(pic, PIC_GET_IRQ); - if (picirq == 255) - return 0; - const register_t msr = mfmsr(); const int pcpl = ci->ci_cpl; + mtmsr(msr & ~PSL_EE); + + picirq = pic->pic_get_irq(pic, PIC_GET_IRQ); + if (picirq == 255) { + mtmsr(msr); + return 0; + } + do { const int virq = virq_map[picirq + pic->pic_intrbase]; @@ -583,11 +598,15 @@ pic_handle_intr(void *cookie) ci->ci_ipending &= ~v_imen; ci->ci_idepth++; - splraise(is->is_ipl); - mtmsr(msr | PSL_EE); + if (!is->is_cascaded) { + splraise(is->is_ipl); + mtmsr(msr | PSL_EE); + } intr_deliver(is, virq); - mtmsr(msr); - ci->ci_cpl = pcpl; + if (!is->is_cascaded) { + mtmsr(msr & ~PSL_EE); + ci->ci_cpl = pcpl; + } ci->ci_data.cpu_nintr++; ci->ci_idepth--; Index: src/sys/arch/powerpc/pic/picvar.h diff -u src/sys/arch/powerpc/pic/picvar.h:1.13 src/sys/arch/powerpc/pic/picvar.h:1.13.16.1 --- src/sys/arch/powerpc/pic/picvar.h:1.13 Mon Mar 22 01:36:10 2021 +++ src/sys/arch/powerpc/pic/picvar.h Sat Feb 22 12:27:48 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: picvar.h,v 1.13 2021/03/22 01:36:10 rin Exp $ */ +/* $NetBSD: picvar.h,v 1.13.16.1 2025/02/22 12:27:48 martin Exp $ */ /*- * Copyright (c) 2007 Michael Lorenz @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: picvar.h,v 1.13 2021/03/22 01:36:10 rin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: picvar.h,v 1.13.16.1 2025/02/22 12:27:48 martin Exp $"); #ifndef PIC_VAR_H #define PIC_VAR_H @@ -61,6 +61,7 @@ struct intr_source { imask_t is_mask; struct intrhand *is_hand; struct pic_ops *is_pic; + bool is_cascaded; struct evcnt is_ev; char is_evname[16]; char is_intrid[INTRIDBUF];