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