Module Name: src Committed By: jmcneill Date: Fri Dec 24 00:27:22 UTC 2021
Modified Files: src/sys/dev/acpi: ehci_acpi.c Log Message: acpi: ehci: Don't assume that a transaction translator is available. Look for companion controllers using the rules in ACPI 6.3 section 9.14.1 "USB 2.0 Host Controllers and _UPC and _PLD", and only assume TT is present if we can't find a USB 1.1 companion. To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/dev/acpi/ehci_acpi.c 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/ehci_acpi.c diff -u src/sys/dev/acpi/ehci_acpi.c:1.8 src/sys/dev/acpi/ehci_acpi.c:1.9 --- src/sys/dev/acpi/ehci_acpi.c:1.8 Wed Dec 22 21:45:02 2021 +++ src/sys/dev/acpi/ehci_acpi.c Fri Dec 24 00:27:22 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: ehci_acpi.c,v 1.8 2021/12/22 21:45:02 skrll Exp $ */ +/* $NetBSD: ehci_acpi.c,v 1.9 2021/12/24 00:27:22 jmcneill Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ehci_acpi.c,v 1.8 2021/12/22 21:45:02 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ehci_acpi.c,v 1.9 2021/12/24 00:27:22 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -69,6 +69,8 @@ static void ehci_acpi_attach(device_t, d static void ehci_acpi_init(struct ehci_softc *); +static int ehci_acpi_num_companions(struct acpi_attach_args *); + CFATTACH_DECL2_NEW(ehci_acpi, sizeof(struct ehci_acpi_softc), ehci_acpi_match, ehci_acpi_attach, NULL, ehci_activate, NULL, ehci_childdet); @@ -94,12 +96,13 @@ ehci_acpi_attach(device_t parent, device int error; void *ih; + acpi_claim_childdevs(self, aa->aa_node); + asc->sc_handle = aa->aa_node->ad_handle; sc->sc_dev = self; sc->sc_bus.ub_hcpriv = sc; sc->sc_bus.ub_revision = USBREV_2_0; - sc->sc_flags = EHCIF_ETTF; sc->sc_vendor_init = ehci_acpi_init; rv = acpi_resource_parse(sc->sc_dev, asc->sc_handle, "_CRS", @@ -107,6 +110,10 @@ ehci_acpi_attach(device_t parent, device if (ACPI_FAILURE(rv)) return; + sc->sc_ncomp = ehci_acpi_num_companions(aa); + if (sc->sc_ncomp == 0) { + sc->sc_flags = EHCIF_ETTF; + } mem = acpi_res_mem(&res, 0); if (mem == NULL) { aprint_error_dev(self, "couldn't find mem resource\n"); @@ -174,3 +181,103 @@ ehci_acpi_init(struct ehci_softc *sc) acpi_usb_post_reset(asc->sc_handle); } + +static int +ehci_acpi_port_has_companion(struct acpi_devnode *portad, ACPI_INTEGER portno) +{ + struct acpi_devnode *ad; + ACPI_BUFFER portbuf, buf; + ACPI_OBJECT *portobj, *obj; + ACPI_OBJECT *portpld, *pld; + ACPI_STATUS rv; + int ncomp = 0; + + rv = acpi_eval_struct(portad->ad_handle, "_PLD", &portbuf); + if (ACPI_FAILURE(rv)) { + return 0; + } + portobj = portbuf.Pointer; + if (portobj->Type != ACPI_TYPE_PACKAGE || + portobj->Package.Count == 0 || + portobj->Package.Elements[0].Type != ACPI_TYPE_BUFFER) { + return 0; + } + portpld = &portobj->Package.Elements[0]; + + /* + * Look through all ACPI device nodes and try to find another + * one that matches our _PLD. If we have a match, it means we + * have a companion controller somewhere. + */ + SIMPLEQ_FOREACH(ad, &acpi_softc->sc_head, ad_list) { + if (ad == portad) { + continue; + } + rv = acpi_eval_struct(ad->ad_handle, "_PLD", &buf); + if (ACPI_FAILURE(rv)) { + continue; + } + obj = buf.Pointer; + if (obj->Type == ACPI_TYPE_PACKAGE && + obj->Package.Count != 0 && + obj->Package.Elements[0].Type == ACPI_TYPE_BUFFER) { + pld = &obj->Package.Elements[0]; + if (memcmp(pld->Buffer.Pointer, portpld->Buffer.Pointer, + pld->Buffer.Length) == 0) { + aprint_verbose_dev(portad->ad_device, + "companion port: %s\n", acpi_name(ad->ad_handle)); + ncomp = 1; + } + } + ACPI_FREE(buf.Pointer); + if (ncomp != 0) { + break; + } + } + + ACPI_FREE(portbuf.Pointer); + + return ncomp; +} + +static int +ehci_acpi_num_companion_ports(struct acpi_devnode *hubad) +{ + struct acpi_devnode *ad; + ACPI_STATUS rv; + ACPI_INTEGER val; + int ncomp = 0; + + /* Look for child ports with _ADR != 0 */ + SIMPLEQ_FOREACH(ad, &hubad->ad_child_head, ad_child_list) { + rv = acpi_eval_integer(ad->ad_handle, "_ADR", &val); + if (ACPI_SUCCESS(rv) && val != 0) { + ncomp += ehci_acpi_port_has_companion(ad, val); + } + } + + return ncomp; +} + +static int +ehci_acpi_num_companions(struct acpi_attach_args *aa) +{ + struct acpi_devnode *ad; + ACPI_STATUS rv; + ACPI_INTEGER val; + int ncomp = 0; + + /* Look for a child node with _ADR 0 that represents our root hub. */ + SIMPLEQ_FOREACH(ad, &aa->aa_node->ad_child_head, ad_child_list) { + rv = acpi_eval_integer(ad->ad_handle, "_ADR", &val); + if (ACPI_SUCCESS(rv) && val == 0) { + /* + * Count the number of ports on this hub. + */ + ncomp = ehci_acpi_num_companion_ports(ad); + break; + } + } + + return ncomp; +}