Discussion:
hpet vs suspend to ram
Andriy Gapon
2018-05-03 08:40:24 UTC
Permalink
Just want to share a strange problem that I see on one system.

If I use HPET as an eventtimer, then after a seemingly successful resume
the system starts to act weird. It becomes unresponsive for periods of
time, then it gets more normal, then it's sluggish, then unresponsive
again. After some time struggling the system finally locks up entirely.

I see this problem both with FreeBSD and Linux (tested with Ubuntu 16
and 17).

If I use any other timer hardware, then everything is okay.
Also, if I switch to HPET after a resume, then it's okay too.
I tried uncommenting the code in acpi_hpet.c that disables the HPET
before suspend, but it didn't change anything.

I suspect that the problem is with SMM code, but don't know how to check
it or whether it would make any difference.
I also tried disabling various devices (e.g. USB) through BIOS config, but that
also didn't help.

The system uses Asus M4A89GTD PRO motherboard.
--
Andriy Gapon
Konstantin Belousov
2018-05-03 09:55:58 UTC
Permalink
Post by Andriy Gapon
Just want to share a strange problem that I see on one system.
If I use HPET as an eventtimer, then after a seemingly successful resume
the system starts to act weird. It becomes unresponsive for periods of
time, then it gets more normal, then it's sluggish, then unresponsive
again. After some time struggling the system finally locks up entirely.
I see this problem both with FreeBSD and Linux (tested with Ubuntu 16
and 17).
If I use any other timer hardware, then everything is okay.
Also, if I switch to HPET after a resume, then it's okay too.
I tried uncommenting the code in acpi_hpet.c that disables the HPET
before suspend, but it didn't change anything.
I suspect that the problem is with SMM code, but don't know how to check
it or whether it would make any difference.
I also tried disabling various devices (e.g. USB) through BIOS config, but that
also didn't help.
Did you tried to clear comparators, besides disabling the HPET ?
Post by Andriy Gapon
The system uses Asus M4A89GTD PRO motherboard.
--
Andriy Gapon
_______________________________________________
https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
Andriy Gapon
2018-05-03 11:50:30 UTC
Permalink
Post by Konstantin Belousov
Post by Andriy Gapon
Just want to share a strange problem that I see on one system.
If I use HPET as an eventtimer, then after a seemingly successful resume
the system starts to act weird. It becomes unresponsive for periods of
time, then it gets more normal, then it's sluggish, then unresponsive
again. After some time struggling the system finally locks up entirely.
I see this problem both with FreeBSD and Linux (tested with Ubuntu 16
and 17).
If I use any other timer hardware, then everything is okay.
Also, if I switch to HPET after a resume, then it's okay too.
I tried uncommenting the code in acpi_hpet.c that disables the HPET
before suspend, but it didn't change anything.
I suspect that the problem is with SMM code, but don't know how to check
it or whether it would make any difference.
I also tried disabling various devices (e.g. USB) through BIOS config, but that
also didn't help.
Did you tried to clear comparators, besides disabling the HPET ?
Thank you very much for the suggestion!
It seems that doing that (and a little bit more[*]) helps indeed.

However there seems to be another issue.
hpet_suspend() is called too early. [Some] Other drivers require a working
event timer for their suspend routines. So after HPET is stopped the suspend
process gets stuck. Repeatedly pressing keyboard keys helps the process to
finally reach the firmware suspend. Everything is okay after resume.

[*] The change:
@@ -838,15 +842,29 @@
static int
hpet_suspend(device_t dev)
{
-// struct hpet_softc *sc;
+ struct hpet_softc *sc;
+ struct hpet_timer *t;
+ int i;

/*
* Disable the timer during suspend. The timer will not lose
* its state in S1 or S2, but we are required to disable
* it.
*/
-// sc = device_get_softc(dev);
-// hpet_disable(sc);
+ sc = device_get_softc(dev);
+ hpet_disable(sc);
+ for (i = 0; i < sc->num_timers; i++) {
+ t = &sc->t[i];
+
+ /*
+ * Clear timer state to minimize chances of confusing
+ * the firmware after resuming from S3.
+ */
+ bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
+ t->caps & ~(HPET_TCNF_INT_ENB | HPET_TCNF_TYPE));
+ bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), 0);
+ bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num);
+ }

return (0);
}
--
Andriy Gapon
Andriy Gapon
2018-05-03 11:57:59 UTC
Permalink
Post by Andriy Gapon
Thank you very much for the suggestion!
It seems that doing that (and a little bit more[*]) helps indeed.
However there seems to be another issue.
hpet_suspend() is called too early. [Some] Other drivers require a working
event timer for their suspend routines. So after HPET is stopped the suspend
process gets stuck. Repeatedly pressing keyboard keys helps the process to
finally reach the firmware suspend. Everything is okay after resume.
Got a patch for this issue as well.
The idea is to suspend children in the reverse order (comparing to their attach
order).

--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -3772,15 +3772,16 @@ int
bus_generic_suspend(device_t dev)
{
int error;
- device_t child, child2;
+ device_t child;

- TAILQ_FOREACH(child, &dev->children, link) {
+ TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) {
error = BUS_SUSPEND_CHILD(dev, child);
- if (error) {
- for (child2 = TAILQ_FIRST(&dev->children);
- child2 && child2 != child;
- child2 = TAILQ_NEXT(child2, link))
- BUS_RESUME_CHILD(dev, child2);
+ if (error != 0) {
+ child = TAILQ_NEXT(child, link);
+ if (child != NULL) {
+ TAILQ_FOREACH_FROM(child, &dev->children, link)
+ BUS_RESUME_CHILD(dev, child);
+ }
return (error);
}
}
--
Andriy Gapon
Loading...