From 964bf2f902c5e05381018532e5d9d456979d4bf7 Mon Sep 17 00:00:00 2001 From: "John F. Carr" Date: Sat, 19 Mar 2022 18:51:43 -0400 Subject: [PATCH] hpet: Allow a MMIO window smaller than 1K Some new AMD systems provide a HPET MMIO region smaller than the 1KB specified, and a correspondingly small number of timers. Handle this in the HPET driver rather than requiring a 1KB window. This allows the HPET driver to attach on such systems. PR: 262638 Reviewed by: markj MFC after: 1 month --- sys/dev/acpica/acpi_hpet.c | 20 +++++++++++++++++--- sys/dev/acpica/acpi_hpet.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c index 0f0a16f336f2..e35e3808a980 100644 --- a/sys/dev/acpica/acpi_hpet.c +++ b/sys/dev/acpica/acpi_hpet.c @@ -477,6 +477,7 @@ hpet_attach(device_t dev) struct make_dev_args mda; int i, j, num_msi, num_timers, num_percpu_et, num_percpu_t, cur_cpu; int pcpu_master, error; + rman_res_t hpet_region_size; static int maxhpetet = 0; uint32_t val, val2, cvectors, dvectors; uint16_t vendor, rev; @@ -493,10 +494,11 @@ hpet_attach(device_t dev) if (sc->mem_res == NULL) return (ENOMEM); - /* Validate that we can access the whole region. */ - if (rman_get_size(sc->mem_res) < HPET_MEM_WIDTH) { + hpet_region_size = rman_get_size(sc->mem_res); + /* Validate that the region is big enough for the control registers. */ + if (hpet_region_size < HPET_MEM_MIN_WIDTH) { device_printf(dev, "memory region width %jd too small\n", - rman_get_size(sc->mem_res)); + hpet_region_size); bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); return (ENXIO); } @@ -526,6 +528,18 @@ hpet_attach(device_t dev) */ if (vendor == HPET_VENDID_AMD && rev < 0x10 && num_timers > 0) num_timers--; + /* + * Now validate that the region is big enough to address all counters. + */ + if (hpet_region_size < HPET_TIMER_CAP_CNF(num_timers)) { + device_printf(dev, + "memory region width %jd too small for %d timers\n", + hpet_region_size, num_timers); + hpet_disable(sc); + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); + return (ENXIO); + } + sc->num_timers = num_timers; if (bootverbose) { device_printf(dev, diff --git a/sys/dev/acpica/acpi_hpet.h b/sys/dev/acpica/acpi_hpet.h index c3941c39a89a..1d6a6022230e 100644 --- a/sys/dev/acpica/acpi_hpet.h +++ b/sys/dev/acpica/acpi_hpet.h @@ -30,6 +30,7 @@ #define __ACPI_HPET_H__ #define HPET_MEM_WIDTH 0x400 /* Expected memory region size */ +#define HPET_MEM_MIN_WIDTH 0x100 /* Minimum memory region size */ /* General registers */ #define HPET_CAPABILITIES 0x0 /* General capabilities and ID */