summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-01-15 18:50:47 +0000
committerjhb <jhb@FreeBSD.org>2008-01-15 18:50:47 +0000
commitff87bab77959c79e5193953dcc0efcdc9fa73389 (patch)
treea91648a83b1ab99f60a4eebd5ef80c5616823f7d /sys/dev/acpica
parentccb885253e11a500ca1ddd474fdbc952e67480ee (diff)
downloadFreeBSD-src-ff87bab77959c79e5193953dcc0efcdc9fa73389.zip
FreeBSD-src-ff87bab77959c79e5193953dcc0efcdc9fa73389.tar.gz
Fix a few minor issues based on a bug report and reading over the HPET
spec: - Use read/modify/write cycles to enable and disable the HPET instead of writing 0 to reserved bits. - Shutdown the HPET during suspend as encouraged by the spec. - Fail to attach to an HPET with a period of zero. MFC after: 1 week PR: kern/119675 [3] Reported by: Leo Bicknell | bicknell ufp.org
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r--sys/dev/acpica/acpi_hpet.c48
1 files changed, 45 insertions, 3 deletions
diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c
index ab64c11..32c0530 100644
--- a/sys/dev/acpica/acpi_hpet.c
+++ b/sys/dev/acpica/acpi_hpet.c
@@ -82,6 +82,24 @@ hpet_get_timecount(struct timecounter *tc)
return (bus_read_4(sc->mem_res, HPET_OFFSET_VALUE));
}
+static void
+hpet_enable(struct acpi_hpet_softc *sc)
+{
+ uint32_t val;
+
+ val = bus_read_4(sc->mem_res, HPET_OFFSET_ENABLE);
+ bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, val | 1);
+}
+
+static void
+hpet_disable(struct acpi_hpet_softc *sc)
+{
+ uint32_t val;
+
+ val = bus_read_4(sc->mem_res, HPET_OFFSET_ENABLE);
+ bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, val & ~1);
+}
+
/* Discover the HPET via the ACPI table of the same name. */
static void
acpi_hpet_identify(driver_t *driver, device_t parent)
@@ -166,10 +184,17 @@ acpi_hpet_attach(device_t dev)
}
/* Be sure timer is enabled. */
- bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 1);
+ hpet_enable(sc);
/* Read basic statistics about the timer. */
val = bus_read_4(sc->mem_res, HPET_OFFSET_PERIOD);
+ if (val == 0) {
+ device_printf(dev, "invalid period\n");
+ hpet_disable(sc);
+ bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
+ return (ENXIO);
+ }
+
freq = (1000000000000000LL + val / 2) / val;
if (bootverbose) {
val = bus_read_4(sc->mem_res, HPET_OFFSET_INFO);
@@ -192,7 +217,7 @@ acpi_hpet_attach(device_t dev)
val2 = bus_read_4(sc->mem_res, HPET_OFFSET_VALUE);
if (val == val2) {
device_printf(dev, "HPET never increments, disabling\n");
- bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 0);
+ hpet_disable(sc);
bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
return (ENXIO);
}
@@ -214,13 +239,29 @@ acpi_hpet_detach(device_t dev)
}
static int
+acpi_hpet_suspend(device_t dev)
+{
+ struct acpi_hpet_softc *sc;
+
+ /*
+ * 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);
+
+ return (0);
+}
+
+static int
acpi_hpet_resume(device_t dev)
{
struct acpi_hpet_softc *sc;
/* Re-enable the timer after a resume to keep the clock advancing. */
sc = device_get_softc(dev);
- bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 1);
+ hpet_enable(sc);
return (0);
}
@@ -260,6 +301,7 @@ static device_method_t acpi_hpet_methods[] = {
DEVMETHOD(device_probe, acpi_hpet_probe),
DEVMETHOD(device_attach, acpi_hpet_attach),
DEVMETHOD(device_detach, acpi_hpet_detach),
+ DEVMETHOD(device_suspend, acpi_hpet_suspend),
DEVMETHOD(device_resume, acpi_hpet_resume),
{0, 0}
OpenPOWER on IntegriCloud