Module Name: src
Committed By: jmcneill
Date: Wed Dec 18 21:19:52 UTC 2024
Modified Files:
src/sys/dev/acpi: acpi.c acpivar.h
Log Message:
acpi: Honour device dependencies ("_DEP" method).
When creating acpi_devnode devices, build a list of devnodes that are
direct dependencies of this node. The list of dependencies are parent
device nodes (if present), along with all devices returned by the _DEP
method.
When rescanning devices, make sure that all dependencies have been
scanned first. This ensures that drivers attach in the correct order.
To generate a diff of this commit:
cvs rdiff -u -r1.299 -r1.300 src/sys/dev/acpi/acpi.c
cvs rdiff -u -r1.92 -r1.93 src/sys/dev/acpi/acpivar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/acpi/acpi.c
diff -u src/sys/dev/acpi/acpi.c:1.299 src/sys/dev/acpi/acpi.c:1.300
--- src/sys/dev/acpi/acpi.c:1.299 Wed Mar 20 03:14:45 2024
+++ src/sys/dev/acpi/acpi.c Wed Dec 18 21:19:52 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi.c,v 1.299 2024/03/20 03:14:45 riastradh Exp $ */
+/* $NetBSD: acpi.c,v 1.300 2024/12/18 21:19:52 jmcneill Exp $ */
/*-
* Copyright (c) 2003, 2007 The NetBSD Foundation, Inc.
@@ -100,7 +100,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.299 2024/03/20 03:14:45 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.300 2024/12/18 21:19:52 jmcneill Exp $");
#include "pci.h"
#include "opt_acpi.h"
@@ -201,6 +201,7 @@ static bool acpi_suspend(device_t, cons
static bool acpi_resume(device_t, const pmf_qual_t *);
static void acpi_build_tree(struct acpi_softc *);
+static void acpi_find_deps(struct acpi_softc *);
static void acpi_config_tree(struct acpi_softc *);
static void acpi_config_dma(struct acpi_softc *);
static ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, uint32_t,
@@ -701,6 +702,11 @@ acpi_build_tree(struct acpi_softc *sc)
(void)AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, UINT32_MAX,
acpi_make_devnode, acpi_make_devnode_post, &awc, NULL);
+ /*
+ * Find device dependencies.
+ */
+ acpi_find_deps(sc);
+
#if NPCI > 0
/*
* Scan the internal namespace.
@@ -710,6 +716,86 @@ acpi_build_tree(struct acpi_softc *sc)
}
static void
+acpi_add_dep(struct acpi_devnode *ad, struct acpi_devnode *depad)
+{
+ struct acpi_devnodedep *dd;
+
+ dd = kmem_alloc(sizeof(*dd), KM_SLEEP);
+ dd->dd_node = depad;
+ SIMPLEQ_INSERT_TAIL(&ad->ad_deps, dd, dd_list);
+}
+
+static void
+acpi_find_deps(struct acpi_softc *sc)
+{
+ struct acpi_devnode *ad;
+
+ SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
+ struct acpi_devnode *depad;
+ ACPI_OBJECT *obj;
+ ACPI_HANDLE _dep;
+ ACPI_BUFFER buf;
+ ACPI_STATUS rv;
+ u_int ref;
+
+ if (acpi_is_scope(ad) ||
+ ad->ad_parent == NULL ||
+ ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) {
+ continue;
+ }
+
+ /* Add an implicit dependency on parent devices. */
+ if (!acpi_is_scope(ad->ad_parent) &&
+ ad->ad_parent->ad_devinfo->Type == ACPI_TYPE_DEVICE) {
+ acpi_add_dep(ad, ad->ad_parent);
+ }
+
+ rv = AcpiGetHandle(ad->ad_handle, "_DEP", &_dep);
+ if (ACPI_FAILURE(rv)) {
+ goto logit;
+ }
+
+ buf.Pointer = NULL;
+ buf.Length = ACPI_ALLOCATE_BUFFER;
+ rv = AcpiEvaluateObjectTyped(_dep, NULL, NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(rv)) {
+ goto logit;
+ }
+ obj = buf.Pointer;
+
+ for (ref = 0; ref < obj->Package.Count; ref++) {
+ ACPI_OBJECT *robj = &obj->Package.Elements[ref];
+ ACPI_HANDLE rhdl;
+
+ rv = acpi_eval_reference_handle(robj, &rhdl);
+ if (ACPI_FAILURE(rv)) {
+ continue;
+ }
+
+ depad = acpi_match_node(rhdl);
+ if (depad != NULL) {
+ acpi_add_dep(ad, depad);
+ }
+ }
+
+ ACPI_FREE(buf.Pointer);
+
+logit:
+ if (!SIMPLEQ_EMPTY(&ad->ad_deps)) {
+ struct acpi_devnodedep *dd;
+
+ aprint_debug_dev(sc->sc_dev, "%s dependencies:",
+ ad->ad_name);
+ SIMPLEQ_FOREACH(dd, &ad->ad_deps, dd_list) {
+ aprint_debug(" %s", dd->dd_node->ad_name);
+ }
+ aprint_debug("\n");
+ }
+ }
+}
+
+static void
acpi_config_tree(struct acpi_softc *sc)
{
/*
@@ -809,6 +895,7 @@ acpi_make_devnode(ACPI_HANDLE handle, ui
SIMPLEQ_INIT(&ad->ad_child_head);
SIMPLEQ_INSERT_TAIL(&sc->sc_head, ad, ad_list);
+ SIMPLEQ_INIT(&ad->ad_deps);
if (ad->ad_parent != NULL) {
@@ -935,9 +1022,62 @@ acpi_rescan(device_t self, const char *i
}
static void
-acpi_rescan_early(struct acpi_softc *sc)
+acpi_rescan_node(struct acpi_softc *sc, struct acpi_devnode *ad)
{
+ const char * const hpet_ids[] = { "PNP0103", NULL };
struct acpi_attach_args aa;
+ struct acpi_devnodedep *dd;
+ ACPI_DEVICE_INFO *di = ad->ad_devinfo;
+
+ if (ad->ad_scanned || ad->ad_device != NULL) {
+ return;
+ }
+
+ /*
+ * Mark as scanned before checking dependencies to
+ * break out of dependency cycles.
+ */
+ ad->ad_scanned = true;
+
+ if (!acpi_device_present(ad->ad_handle)) {
+ return;
+ }
+
+ if (acpi_match_hid(di, acpi_ignored_ids) != 0) {
+ return;
+ }
+
+ if (acpi_match_hid(di, hpet_ids) != 0 && sc->sc_hpet != NULL) {
+ return;
+ }
+
+ /* Rescan dependencies first. */
+ SIMPLEQ_FOREACH(dd, &ad->ad_deps, dd_list) {
+ if (!dd->dd_node->ad_scanned) {
+ acpi_rescan_node(sc, dd->dd_node);
+ }
+ }
+
+ aa.aa_node = ad;
+ aa.aa_iot = sc->sc_iot;
+ aa.aa_memt = sc->sc_memt;
+ if (ad->ad_pciinfo != NULL) {
+ aa.aa_pc = ad->ad_pciinfo->ap_pc;
+ aa.aa_pciflags = sc->sc_pciflags;
+ }
+ aa.aa_ic = sc->sc_ic;
+ aa.aa_dmat = ad->ad_dmat;
+ aa.aa_dmat64 = ad->ad_dmat64;
+
+ ad->ad_device = config_found(sc->sc_dev, &aa, acpi_print,
+ CFARGS(.iattr = "acpinodebus",
+ .devhandle = devhandle_from_acpi(devhandle_invalid(),
+ ad->ad_handle)));
+}
+
+static void
+acpi_rescan_early(struct acpi_softc *sc)
+{
struct acpi_devnode *ad;
/*
@@ -959,32 +1099,21 @@ acpi_rescan_early(struct acpi_softc *sc)
KASSERT(ad->ad_handle != NULL);
- aa.aa_node = ad;
- aa.aa_iot = sc->sc_iot;
- aa.aa_memt = sc->sc_memt;
- if (ad->ad_pciinfo != NULL) {
- aa.aa_pc = ad->ad_pciinfo->ap_pc;
- aa.aa_pciflags = sc->sc_pciflags;
- }
- aa.aa_ic = sc->sc_ic;
- aa.aa_dmat = ad->ad_dmat;
- aa.aa_dmat64 = ad->ad_dmat64;
-
- ad->ad_device = config_found(sc->sc_dev, &aa, acpi_print,
- CFARGS(.iattr = "acpinodebus",
- .devhandle = devhandle_from_acpi(devhandle_invalid(),
- ad->ad_handle)));
+ acpi_rescan_node(sc, ad);
}
}
static void
acpi_rescan_nodes(struct acpi_softc *sc)
{
- const char * const hpet_ids[] = { "PNP0103", NULL };
- struct acpi_attach_args aa;
struct acpi_devnode *ad;
ACPI_DEVICE_INFO *di;
+ /* Reset scan state. */
+ SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
+ ad->ad_scanned = false;
+ }
+
SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
if (ad->ad_device != NULL)
@@ -1019,29 +1148,9 @@ acpi_rescan_nodes(struct acpi_softc *sc)
if (acpi_match_hid(di, acpi_early_ids) != 0)
continue;
- if (acpi_match_hid(di, acpi_ignored_ids) != 0)
- continue;
-
- if (acpi_match_hid(di, hpet_ids) != 0 && sc->sc_hpet != NULL)
- continue;
-
KASSERT(ad->ad_handle != NULL);
- aa.aa_node = ad;
- aa.aa_iot = sc->sc_iot;
- aa.aa_memt = sc->sc_memt;
- if (ad->ad_pciinfo != NULL) {
- aa.aa_pc = ad->ad_pciinfo->ap_pc;
- aa.aa_pciflags = sc->sc_pciflags;
- }
- aa.aa_ic = sc->sc_ic;
- aa.aa_dmat = ad->ad_dmat;
- aa.aa_dmat64 = ad->ad_dmat64;
-
- ad->ad_device = config_found(sc->sc_dev, &aa, acpi_print,
- CFARGS(.iattr = "acpinodebus",
- .devhandle = devhandle_from_acpi(devhandle_invalid(),
- ad->ad_handle)));
+ acpi_rescan_node(sc, ad);
}
}
Index: src/sys/dev/acpi/acpivar.h
diff -u src/sys/dev/acpi/acpivar.h:1.92 src/sys/dev/acpi/acpivar.h:1.93
--- src/sys/dev/acpi/acpivar.h:1.92 Mon Dec 9 22:10:25 2024
+++ src/sys/dev/acpi/acpivar.h Wed Dec 18 21:19:52 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: acpivar.h,v 1.92 2024/12/09 22:10:25 jmcneill Exp $ */
+/* $NetBSD: acpivar.h,v 1.93 2024/12/18 21:19:52 jmcneill Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -102,6 +102,12 @@ struct acpi_pci_info {
#define ACPI_PCI_INFO_DEVICE __BIT(0) /* PCI device */
#define ACPI_PCI_INFO_BRIDGE __BIT(1) /* PCI bridge */
+/* Represents a device node dependency. */
+struct acpi_devnodedep {
+ SIMPLEQ_ENTRY(acpi_devnodedep) dd_list;
+ struct acpi_devnode *dd_node;
+};
+
/*
* An ACPI device node.
*
@@ -142,6 +148,9 @@ struct acpi_devnode {
SIMPLEQ_ENTRY(acpi_devnode) ad_list;
SIMPLEQ_ENTRY(acpi_devnode) ad_child_list;
SIMPLEQ_HEAD(, acpi_devnode) ad_child_head;
+ SIMPLEQ_HEAD(, acpi_devnodedep) ad_deps;
+
+ bool ad_scanned; /* private: acpi_rescan state */
};
/*