Loading...
1/*******************************************************************************
2 *
3 * Module Name: hwpci - Obtain PCI bus, device, and function numbers
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2011, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <acpi/acpi.h>
45#include "accommon.h"
46
47#define _COMPONENT ACPI_NAMESPACE
48ACPI_MODULE_NAME("hwpci")
49
50/* PCI configuration space values */
51#define PCI_CFG_HEADER_TYPE_REG 0x0E
52#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18
53#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19
54/* PCI header values */
55#define PCI_HEADER_TYPE_MASK 0x7F
56#define PCI_TYPE_BRIDGE 0x01
57#define PCI_TYPE_CARDBUS_BRIDGE 0x02
58typedef struct acpi_pci_device {
59 acpi_handle device;
60 struct acpi_pci_device *next;
61
62} acpi_pci_device;
63
64/* Local prototypes */
65
66static acpi_status
67acpi_hw_build_pci_list(acpi_handle root_pci_device,
68 acpi_handle pci_region,
69 struct acpi_pci_device **return_list_head);
70
71static acpi_status
72acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
73 struct acpi_pci_device *list_head);
74
75static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
76
77static acpi_status
78acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
79 acpi_handle pci_device,
80 u16 *bus_number, u8 *is_bridge);
81
82/*******************************************************************************
83 *
84 * FUNCTION: acpi_hw_derive_pci_id
85 *
86 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
87 * modified by this function.
88 * root_pci_device - A handle to a PCI device object. This
89 * object must be a PCI Root Bridge having a
90 * _HID value of either PNP0A03 or PNP0A08
91 * pci_region - A handle to a PCI configuration space
92 * Operation Region being initialized
93 *
94 * RETURN: Status
95 *
96 * DESCRIPTION: This function derives a full PCI ID for a PCI device,
97 * consisting of a Segment number, Bus number, Device number,
98 * and function code.
99 *
100 * The PCI hardware dynamically configures PCI bus numbers
101 * depending on the bus topology discovered during system
102 * initialization. This function is invoked during configuration
103 * of a PCI_Config Operation Region in order to (possibly) update
104 * the Bus/Device/Function numbers in the pci_id with the actual
105 * values as determined by the hardware and operating system
106 * configuration.
107 *
108 * The pci_id parameter is initially populated during the Operation
109 * Region initialization. This function is then called, and is
110 * will make any necessary modifications to the Bus, Device, or
111 * Function number PCI ID subfields as appropriate for the
112 * current hardware and OS configuration.
113 *
114 * NOTE: Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id
115 * interface since this feature is OS-independent. This module
116 * specifically avoids any use of recursion by building a local
117 * temporary device list.
118 *
119 ******************************************************************************/
120
121acpi_status
122acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
123 acpi_handle root_pci_device, acpi_handle pci_region)
124{
125 acpi_status status;
126 struct acpi_pci_device *list_head = NULL;
127
128 ACPI_FUNCTION_TRACE(hw_derive_pci_id);
129
130 if (!pci_id) {
131 return_ACPI_STATUS(AE_BAD_PARAMETER);
132 }
133
134 /* Build a list of PCI devices, from pci_region up to root_pci_device */
135
136 status =
137 acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
138 if (ACPI_SUCCESS(status)) {
139
140 /* Walk the list, updating the PCI device/function/bus numbers */
141
142 status = acpi_hw_process_pci_list(pci_id, list_head);
143 }
144
145 /* Always delete the list */
146
147 acpi_hw_delete_pci_list(list_head);
148 return_ACPI_STATUS(status);
149}
150
151/*******************************************************************************
152 *
153 * FUNCTION: acpi_hw_build_pci_list
154 *
155 * PARAMETERS: root_pci_device - A handle to a PCI device object. This
156 * object is guaranteed to be a PCI Root
157 * Bridge having a _HID value of either
158 * PNP0A03 or PNP0A08
159 * pci_region - A handle to the PCI configuration space
160 * Operation Region
161 * return_list_head - Where the PCI device list is returned
162 *
163 * RETURN: Status
164 *
165 * DESCRIPTION: Builds a list of devices from the input PCI region up to the
166 * Root PCI device for this namespace subtree.
167 *
168 ******************************************************************************/
169
170static acpi_status
171acpi_hw_build_pci_list(acpi_handle root_pci_device,
172 acpi_handle pci_region,
173 struct acpi_pci_device **return_list_head)
174{
175 acpi_handle current_device;
176 acpi_handle parent_device;
177 acpi_status status;
178 struct acpi_pci_device *list_element;
179 struct acpi_pci_device *list_head = NULL;
180
181 /*
182 * Ascend namespace branch until the root_pci_device is reached, building
183 * a list of device nodes. Loop will exit when either the PCI device is
184 * found, or the root of the namespace is reached.
185 */
186 current_device = pci_region;
187 while (1) {
188 status = acpi_get_parent(current_device, &parent_device);
189 if (ACPI_FAILURE(status)) {
190 return (status);
191 }
192
193 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
194
195 if (parent_device == root_pci_device) {
196 *return_list_head = list_head;
197 return (AE_OK);
198 }
199
200 list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
201 if (!list_element) {
202 return (AE_NO_MEMORY);
203 }
204
205 /* Put new element at the head of the list */
206
207 list_element->next = list_head;
208 list_element->device = parent_device;
209 list_head = list_element;
210
211 current_device = parent_device;
212 }
213}
214
215/*******************************************************************************
216 *
217 * FUNCTION: acpi_hw_process_pci_list
218 *
219 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
220 * modified by this function.
221 * list_head - Device list created by
222 * acpi_hw_build_pci_list
223 *
224 * RETURN: Status
225 *
226 * DESCRIPTION: Walk downward through the PCI device list, getting the device
227 * info for each, via the PCI configuration space and updating
228 * the PCI ID as necessary. Deletes the list during traversal.
229 *
230 ******************************************************************************/
231
232static acpi_status
233acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
234 struct acpi_pci_device *list_head)
235{
236 acpi_status status = AE_OK;
237 struct acpi_pci_device *info;
238 u16 bus_number;
239 u8 is_bridge = TRUE;
240
241 ACPI_FUNCTION_NAME(hw_process_pci_list);
242
243 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
244 "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
245 pci_id->segment, pci_id->bus, pci_id->device,
246 pci_id->function));
247
248 bus_number = pci_id->bus;
249
250 /*
251 * Descend down the namespace tree, collecting PCI device, function,
252 * and bus numbers. bus_number is only important for PCI bridges.
253 * Algorithm: As we descend the tree, use the last valid PCI device,
254 * function, and bus numbers that are discovered, and assign them
255 * to the PCI ID for the target device.
256 */
257 info = list_head;
258 while (info) {
259 status = acpi_hw_get_pci_device_info(pci_id, info->device,
260 &bus_number, &is_bridge);
261 if (ACPI_FAILURE(status)) {
262 return_ACPI_STATUS(status);
263 }
264
265 info = info->next;
266 }
267
268 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
269 "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
270 "Status %X BusNumber %X IsBridge %X\n",
271 pci_id->segment, pci_id->bus, pci_id->device,
272 pci_id->function, status, bus_number, is_bridge));
273
274 return_ACPI_STATUS(AE_OK);
275}
276
277/*******************************************************************************
278 *
279 * FUNCTION: acpi_hw_delete_pci_list
280 *
281 * PARAMETERS: list_head - Device list created by
282 * acpi_hw_build_pci_list
283 *
284 * RETURN: None
285 *
286 * DESCRIPTION: Free the entire PCI list.
287 *
288 ******************************************************************************/
289
290static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
291{
292 struct acpi_pci_device *next;
293 struct acpi_pci_device *previous;
294
295 next = list_head;
296 while (next) {
297 previous = next;
298 next = previous->next;
299 ACPI_FREE(previous);
300 }
301}
302
303/*******************************************************************************
304 *
305 * FUNCTION: acpi_hw_get_pci_device_info
306 *
307 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
308 * modified by this function.
309 * pci_device - Handle for the PCI device object
310 * bus_number - Where a PCI bridge bus number is returned
311 * is_bridge - Return value, indicates if this PCI
312 * device is a PCI bridge
313 *
314 * RETURN: Status
315 *
316 * DESCRIPTION: Get the device info for a single PCI device object. Get the
317 * _ADR (contains PCI device and function numbers), and for PCI
318 * bridge devices, get the bus number from PCI configuration
319 * space.
320 *
321 ******************************************************************************/
322
323static acpi_status
324acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
325 acpi_handle pci_device,
326 u16 *bus_number, u8 *is_bridge)
327{
328 acpi_status status;
329 acpi_object_type object_type;
330 u64 return_value;
331 u64 pci_value;
332
333 /* We only care about objects of type Device */
334
335 status = acpi_get_type(pci_device, &object_type);
336 if (ACPI_FAILURE(status)) {
337 return (status);
338 }
339
340 if (object_type != ACPI_TYPE_DEVICE) {
341 return (AE_OK);
342 }
343
344 /* We need an _ADR. Ignore device if not present */
345
346 status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
347 pci_device, &return_value);
348 if (ACPI_FAILURE(status)) {
349 return (AE_OK);
350 }
351
352 /*
353 * From _ADR, get the PCI Device and Function and
354 * update the PCI ID.
355 */
356 pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
357 pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
358
359 /*
360 * If the previous device was a bridge, use the previous
361 * device bus number
362 */
363 if (*is_bridge) {
364 pci_id->bus = *bus_number;
365 }
366
367 /*
368 * Get the bus numbers from PCI Config space:
369 *
370 * First, get the PCI header_type
371 */
372 *is_bridge = FALSE;
373 status = acpi_os_read_pci_configuration(pci_id,
374 PCI_CFG_HEADER_TYPE_REG,
375 &pci_value, 8);
376 if (ACPI_FAILURE(status)) {
377 return (status);
378 }
379
380 /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
381
382 pci_value &= PCI_HEADER_TYPE_MASK;
383
384 if ((pci_value != PCI_TYPE_BRIDGE) &&
385 (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
386 return (AE_OK);
387 }
388
389 /* Bridge: Get the Primary bus_number */
390
391 status = acpi_os_read_pci_configuration(pci_id,
392 PCI_CFG_PRIMARY_BUS_NUMBER_REG,
393 &pci_value, 8);
394 if (ACPI_FAILURE(status)) {
395 return (status);
396 }
397
398 *is_bridge = TRUE;
399 pci_id->bus = (u16)pci_value;
400
401 /* Bridge: Get the Secondary bus_number */
402
403 status = acpi_os_read_pci_configuration(pci_id,
404 PCI_CFG_SECONDARY_BUS_NUMBER_REG,
405 &pci_value, 8);
406 if (ACPI_FAILURE(status)) {
407 return (status);
408 }
409
410 *bus_number = (u16)pci_value;
411 return (AE_OK);
412}
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/*******************************************************************************
3 *
4 * Module Name: hwpci - Obtain PCI bus, device, and function numbers
5 *
6 ******************************************************************************/
7
8#include <acpi/acpi.h>
9#include "accommon.h"
10
11#define _COMPONENT ACPI_NAMESPACE
12ACPI_MODULE_NAME("hwpci")
13
14/* PCI configuration space values */
15#define PCI_CFG_HEADER_TYPE_REG 0x0E
16#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18
17#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19
18/* PCI header values */
19#define PCI_HEADER_TYPE_MASK 0x7F
20#define PCI_TYPE_BRIDGE 0x01
21#define PCI_TYPE_CARDBUS_BRIDGE 0x02
22typedef struct acpi_pci_device {
23 acpi_handle device;
24 struct acpi_pci_device *next;
25
26} acpi_pci_device;
27
28/* Local prototypes */
29
30static acpi_status
31acpi_hw_build_pci_list(acpi_handle root_pci_device,
32 acpi_handle pci_region,
33 struct acpi_pci_device **return_list_head);
34
35static acpi_status
36acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
37 struct acpi_pci_device *list_head);
38
39static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
40
41static acpi_status
42acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
43 acpi_handle pci_device,
44 u16 *bus_number, u8 *is_bridge);
45
46/*******************************************************************************
47 *
48 * FUNCTION: acpi_hw_derive_pci_id
49 *
50 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
51 * modified by this function.
52 * root_pci_device - A handle to a PCI device object. This
53 * object must be a PCI Root Bridge having a
54 * _HID value of either PNP0A03 or PNP0A08
55 * pci_region - A handle to a PCI configuration space
56 * Operation Region being initialized
57 *
58 * RETURN: Status
59 *
60 * DESCRIPTION: This function derives a full PCI ID for a PCI device,
61 * consisting of a Segment number, Bus number, Device number,
62 * and function code.
63 *
64 * The PCI hardware dynamically configures PCI bus numbers
65 * depending on the bus topology discovered during system
66 * initialization. This function is invoked during configuration
67 * of a PCI_Config Operation Region in order to (possibly) update
68 * the Bus/Device/Function numbers in the pci_id with the actual
69 * values as determined by the hardware and operating system
70 * configuration.
71 *
72 * The pci_id parameter is initially populated during the Operation
73 * Region initialization. This function is then called, and is
74 * will make any necessary modifications to the Bus, Device, or
75 * Function number PCI ID subfields as appropriate for the
76 * current hardware and OS configuration.
77 *
78 * NOTE: Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id
79 * interface since this feature is OS-independent. This module
80 * specifically avoids any use of recursion by building a local
81 * temporary device list.
82 *
83 ******************************************************************************/
84
85acpi_status
86acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
87 acpi_handle root_pci_device, acpi_handle pci_region)
88{
89 acpi_status status;
90 struct acpi_pci_device *list_head;
91
92 ACPI_FUNCTION_TRACE(hw_derive_pci_id);
93
94 if (!pci_id) {
95 return_ACPI_STATUS(AE_BAD_PARAMETER);
96 }
97
98 /* Build a list of PCI devices, from pci_region up to root_pci_device */
99
100 status =
101 acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
102 if (ACPI_SUCCESS(status)) {
103
104 /* Walk the list, updating the PCI device/function/bus numbers */
105
106 status = acpi_hw_process_pci_list(pci_id, list_head);
107
108 /* Delete the list */
109
110 acpi_hw_delete_pci_list(list_head);
111 }
112
113 return_ACPI_STATUS(status);
114}
115
116/*******************************************************************************
117 *
118 * FUNCTION: acpi_hw_build_pci_list
119 *
120 * PARAMETERS: root_pci_device - A handle to a PCI device object. This
121 * object is guaranteed to be a PCI Root
122 * Bridge having a _HID value of either
123 * PNP0A03 or PNP0A08
124 * pci_region - A handle to the PCI configuration space
125 * Operation Region
126 * return_list_head - Where the PCI device list is returned
127 *
128 * RETURN: Status
129 *
130 * DESCRIPTION: Builds a list of devices from the input PCI region up to the
131 * Root PCI device for this namespace subtree.
132 *
133 ******************************************************************************/
134
135static acpi_status
136acpi_hw_build_pci_list(acpi_handle root_pci_device,
137 acpi_handle pci_region,
138 struct acpi_pci_device **return_list_head)
139{
140 acpi_handle current_device;
141 acpi_handle parent_device;
142 acpi_status status;
143 struct acpi_pci_device *list_element;
144
145 /*
146 * Ascend namespace branch until the root_pci_device is reached, building
147 * a list of device nodes. Loop will exit when either the PCI device is
148 * found, or the root of the namespace is reached.
149 */
150 *return_list_head = NULL;
151 current_device = pci_region;
152 while (1) {
153 status = acpi_get_parent(current_device, &parent_device);
154 if (ACPI_FAILURE(status)) {
155
156 /* Must delete the list before exit */
157
158 acpi_hw_delete_pci_list(*return_list_head);
159 return (status);
160 }
161
162 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
163
164 if (parent_device == root_pci_device) {
165 return (AE_OK);
166 }
167
168 list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
169 if (!list_element) {
170
171 /* Must delete the list before exit */
172
173 acpi_hw_delete_pci_list(*return_list_head);
174 return (AE_NO_MEMORY);
175 }
176
177 /* Put new element at the head of the list */
178
179 list_element->next = *return_list_head;
180 list_element->device = parent_device;
181 *return_list_head = list_element;
182
183 current_device = parent_device;
184 }
185}
186
187/*******************************************************************************
188 *
189 * FUNCTION: acpi_hw_process_pci_list
190 *
191 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
192 * modified by this function.
193 * list_head - Device list created by
194 * acpi_hw_build_pci_list
195 *
196 * RETURN: Status
197 *
198 * DESCRIPTION: Walk downward through the PCI device list, getting the device
199 * info for each, via the PCI configuration space and updating
200 * the PCI ID as necessary. Deletes the list during traversal.
201 *
202 ******************************************************************************/
203
204static acpi_status
205acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
206 struct acpi_pci_device *list_head)
207{
208 acpi_status status = AE_OK;
209 struct acpi_pci_device *info;
210 u16 bus_number;
211 u8 is_bridge = TRUE;
212
213 ACPI_FUNCTION_NAME(hw_process_pci_list);
214
215 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
216 "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
217 pci_id->segment, pci_id->bus, pci_id->device,
218 pci_id->function));
219
220 bus_number = pci_id->bus;
221
222 /*
223 * Descend down the namespace tree, collecting PCI device, function,
224 * and bus numbers. bus_number is only important for PCI bridges.
225 * Algorithm: As we descend the tree, use the last valid PCI device,
226 * function, and bus numbers that are discovered, and assign them
227 * to the PCI ID for the target device.
228 */
229 info = list_head;
230 while (info) {
231 status = acpi_hw_get_pci_device_info(pci_id, info->device,
232 &bus_number, &is_bridge);
233 if (ACPI_FAILURE(status)) {
234 return (status);
235 }
236
237 info = info->next;
238 }
239
240 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
241 "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
242 "Status %X BusNumber %X IsBridge %X\n",
243 pci_id->segment, pci_id->bus, pci_id->device,
244 pci_id->function, status, bus_number, is_bridge));
245
246 return (AE_OK);
247}
248
249/*******************************************************************************
250 *
251 * FUNCTION: acpi_hw_delete_pci_list
252 *
253 * PARAMETERS: list_head - Device list created by
254 * acpi_hw_build_pci_list
255 *
256 * RETURN: None
257 *
258 * DESCRIPTION: Free the entire PCI list.
259 *
260 ******************************************************************************/
261
262static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
263{
264 struct acpi_pci_device *next;
265 struct acpi_pci_device *previous;
266
267 next = list_head;
268 while (next) {
269 previous = next;
270 next = previous->next;
271 ACPI_FREE(previous);
272 }
273}
274
275/*******************************************************************************
276 *
277 * FUNCTION: acpi_hw_get_pci_device_info
278 *
279 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
280 * modified by this function.
281 * pci_device - Handle for the PCI device object
282 * bus_number - Where a PCI bridge bus number is returned
283 * is_bridge - Return value, indicates if this PCI
284 * device is a PCI bridge
285 *
286 * RETURN: Status
287 *
288 * DESCRIPTION: Get the device info for a single PCI device object. Get the
289 * _ADR (contains PCI device and function numbers), and for PCI
290 * bridge devices, get the bus number from PCI configuration
291 * space.
292 *
293 ******************************************************************************/
294
295static acpi_status
296acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
297 acpi_handle pci_device,
298 u16 *bus_number, u8 *is_bridge)
299{
300 acpi_status status;
301 acpi_object_type object_type;
302 u64 return_value;
303 u64 pci_value;
304
305 /* We only care about objects of type Device */
306
307 status = acpi_get_type(pci_device, &object_type);
308 if (ACPI_FAILURE(status)) {
309 return (status);
310 }
311
312 if (object_type != ACPI_TYPE_DEVICE) {
313 return (AE_OK);
314 }
315
316 /* We need an _ADR. Ignore device if not present */
317
318 status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
319 pci_device, &return_value);
320 if (ACPI_FAILURE(status)) {
321 return (AE_OK);
322 }
323
324 /*
325 * From _ADR, get the PCI Device and Function and
326 * update the PCI ID.
327 */
328 pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
329 pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
330
331 /*
332 * If the previous device was a bridge, use the previous
333 * device bus number
334 */
335 if (*is_bridge) {
336 pci_id->bus = *bus_number;
337 }
338
339 /*
340 * Get the bus numbers from PCI Config space:
341 *
342 * First, get the PCI header_type
343 */
344 *is_bridge = FALSE;
345 status = acpi_os_read_pci_configuration(pci_id,
346 PCI_CFG_HEADER_TYPE_REG,
347 &pci_value, 8);
348 if (ACPI_FAILURE(status)) {
349 return (status);
350 }
351
352 /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
353
354 pci_value &= PCI_HEADER_TYPE_MASK;
355
356 if ((pci_value != PCI_TYPE_BRIDGE) &&
357 (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
358 return (AE_OK);
359 }
360
361 /* Bridge: Get the Primary bus_number */
362
363 status = acpi_os_read_pci_configuration(pci_id,
364 PCI_CFG_PRIMARY_BUS_NUMBER_REG,
365 &pci_value, 8);
366 if (ACPI_FAILURE(status)) {
367 return (status);
368 }
369
370 *is_bridge = TRUE;
371 pci_id->bus = (u16)pci_value;
372
373 /* Bridge: Get the Secondary bus_number */
374
375 status = acpi_os_read_pci_configuration(pci_id,
376 PCI_CFG_SECONDARY_BUS_NUMBER_REG,
377 &pci_value, 8);
378 if (ACPI_FAILURE(status)) {
379 return (status);
380 }
381
382 *bus_number = (u16)pci_value;
383 return (AE_OK);
384}