git: 972ea9cc57fd - stable/13 - hpet: Allow a MMIO window smaller than 1K

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Wed, 27 Apr 2022 13:47:10 UTC
The branch stable/13 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=972ea9cc57fd9c13c118dab0d8797e6716fdc171

commit 972ea9cc57fd9c13c118dab0d8797e6716fdc171
Author:     John F. Carr <jfc@mit.edu>
AuthorDate: 2022-03-19 22:51:43 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2022-04-27 13:33:56 +0000

    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
    
    (cherry picked from commit 964bf2f902c5e05381018532e5d9d456979d4bf7)
---
 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 */