aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/acpica/acpi.c3
-rw-r--r--sys/dev/acpica/acpi_hpet.c79
-rw-r--r--sys/dev/acpica/acpivar.h1
3 files changed, 51 insertions, 32 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index bd57ec33a75b..038363cdc37f 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -143,7 +143,6 @@ static void acpi_probe_children(device_t bus);
static void acpi_probe_order(ACPI_HANDLE handle, int *order);
static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level,
void *context, void **status);
-static BOOLEAN acpi_MatchHid(ACPI_HANDLE h, const char *hid);
static void acpi_sleep_enable(void *arg);
static ACPI_STATUS acpi_sleep_disable(struct acpi_softc *sc);
static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, int state);
@@ -1924,7 +1923,7 @@ acpi_BatteryIsPresent(device_t dev)
/*
* Match a HID string against a handle
*/
-static BOOLEAN
+BOOLEAN
acpi_MatchHid(ACPI_HANDLE h, const char *hid)
{
ACPI_DEVICE_INFO *devinfo;
diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c
index a98a8260f953..b3f666f41ce0 100644
--- a/sys/dev/acpica/acpi_hpet.c
+++ b/sys/dev/acpica/acpi_hpet.c
@@ -101,41 +101,60 @@ hpet_disable(struct acpi_hpet_softc *sc)
bus_write_4(sc->mem_res, HPET_CONFIG, val);
}
+static ACPI_STATUS
+acpi_hpet_find(ACPI_HANDLE handle, UINT32 level, void *context,
+ void **status)
+{
+ char **ids;
+ uint32_t id = (uint32_t)(uintptr_t)context;
+ uint32_t uid = 0;
+
+ for (ids = hpet_ids; *ids != NULL; ids++) {
+ if (acpi_MatchHid(handle, *ids))
+ break;
+ }
+ if (*ids == NULL)
+ return (AE_OK);
+ if (ACPI_FAILURE(acpi_GetInteger(handle, "_UID", &uid)))
+ uid = 0;
+ if (id == uid)
+ *((int *)status) = 1;
+ return (AE_OK);
+}
+
/* Discover the HPET via the ACPI table of the same name. */
static void
acpi_hpet_identify(driver_t *driver, device_t parent)
{
ACPI_TABLE_HPET *hpet;
- ACPI_TABLE_HEADER *hdr;
ACPI_STATUS status;
device_t child;
+ int i, found;
/* Only one HPET device can be added. */
if (devclass_get_device(acpi_hpet_devclass, 0))
return;
-
- /* Currently, ID and minimum clock tick info is unused. */
-
- status = AcpiGetTable(ACPI_SIG_HPET, 1, (ACPI_TABLE_HEADER **)&hdr);
- if (ACPI_FAILURE(status))
- return;
-
- /*
- * The unit number could be derived from hdr->Sequence but we only
- * support one HPET device.
- */
- hpet = (ACPI_TABLE_HPET *)hdr;
- if (hpet->Sequence != 0)
- printf("ACPI HPET table warning: Sequence is non-zero (%d)\n",
- hpet->Sequence);
- child = BUS_ADD_CHILD(parent, ACPI_DEV_BASE_ORDER, "acpi_hpet", 0);
- if (child == NULL) {
- printf("%s: can't add child\n", __func__);
- return;
+ for (i = 1; ; i++) {
+ /* Search for HPET table. */
+ status = AcpiGetTable(ACPI_SIG_HPET, i, (ACPI_TABLE_HEADER **)&hpet);
+ if (ACPI_FAILURE(status))
+ return;
+ /* Search for HPET device with same ID. */
+ found = 0;
+ AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ 100, acpi_hpet_find, NULL, (void *)(uintptr_t)hpet->Sequence, (void *)&found);
+ /* If found - let it be probed in normal way. */
+ if (found)
+ continue;
+ /* If not - create it from table info. */
+ child = BUS_ADD_CHILD(parent, ACPI_DEV_BASE_ORDER, "acpi_hpet", 0);
+ if (child == NULL) {
+ printf("%s: can't add child\n", __func__);
+ continue;
+ }
+ bus_set_resource(child, SYS_RES_MEMORY, 0, hpet->Address.Address,
+ HPET_MEM_WIDTH);
}
-
- bus_set_resource(child, SYS_RES_MEMORY, 0, hpet->Address.Address,
- HPET_MEM_WIDTH);
}
static int
@@ -146,8 +165,7 @@ acpi_hpet_probe(device_t dev)
if (acpi_disabled("hpet"))
return (ENXIO);
if (acpi_get_handle(dev) != NULL &&
- (ACPI_ID_PROBE(device_get_parent(dev), dev, hpet_ids) == NULL ||
- device_get_unit(dev) != 0))
+ ACPI_ID_PROBE(device_get_parent(dev), dev, hpet_ids) == NULL)
return (ENXIO);
device_set_desc(dev, "High Precision Event Timer");
@@ -233,11 +251,12 @@ acpi_hpet_attach(device_t dev)
bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
return (ENXIO);
}
-
- hpet_timecounter.tc_frequency = freq;
- hpet_timecounter.tc_priv = sc;
- tc_init(&hpet_timecounter);
-
+ /* Announce first HPET as timecounter. */
+ if (device_get_unit(dev) == 0) {
+ hpet_timecounter.tc_frequency = freq;
+ hpet_timecounter.tc_priv = sc;
+ tc_init(&hpet_timecounter);
+ }
return (0);
}
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index b0f2c93b8f74..84a8d4c78a29 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -344,6 +344,7 @@ int acpi_bus_alloc_gas(device_t dev, int *type, int *rid,
u_int flags);
void acpi_walk_subtables(void *first, void *end,
acpi_subtable_handler *handler, void *arg);
+BOOLEAN acpi_MatchHid(ACPI_HANDLE h, const char *hid);
struct acpi_parse_resource_set {
void (*set_init)(device_t dev, void *arg, void **context);