| @@ -1,582 +1,579 @@ | | | @@ -1,582 +1,579 @@ |
1 | /* $NetBSD: acpi_pci.c,v 1.34 2022/01/22 11:49:17 thorpej Exp $ */ | | 1 | /* $NetBSD: acpi_pci.c,v 1.35 2022/02/11 23:19:59 riastradh Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Christoph Egger and Gregoire Sutre. | | 8 | * by Christoph Egger and Gregoire Sutre. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. The name of the author may not be used to endorse or promote products | | 15 | * 2. The name of the author may not be used to endorse or promote products |
16 | * derived from this software without specific prior written permission. | | 16 | * derived from this software without specific prior written permission. |
17 | * | | 17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 | * SUCH DAMAGE. | | 28 | * SUCH DAMAGE. |
29 | */ | | 29 | */ |
30 | | | 30 | |
31 | #include <sys/cdefs.h> | | 31 | #include <sys/cdefs.h> |
32 | __KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.34 2022/01/22 11:49:17 thorpej Exp $"); | | 32 | __KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.35 2022/02/11 23:19:59 riastradh Exp $"); |
33 | | | 33 | |
34 | #include <sys/param.h> | | 34 | #include <sys/param.h> |
35 | #include <sys/device.h> | | 35 | #include <sys/device.h> |
36 | #include <sys/kmem.h> | | 36 | #include <sys/kmem.h> |
37 | #include <sys/systm.h> | | 37 | #include <sys/systm.h> |
38 | | | 38 | |
39 | #include <dev/pci/pcireg.h> | | 39 | #include <dev/pci/pcireg.h> |
40 | #include <dev/pci/pcivar.h> | | 40 | #include <dev/pci/pcivar.h> |
41 | #include <dev/pci/pcidevs.h> | | 41 | #include <dev/pci/pcidevs.h> |
42 | #include <dev/pci/ppbreg.h> | | 42 | #include <dev/pci/ppbreg.h> |
43 | | | 43 | |
44 | #include <dev/pci/pci_calls.h> | | 44 | #include <dev/pci/pci_calls.h> |
45 | | | 45 | |
46 | #include <dev/acpi/acpireg.h> | | 46 | #include <dev/acpi/acpireg.h> |
47 | #include <dev/acpi/acpivar.h> | | 47 | #include <dev/acpi/acpivar.h> |
48 | #include <dev/acpi/acpi_pci.h> | | 48 | #include <dev/acpi/acpi_pci.h> |
49 | | | 49 | |
50 | #include "locators.h" | | 50 | #include "locators.h" |
51 | | | 51 | |
52 | #define _COMPONENT ACPI_BUS_COMPONENT | | 52 | #define _COMPONENT ACPI_BUS_COMPONENT |
53 | ACPI_MODULE_NAME ("acpi_pci") | | 53 | ACPI_MODULE_NAME ("acpi_pci") |
54 | | | 54 | |
55 | #define ACPI_HILODWORD(x) ACPI_HIWORD(ACPI_LODWORD((x))) | | 55 | #define ACPI_HILODWORD(x) ACPI_HIWORD(ACPI_LODWORD((x))) |
56 | #define ACPI_LOLODWORD(x) ACPI_LOWORD(ACPI_LODWORD((x))) | | 56 | #define ACPI_LOLODWORD(x) ACPI_LOWORD(ACPI_LODWORD((x))) |
57 | | | 57 | |
58 | static ACPI_STATUS acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *, | | 58 | static ACPI_STATUS acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *, |
59 | void *); | | 59 | void *); |
60 | | | 60 | |
61 | /* | | 61 | /* |
62 | * UUID for _DSM control method, from PCI Firmware Specification. | | 62 | * UUID for _DSM control method, from PCI Firmware Specification. |
63 | */ | | 63 | */ |
64 | static UINT8 acpi_pci_dsm_uuid[ACPI_UUID_LENGTH] = { | | 64 | static UINT8 acpi_pci_dsm_uuid[ACPI_UUID_LENGTH] = { |
65 | 0xd0, 0x37, 0xc9, 0xe5, 0x53, 0x35, 0x7a, 0x4d, | | 65 | 0xd0, 0x37, 0xc9, 0xe5, 0x53, 0x35, 0x7a, 0x4d, |
66 | 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d | | 66 | 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d |
67 | }; | | 67 | }; |
68 | | | 68 | |
69 | /* | | 69 | /* |
70 | * Regarding PCI Segment Groups (ACPI 4.0, p. 277): | | 70 | * Regarding PCI Segment Groups (ACPI 4.0, p. 277): |
71 | * | | 71 | * |
72 | * "The optional _SEG object is located under a PCI host bridge and | | 72 | * "The optional _SEG object is located under a PCI host bridge and |
73 | * evaluates to an integer that describes the PCI Segment Group (see PCI | | 73 | * evaluates to an integer that describes the PCI Segment Group (see PCI |
74 | * Firmware Specification v3.0)." | | 74 | * Firmware Specification v3.0)." |
75 | * | | 75 | * |
76 | * "PCI Segment Group is purely a software concept managed by system | | 76 | * "PCI Segment Group is purely a software concept managed by system |
77 | * firmware and used by OSPM. It is a logical collection of PCI buses | | 77 | * firmware and used by OSPM. It is a logical collection of PCI buses |
78 | * (or bus segments). It is a way to logically group the PCI bus segments | | 78 | * (or bus segments). It is a way to logically group the PCI bus segments |
79 | * and PCI Express Hierarchies. _SEG is a level higher than _BBN." | | 79 | * and PCI Express Hierarchies. _SEG is a level higher than _BBN." |
80 | * | | 80 | * |
81 | * "PCI Segment Group supports more than 256 buses in a system by allowing | | 81 | * "PCI Segment Group supports more than 256 buses in a system by allowing |
82 | * the reuse of the PCI bus numbers. Within each PCI Segment Group, the bus | | 82 | * the reuse of the PCI bus numbers. Within each PCI Segment Group, the bus |
83 | * numbers for the PCI buses must be unique. PCI buses in different PCI | | 83 | * numbers for the PCI buses must be unique. PCI buses in different PCI |
84 | * Segment Group are permitted to have the same bus number." | | 84 | * Segment Group are permitted to have the same bus number." |
85 | */ | | 85 | */ |
86 | | | 86 | |
87 | /* | | 87 | /* |
88 | * Regarding PCI Base Bus Numbers (ACPI 4.0, p. 277): | | 88 | * Regarding PCI Base Bus Numbers (ACPI 4.0, p. 277): |
89 | * | | 89 | * |
90 | * "For multi-root PCI platforms, the _BBN object evaluates to the PCI bus | | 90 | * "For multi-root PCI platforms, the _BBN object evaluates to the PCI bus |
91 | * number that the BIOS assigns. This is needed to access a PCI_Config | | 91 | * number that the BIOS assigns. This is needed to access a PCI_Config |
92 | * operation region for the specified bus. The _BBN object is located under | | 92 | * operation region for the specified bus. The _BBN object is located under |
93 | * a PCI host bridge and must be unique for every host bridge within a | | 93 | * a PCI host bridge and must be unique for every host bridge within a |
94 | * segment since it is the PCI bus number." | | 94 | * segment since it is the PCI bus number." |
95 | * | | 95 | * |
96 | * Moreover, the ACPI FAQ (http://www.acpi.info/acpi_faq.htm) says: | | 96 | * Moreover, the ACPI FAQ (http://www.acpi.info/acpi_faq.htm) says: |
97 | * | | 97 | * |
98 | * "For a multiple root bus machine, _BBN is required for each bus. _BBN | | 98 | * "For a multiple root bus machine, _BBN is required for each bus. _BBN |
99 | * should provide the bus number assigned to this bus by the BIOS at boot | | 99 | * should provide the bus number assigned to this bus by the BIOS at boot |
100 | * time." | | 100 | * time." |
101 | */ | | 101 | */ |
102 | | | 102 | |
103 | /* | | 103 | /* |
104 | * acpi_pcidev_pciroot_bus: | | 104 | * acpi_pcidev_pciroot_bus: |
105 | * | | 105 | * |
106 | * Derive the PCI bus number of a PCI root bridge from its resources. | | 106 | * Derive the PCI bus number of a PCI root bridge from its resources. |
107 | * If successful, return AE_OK and fill *busp. Otherwise, return an | | 107 | * If successful, return AE_OK and fill *busp. Otherwise, return an |
108 | * exception code and leave *busp unchanged. | | 108 | * exception code and leave *busp unchanged. |
109 | */ | | 109 | */ |
110 | ACPI_STATUS | | 110 | ACPI_STATUS |
111 | acpi_pcidev_pciroot_bus(ACPI_HANDLE handle, uint16_t *busp) | | 111 | acpi_pcidev_pciroot_bus(ACPI_HANDLE handle, uint16_t *busp) |
112 | { | | 112 | { |
113 | ACPI_STATUS rv; | | 113 | ACPI_STATUS rv; |
114 | int32_t bus; | | 114 | int32_t bus; |
115 | | | 115 | |
116 | bus = -1; | | 116 | bus = -1; |
117 | | | 117 | |
118 | /* | | 118 | /* |
119 | * XXX: Use the ACPI resource parsing functions (acpi_resource.c) | | 119 | * XXX: Use the ACPI resource parsing functions (acpi_resource.c) |
120 | * once bus number ranges have been implemented there. | | 120 | * once bus number ranges have been implemented there. |
121 | */ | | 121 | */ |
122 | rv = AcpiWalkResources(handle, "_CRS", | | 122 | rv = AcpiWalkResources(handle, "_CRS", |
123 | acpi_pcidev_pciroot_bus_callback, &bus); | | 123 | acpi_pcidev_pciroot_bus_callback, &bus); |
124 | | | 124 | |
125 | if (ACPI_FAILURE(rv)) | | 125 | if (ACPI_FAILURE(rv)) |
126 | return rv; | | 126 | return rv; |
127 | | | 127 | |
128 | if (bus == -1) | | 128 | if (bus == -1) |
129 | return AE_NOT_EXIST; | | 129 | return AE_NOT_EXIST; |
130 | | | 130 | |
131 | /* Here it holds that 0 <= bus <= 0xFFFF. */ | | 131 | /* Here it holds that 0 <= bus <= 0xFFFF. */ |
132 | *busp = (uint16_t)bus; | | 132 | *busp = (uint16_t)bus; |
133 | | | 133 | |
134 | return rv; | | 134 | return rv; |
135 | } | | 135 | } |
136 | | | 136 | |
137 | static ACPI_STATUS | | 137 | static ACPI_STATUS |
138 | acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *res, void *context) | | 138 | acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *res, void *context) |
139 | { | | 139 | { |
140 | ACPI_RESOURCE_ADDRESS64 addr64; | | 140 | ACPI_RESOURCE_ADDRESS64 addr64; |
141 | int32_t *bus = context; | | 141 | int32_t *bus = context; |
142 | | | 142 | |
143 | /* Always continue the walk by returning AE_OK. */ | | 143 | /* Always continue the walk by returning AE_OK. */ |
144 | if ((res->Type != ACPI_RESOURCE_TYPE_ADDRESS16) && | | 144 | if ((res->Type != ACPI_RESOURCE_TYPE_ADDRESS16) && |
145 | (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32) && | | 145 | (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32) && |
146 | (res->Type != ACPI_RESOURCE_TYPE_ADDRESS64)) | | 146 | (res->Type != ACPI_RESOURCE_TYPE_ADDRESS64)) |
147 | return AE_OK; | | 147 | return AE_OK; |
148 | | | 148 | |
149 | if (ACPI_FAILURE(AcpiResourceToAddress64(res, &addr64))) | | 149 | if (ACPI_FAILURE(AcpiResourceToAddress64(res, &addr64))) |
150 | return AE_OK; | | 150 | return AE_OK; |
151 | | | 151 | |
152 | if (addr64.ResourceType != ACPI_BUS_NUMBER_RANGE) | | 152 | if (addr64.ResourceType != ACPI_BUS_NUMBER_RANGE) |
153 | return AE_OK; | | 153 | return AE_OK; |
154 | | | 154 | |
155 | if (*bus != -1) | | 155 | if (*bus != -1) |
156 | return AE_ALREADY_EXISTS; | | 156 | return AE_ALREADY_EXISTS; |
157 | | | 157 | |
158 | if (addr64.Address.Minimum > 0xFFFF) | | 158 | if (addr64.Address.Minimum > 0xFFFF) |
159 | return AE_BAD_DATA; | | 159 | return AE_BAD_DATA; |
160 | | | 160 | |
161 | *bus = (int32_t)addr64.Address.Minimum; | | 161 | *bus = (int32_t)addr64.Address.Minimum; |
162 | | | 162 | |
163 | return AE_OK; | | 163 | return AE_OK; |
164 | } | | 164 | } |
165 | | | 165 | |
166 | /* | | 166 | /* |
167 | * acpi_pcidev_scan: | | 167 | * acpi_pcidev_scan: |
168 | * | | 168 | * |
169 | * Scan the ACPI device tree for PCI devices. A node is detected as a | | 169 | * Scan the ACPI device tree for PCI devices. A node is detected as a |
170 | * PCI device if it has an ancestor that is a PCI root bridge and such | | 170 | * PCI device if it has an ancestor that is a PCI root bridge and such |
171 | * that all intermediate nodes are PCI-to-PCI bridges. Depth-first | | 171 | * that all intermediate nodes are PCI-to-PCI bridges. Depth-first |
172 | * recursive implementation. | | 172 | * recursive implementation. |
173 | * | | 173 | * |
174 | * PCI root bridges do not necessarily contain an _ADR, since they already | | 174 | * PCI root bridges do not necessarily contain an _ADR, since they already |
175 | * contain an _HID (ACPI 4.0a, p. 197). However we require an _ADR for | | 175 | * contain an _HID (ACPI 4.0a, p. 197). However we require an _ADR for |
176 | * all non-root PCI devices. | | 176 | * all non-root PCI devices. |
177 | */ | | 177 | */ |
178 | ACPI_STATUS | | 178 | ACPI_STATUS |
179 | acpi_pcidev_scan(struct acpi_devnode *ad) | | 179 | acpi_pcidev_scan(struct acpi_devnode *ad) |
180 | { | | 180 | { |
181 | struct acpi_devnode *child; | | 181 | struct acpi_devnode *child; |
182 | struct acpi_pci_info *ap; | | 182 | struct acpi_pci_info *ap; |
183 | ACPI_INTEGER val; | | 183 | ACPI_INTEGER val; |
184 | ACPI_STATUS rv; | | 184 | ACPI_STATUS rv; |
185 | | | 185 | |
186 | ad->ad_pciinfo = NULL; | | 186 | ad->ad_pciinfo = NULL; |
187 | | | 187 | |
188 | /* | | 188 | /* |
189 | * We attach PCI information only to devices that are present, | | 189 | * We attach PCI information only to devices that are present, |
190 | * enabled, and functioning properly. | | 190 | * enabled, and functioning properly. |
191 | * Note: there is a possible race condition, because _STA may | | 191 | * Note: there is a possible race condition, because _STA may |
192 | * have changed since ad->ad_devinfo->CurrentStatus was set. | | 192 | * have changed since ad->ad_devinfo->CurrentStatus was set. |
193 | */ | | 193 | */ |
194 | if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) | | 194 | if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) |
195 | goto rec; | | 195 | goto rec; |
196 | | | 196 | |
197 | if (!acpi_device_present(ad->ad_handle)) | | 197 | if (!acpi_device_present(ad->ad_handle)) |
198 | goto rec; | | 198 | goto rec; |
199 | | | 199 | |
200 | if (ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) { | | 200 | if (ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) { |
201 | | | 201 | |
202 | ap = kmem_zalloc(sizeof(*ap), KM_SLEEP); | | 202 | ap = kmem_zalloc(sizeof(*ap), KM_SLEEP); |
203 | | | 203 | |
204 | /* | | 204 | /* |
205 | * If no _SEG exist, all PCI bus segments are assumed | | 205 | * If no _SEG exist, all PCI bus segments are assumed |
206 | * to be in the PCI segment group 0 (ACPI 4.0, p. 277). | | 206 | * to be in the PCI segment group 0 (ACPI 4.0, p. 277). |
207 | * The segment group number is conveyed in the lower | | 207 | * The segment group number is conveyed in the lower |
208 | * 16 bits of _SEG (the other bits are all reserved). | | 208 | * 16 bits of _SEG (the other bits are all reserved). |
209 | */ | | 209 | */ |
210 | rv = acpi_eval_integer(ad->ad_handle, "_SEG", &val); | | 210 | rv = acpi_eval_integer(ad->ad_handle, "_SEG", &val); |
211 | | | 211 | |
212 | if (ACPI_SUCCESS(rv)) | | 212 | if (ACPI_SUCCESS(rv)) |
213 | ap->ap_segment = ACPI_LOWORD(val); | | 213 | ap->ap_segment = ACPI_LOWORD(val); |
214 | | | 214 | |
215 | /* Try to get downstream bus number using _CRS first. */ | | 215 | /* Try to get downstream bus number using _CRS first. */ |
216 | rv = acpi_pcidev_pciroot_bus(ad->ad_handle, &ap->ap_downbus); | | 216 | rv = acpi_pcidev_pciroot_bus(ad->ad_handle, &ap->ap_downbus); |
217 | | | 217 | |
218 | if (ACPI_FAILURE(rv)) { | | 218 | if (ACPI_FAILURE(rv)) { |
219 | rv = acpi_eval_integer(ad->ad_handle, "_BBN", &val); | | 219 | rv = acpi_eval_integer(ad->ad_handle, "_BBN", &val); |
220 | | | 220 | |
221 | if (ACPI_SUCCESS(rv)) | | 221 | if (ACPI_SUCCESS(rv)) |
222 | ap->ap_downbus = ACPI_LOWORD(val); | | 222 | ap->ap_downbus = ACPI_LOWORD(val); |
223 | } | | 223 | } |
224 | | | 224 | |
225 | if (ap->ap_downbus > 255) { | | 225 | if (ap->ap_downbus > 255) { |
226 | aprint_error_dev(ad->ad_root, | | 226 | aprint_error_dev(ad->ad_root, |
227 | "invalid PCI downstream bus for %s\n", ad->ad_name); | | 227 | "invalid PCI downstream bus for %s\n", ad->ad_name); |
228 | kmem_free(ap, sizeof(*ap)); | | 228 | kmem_free(ap, sizeof(*ap)); |
229 | goto rec; | | 229 | goto rec; |
230 | } | | 230 | } |
231 | | | 231 | |
232 | ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; | | 232 | ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; |
233 | | | 233 | |
234 | ap->ap_pc = acpi_get_pci_chipset_tag(acpi_softc, ap->ap_segment, ap->ap_downbus); | | 234 | ap->ap_pc = acpi_get_pci_chipset_tag(acpi_softc, ap->ap_segment, ap->ap_downbus); |
235 | | | 235 | |
236 | /* | | 236 | /* |
237 | * This ACPI node denotes a PCI root bridge, but it may also | | 237 | * This ACPI node denotes a PCI root bridge, but it may also |
238 | * denote a PCI device on the bridge's downstream bus segment. | | 238 | * denote a PCI device on the bridge's downstream bus segment. |
239 | */ | | 239 | */ |
240 | if (ad->ad_devinfo->Valid & ACPI_VALID_ADR) { | | 240 | if (ad->ad_devinfo->Valid & ACPI_VALID_ADR) { |
241 | ap->ap_bus = ap->ap_downbus; | | 241 | ap->ap_bus = ap->ap_downbus; |
242 | ap->ap_device = | | 242 | ap->ap_device = |
243 | ACPI_HILODWORD(ad->ad_devinfo->Address); | | 243 | ACPI_HILODWORD(ad->ad_devinfo->Address); |
244 | ap->ap_function = | | 244 | ap->ap_function = |
245 | ACPI_LOLODWORD(ad->ad_devinfo->Address); | | 245 | ACPI_LOLODWORD(ad->ad_devinfo->Address); |
246 | | | 246 | |
247 | if (ap->ap_device > 31 || | | 247 | if (ap->ap_device > 31 || |
248 | (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) | | 248 | (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) |
249 | aprint_error_dev(ad->ad_root, | | 249 | aprint_error_dev(ad->ad_root, |
250 | "invalid PCI address for %s\n", ad->ad_name); | | 250 | "invalid PCI address for %s\n", ad->ad_name); |
251 | else | | 251 | else |
252 | ap->ap_flags |= ACPI_PCI_INFO_DEVICE; | | 252 | ap->ap_flags |= ACPI_PCI_INFO_DEVICE; |
253 | } | | 253 | } |
254 | | | 254 | |
255 | ad->ad_pciinfo = ap; | | 255 | ad->ad_pciinfo = ap; |
256 | | | 256 | |
257 | goto rec; | | 257 | goto rec; |
258 | } | | 258 | } |
259 | | | 259 | |
260 | if ((ad->ad_parent != NULL) && | | 260 | if ((ad->ad_parent != NULL) && |
261 | (ad->ad_parent->ad_pciinfo != NULL) && | | 261 | (ad->ad_parent->ad_pciinfo != NULL) && |
262 | (ad->ad_parent->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) && | | 262 | (ad->ad_parent->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) && |
263 | (ad->ad_devinfo->Valid & ACPI_VALID_ADR)) { | | 263 | (ad->ad_devinfo->Valid & ACPI_VALID_ADR)) { |
264 | | | 264 | |
265 | /* | | 265 | /* |
266 | * Our parent is a PCI root bridge or a PCI-to-PCI | | 266 | * Our parent is a PCI root bridge or a PCI-to-PCI |
267 | * bridge. We have the same PCI segment number, and | | 267 | * bridge. We have the same PCI segment number, and |
268 | * our bus number is its downstream bus number. | | 268 | * our bus number is its downstream bus number. |
269 | */ | | 269 | */ |
270 | ap = kmem_zalloc(sizeof(*ap), KM_SLEEP); | | 270 | ap = kmem_zalloc(sizeof(*ap), KM_SLEEP); |
271 | | | 271 | |
272 | ap->ap_pc = ad->ad_parent->ad_pciinfo->ap_pc; | | 272 | ap->ap_pc = ad->ad_parent->ad_pciinfo->ap_pc; |
273 | ap->ap_segment = ad->ad_parent->ad_pciinfo->ap_segment; | | 273 | ap->ap_segment = ad->ad_parent->ad_pciinfo->ap_segment; |
274 | ap->ap_bus = ad->ad_parent->ad_pciinfo->ap_downbus; | | 274 | ap->ap_bus = ad->ad_parent->ad_pciinfo->ap_downbus; |
275 | | | 275 | |
276 | ap->ap_device = ACPI_HILODWORD(ad->ad_devinfo->Address); | | 276 | ap->ap_device = ACPI_HILODWORD(ad->ad_devinfo->Address); |
277 | ap->ap_function = ACPI_LOLODWORD(ad->ad_devinfo->Address); | | 277 | ap->ap_function = ACPI_LOLODWORD(ad->ad_devinfo->Address); |
278 | | | 278 | |
279 | if (ap->ap_device > 31 || | | 279 | if (ap->ap_device > 31 || |
280 | (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) { | | 280 | (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) { |
281 | aprint_error_dev(ad->ad_root, | | 281 | aprint_error_dev(ad->ad_root, |
282 | "invalid PCI address for %s\n", ad->ad_name); | | 282 | "invalid PCI address for %s\n", ad->ad_name); |
283 | kmem_free(ap, sizeof(*ap)); | | 283 | kmem_free(ap, sizeof(*ap)); |
284 | goto rec; | | 284 | goto rec; |
285 | } | | 285 | } |
286 | | | 286 | |
287 | ap->ap_flags |= ACPI_PCI_INFO_DEVICE; | | 287 | ap->ap_flags |= ACPI_PCI_INFO_DEVICE; |
288 | | | 288 | |
289 | if (ap->ap_function == 0xFFFF) { | | 289 | if (ap->ap_function == 0xFFFF) { |
290 | /* | | 290 | /* |
291 | * Assume that this device is not a PCI-to-PCI bridge. | | 291 | * Assume that this device is not a PCI-to-PCI bridge. |
292 | * XXX: Do we need to be smarter? | | 292 | * XXX: Do we need to be smarter? |
293 | */ | | 293 | */ |
294 | } else { | | 294 | } else { |
295 | /* | | 295 | /* |
296 | * Check whether this device is a PCI-to-PCI | | 296 | * Check whether this device is a PCI-to-PCI |
297 | * bridge and get its secondary bus number. | | 297 | * bridge and get its secondary bus number. |
298 | */ | | 298 | */ |
299 | rv = acpi_pcidev_ppb_downbus( | | 299 | rv = acpi_pcidev_ppb_downbus( |
300 | ad->ad_parent->ad_pciinfo->ap_pc, | | 300 | ad->ad_parent->ad_pciinfo->ap_pc, |
301 | ap->ap_segment, ap->ap_bus, ap->ap_device, | | 301 | ap->ap_segment, ap->ap_bus, ap->ap_device, |
302 | ap->ap_function, &ap->ap_downbus); | | 302 | ap->ap_function, &ap->ap_downbus); |
303 | | | 303 | |
304 | if (ACPI_SUCCESS(rv)) | | 304 | if (ACPI_SUCCESS(rv)) |
305 | ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; | | 305 | ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; |
306 | } | | 306 | } |
307 | | | 307 | |
308 | ad->ad_pciinfo = ap; | | 308 | ad->ad_pciinfo = ap; |
309 | | | 309 | |
310 | goto rec; | | 310 | goto rec; |
311 | } | | 311 | } |
312 | | | 312 | |
313 | rec: | | 313 | rec: |
314 | SIMPLEQ_FOREACH(child, &ad->ad_child_head, ad_child_list) { | | 314 | SIMPLEQ_FOREACH(child, &ad->ad_child_head, ad_child_list) { |
315 | rv = acpi_pcidev_scan(child); | | 315 | rv = acpi_pcidev_scan(child); |
316 | | | 316 | |
317 | if (ACPI_FAILURE(rv)) | | 317 | if (ACPI_FAILURE(rv)) |
318 | return rv; | | 318 | return rv; |
319 | } | | 319 | } |
320 | | | 320 | |
321 | return AE_OK; | | 321 | return AE_OK; |
322 | } | | 322 | } |
323 | | | 323 | |
324 | /* | | 324 | /* |
325 | * acpi_pcidev_ppb_downbus: | | 325 | * acpi_pcidev_ppb_downbus: |
326 | * | | 326 | * |
327 | * Retrieve the secondary bus number of the PCI-to-PCI bridge having the | | 327 | * Retrieve the secondary bus number of the PCI-to-PCI bridge having the |
328 | * given PCI id. If successful, return AE_OK and fill *downbus. | | 328 | * given PCI id. If successful, return AE_OK and fill *downbus. |
329 | * Otherwise, return an exception code and leave *downbus unchanged. | | 329 | * Otherwise, return an exception code and leave *downbus unchanged. |
330 | * | | 330 | * |
331 | * XXX Need to deal with PCI segment groups (see also acpica/OsdHardware.c). | | 331 | * XXX Need to deal with PCI segment groups (see also acpica/OsdHardware.c). |
332 | */ | | 332 | */ |
333 | ACPI_STATUS | | 333 | ACPI_STATUS |
334 | acpi_pcidev_ppb_downbus(pci_chipset_tag_t pc, uint16_t segment, uint16_t bus, | | 334 | acpi_pcidev_ppb_downbus(pci_chipset_tag_t pc, uint16_t segment, uint16_t bus, |
335 | uint16_t device, uint16_t function, uint16_t *downbus) | | 335 | uint16_t device, uint16_t function, uint16_t *downbus) |
336 | { | | 336 | { |
337 | pcitag_t tag; | | 337 | pcitag_t tag; |
338 | pcireg_t val; | | 338 | pcireg_t val; |
339 | | | 339 | |
340 | if (bus > 255 || device > 31 || function > 7) | | 340 | if (bus > 255 || device > 31 || function > 7) |
341 | return AE_BAD_PARAMETER; | | 341 | return AE_BAD_PARAMETER; |
342 | | | 342 | |
343 | tag = pci_make_tag(pc, bus, device, function); | | 343 | tag = pci_make_tag(pc, bus, device, function); |
344 | | | 344 | |
345 | /* Check that this device exists. */ | | 345 | /* Check that this device exists. */ |
346 | val = pci_conf_read(pc, tag, PCI_ID_REG); | | 346 | val = pci_conf_read(pc, tag, PCI_ID_REG); |
347 | | | 347 | |
348 | if (PCI_VENDOR(val) == PCI_VENDOR_INVALID || | | 348 | if (PCI_VENDOR(val) == PCI_VENDOR_INVALID || |
349 | PCI_VENDOR(val) == 0) | | 349 | PCI_VENDOR(val) == 0) |
350 | return AE_NOT_EXIST; | | 350 | return AE_NOT_EXIST; |
351 | | | 351 | |
352 | /* Check that this device is a PCI-to-PCI bridge. */ | | 352 | /* Check that this device is a PCI-to-PCI bridge. */ |
353 | val = pci_conf_read(pc, tag, PCI_BHLC_REG); | | 353 | val = pci_conf_read(pc, tag, PCI_BHLC_REG); |
354 | | | 354 | |
355 | if (PCI_HDRTYPE_TYPE(val) != PCI_HDRTYPE_PPB) | | 355 | if (PCI_HDRTYPE_TYPE(val) != PCI_HDRTYPE_PPB) |
356 | return AE_TYPE; | | 356 | return AE_TYPE; |
357 | | | 357 | |
358 | /* This is a PCI-to-PCI bridge. Get its secondary bus#. */ | | 358 | /* This is a PCI-to-PCI bridge. Get its secondary bus#. */ |
359 | val = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG); | | 359 | val = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG); |
360 | *downbus = PCI_BRIDGE_BUS_NUM_SECONDARY(val); | | 360 | *downbus = PCI_BRIDGE_BUS_NUM_SECONDARY(val); |
361 | | | 361 | |
362 | return AE_OK; | | 362 | return AE_OK; |
363 | } | | 363 | } |
364 | | | 364 | |
365 | /* | | 365 | /* |
366 | * acpi_pcidev_find: | | 366 | * acpi_pcidev_find: |
367 | * | | 367 | * |
368 | * Finds a PCI device in the ACPI name space. | | 368 | * Finds a PCI device in the ACPI name space. |
369 | * | | 369 | * |
370 | * Returns an ACPI device node on success and NULL on failure. | | 370 | * Returns an ACPI device node on success and NULL on failure. |
371 | */ | | 371 | */ |
372 | struct acpi_devnode * | | 372 | struct acpi_devnode * |
373 | acpi_pcidev_find(uint16_t segment, uint16_t bus, | | 373 | acpi_pcidev_find(uint16_t segment, uint16_t bus, |
374 | uint16_t device, uint16_t function) | | 374 | uint16_t device, uint16_t function) |
375 | { | | 375 | { |
376 | struct acpi_softc *sc = acpi_softc; | | 376 | struct acpi_softc *sc = acpi_softc; |
377 | struct acpi_devnode *ad; | | 377 | struct acpi_devnode *ad; |
378 | | | 378 | |
379 | if (sc == NULL) | | 379 | if (sc == NULL) |
380 | return NULL; | | 380 | return NULL; |
381 | | | 381 | |
382 | SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { | | 382 | SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { |
383 | | | 383 | |
384 | if (ad->ad_pciinfo != NULL && | | 384 | if (ad->ad_pciinfo != NULL && |
385 | (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_DEVICE) && | | 385 | (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_DEVICE) && |
386 | ad->ad_pciinfo->ap_segment == segment && | | 386 | ad->ad_pciinfo->ap_segment == segment && |
387 | ad->ad_pciinfo->ap_bus == bus && | | 387 | ad->ad_pciinfo->ap_bus == bus && |
388 | ad->ad_pciinfo->ap_device == device && | | 388 | ad->ad_pciinfo->ap_device == device && |
389 | ad->ad_pciinfo->ap_function == function) | | 389 | ad->ad_pciinfo->ap_function == function) |
390 | return ad; | | 390 | return ad; |
391 | } | | 391 | } |
392 | | | 392 | |
393 | return NULL; | | 393 | return NULL; |
394 | } | | 394 | } |
395 | | | 395 | |
396 | /* | | 396 | /* |
397 | * acpi_pcidev_get_tag: | | 397 | * acpi_pcidev_get_tag: |
398 | * | | 398 | * |
399 | * Returns a PCI chipset tag for a PCI device in the ACPI name space. | | 399 | * Returns a PCI chipset tag for a PCI device in the ACPI name space. |
400 | */ | | 400 | */ |
401 | pci_chipset_tag_t | | 401 | pci_chipset_tag_t |
402 | acpi_pcidev_get_tag(uint16_t segment, uint16_t bus, | | 402 | acpi_pcidev_get_tag(uint16_t segment, uint16_t bus, |
403 | uint16_t device, uint16_t function) | | 403 | uint16_t device, uint16_t function) |
404 | { | | 404 | { |
405 | struct acpi_devnode *ad; | | 405 | struct acpi_devnode *ad; |
406 | | | 406 | |
407 | ad = acpi_pcidev_find(segment, bus, device, function); | | 407 | ad = acpi_pcidev_find(segment, bus, device, function); |
408 | if (ad == NULL || ad->ad_pciinfo == NULL) | | 408 | if (ad == NULL || ad->ad_pciinfo == NULL) |
409 | return NULL; | | 409 | return NULL; |
410 | | | 410 | |
411 | return ad->ad_pciinfo->ap_pc; | | 411 | return ad->ad_pciinfo->ap_pc; |
412 | } | | 412 | } |
413 | | | 413 | |
414 | /* | | 414 | /* |
415 | * acpi_pciroot_find: | | 415 | * acpi_pciroot_find: |
416 | * | | 416 | * |
417 | * Finds a PCI root bridge in the ACPI name space. | | 417 | * Finds a PCI root bridge in the ACPI name space. |
418 | * | | 418 | * |
419 | * Returns an ACPI device node on success and NULL on failure. | | 419 | * Returns an ACPI device node on success and NULL on failure. |
420 | */ | | 420 | */ |
421 | struct acpi_devnode * | | 421 | struct acpi_devnode * |
422 | acpi_pciroot_find(uint16_t segment, uint16_t bus) | | 422 | acpi_pciroot_find(uint16_t segment, uint16_t bus) |
423 | { | | 423 | { |
424 | struct acpi_softc *sc = acpi_softc; | | 424 | struct acpi_softc *sc = acpi_softc; |
425 | struct acpi_devnode *ad; | | 425 | struct acpi_devnode *ad; |
426 | | | 426 | |
427 | if (sc == NULL) | | 427 | if (sc == NULL) |
428 | return NULL; | | 428 | return NULL; |
429 | | | 429 | |
430 | SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { | | 430 | SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { |
431 | | | 431 | |
432 | if (ad->ad_pciinfo != NULL && | | 432 | if (ad->ad_pciinfo != NULL && |
433 | (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) && | | 433 | (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) && |
434 | ad->ad_pciinfo->ap_segment == segment && | | 434 | ad->ad_pciinfo->ap_segment == segment && |
435 | ad->ad_pciinfo->ap_bus == bus) | | 435 | ad->ad_pciinfo->ap_bus == bus) |
436 | return ad; | | 436 | return ad; |
437 | } | | 437 | } |
438 | | | 438 | |
439 | return NULL; | | 439 | return NULL; |
440 | } | | 440 | } |
441 | | | 441 | |
442 | /* | | 442 | /* |
443 | * acpi_pcidev_find_dev: | | 443 | * acpi_pcidev_find_dev: |
444 | * | | 444 | * |
445 | * Returns the device corresponding to the given PCI info, or NULL | | 445 | * Returns the device corresponding to the given PCI info, or NULL |
446 | * if it doesn't exist. | | 446 | * if it doesn't exist. |
447 | */ | | 447 | */ |
448 | device_t | | 448 | device_t |
449 | acpi_pcidev_find_dev(struct acpi_devnode *ad) | | 449 | acpi_pcidev_find_dev(struct acpi_devnode *ad) |
450 | { | | 450 | { |
451 | struct acpi_pci_info *ap; | | 451 | struct acpi_pci_info *ap; |
452 | struct pci_softc *pci; | | 452 | struct pci_softc *pci; |
453 | device_t dv, pr; | | 453 | device_t dv, pr; |
454 | deviter_t di; | | 454 | deviter_t di; |
455 | | | 455 | |
456 | if (ad == NULL) | | 456 | if (ad == NULL) |
457 | return NULL; | | 457 | return NULL; |
458 | | | 458 | |
459 | if (ad->ad_pciinfo == NULL) | | 459 | if (ad->ad_pciinfo == NULL) |
460 | return NULL; | | 460 | return NULL; |
461 | | | 461 | |
462 | ap = ad->ad_pciinfo; | | 462 | ap = ad->ad_pciinfo; |
463 | | | 463 | |
464 | if (ap->ap_function == 0xFFFF) | | 464 | if (ap->ap_function == 0xFFFF) |
465 | return NULL; | | 465 | return NULL; |
466 | | | 466 | |
467 | for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); | | 467 | for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); |
468 | dv != NULL; dv = deviter_next(&di)) { | | 468 | dv != NULL; dv = deviter_next(&di)) { |
469 | | | 469 | |
470 | pr = device_parent(dv); | | 470 | pr = device_parent(dv); |
471 | | | 471 | |
472 | if (pr == NULL || device_is_a(pr, "pci") != true) | | 472 | if (pr == NULL || device_is_a(pr, "pci") != true) |
473 | continue; | | 473 | continue; |
474 | | | 474 | |
475 | if (dv->dv_locators == NULL) /* This should not happen. */ | | | |
476 | continue; | | | |
477 | | | | |
478 | pci = device_private(pr); | | 475 | pci = device_private(pr); |
479 | | | 476 | |
480 | if (pci->sc_bus == ap->ap_bus && | | 477 | if (pci->sc_bus == ap->ap_bus && |
481 | device_locator(dv, PCICF_DEV) == ap->ap_device && | | 478 | device_locator(dv, PCICF_DEV) == ap->ap_device && |
482 | device_locator(dv, PCICF_FUNCTION) == ap->ap_function) | | 479 | device_locator(dv, PCICF_FUNCTION) == ap->ap_function) |
483 | break; | | 480 | break; |
484 | } | | 481 | } |
485 | | | 482 | |
486 | deviter_release(&di); | | 483 | deviter_release(&di); |
487 | | | 484 | |
488 | return dv; | | 485 | return dv; |
489 | } | | 486 | } |
490 | | | 487 | |
491 | /* | | 488 | /* |
492 | * acpi_pci_ignore_boot_config: | | 489 | * acpi_pci_ignore_boot_config: |
493 | * | | 490 | * |
494 | * Returns 1 if the operating system may ignore the boot configuration | | 491 | * Returns 1 if the operating system may ignore the boot configuration |
495 | * of PCI resources. | | 492 | * of PCI resources. |
496 | */ | | 493 | */ |
497 | ACPI_INTEGER | | 494 | ACPI_INTEGER |
498 | acpi_pci_ignore_boot_config(ACPI_HANDLE handle) | | 495 | acpi_pci_ignore_boot_config(ACPI_HANDLE handle) |
499 | { | | 496 | { |
500 | ACPI_OBJECT *pobj = NULL; | | 497 | ACPI_OBJECT *pobj = NULL; |
501 | ACPI_INTEGER ret; | | 498 | ACPI_INTEGER ret; |
502 | | | 499 | |
503 | /* | | 500 | /* |
504 | * This one is a little confusing, but the result of | | 501 | * This one is a little confusing, but the result of |
505 | * evaluating _DSM #5 is: | | 502 | * evaluating _DSM #5 is: |
506 | * | | 503 | * |
507 | * 0: The operating system may not ignore the boot configuration | | 504 | * 0: The operating system may not ignore the boot configuration |
508 | * of PCI resources. | | 505 | * of PCI resources. |
509 | * | | 506 | * |
510 | * 1: The operating system may ignore the boot configuration of | | 507 | * 1: The operating system may ignore the boot configuration of |
511 | * PCI resources, and reconfigure or rebalance these resources | | 508 | * PCI resources, and reconfigure or rebalance these resources |
512 | * in the hierarchy as required. | | 509 | * in the hierarchy as required. |
513 | */ | | 510 | */ |
514 | | | 511 | |
515 | if (ACPI_FAILURE(acpi_dsm(handle, acpi_pci_dsm_uuid, | | 512 | if (ACPI_FAILURE(acpi_dsm(handle, acpi_pci_dsm_uuid, |
516 | 1, 5, NULL, &pobj))) { | | 513 | 1, 5, NULL, &pobj))) { |
517 | /* | | 514 | /* |
518 | * In the absence of _DSM #5, we may assume that the | | 515 | * In the absence of _DSM #5, we may assume that the |
519 | * boot config can be ignored. | | 516 | * boot config can be ignored. |
520 | */ | | 517 | */ |
521 | return 1; | | 518 | return 1; |
522 | } | | 519 | } |
523 | | | 520 | |
524 | /* | | 521 | /* |
525 | * ...and we default to "may ignore" in the event that the | | 522 | * ...and we default to "may ignore" in the event that the |
526 | * method returns nonsense. | | 523 | * method returns nonsense. |
527 | */ | | 524 | */ |
528 | ret = 1; | | 525 | ret = 1; |
529 | | | 526 | |
530 | if (pobj != NULL) { | | 527 | if (pobj != NULL) { |
531 | switch (pobj->Type) { | | 528 | switch (pobj->Type) { |
532 | case ACPI_TYPE_INTEGER: | | 529 | case ACPI_TYPE_INTEGER: |
533 | ret = pobj->Integer.Value; | | 530 | ret = pobj->Integer.Value; |
534 | break; | | 531 | break; |
535 | | | 532 | |
536 | case ACPI_TYPE_PACKAGE: | | 533 | case ACPI_TYPE_PACKAGE: |
537 | if (pobj->Package.Count == 1 && | | 534 | if (pobj->Package.Count == 1 && |
538 | pobj->Package.Elements[0].Type == ACPI_TYPE_INTEGER) | | 535 | pobj->Package.Elements[0].Type == ACPI_TYPE_INTEGER) |
539 | ret = pobj->Package.Elements[0].Integer.Value; | | 536 | ret = pobj->Package.Elements[0].Integer.Value; |
540 | break; | | 537 | break; |
541 | } | | 538 | } |
542 | ACPI_FREE(pobj); | | 539 | ACPI_FREE(pobj); |
543 | } | | 540 | } |
544 | | | 541 | |
545 | return ret; | | 542 | return ret; |
546 | } | | 543 | } |
547 | | | 544 | |
548 | /* | | 545 | /* |
549 | * acpi_pci_bus_get_child_devhandle: | | 546 | * acpi_pci_bus_get_child_devhandle: |
550 | * | | 547 | * |
551 | * Implements the "pci-bus-get-child-devhandle" device call for | | 548 | * Implements the "pci-bus-get-child-devhandle" device call for |
552 | * ACPI device handles | | 549 | * ACPI device handles |
553 | */ | | 550 | */ |
554 | static int | | 551 | static int |
555 | acpi_pci_bus_get_child_devhandle(device_t dev, devhandle_t call_handle, void *v) | | 552 | acpi_pci_bus_get_child_devhandle(device_t dev, devhandle_t call_handle, void *v) |
556 | { | | 553 | { |
557 | struct pci_bus_get_child_devhandle_args *args = v; | | 554 | struct pci_bus_get_child_devhandle_args *args = v; |
558 | struct acpi_devnode *ad; | | 555 | struct acpi_devnode *ad; |
559 | ACPI_HANDLE hdl; | | 556 | ACPI_HANDLE hdl; |
560 | int b, d, f; | | 557 | int b, d, f; |
561 | u_int segment; | | 558 | u_int segment; |
562 | | | 559 | |
563 | #ifdef __HAVE_PCI_GET_SEGMENT | | 560 | #ifdef __HAVE_PCI_GET_SEGMENT |
564 | segment = pci_get_segment(args->pc); | | 561 | segment = pci_get_segment(args->pc); |
565 | #else | | 562 | #else |
566 | segment = 0; | | 563 | segment = 0; |
567 | #endif /* __HAVE_PCI_GET_SEGMENT */ | | 564 | #endif /* __HAVE_PCI_GET_SEGMENT */ |
568 | | | 565 | |
569 | pci_decompose_tag(args->pc, args->tag, &b, &d, &f); | | 566 | pci_decompose_tag(args->pc, args->tag, &b, &d, &f); |
570 | | | 567 | |
571 | ad = acpi_pcidev_find(segment, b, d, f); | | 568 | ad = acpi_pcidev_find(segment, b, d, f); |
572 | | | 569 | |
573 | if (ad != NULL && (hdl = ad->ad_handle) != NULL) { | | 570 | if (ad != NULL && (hdl = ad->ad_handle) != NULL) { |
574 | /* Found it! */ | | 571 | /* Found it! */ |
575 | args->devhandle = devhandle_from_acpi(call_handle, hdl); | | 572 | args->devhandle = devhandle_from_acpi(call_handle, hdl); |
576 | return 0; | | 573 | return 0; |
577 | } | | 574 | } |
578 | | | 575 | |
579 | return ENODEV; | | 576 | return ENODEV; |
580 | } | | 577 | } |
581 | ACPI_DEVICE_CALL_REGISTER(PCI_BUS_GET_CHILD_DEVHANDLE_STR, | | 578 | ACPI_DEVICE_CALL_REGISTER(PCI_BUS_GET_CHILD_DEVHANDLE_STR, |
582 | acpi_pci_bus_get_child_devhandle) | | 579 | acpi_pci_bus_get_child_devhandle) |