diff --git a/sys/dev/cons.c b/sys/dev/cons.c index fd2a5b507503..12525d2f75e2 100644 --- a/sys/dev/cons.c +++ b/sys/dev/cons.c @@ -42,20 +42,21 @@ __KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.92 2022/10/25 23:21:33 riastradh Exp $"); #include -#include -#include + +#include #include -#include -#include -#include -#include #include -#include +#include +#include #include -#include #include -#include +#include +#include +#include #include +#include +#include +#include #include diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c index 0f1b73eda04d..ae58cd5c5500 100644 --- a/sys/dev/usb/ukbd.c +++ b/sys/dev/usb/ukbd.c @@ -47,28 +47,30 @@ __KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.162 2023/01/10 18:20:10 mrg Exp $"); #endif /* _KERNEL_OPT */ #include -#include + #include -#include #include -#include #include -#include +#include +#include +#include +#include #include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include +#include #include #include @@ -1055,11 +1057,18 @@ ukbd_cnpollc(void *v, int on) if (on) { sc->sc_spl = splusb(); pollenter++; - } else { - splx(sc->sc_spl); - pollenter--; +#ifdef HEARTBEAT + heartbeat_suspend(); +#endif } usbd_set_polling(dev, on); + if (!on) { +#ifdef HEARTBEAT + heartbeat_resume(); +#endif + pollenter--; + splx(sc->sc_spl); + } } int diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c index d082994d2661..88cb8f505617 100644 --- a/sys/kern/kern_cpu.c +++ b/sys/kern/kern_cpu.c @@ -370,6 +370,10 @@ cpu_xc_offline(struct cpu_info *ci, void *unused) pcu_save_all_on_cpu(); #endif +#ifdef HEARTBEAT + heartbeat_suspend(); +#endif + #ifdef __HAVE_MD_CPU_OFFLINE cpu_offline_md(); #endif @@ -379,10 +383,6 @@ fail: s = splsched(); spc->spc_flags &= ~SPCF_OFFLINE; splx(s); - -#ifdef HEARTBEAT - heartbeat_suspend(); -#endif } static void diff --git a/sys/kern/kern_heartbeat.c b/sys/kern/kern_heartbeat.c index e293eb4ad3e2..32d2b44d33e0 100644 --- a/sys/kern/kern_heartbeat.c +++ b/sys/kern/kern_heartbeat.c @@ -127,17 +127,22 @@ void *heartbeat_sih __read_mostly; * Suspend heartbeat monitoring of the current CPU. * * Called after the current CPU has been marked offline but before - * it has stopped running. Caller must have preemption disabled. + * it has stopped running, or after IPL has been raised for + * polling-mode console input. Caller must have preemption + * disabled. Non-nestable. Reversed by heartbeat_resume. */ void heartbeat_suspend(void) { + struct cpu_info *ci = curcpu(); + int s; KASSERT(curcpu_stable()); + KASSERT((ci->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED) == 0); - /* - * Nothing to do -- we just check the SPCF_OFFLINE flag. - */ + s = splsched(); + ci->ci_schedstate.spc_flags |= SPCF_HEARTBEATSUSPENDED; + splx(s); } /* @@ -148,6 +153,8 @@ heartbeat_suspend(void) * Called at startup while cold, and whenever heartbeat monitoring * is re-enabled after being disabled or the period is changed. * When not cold, ci must be the current CPU. + * + * Must be run at splsched. */ static void heartbeat_resume_cpu(struct cpu_info *ci) @@ -155,6 +162,7 @@ heartbeat_resume_cpu(struct cpu_info *ci) KASSERT(__predict_false(cold) || curcpu_stable()); KASSERT(__predict_false(cold) || ci == curcpu()); + /* XXX KASSERT IPL_SCHED */ ci->ci_heartbeat_count = 0; ci->ci_heartbeat_uptime_cache = time_uptime; @@ -167,9 +175,8 @@ heartbeat_resume_cpu(struct cpu_info *ci) * Resume heartbeat monitoring of the current CPU. * * Called after the current CPU has started running but before it - * has been marked online. Also used internally when starting up - * heartbeat monitoring at boot or when the maximum period is set - * from zero to nonzero. Caller must have preemption disabled. + * has been marked online, or when ending polling-mode input + * before IPL is restored. Caller must have preemption disabled. */ void heartbeat_resume(void) @@ -178,6 +185,7 @@ heartbeat_resume(void) int s; KASSERT(curcpu_stable()); + KASSERT(ci->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED); /* * Block heartbeats while we reset the state so we don't @@ -185,6 +193,7 @@ heartbeat_resume(void) * resetting the count and the uptime stamp. */ s = splsched(); + ci->ci_schedstate.spc_flags &= ~SPCF_HEARTBEATSUSPENDED; heartbeat_resume_cpu(ci); splx(s); } @@ -198,8 +207,11 @@ heartbeat_resume(void) static void heartbeat_reset_xc(void *a, void *b) { + int s; - heartbeat_resume(); + s = splsched(); + heartbeat_resume_cpu(curcpu()); + splx(s); } /* @@ -488,7 +500,7 @@ select_patient(void) * in the iteration order. */ for (CPU_INFO_FOREACH(cii, ci)) { - if (ci->ci_schedstate.spc_flags & SPCF_OFFLINE) + if (ci->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED) continue; if (passedcur) { /* @@ -565,7 +577,8 @@ heartbeat(void) period_secs = atomic_load_relaxed(&heartbeat_max_period_secs); if (__predict_false(period_ticks == 0) || __predict_false(period_secs == 0) || - __predict_false(curcpu()->ci_schedstate.spc_flags & SPCF_OFFLINE)) + __predict_false(curcpu()->ci_schedstate.spc_flags & + SPCF_HEARTBEATSUSPENDED)) return; /* @@ -637,8 +650,8 @@ heartbeat(void) * Verify that time is advancing on the patient CPU. If the * delta exceeds UINT_MAX/2, that means it is already ahead by * a little on the other CPU, and the subtraction went - * negative, which is OK. If the CPU has been - * offlined since we selected it, no worries. + * negative, which is OK. If the CPU's heartbeats have been + * suspended since we selected it, no worries. * * This uses the current CPU to ensure the other CPU has made * progress, even if the other CPU's hard timer interrupt @@ -650,7 +663,8 @@ heartbeat(void) d = uptime - atomic_load_relaxed(&patient->ci_heartbeat_uptime_cache); if (__predict_false(d > period_secs) && __predict_false(d < UINT_MAX/2) && - ((patient->ci_schedstate.spc_flags & SPCF_OFFLINE) == 0)) + ((patient->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED) + == 0)) defibrillate(patient, d); } diff --git a/sys/sys/sched.h b/sys/sys/sched.h index 119aa1c768d1..2e67b59b4c01 100644 --- a/sys/sys/sched.h +++ b/sys/sys/sched.h @@ -188,6 +188,7 @@ struct schedstate_percpu { #define SPCF_1STCLASS 0x0040 /* first class scheduling entity */ #define SPCF_CORE1ST 0x0100 /* first CPU in core */ #define SPCF_PACKAGE1ST 0x0200 /* first CPU in package */ +#define SPCF_HEARTBEATSUSPENDED 0x0400 /* heartbeat (temporarily) suspended */ #define SPCF_SWITCHCLEAR (SPCF_SEENRR|SPCF_SHOULDYIELD)