xref: /netbsd-src/sys/dev/acpi/acpi_pci.c (revision 1099f047a0006cc19f46e1118dd280c2811d7696)
1*1099f047Sjmcneill /* $NetBSD: acpi_pci.c,v 1.37 2022/10/14 22:10:15 jmcneill Exp $ */
282b81a0cScegger 
382b81a0cScegger /*
4b3ff23fbSjruoho  * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
582b81a0cScegger  * All rights reserved.
682b81a0cScegger  *
782b81a0cScegger  * This code is derived from software contributed to The NetBSD Foundation
8b3ff23fbSjruoho  * by Christoph Egger and Gregoire Sutre.
982b81a0cScegger  *
1082b81a0cScegger  * Redistribution and use in source and binary forms, with or without
1182b81a0cScegger  * modification, are permitted provided that the following conditions
1282b81a0cScegger  * are met:
1382b81a0cScegger  * 1. Redistributions of source code must retain the above copyright
1482b81a0cScegger  *    notice, this list of conditions and the following disclaimer.
1582b81a0cScegger  * 2. The name of the author may not be used to endorse or promote products
1682b81a0cScegger  *    derived from this software without specific prior written permission.
1782b81a0cScegger  *
1882b81a0cScegger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1982b81a0cScegger  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2082b81a0cScegger  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2182b81a0cScegger  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2282b81a0cScegger  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2382b81a0cScegger  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2482b81a0cScegger  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2582b81a0cScegger  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2682b81a0cScegger  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2782b81a0cScegger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2882b81a0cScegger  * SUCH DAMAGE.
2982b81a0cScegger  */
3082b81a0cScegger 
3182b81a0cScegger #include <sys/cdefs.h>
32*1099f047Sjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.37 2022/10/14 22:10:15 jmcneill Exp $");
3382b81a0cScegger 
3482b81a0cScegger #include <sys/param.h>
3582b81a0cScegger #include <sys/device.h>
3682b81a0cScegger #include <sys/kmem.h>
375a425210Sjruoho #include <sys/systm.h>
3882b81a0cScegger 
39b3ff23fbSjruoho #include <dev/pci/pcireg.h>
40aa705fc9Sjruoho #include <dev/pci/pcivar.h>
41b3ff23fbSjruoho #include <dev/pci/pcidevs.h>
42b3ff23fbSjruoho #include <dev/pci/ppbreg.h>
43b3ff23fbSjruoho 
444ecce2b2Sthorpej #include <dev/pci/pci_calls.h>
454ecce2b2Sthorpej 
4682b81a0cScegger #include <dev/acpi/acpireg.h>
4782b81a0cScegger #include <dev/acpi/acpivar.h>
4882b81a0cScegger #include <dev/acpi/acpi_pci.h>
4982b81a0cScegger 
50aa705fc9Sjruoho #include "locators.h"
51aa705fc9Sjruoho 
52b3ff23fbSjruoho #define _COMPONENT	  ACPI_BUS_COMPONENT
53b3ff23fbSjruoho ACPI_MODULE_NAME	  ("acpi_pci")
5482b81a0cScegger 
551af445daSjruoho #define ACPI_HILODWORD(x) ACPI_HIWORD(ACPI_LODWORD((x)))
561af445daSjruoho #define ACPI_LOLODWORD(x) ACPI_LOWORD(ACPI_LODWORD((x)))
571af445daSjruoho 
58b3ff23fbSjruoho static ACPI_STATUS	  acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *,
59b3ff23fbSjruoho 							   void *);
6082b81a0cScegger 
6182b81a0cScegger /*
62727f1f57Sjruoho  * Regarding PCI Segment Groups (ACPI 4.0, p. 277):
6382b81a0cScegger  *
64b3ff23fbSjruoho  * "The optional _SEG object is located under a PCI host bridge and
65b3ff23fbSjruoho  *  evaluates to an integer that describes the PCI Segment Group (see PCI
66b3ff23fbSjruoho  *  Firmware Specification v3.0)."
67b3ff23fbSjruoho  *
68727f1f57Sjruoho  * "PCI Segment Group is purely a software concept managed by system
69727f1f57Sjruoho  *  firmware and used by OSPM. It is a logical collection of PCI buses
70727f1f57Sjruoho  *  (or bus segments). It is a way to logically group the PCI bus segments
71727f1f57Sjruoho  *  and PCI Express Hierarchies. _SEG is a level higher than _BBN."
72727f1f57Sjruoho  *
73b3ff23fbSjruoho  * "PCI Segment Group supports more than 256 buses in a system by allowing
74b3ff23fbSjruoho  *  the reuse of the PCI bus numbers.  Within each PCI Segment Group, the bus
75b3ff23fbSjruoho  *  numbers for the PCI buses must be unique. PCI buses in different PCI
76b3ff23fbSjruoho  *  Segment Group are permitted to have the same bus number."
7782b81a0cScegger  */
78b3ff23fbSjruoho 
7982b81a0cScegger /*
80727f1f57Sjruoho  * Regarding PCI Base Bus Numbers (ACPI 4.0, p. 277):
81b3ff23fbSjruoho  *
82b3ff23fbSjruoho  * "For multi-root PCI platforms, the _BBN object evaluates to the PCI bus
83b3ff23fbSjruoho  *  number that the BIOS assigns.  This is needed to access a PCI_Config
84b3ff23fbSjruoho  *  operation region for the specified bus.  The _BBN object is located under
85b3ff23fbSjruoho  *  a PCI host bridge and must be unique for every host bridge within a
86b3ff23fbSjruoho  *  segment since it is the PCI bus number."
87b3ff23fbSjruoho  *
88b3ff23fbSjruoho  * Moreover, the ACPI FAQ (http://www.acpi.info/acpi_faq.htm) says:
89b3ff23fbSjruoho  *
90b3ff23fbSjruoho  * "For a multiple root bus machine, _BBN is required for each bus.  _BBN
91b3ff23fbSjruoho  *  should provide the bus number assigned to this bus by the BIOS at boot
92b3ff23fbSjruoho  *  time."
9382b81a0cScegger  */
94b3ff23fbSjruoho 
95b3ff23fbSjruoho /*
96b3ff23fbSjruoho  * acpi_pcidev_pciroot_bus:
97b3ff23fbSjruoho  *
98b3ff23fbSjruoho  *	Derive the PCI bus number of a PCI root bridge from its resources.
99b3ff23fbSjruoho  *	If successful, return AE_OK and fill *busp.  Otherwise, return an
100b3ff23fbSjruoho  *	exception code and leave *busp unchanged.
101b3ff23fbSjruoho  */
102b878b401Sjmcneill ACPI_STATUS
acpi_pcidev_pciroot_bus(ACPI_HANDLE handle,uint16_t * busp)103b3ff23fbSjruoho acpi_pcidev_pciroot_bus(ACPI_HANDLE handle, uint16_t *busp)
104b3ff23fbSjruoho {
105b3ff23fbSjruoho 	ACPI_STATUS rv;
106b3ff23fbSjruoho 	int32_t bus;
107b3ff23fbSjruoho 
108b3ff23fbSjruoho 	bus = -1;
109727f1f57Sjruoho 
110727f1f57Sjruoho 	/*
111727f1f57Sjruoho 	 * XXX:	Use the ACPI resource parsing functions (acpi_resource.c)
112727f1f57Sjruoho 	 *	once bus number ranges have been implemented there.
113727f1f57Sjruoho 	 */
114727f1f57Sjruoho 	rv = AcpiWalkResources(handle, "_CRS",
115b3ff23fbSjruoho 	    acpi_pcidev_pciroot_bus_callback, &bus);
116b3ff23fbSjruoho 
117b3ff23fbSjruoho 	if (ACPI_FAILURE(rv))
118b3ff23fbSjruoho 		return rv;
119b3ff23fbSjruoho 
120a9c05683Sgsutre 	if (bus == -1)
121b3ff23fbSjruoho 		return AE_NOT_EXIST;
122b3ff23fbSjruoho 
123a9c05683Sgsutre 	/* Here it holds that 0 <= bus <= 0xFFFF. */
124b3ff23fbSjruoho 	*busp = (uint16_t)bus;
125e0aec4e1Sjruoho 
126b3ff23fbSjruoho 	return rv;
12782b81a0cScegger }
12882b81a0cScegger 
129b3ff23fbSjruoho static ACPI_STATUS
acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE * res,void * context)130b3ff23fbSjruoho acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *res, void *context)
131b3ff23fbSjruoho {
132b3ff23fbSjruoho 	ACPI_RESOURCE_ADDRESS64 addr64;
133e0aec4e1Sjruoho 	int32_t *bus = context;
134b3ff23fbSjruoho 
135e0aec4e1Sjruoho 	/* Always continue the walk by returning AE_OK. */
136b3ff23fbSjruoho 	if ((res->Type != ACPI_RESOURCE_TYPE_ADDRESS16) &&
137b3ff23fbSjruoho 	    (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
138b3ff23fbSjruoho 	    (res->Type != ACPI_RESOURCE_TYPE_ADDRESS64))
139e0aec4e1Sjruoho 		return AE_OK;
140b3ff23fbSjruoho 
141b3ff23fbSjruoho 	if (ACPI_FAILURE(AcpiResourceToAddress64(res, &addr64)))
142e0aec4e1Sjruoho 		return AE_OK;
143b3ff23fbSjruoho 
144b3ff23fbSjruoho 	if (addr64.ResourceType != ACPI_BUS_NUMBER_RANGE)
145e0aec4e1Sjruoho 		return AE_OK;
146b3ff23fbSjruoho 
147b3ff23fbSjruoho 	if (*bus != -1)
148b3ff23fbSjruoho 		return AE_ALREADY_EXISTS;
149b3ff23fbSjruoho 
1506252065cSchristos 	if (addr64.Address.Minimum > 0xFFFF)
151a9c05683Sgsutre 		return AE_BAD_DATA;
152a9c05683Sgsutre 
1536252065cSchristos 	*bus = (int32_t)addr64.Address.Minimum;
154e0aec4e1Sjruoho 
155e0aec4e1Sjruoho 	return AE_OK;
15682b81a0cScegger }
15782b81a0cScegger 
158b3ff23fbSjruoho /*
159bdb6986fSjruoho  * acpi_pcidev_scan:
160b3ff23fbSjruoho  *
161b3ff23fbSjruoho  *	Scan the ACPI device tree for PCI devices.  A node is detected as a
162b3ff23fbSjruoho  *	PCI device if it has an ancestor that is a PCI root bridge and such
163b3ff23fbSjruoho  *	that all intermediate nodes are PCI-to-PCI bridges.  Depth-first
164b3ff23fbSjruoho  *	recursive implementation.
165af565a28Sgsutre  *
166af565a28Sgsutre  *	PCI root bridges do not necessarily contain an _ADR, since they already
167af565a28Sgsutre  *	contain an _HID (ACPI 4.0a, p. 197).  However we require an _ADR for
168af565a28Sgsutre  *	all non-root PCI devices.
169b3ff23fbSjruoho  */
170bdb6986fSjruoho ACPI_STATUS
acpi_pcidev_scan(struct acpi_devnode * ad)171bdb6986fSjruoho acpi_pcidev_scan(struct acpi_devnode *ad)
172b3ff23fbSjruoho {
173b3ff23fbSjruoho 	struct acpi_devnode *child;
174b3ff23fbSjruoho 	struct acpi_pci_info *ap;
175b3ff23fbSjruoho 	ACPI_INTEGER val;
176b3ff23fbSjruoho 	ACPI_STATUS rv;
177b3ff23fbSjruoho 
178b3ff23fbSjruoho 	ad->ad_pciinfo = NULL;
179110cd99bSgsutre 
180474664a9Sgsutre 	/*
181474664a9Sgsutre 	 * We attach PCI information only to devices that are present,
182474664a9Sgsutre 	 * enabled, and functioning properly.
183474664a9Sgsutre 	 * Note: there is a possible race condition, because _STA may
184474664a9Sgsutre 	 * have changed since ad->ad_devinfo->CurrentStatus was set.
185474664a9Sgsutre 	 */
186af565a28Sgsutre 	if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE)
187af565a28Sgsutre 		goto rec;
188474664a9Sgsutre 
189a2cf80f2Schristos 	if (!acpi_device_present(ad->ad_handle))
190a2cf80f2Schristos 		goto rec;
191a2cf80f2Schristos 
192b3ff23fbSjruoho 	if (ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) {
193e0aec4e1Sjruoho 
194b3ff23fbSjruoho 		ap = kmem_zalloc(sizeof(*ap), KM_SLEEP);
195e0aec4e1Sjruoho 
196727f1f57Sjruoho 		/*
197727f1f57Sjruoho 		 * If no _SEG exist, all PCI bus segments are assumed
198727f1f57Sjruoho 		 * to be in the PCI segment group 0 (ACPI 4.0, p. 277).
199727f1f57Sjruoho 		 * The segment group number is conveyed in the lower
200727f1f57Sjruoho 		 * 16 bits of _SEG (the other bits are all reserved).
201727f1f57Sjruoho 		 */
202e0aec4e1Sjruoho 		rv = acpi_eval_integer(ad->ad_handle, "_SEG", &val);
203e0aec4e1Sjruoho 
204b3ff23fbSjruoho 		if (ACPI_SUCCESS(rv))
205b3ff23fbSjruoho 			ap->ap_segment = ACPI_LOWORD(val);
20682b81a0cScegger 
207af565a28Sgsutre 		/* Try to get downstream bus number using _CRS first. */
208af565a28Sgsutre 		rv = acpi_pcidev_pciroot_bus(ad->ad_handle, &ap->ap_downbus);
209e0aec4e1Sjruoho 
210b3ff23fbSjruoho 		if (ACPI_FAILURE(rv)) {
211e0aec4e1Sjruoho 			rv = acpi_eval_integer(ad->ad_handle, "_BBN", &val);
212e0aec4e1Sjruoho 
213b3ff23fbSjruoho 			if (ACPI_SUCCESS(rv))
214af565a28Sgsutre 				ap->ap_downbus = ACPI_LOWORD(val);
215b3ff23fbSjruoho 		}
21682b81a0cScegger 
217af565a28Sgsutre 		if (ap->ap_downbus > 255) {
218110cd99bSgsutre 			aprint_error_dev(ad->ad_root,
219af565a28Sgsutre 			    "invalid PCI downstream bus for %s\n", ad->ad_name);
220110cd99bSgsutre 			kmem_free(ap, sizeof(*ap));
221110cd99bSgsutre 			goto rec;
222110cd99bSgsutre 		}
223110cd99bSgsutre 
224af565a28Sgsutre 		ap->ap_flags |= ACPI_PCI_INFO_BRIDGE;
225af565a28Sgsutre 
2266f25f864Sjmcneill 		ap->ap_pc = acpi_get_pci_chipset_tag(acpi_softc, ap->ap_segment, ap->ap_downbus);
2276f25f864Sjmcneill 
228af565a28Sgsutre 		/*
229af565a28Sgsutre 		 * This ACPI node denotes a PCI root bridge, but it may also
230af565a28Sgsutre 		 * denote a PCI device on the bridge's downstream bus segment.
231af565a28Sgsutre 		 */
232af565a28Sgsutre 		if (ad->ad_devinfo->Valid & ACPI_VALID_ADR) {
233af565a28Sgsutre 			ap->ap_bus = ap->ap_downbus;
234af565a28Sgsutre 			ap->ap_device =
235af565a28Sgsutre 			    ACPI_HILODWORD(ad->ad_devinfo->Address);
236af565a28Sgsutre 			ap->ap_function =
237af565a28Sgsutre 			    ACPI_LOLODWORD(ad->ad_devinfo->Address);
238af565a28Sgsutre 
239af565a28Sgsutre 			if (ap->ap_device > 31 ||
240af565a28Sgsutre 			    (ap->ap_function > 7 && ap->ap_function != 0xFFFF))
241af565a28Sgsutre 				aprint_error_dev(ad->ad_root,
242af565a28Sgsutre 				    "invalid PCI address for %s\n", ad->ad_name);
243af565a28Sgsutre 			else
244af565a28Sgsutre 				ap->ap_flags |= ACPI_PCI_INFO_DEVICE;
245af565a28Sgsutre 		}
246b3ff23fbSjruoho 
247b3ff23fbSjruoho 		ad->ad_pciinfo = ap;
248e0aec4e1Sjruoho 
249b3ff23fbSjruoho 		goto rec;
250b3ff23fbSjruoho 	}
251b3ff23fbSjruoho 
252b3ff23fbSjruoho 	if ((ad->ad_parent != NULL) &&
253b3ff23fbSjruoho 	    (ad->ad_parent->ad_pciinfo != NULL) &&
254af565a28Sgsutre 	    (ad->ad_parent->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) &&
255af565a28Sgsutre 	    (ad->ad_devinfo->Valid & ACPI_VALID_ADR)) {
256727f1f57Sjruoho 
257b3ff23fbSjruoho 		/*
258727f1f57Sjruoho 		 * Our parent is a PCI root bridge or a PCI-to-PCI
259727f1f57Sjruoho 		 * bridge. We have the same PCI segment number, and
260727f1f57Sjruoho 		 * our bus number is its downstream bus number.
261b3ff23fbSjruoho 		 */
262b3ff23fbSjruoho 		ap = kmem_zalloc(sizeof(*ap), KM_SLEEP);
263e0aec4e1Sjruoho 
2646f25f864Sjmcneill 		ap->ap_pc = ad->ad_parent->ad_pciinfo->ap_pc;
265b3ff23fbSjruoho 		ap->ap_segment = ad->ad_parent->ad_pciinfo->ap_segment;
266b3ff23fbSjruoho 		ap->ap_bus = ad->ad_parent->ad_pciinfo->ap_downbus;
2671af445daSjruoho 
2681af445daSjruoho 		ap->ap_device = ACPI_HILODWORD(ad->ad_devinfo->Address);
2691af445daSjruoho 		ap->ap_function = ACPI_LOLODWORD(ad->ad_devinfo->Address);
270b3ff23fbSjruoho 
271a9c05683Sgsutre 		if (ap->ap_device > 31 ||
272a9c05683Sgsutre 		    (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) {
273110cd99bSgsutre 			aprint_error_dev(ad->ad_root,
274110cd99bSgsutre 			    "invalid PCI address for %s\n", ad->ad_name);
275110cd99bSgsutre 			kmem_free(ap, sizeof(*ap));
276110cd99bSgsutre 			goto rec;
277110cd99bSgsutre 		}
278110cd99bSgsutre 
279af565a28Sgsutre 		ap->ap_flags |= ACPI_PCI_INFO_DEVICE;
280af565a28Sgsutre 
281a9c05683Sgsutre 		if (ap->ap_function == 0xFFFF) {
282a9c05683Sgsutre 			/*
283a9c05683Sgsutre 			 * Assume that this device is not a PCI-to-PCI bridge.
284a9c05683Sgsutre 			 * XXX: Do we need to be smarter?
285a9c05683Sgsutre 			 */
286a9c05683Sgsutre 		} else {
287b3ff23fbSjruoho 			/*
288727f1f57Sjruoho 			 * Check whether this device is a PCI-to-PCI
289727f1f57Sjruoho 			 * bridge and get its secondary bus number.
290b3ff23fbSjruoho 			 */
2916f25f864Sjmcneill 			rv = acpi_pcidev_ppb_downbus(
2926f25f864Sjmcneill 			    ad->ad_parent->ad_pciinfo->ap_pc,
2936f25f864Sjmcneill 			    ap->ap_segment, ap->ap_bus, ap->ap_device,
2946f25f864Sjmcneill 			    ap->ap_function, &ap->ap_downbus);
295b3ff23fbSjruoho 
296af565a28Sgsutre 			if (ACPI_SUCCESS(rv))
297af565a28Sgsutre 				ap->ap_flags |= ACPI_PCI_INFO_BRIDGE;
298a9c05683Sgsutre 		}
299a9c05683Sgsutre 
300b3ff23fbSjruoho 		ad->ad_pciinfo = ap;
301e0aec4e1Sjruoho 
302b3ff23fbSjruoho 		goto rec;
303b3ff23fbSjruoho 	}
304bdb6986fSjruoho 
305b3ff23fbSjruoho rec:
306b3ff23fbSjruoho 	SIMPLEQ_FOREACH(child, &ad->ad_child_head, ad_child_list) {
307bdb6986fSjruoho 		rv = acpi_pcidev_scan(child);
308e0aec4e1Sjruoho 
309b3ff23fbSjruoho 		if (ACPI_FAILURE(rv))
310b3ff23fbSjruoho 			return rv;
311b3ff23fbSjruoho 	}
312b3ff23fbSjruoho 
313b3ff23fbSjruoho 	return AE_OK;
314b3ff23fbSjruoho }
315b3ff23fbSjruoho 
316b3ff23fbSjruoho /*
317b3ff23fbSjruoho  * acpi_pcidev_ppb_downbus:
318b3ff23fbSjruoho  *
319b3ff23fbSjruoho  *	Retrieve the secondary bus number of the PCI-to-PCI bridge having the
320110cd99bSgsutre  *	given PCI id.  If successful, return AE_OK and fill *downbus.
321110cd99bSgsutre  *	Otherwise, return an exception code and leave *downbus unchanged.
322b3ff23fbSjruoho  *
323b3ff23fbSjruoho  * XXX	Need to deal with PCI segment groups (see also acpica/OsdHardware.c).
324b3ff23fbSjruoho  */
325b3ff23fbSjruoho ACPI_STATUS
acpi_pcidev_ppb_downbus(pci_chipset_tag_t pc,uint16_t segment,uint16_t bus,uint16_t device,uint16_t function,uint16_t * downbus)3266f25f864Sjmcneill acpi_pcidev_ppb_downbus(pci_chipset_tag_t pc, uint16_t segment, uint16_t bus,
3276f25f864Sjmcneill     uint16_t device, uint16_t function, uint16_t *downbus)
328b3ff23fbSjruoho {
329b3ff23fbSjruoho 	pcitag_t tag;
330b3ff23fbSjruoho 	pcireg_t val;
331b3ff23fbSjruoho 
332b3ff23fbSjruoho 	if (bus > 255 || device > 31 || function > 7)
333b3ff23fbSjruoho 		return AE_BAD_PARAMETER;
334b3ff23fbSjruoho 
335b3ff23fbSjruoho 	tag = pci_make_tag(pc, bus, device, function);
336b3ff23fbSjruoho 
337b3ff23fbSjruoho 	/* Check that this device exists. */
338b3ff23fbSjruoho 	val = pci_conf_read(pc, tag, PCI_ID_REG);
339e0aec4e1Sjruoho 
340b3ff23fbSjruoho 	if (PCI_VENDOR(val) == PCI_VENDOR_INVALID ||
341b3ff23fbSjruoho 	    PCI_VENDOR(val) == 0)
342b3ff23fbSjruoho 		return AE_NOT_EXIST;
343b3ff23fbSjruoho 
344b3ff23fbSjruoho 	/* Check that this device is a PCI-to-PCI bridge. */
345b3ff23fbSjruoho 	val = pci_conf_read(pc, tag, PCI_BHLC_REG);
346e0aec4e1Sjruoho 
347b3ff23fbSjruoho 	if (PCI_HDRTYPE_TYPE(val) != PCI_HDRTYPE_PPB)
348b3ff23fbSjruoho 		return AE_TYPE;
349b3ff23fbSjruoho 
350b3ff23fbSjruoho 	/* This is a PCI-to-PCI bridge.  Get its secondary bus#. */
35179770474Smsaitoh 	val = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG);
35279770474Smsaitoh 	*downbus = PCI_BRIDGE_BUS_NUM_SECONDARY(val);
353e0aec4e1Sjruoho 
354b3ff23fbSjruoho 	return AE_OK;
35582b81a0cScegger }
35682b81a0cScegger 
35782b81a0cScegger /*
35882b81a0cScegger  * acpi_pcidev_find:
35982b81a0cScegger  *
36082b81a0cScegger  *      Finds a PCI device in the ACPI name space.
36184377acdSjruoho  *
36284377acdSjruoho  *      Returns an ACPI device node on success and NULL on failure.
36382b81a0cScegger  */
36484377acdSjruoho struct acpi_devnode *
acpi_pcidev_find(uint16_t segment,uint16_t bus,uint16_t device,uint16_t function)36584377acdSjruoho acpi_pcidev_find(uint16_t segment, uint16_t bus,
36684377acdSjruoho     uint16_t device, uint16_t function)
36782b81a0cScegger {
368b3ff23fbSjruoho 	struct acpi_softc *sc = acpi_softc;
369b3ff23fbSjruoho 	struct acpi_devnode *ad;
37082b81a0cScegger 
371b3ff23fbSjruoho 	if (sc == NULL)
37284377acdSjruoho 		return NULL;
37382b81a0cScegger 
374de6a49e8Sskrll 	SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
375e0aec4e1Sjruoho 
37684377acdSjruoho 		if (ad->ad_pciinfo != NULL &&
377af565a28Sgsutre 		    (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_DEVICE) &&
37884377acdSjruoho 		    ad->ad_pciinfo->ap_segment == segment &&
37984377acdSjruoho 		    ad->ad_pciinfo->ap_bus == bus &&
38084377acdSjruoho 		    ad->ad_pciinfo->ap_device == device &&
38184377acdSjruoho 		    ad->ad_pciinfo->ap_function == function)
38284377acdSjruoho 			return ad;
383b3ff23fbSjruoho 	}
384e0aec4e1Sjruoho 
38584377acdSjruoho 	return NULL;
38682b81a0cScegger }
387aa705fc9Sjruoho 
3887a0ad363Sjmcneill /*
3896f25f864Sjmcneill  * acpi_pcidev_get_tag:
3906f25f864Sjmcneill  *
3916f25f864Sjmcneill  *	Returns a PCI chipset tag for a PCI device in the ACPI name space.
3926f25f864Sjmcneill  */
3936f25f864Sjmcneill pci_chipset_tag_t
acpi_pcidev_get_tag(uint16_t segment,uint16_t bus,uint16_t device,uint16_t function)3946f25f864Sjmcneill acpi_pcidev_get_tag(uint16_t segment, uint16_t bus,
3956f25f864Sjmcneill     uint16_t device, uint16_t function)
3966f25f864Sjmcneill {
3976f25f864Sjmcneill 	struct acpi_devnode *ad;
3986f25f864Sjmcneill 
3996f25f864Sjmcneill 	ad = acpi_pcidev_find(segment, bus, device, function);
4006f25f864Sjmcneill 	if (ad == NULL || ad->ad_pciinfo == NULL)
4016f25f864Sjmcneill 		return NULL;
4026f25f864Sjmcneill 
4036f25f864Sjmcneill 	return ad->ad_pciinfo->ap_pc;
4046f25f864Sjmcneill }
4056f25f864Sjmcneill 
4066f25f864Sjmcneill /*
4077a0ad363Sjmcneill  * acpi_pciroot_find:
4087a0ad363Sjmcneill  *
4097a0ad363Sjmcneill  *	Finds a PCI root bridge in the ACPI name space.
4107a0ad363Sjmcneill  *
4117a0ad363Sjmcneill  *	Returns an ACPI device node on success and NULL on failure.
4127a0ad363Sjmcneill  */
4137a0ad363Sjmcneill struct acpi_devnode *
acpi_pciroot_find(uint16_t segment,uint16_t bus)4147a0ad363Sjmcneill acpi_pciroot_find(uint16_t segment, uint16_t bus)
4157a0ad363Sjmcneill {
4167a0ad363Sjmcneill 	struct acpi_softc *sc = acpi_softc;
4177a0ad363Sjmcneill 	struct acpi_devnode *ad;
4187a0ad363Sjmcneill 
4197a0ad363Sjmcneill 	if (sc == NULL)
4207a0ad363Sjmcneill 		return NULL;
4217a0ad363Sjmcneill 
422de6a49e8Sskrll 	SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
4237a0ad363Sjmcneill 
4247a0ad363Sjmcneill 		if (ad->ad_pciinfo != NULL &&
4257a0ad363Sjmcneill 		    (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) &&
4267a0ad363Sjmcneill 		    ad->ad_pciinfo->ap_segment == segment &&
4277a0ad363Sjmcneill 		    ad->ad_pciinfo->ap_bus == bus)
4287a0ad363Sjmcneill 			return ad;
4297a0ad363Sjmcneill 	}
4307a0ad363Sjmcneill 
4317a0ad363Sjmcneill 	return NULL;
4327a0ad363Sjmcneill }
433aa705fc9Sjruoho 
434aa705fc9Sjruoho /*
435aa705fc9Sjruoho  * acpi_pcidev_find_dev:
436aa705fc9Sjruoho  *
437aa705fc9Sjruoho  *	Returns the device corresponding to the given PCI info, or NULL
438aa705fc9Sjruoho  *	if it doesn't exist.
439aa705fc9Sjruoho  */
440aa705fc9Sjruoho device_t
acpi_pcidev_find_dev(struct acpi_devnode * ad)44139621064Sjruoho acpi_pcidev_find_dev(struct acpi_devnode *ad)
442aa705fc9Sjruoho {
44339621064Sjruoho 	struct acpi_pci_info *ap;
444aa705fc9Sjruoho 	struct pci_softc *pci;
445aa705fc9Sjruoho 	device_t dv, pr;
446aa705fc9Sjruoho 	deviter_t di;
447aa705fc9Sjruoho 
44839621064Sjruoho 	if (ad == NULL)
449aa705fc9Sjruoho 		return NULL;
450aa705fc9Sjruoho 
45139621064Sjruoho 	if (ad->ad_pciinfo == NULL)
45239621064Sjruoho 		return NULL;
45339621064Sjruoho 
45439621064Sjruoho 	ap = ad->ad_pciinfo;
45539621064Sjruoho 
456aa705fc9Sjruoho 	if (ap->ap_function == 0xFFFF)
457aa705fc9Sjruoho 		return NULL;
458aa705fc9Sjruoho 
459aa705fc9Sjruoho 	for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
460aa705fc9Sjruoho 	     dv != NULL; dv = deviter_next(&di)) {
461aa705fc9Sjruoho 
462aa705fc9Sjruoho 		pr = device_parent(dv);
463aa705fc9Sjruoho 
464aa705fc9Sjruoho 		if (pr == NULL || device_is_a(pr, "pci") != true)
465aa705fc9Sjruoho 			continue;
466aa705fc9Sjruoho 
467aa705fc9Sjruoho 		pci = device_private(pr);
468aa705fc9Sjruoho 
469aa705fc9Sjruoho 		if (pci->sc_bus == ap->ap_bus &&
470aa705fc9Sjruoho 		    device_locator(dv, PCICF_DEV) == ap->ap_device &&
471aa705fc9Sjruoho 		    device_locator(dv, PCICF_FUNCTION) == ap->ap_function)
472aa705fc9Sjruoho 			break;
473aa705fc9Sjruoho 	}
474aa705fc9Sjruoho 
475aa705fc9Sjruoho 	deviter_release(&di);
476aa705fc9Sjruoho 
477aa705fc9Sjruoho 	return dv;
478aa705fc9Sjruoho }
47916d1d113Sjmcneill 
48016d1d113Sjmcneill /*
4814c5901a8Sthorpej  * acpi_pci_bus_get_child_devhandle:
4824c5901a8Sthorpej  *
4834c5901a8Sthorpej  *	Implements the "pci-bus-get-child-devhandle" device call for
4844c5901a8Sthorpej  *	ACPI device handles
4854c5901a8Sthorpej  */
4864c5901a8Sthorpej static int
acpi_pci_bus_get_child_devhandle(device_t dev,devhandle_t call_handle,void * v)4874c5901a8Sthorpej acpi_pci_bus_get_child_devhandle(device_t dev, devhandle_t call_handle, void *v)
4884c5901a8Sthorpej {
4894c5901a8Sthorpej 	struct pci_bus_get_child_devhandle_args *args = v;
4904c5901a8Sthorpej 	struct acpi_devnode *ad;
4914c5901a8Sthorpej 	ACPI_HANDLE hdl;
4924c5901a8Sthorpej 	int b, d, f;
4934c5901a8Sthorpej 	u_int segment;
4944c5901a8Sthorpej 
4954c5901a8Sthorpej 	segment = pci_get_segment(args->pc);
4964c5901a8Sthorpej 
4974c5901a8Sthorpej 	pci_decompose_tag(args->pc, args->tag, &b, &d, &f);
4984c5901a8Sthorpej 
4994c5901a8Sthorpej 	ad = acpi_pcidev_find(segment, b, d, f);
5004c5901a8Sthorpej 
5014c5901a8Sthorpej 	if (ad != NULL && (hdl = ad->ad_handle) != NULL) {
5024c5901a8Sthorpej 		/* Found it! */
5033944ff70Sthorpej 		args->devhandle = devhandle_from_acpi(call_handle, hdl);
5044c5901a8Sthorpej 		return 0;
5054c5901a8Sthorpej 	}
5064c5901a8Sthorpej 
5074c5901a8Sthorpej 	return ENODEV;
5084c5901a8Sthorpej }
5094ecce2b2Sthorpej ACPI_DEVICE_CALL_REGISTER(PCI_BUS_GET_CHILD_DEVHANDLE_STR,
5104c5901a8Sthorpej 			  acpi_pci_bus_get_child_devhandle)
511