Module Name: src Committed By: gsutre Date: Tue Oct 26 22:27:44 UTC 2010
Modified Files: src/sys/dev/acpi: acpi_display.c acpi_pci.c acpi_verbose.c acpivar.h Log Message: An _ADR object is not required for PCI root bridges. To solve this, the structure acpi_pciinfo now tells whether the ACPI device node is a PCI bridge, a regular PCI device, or both. Problem reported by jmcneill@, who also suggested the solution. ok jmcneill@, jruoho@ To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/dev/acpi/acpi_display.c cvs rdiff -u -r1.15 -r1.16 src/sys/dev/acpi/acpi_pci.c cvs rdiff -u -r1.11 -r1.12 src/sys/dev/acpi/acpi_verbose.c cvs rdiff -u -r1.64 -r1.65 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_display.c diff -u src/sys/dev/acpi/acpi_display.c:1.2 src/sys/dev/acpi/acpi_display.c:1.3 --- src/sys/dev/acpi/acpi_display.c:1.2 Mon Oct 25 17:06:58 2010 +++ src/sys/dev/acpi/acpi_display.c Tue Oct 26 22:27:44 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_display.c,v 1.2 2010/10/25 17:06:58 jruoho Exp $ */ +/* $NetBSD: acpi_display.c,v 1.3 2010/10/26 22:27:44 gsutre Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_display.c,v 1.2 2010/10/25 17:06:58 jruoho Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_display.c,v 1.3 2010/10/26 22:27:44 gsutre Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -406,7 +406,9 @@ return 0; ap = ad->ad_pciinfo; - if ((ap == NULL) || (ap->ap_function == 0xffff)) + if ((ap == NULL) || + !(ap->ap_flags & ACPI_PCI_INFO_DEVICE) || + (ap->ap_function == 0xffff)) return 0; KASSERT(ap->ap_bus < 256 && ap->ap_device < 32 && ap->ap_function < 8); Index: src/sys/dev/acpi/acpi_pci.c diff -u src/sys/dev/acpi/acpi_pci.c:1.15 src/sys/dev/acpi/acpi_pci.c:1.16 --- src/sys/dev/acpi/acpi_pci.c:1.15 Fri Sep 24 07:48:59 2010 +++ src/sys/dev/acpi/acpi_pci.c Tue Oct 26 22:27:44 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_pci.c,v 1.15 2010/09/24 07:48:59 gsutre Exp $ */ +/* $NetBSD: acpi_pci.c,v 1.16 2010/10/26 22:27:44 gsutre Exp $ */ /* * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.15 2010/09/24 07:48:59 gsutre Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.16 2010/10/26 22:27:44 gsutre Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -158,6 +158,10 @@ * PCI device if it has an ancestor that is a PCI root bridge and such * that all intermediate nodes are PCI-to-PCI bridges. Depth-first * recursive implementation. + * + * PCI root bridges do not necessarily contain an _ADR, since they already + * contain an _HID (ACPI 4.0a, p. 197). However we require an _ADR for + * all non-root PCI devices. */ ACPI_STATUS acpi_pcidev_scan(struct acpi_devnode *ad) @@ -169,16 +173,14 @@ ad->ad_pciinfo = NULL; - if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE || - !(ad->ad_devinfo->Valid & ACPI_VALID_ADR)) - goto rec; - /* * We attach PCI information only to devices that are present, * enabled, and functioning properly. * Note: there is a possible race condition, because _STA may * have changed since ad->ad_devinfo->CurrentStatus was set. */ + if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) + goto rec; if ((ad->ad_devinfo->Valid & ACPI_VALID_STA) != 0 && (ad->ad_devinfo->CurrentStatus & ACPI_STA_OK) != ACPI_STA_OK) goto rec; @@ -201,29 +203,43 @@ if (ACPI_SUCCESS(rv)) ap->ap_segment = ACPI_LOWORD(val); - /* Try to get bus number using _CRS first. */ - rv = acpi_pcidev_pciroot_bus(ad->ad_handle, &ap->ap_bus); + /* Try to get downstream bus number using _CRS first. */ + rv = acpi_pcidev_pciroot_bus(ad->ad_handle, &ap->ap_downbus); if (ACPI_FAILURE(rv)) { rv = acpi_eval_integer(ad->ad_handle, "_BBN", &val); if (ACPI_SUCCESS(rv)) - ap->ap_bus = ACPI_LOWORD(val); + ap->ap_downbus = ACPI_LOWORD(val); } - ap->ap_device = ACPI_HILODWORD(ad->ad_devinfo->Address); - ap->ap_function = ACPI_LOLODWORD(ad->ad_devinfo->Address); - - if (ap->ap_bus > 255 || ap->ap_device > 31 || - (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) { + if (ap->ap_downbus > 255) { aprint_error_dev(ad->ad_root, - "invalid PCI address for %s\n", ad->ad_name); + "invalid PCI downstream bus for %s\n", ad->ad_name); kmem_free(ap, sizeof(*ap)); goto rec; } - ap->ap_bridge = true; - ap->ap_downbus = ap->ap_bus; + ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; + + /* + * This ACPI node denotes a PCI root bridge, but it may also + * denote a PCI device on the bridge's downstream bus segment. + */ + if (ad->ad_devinfo->Valid & ACPI_VALID_ADR) { + ap->ap_bus = ap->ap_downbus; + ap->ap_device = + ACPI_HILODWORD(ad->ad_devinfo->Address); + ap->ap_function = + ACPI_LOLODWORD(ad->ad_devinfo->Address); + + if (ap->ap_device > 31 || + (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) + aprint_error_dev(ad->ad_root, + "invalid PCI address for %s\n", ad->ad_name); + else + ap->ap_flags |= ACPI_PCI_INFO_DEVICE; + } ad->ad_pciinfo = ap; @@ -232,7 +248,8 @@ if ((ad->ad_parent != NULL) && (ad->ad_parent->ad_pciinfo != NULL) && - (ad->ad_parent->ad_pciinfo->ap_bridge)) { + (ad->ad_parent->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) && + (ad->ad_devinfo->Valid & ACPI_VALID_ADR)) { /* * Our parent is a PCI root bridge or a PCI-to-PCI @@ -258,12 +275,13 @@ goto rec; } + ap->ap_flags |= ACPI_PCI_INFO_DEVICE; + if (ap->ap_function == 0xFFFF) { /* * Assume that this device is not a PCI-to-PCI bridge. * XXX: Do we need to be smarter? */ - ap->ap_bridge = false; } else { /* * Check whether this device is a PCI-to-PCI @@ -272,7 +290,8 @@ rv = acpi_pcidev_ppb_downbus(ap->ap_segment, ap->ap_bus, ap->ap_device, ap->ap_function, &ap->ap_downbus); - ap->ap_bridge = (rv != AE_OK) ? false : true; + if (ACPI_SUCCESS(rv)) + ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; } ad->ad_pciinfo = ap; @@ -356,6 +375,7 @@ SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { if (ad->ad_pciinfo != NULL && + (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_DEVICE) && ad->ad_pciinfo->ap_segment == segment && ad->ad_pciinfo->ap_bus == bus && ad->ad_pciinfo->ap_device == device && Index: src/sys/dev/acpi/acpi_verbose.c diff -u src/sys/dev/acpi/acpi_verbose.c:1.11 src/sys/dev/acpi/acpi_verbose.c:1.12 --- src/sys/dev/acpi/acpi_verbose.c:1.11 Fri Sep 24 07:48:59 2010 +++ src/sys/dev/acpi/acpi_verbose.c Tue Oct 26 22:27:44 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_verbose.c,v 1.11 2010/09/24 07:48:59 gsutre Exp $ */ +/* $NetBSD: acpi_verbose.c,v 1.12 2010/10/26 22:27:44 gsutre Exp $ */ /*- * Copyright (c) 2003, 2007, 2010 The NetBSD Foundation, Inc. @@ -65,7 +65,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_verbose.c,v 1.11 2010/09/24 07:48:59 gsutre Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_verbose.c,v 1.12 2010/10/26 22:27:44 gsutre Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -466,29 +466,35 @@ for (i = 0; i < level; i++) aprint_normal(" "); - aprint_normal("%-5s [%02u] [%c%c] ", ad->ad_name, ad->ad_type, + aprint_normal("%-5s [%02u] [%c%c]", ad->ad_name, ad->ad_type, ((ad->ad_flags & ACPI_DEVICE_POWER) != 0) ? 'P' : ' ', ((ad->ad_flags & ACPI_DEVICE_WAKEUP) != 0) ? 'W' : ' '); if (ad->ad_device != NULL) - aprint_normal("<%s> ", device_xname(ad->ad_device)); + aprint_normal(" <%s>", device_xname(ad->ad_device)); if (ad->ad_pciinfo != NULL) { - aprint_normal("(PCI) @ 0x%02X:0x%02X:0x%02X:0x%02X ", - ad->ad_pciinfo->ap_segment, ad->ad_pciinfo->ap_bus, - ad->ad_pciinfo->ap_device, ad->ad_pciinfo->ap_function); + aprint_normal(" (PCI)"); + + if ((ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_DEVICE) != 0) + aprint_normal(" @ 0x%02X:0x%02X:0x%02X:0x%02X", + ad->ad_pciinfo->ap_segment, + ad->ad_pciinfo->ap_bus, + ad->ad_pciinfo->ap_device, + ad->ad_pciinfo->ap_function); if ((ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) - aprint_normal("[R] "); + aprint_normal(" [R]"); - if (ad->ad_pciinfo->ap_bridge != false) - aprint_normal("[B] -> 0x%02X ", + if ((ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) != 0) + aprint_normal(" [B] -> 0x%02X:0x%02X", + ad->ad_pciinfo->ap_segment, ad->ad_pciinfo->ap_downbus); pcidev = device_find_by_acpi_pci_info(ad->ad_pciinfo); if (pcidev != NULL) - aprint_normal("<%s>", device_xname(pcidev)); + aprint_normal(" <%s>", device_xname(pcidev)); } aprint_normal("\n"); Index: src/sys/dev/acpi/acpivar.h diff -u src/sys/dev/acpi/acpivar.h:1.64 src/sys/dev/acpi/acpivar.h:1.65 --- src/sys/dev/acpi/acpivar.h:1.64 Sun Oct 24 07:53:04 2010 +++ src/sys/dev/acpi/acpivar.h Tue Oct 26 22:27:44 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpivar.h,v 1.64 2010/10/24 07:53:04 jruoho Exp $ */ +/* $NetBSD: acpivar.h,v 1.65 2010/10/26 22:27:44 gsutre Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -72,22 +72,34 @@ * ap_bus <= 255 * ap_device <= 31 * ap_function <= 7 or ap_function == 0xFFFF - * ap_downbus <= 255 if ap_bridge == true + * ap_downbus <= 255 + * + * Validity of some fields depends on the value of ap_flags: + * + * ap_segment always valid + * ap_bus, ap_device, ap_function valid for PCI devices + * ap_downbus valid for PCI bridges * * The device and function numbers are encoded in the value returned by * _ADR. A function number of 0xFFFF is used to refer to all the * functions on a PCI device (ACPI 4.0a, p. 200). */ struct acpi_pci_info { + uint16_t ap_flags; /* Flags (cf. below) */ uint16_t ap_segment; /* PCI segment group */ uint16_t ap_bus; /* PCI bus */ uint16_t ap_device; /* PCI device */ uint16_t ap_function; /* PCI function */ - bool ap_bridge; /* PCI bridge (PHB or PPB) */ uint16_t ap_downbus; /* PCI bridge downstream bus */ }; /* + * Flags for PCI information. + */ +#define ACPI_PCI_INFO_DEVICE __BIT(0) /* PCI device */ +#define ACPI_PCI_INFO_BRIDGE __BIT(1) /* PCI bridge */ + +/* * An ACPI device node. * * Remarks: