mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-03 23:28:58 +00:00
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
This commit is contained in:
parent
dd8c2454a8
commit
572f347d9f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=175361
|
@ -82,6 +82,24 @@ hpet_get_timecount(struct timecounter *tc)
|
||||||
return (bus_read_4(sc->mem_res, HPET_OFFSET_VALUE));
|
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. */
|
/* Discover the HPET via the ACPI table of the same name. */
|
||||||
static void
|
static void
|
||||||
acpi_hpet_identify(driver_t *driver, device_t parent)
|
acpi_hpet_identify(driver_t *driver, device_t parent)
|
||||||
|
@ -166,10 +184,17 @@ acpi_hpet_attach(device_t dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Be sure timer is enabled. */
|
/* Be sure timer is enabled. */
|
||||||
bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 1);
|
hpet_enable(sc);
|
||||||
|
|
||||||
/* Read basic statistics about the timer. */
|
/* Read basic statistics about the timer. */
|
||||||
val = bus_read_4(sc->mem_res, HPET_OFFSET_PERIOD);
|
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;
|
freq = (1000000000000000LL + val / 2) / val;
|
||||||
if (bootverbose) {
|
if (bootverbose) {
|
||||||
val = bus_read_4(sc->mem_res, HPET_OFFSET_INFO);
|
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);
|
val2 = bus_read_4(sc->mem_res, HPET_OFFSET_VALUE);
|
||||||
if (val == val2) {
|
if (val == val2) {
|
||||||
device_printf(dev, "HPET never increments, disabling\n");
|
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);
|
bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
@ -213,6 +238,22 @@ acpi_hpet_detach(device_t dev)
|
||||||
return (EBUSY);
|
return (EBUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static int
|
||||||
acpi_hpet_resume(device_t dev)
|
acpi_hpet_resume(device_t dev)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +261,7 @@ acpi_hpet_resume(device_t dev)
|
||||||
|
|
||||||
/* Re-enable the timer after a resume to keep the clock advancing. */
|
/* Re-enable the timer after a resume to keep the clock advancing. */
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
bus_write_4(sc->mem_res, HPET_OFFSET_ENABLE, 1);
|
hpet_enable(sc);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -260,6 +301,7 @@ static device_method_t acpi_hpet_methods[] = {
|
||||||
DEVMETHOD(device_probe, acpi_hpet_probe),
|
DEVMETHOD(device_probe, acpi_hpet_probe),
|
||||||
DEVMETHOD(device_attach, acpi_hpet_attach),
|
DEVMETHOD(device_attach, acpi_hpet_attach),
|
||||||
DEVMETHOD(device_detach, acpi_hpet_detach),
|
DEVMETHOD(device_detach, acpi_hpet_detach),
|
||||||
|
DEVMETHOD(device_suspend, acpi_hpet_suspend),
|
||||||
DEVMETHOD(device_resume, acpi_hpet_resume),
|
DEVMETHOD(device_resume, acpi_hpet_resume),
|
||||||
|
|
||||||
{0, 0}
|
{0, 0}
|
||||||
|
|
Loading…
Reference in a new issue