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 */ }; /*