1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
4 * Module Name: hwpci - Obtain PCI bus, device, and function numbers
6 ******************************************************************************/
11 #define _COMPONENT ACPI_NAMESPACE
12 ACPI_MODULE_NAME("hwpci")
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
22 typedef struct acpi_pci_device
{
24 struct acpi_pci_device
*next
;
28 /* Local prototypes */
31 acpi_hw_build_pci_list(acpi_handle root_pci_device
,
32 acpi_handle pci_region
,
33 struct acpi_pci_device
**return_list_head
);
36 acpi_hw_process_pci_list(struct acpi_pci_id
*pci_id
,
37 struct acpi_pci_device
*list_head
);
39 static void acpi_hw_delete_pci_list(struct acpi_pci_device
*list_head
);
42 acpi_hw_get_pci_device_info(struct acpi_pci_id
*pci_id
,
43 acpi_handle pci_device
,
44 u16
*bus_number
, u8
*is_bridge
);
46 /*******************************************************************************
48 * FUNCTION: acpi_hw_derive_pci_id
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
60 * DESCRIPTION: This function derives a full PCI ID for a PCI device,
61 * consisting of a Segment number, Bus number, Device number,
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
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.
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.
83 ******************************************************************************/
86 acpi_hw_derive_pci_id(struct acpi_pci_id
*pci_id
,
87 acpi_handle root_pci_device
, acpi_handle pci_region
)
90 struct acpi_pci_device
*list_head
;
92 ACPI_FUNCTION_TRACE(hw_derive_pci_id
);
95 return_ACPI_STATUS(AE_BAD_PARAMETER
);
98 /* Build a list of PCI devices, from pci_region up to root_pci_device */
101 acpi_hw_build_pci_list(root_pci_device
, pci_region
, &list_head
);
102 if (ACPI_SUCCESS(status
)) {
104 /* Walk the list, updating the PCI device/function/bus numbers */
106 status
= acpi_hw_process_pci_list(pci_id
, list_head
);
108 /* Delete the list */
110 acpi_hw_delete_pci_list(list_head
);
113 return_ACPI_STATUS(status
);
116 /*******************************************************************************
118 * FUNCTION: acpi_hw_build_pci_list
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
124 * pci_region - A handle to the PCI configuration space
126 * return_list_head - Where the PCI device list is returned
130 * DESCRIPTION: Builds a list of devices from the input PCI region up to the
131 * Root PCI device for this namespace subtree.
133 ******************************************************************************/
136 acpi_hw_build_pci_list(acpi_handle root_pci_device
,
137 acpi_handle pci_region
,
138 struct acpi_pci_device
**return_list_head
)
140 acpi_handle current_device
;
141 acpi_handle parent_device
;
143 struct acpi_pci_device
*list_element
;
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.
150 *return_list_head
= NULL
;
151 current_device
= pci_region
;
153 status
= acpi_get_parent(current_device
, &parent_device
);
154 if (ACPI_FAILURE(status
)) {
156 /* Must delete the list before exit */
158 acpi_hw_delete_pci_list(*return_list_head
);
162 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
164 if (parent_device
== root_pci_device
) {
168 list_element
= ACPI_ALLOCATE(sizeof(struct acpi_pci_device
));
171 /* Must delete the list before exit */
173 acpi_hw_delete_pci_list(*return_list_head
);
174 return (AE_NO_MEMORY
);
177 /* Put new element at the head of the list */
179 list_element
->next
= *return_list_head
;
180 list_element
->device
= parent_device
;
181 *return_list_head
= list_element
;
183 current_device
= parent_device
;
187 /*******************************************************************************
189 * FUNCTION: acpi_hw_process_pci_list
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
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.
202 ******************************************************************************/
205 acpi_hw_process_pci_list(struct acpi_pci_id
*pci_id
,
206 struct acpi_pci_device
*list_head
)
208 acpi_status status
= AE_OK
;
209 struct acpi_pci_device
*info
;
213 ACPI_FUNCTION_NAME(hw_process_pci_list
);
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
,
220 bus_number
= pci_id
->bus
;
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.
231 status
= acpi_hw_get_pci_device_info(pci_id
, info
->device
,
232 &bus_number
, &is_bridge
);
233 if (ACPI_FAILURE(status
)) {
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
));
249 /*******************************************************************************
251 * FUNCTION: acpi_hw_delete_pci_list
253 * PARAMETERS: list_head - Device list created by
254 * acpi_hw_build_pci_list
258 * DESCRIPTION: Free the entire PCI list.
260 ******************************************************************************/
262 static void acpi_hw_delete_pci_list(struct acpi_pci_device
*list_head
)
264 struct acpi_pci_device
*next
;
265 struct acpi_pci_device
*previous
;
270 next
= previous
->next
;
275 /*******************************************************************************
277 * FUNCTION: acpi_hw_get_pci_device_info
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
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
293 ******************************************************************************/
296 acpi_hw_get_pci_device_info(struct acpi_pci_id
*pci_id
,
297 acpi_handle pci_device
,
298 u16
*bus_number
, u8
*is_bridge
)
301 acpi_object_type object_type
;
305 /* We only care about objects of type Device */
307 status
= acpi_get_type(pci_device
, &object_type
);
308 if (ACPI_FAILURE(status
)) {
312 if (object_type
!= ACPI_TYPE_DEVICE
) {
316 /* We need an _ADR. Ignore device if not present */
318 status
= acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR
,
319 pci_device
, &return_value
);
320 if (ACPI_FAILURE(status
)) {
325 * From _ADR, get the PCI Device and Function and
328 pci_id
->device
= ACPI_HIWORD(ACPI_LODWORD(return_value
));
329 pci_id
->function
= ACPI_LOWORD(ACPI_LODWORD(return_value
));
332 * If the previous device was a bridge, use the previous
336 pci_id
->bus
= *bus_number
;
340 * Get the bus numbers from PCI Config space:
342 * First, get the PCI header_type
345 status
= acpi_os_read_pci_configuration(pci_id
,
346 PCI_CFG_HEADER_TYPE_REG
,
348 if (ACPI_FAILURE(status
)) {
352 /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
354 pci_value
&= PCI_HEADER_TYPE_MASK
;
356 if ((pci_value
!= PCI_TYPE_BRIDGE
) &&
357 (pci_value
!= PCI_TYPE_CARDBUS_BRIDGE
)) {
361 /* Bridge: Get the Primary bus_number */
363 status
= acpi_os_read_pci_configuration(pci_id
,
364 PCI_CFG_PRIMARY_BUS_NUMBER_REG
,
366 if (ACPI_FAILURE(status
)) {
371 pci_id
->bus
= (u16
)pci_value
;
373 /* Bridge: Get the Secondary bus_number */
375 status
= acpi_os_read_pci_configuration(pci_id
,
376 PCI_CFG_SECONDARY_BUS_NUMBER_REG
,
378 if (ACPI_FAILURE(status
)) {
382 *bus_number
= (u16
)pci_value
;