stop and restart kernel event timers in the suspend / resume cycle

I have a system that is very unstable after resuming from suspend-to-RAM
but only if HPET is used as the event timer.  The theory is that SMM
code / firmware could be enabling HPET for its own uses and unexpected
interrupts cause a trouble for it.  Originally I wanted to solve the
problem in hpet_suspend() method, but that was insufficient as the event
timer could get reprogrammed again.

So, it's better, for my case and in general, to stop the event timer(s)
before entering the hardware suspend.

MFC after:	4 weeks
Differential Revision: https://reviews.freebsd.org/D15413
This commit is contained in:
Andriy Gapon 2018-05-21 20:23:04 +00:00
parent 5988464ec4
commit 27dca831a6
3 changed files with 21 additions and 0 deletions

View File

@ -2958,6 +2958,7 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state)
if (sc->acpi_sleep_delay > 0)
DELAY(sc->acpi_sleep_delay * 1000000);
suspendclock();
intr = intr_disable();
if (state != ACPI_STATE_S1) {
sleep_result = acpi_sleep_machdep(sc, state);
@ -3028,6 +3029,8 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state)
* process. This handles both the error and success cases.
*/
backout:
if (slp_state >= ACPI_SS_SLP_PREP)
resumeclock();
if (slp_state >= ACPI_SS_GPE_SET) {
acpi_wake_prep_walk(state);
sc->acpi_sstate = ACPI_STATE_S0;

View File

@ -698,6 +698,22 @@ cpu_initclocks_ap(void)
spinlock_exit();
}
void
suspendclock(void)
{
ET_LOCK();
configtimer(0);
ET_UNLOCK();
}
void
resumeclock(void)
{
ET_LOCK();
configtimer(1);
ET_UNLOCK();
}
/*
* Switch to profiling clock rates.
*/

View File

@ -333,6 +333,8 @@ void startprofclock(struct proc *);
void stopprofclock(struct proc *);
void cpu_startprofclock(void);
void cpu_stopprofclock(void);
void suspendclock(void);
void resumeclock(void);
sbintime_t cpu_idleclock(void);
void cpu_activeclock(void);
void cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt);