From: cheloha Date: Sun, 24 Jul 2022 00:28:09 +0000 (+0000) Subject: macppc, powerpc: retrigger deferred DEC interrupts from splx(9) X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=de0524796acd867538c2bb2b0f4ab84447da8e6c;p=openbsd macppc, powerpc: retrigger deferred DEC interrupts from splx(9) On PowerPC, by design, you cannot mask decrementer (DEC) interrupts without also masking other interrupts that we want to leave unmasked at or above IPL_CLOCK. So, currently, the DEC is left unmasked, even when we're working at IPL_CLOCK or IPL_HIGH. If a DEC interrupt arrives while we're at those priority levels, the current solution is to postpone any clock interrupt work until the next hardclock(9) or statclock tick. This is a problem for a machine-independent clock interrupt subsystem because the MD code, e.g. decr_intr(), ideally shouldn't need to know anything about when the next event is scheduled to occur. The most obvious solution to this problem that I can think of is to instead postpone clock interrupt work until the next time our priority level drops below IPL_CLOCK. This is something we can do from the MD code without any knowledge of when the next clock interrupt event is scheduled to occur. So: - Add a new boolean, ci_dec_deferred, to the PowerPC cpu_info struct. - If we reach decr_intr() when the CPU's priority level is too high, set ci_dec_deferred, clear the DEC exception, and return. - If we reach decr_intr() and the CPU's priority level is low enough, clear ci_dec_deferred and do any needed clock interrupt work. - In splx(9) (there are three different versions we need to update), check ci_dec_deferred. If it's set and our priority level is dropping below IPL_CLOCK, raise a DEC exception. Tested by me on PowerMac7,3 (openpic). Tested by miod@ on PowerMac1,1 (macintr) (`make build` completes). Tested by gkoehler@ on an unknown PowerMac (probably openpic). With lots of help from kettenis@. ok gkoehler@ miod@ --- diff --git a/sys/arch/macppc/dev/macintr.c b/sys/arch/macppc/dev/macintr.c index 87dae89b856..123a3f3f114 100644 --- a/sys/arch/macppc/dev/macintr.c +++ b/sys/arch/macppc/dev/macintr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macintr.c,v 1.56 2022/03/13 12:33:01 mpi Exp $ */ +/* $OpenBSD: macintr.c,v 1.57 2022/07/24 00:28:09 cheloha Exp $ */ /*- * Copyright (c) 2008 Dale Rahn @@ -170,6 +170,10 @@ macintr_splx(int newcpl) intr = ppc_intr_disable(); macintr_setipl(newcpl); + if (ci->ci_dec_deferred && newcpl < IPL_CLOCK) { + ppc_mtdec(0); + ppc_mtdec(UINT32_MAX); /* raise DEC exception */ + } if ((newcpl < IPL_SOFTTTY && ci->ci_ipending & ppc_smask[newcpl])) { s = splsofttty(); dosoftint(newcpl); diff --git a/sys/arch/macppc/dev/openpic.c b/sys/arch/macppc/dev/openpic.c index ae6931f330f..35fdf7caca3 100644 --- a/sys/arch/macppc/dev/openpic.c +++ b/sys/arch/macppc/dev/openpic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: openpic.c,v 1.89 2022/02/21 10:38:50 jsg Exp $ */ +/* $OpenBSD: openpic.c,v 1.90 2022/07/24 00:28:09 cheloha Exp $ */ /*- * Copyright (c) 2008 Dale Rahn @@ -382,6 +382,10 @@ openpic_splx(int newcpl) intr = ppc_intr_disable(); openpic_setipl(newcpl); + if (ci->ci_dec_deferred && newcpl < IPL_CLOCK) { + ppc_mtdec(0); + ppc_mtdec(UINT32_MAX); /* raise DEC exception */ + } if (newcpl < IPL_SOFTTTY && (ci->ci_ipending & ppc_smask[newcpl])) { s = splsofttty(); dosoftint(newcpl); diff --git a/sys/arch/macppc/macppc/clock.c b/sys/arch/macppc/macppc/clock.c index a24e7f997f0..14428600e47 100644 --- a/sys/arch/macppc/macppc/clock.c +++ b/sys/arch/macppc/macppc/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.48 2021/02/23 04:44:30 cheloha Exp $ */ +/* $OpenBSD: clock.c,v 1.49 2022/07/24 00:28:09 cheloha Exp $ */ /* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */ /* @@ -127,6 +127,19 @@ decr_intr(struct clockframe *frame) if (!ticks_per_intr) return; + /* + * We can't actually mask DEC interrupts at or above IPL_CLOCK + * without masking other essential interrupts. To simulate + * masking, we retrigger the DEC by hand from splx(9) the next + * time our IPL drops below IPL_CLOCK. + */ + if (ci->ci_cpl >= IPL_CLOCK) { + ci->ci_dec_deferred = 1; + ppc_mtdec(UINT32_MAX >> 1); /* clear DEC exception */ + return; + } + ci->ci_dec_deferred = 0; + /* * Based on the actual time delay since the last decrementer reload, * we arrange for earlier interrupt next time. @@ -160,39 +173,35 @@ decr_intr(struct clockframe *frame) */ ppc_mtdec(nextevent - tb); - if (ci->ci_cpl >= IPL_CLOCK) { - ci->ci_statspending += nstats; - } else { - nstats += ci->ci_statspending; - ci->ci_statspending = 0; - - s = splclock(); - - /* - * Reenable interrupts - */ - ppc_intr_enable(1); - - /* - * Do standard timer interrupt stuff. - */ - while (ci->ci_lasttb < ci->ci_prevtb) { - /* sync lasttb with hardclock */ - ci->ci_lasttb += ticks_per_intr; - clk_count.ec_count++; - hardclock(frame); - } + nstats += ci->ci_statspending; + ci->ci_statspending = 0; - while (nstats-- > 0) - statclock(frame); + s = splclock(); - splx(s); - (void) ppc_intr_disable(); + /* + * Reenable interrupts + */ + ppc_intr_enable(1); - /* if a tick has occurred while dealing with these, - * dont service it now, delay until the next tick. - */ + /* + * Do standard timer interrupt stuff. + */ + while (ci->ci_lasttb < ci->ci_prevtb) { + /* sync lasttb with hardclock */ + ci->ci_lasttb += ticks_per_intr; + clk_count.ec_count++; + hardclock(frame); } + + while (nstats-- > 0) + statclock(frame); + + splx(s); + (void) ppc_intr_disable(); + + /* if a tick has occurred while dealing with these, + * dont service it now, delay until the next tick. + */ } void cpu_startclock(void); diff --git a/sys/arch/powerpc/include/cpu.h b/sys/arch/powerpc/include/cpu.h index 727cd200096..86630d5bbcf 100644 --- a/sys/arch/powerpc/include/cpu.h +++ b/sys/arch/powerpc/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.71 2022/02/10 05:48:02 gkoehler Exp $ */ +/* $OpenBSD: cpu.h,v 1.72 2022/07/24 00:28:09 cheloha Exp $ */ /* $NetBSD: cpu.h,v 1.1 1996/09/30 16:34:21 ws Exp $ */ /* @@ -55,6 +55,7 @@ struct cpu_info { volatile int ci_want_resched; volatile int ci_cpl; volatile int ci_ipending; + volatile int ci_dec_deferred; volatile int ci_flags; #define CI_FLAGS_SLEEPING 2 diff --git a/sys/arch/powerpc/powerpc/intr.c b/sys/arch/powerpc/powerpc/intr.c index 84718250ad6..4b5195bca93 100644 --- a/sys/arch/powerpc/powerpc/intr.c +++ b/sys/arch/powerpc/powerpc/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.9 2015/09/13 14:06:40 kettenis Exp $ */ +/* $OpenBSD: intr.c,v 1.10 2022/07/24 00:28:09 cheloha Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA. @@ -120,6 +120,11 @@ ppc_dflt_splx(int newcpl) ci->ci_cpl = newcpl; + if (ci->ci_dec_deferred && newcpl < IPL_CLOCK) { + ppc_mtdec(0); + ppc_mtdec(UINT32_MAX); /* raise DEC exception */ + } + if (ci->ci_ipending & ppc_smask[newcpl]) dosoftint(newcpl); }