xref: /openbmc/linux/drivers/acpi/acpica/hwpci.c (revision 95857638)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295abccb5SBob Moore /*******************************************************************************
395abccb5SBob Moore  *
495abccb5SBob Moore  * Module Name: hwpci - Obtain PCI bus, device, and function numbers
595abccb5SBob Moore  *
695abccb5SBob Moore  ******************************************************************************/
795abccb5SBob Moore 
895abccb5SBob Moore #include <acpi/acpi.h>
995abccb5SBob Moore #include "accommon.h"
1095abccb5SBob Moore 
1195abccb5SBob Moore #define _COMPONENT          ACPI_NAMESPACE
1295abccb5SBob Moore ACPI_MODULE_NAME("hwpci")
1395abccb5SBob Moore 
1495abccb5SBob Moore /* PCI configuration space values */
1595abccb5SBob Moore #define PCI_CFG_HEADER_TYPE_REG             0x0E
1695abccb5SBob Moore #define PCI_CFG_PRIMARY_BUS_NUMBER_REG      0x18
1795abccb5SBob Moore #define PCI_CFG_SECONDARY_BUS_NUMBER_REG    0x19
1895abccb5SBob Moore /* PCI header values */
1995abccb5SBob Moore #define PCI_HEADER_TYPE_MASK                0x7F
2095abccb5SBob Moore #define PCI_TYPE_BRIDGE                     0x01
2195abccb5SBob Moore #define PCI_TYPE_CARDBUS_BRIDGE             0x02
2295abccb5SBob Moore typedef struct acpi_pci_device {
2395abccb5SBob Moore 	acpi_handle device;
2495abccb5SBob Moore 	struct acpi_pci_device *next;
2595abccb5SBob Moore 
2695abccb5SBob Moore } acpi_pci_device;
2795abccb5SBob Moore 
2895abccb5SBob Moore /* Local prototypes */
2995abccb5SBob Moore 
3095abccb5SBob Moore static acpi_status
3195abccb5SBob Moore acpi_hw_build_pci_list(acpi_handle root_pci_device,
3295abccb5SBob Moore 		       acpi_handle pci_region,
3395abccb5SBob Moore 		       struct acpi_pci_device **return_list_head);
3495abccb5SBob Moore 
3595abccb5SBob Moore static acpi_status
3695abccb5SBob Moore acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
3795abccb5SBob Moore 			 struct acpi_pci_device *list_head);
3895abccb5SBob Moore 
3995abccb5SBob Moore static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
4095abccb5SBob Moore 
4195abccb5SBob Moore static acpi_status
4295abccb5SBob Moore acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
4395abccb5SBob Moore 			    acpi_handle pci_device,
4495abccb5SBob Moore 			    u16 *bus_number, u8 *is_bridge);
4595abccb5SBob Moore 
4695abccb5SBob Moore /*******************************************************************************
4795abccb5SBob Moore  *
4895abccb5SBob Moore  * FUNCTION:    acpi_hw_derive_pci_id
4995abccb5SBob Moore  *
5095abccb5SBob Moore  * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
5195abccb5SBob Moore  *                                    modified by this function.
5295abccb5SBob Moore  *              root_pci_device     - A handle to a PCI device object. This
5395abccb5SBob Moore  *                                    object must be a PCI Root Bridge having a
5495abccb5SBob Moore  *                                    _HID value of either PNP0A03 or PNP0A08
5595abccb5SBob Moore  *              pci_region          - A handle to a PCI configuration space
5695abccb5SBob Moore  *                                    Operation Region being initialized
5795abccb5SBob Moore  *
5895abccb5SBob Moore  * RETURN:      Status
5995abccb5SBob Moore  *
6095abccb5SBob Moore  * DESCRIPTION: This function derives a full PCI ID for a PCI device,
6195abccb5SBob Moore  *              consisting of a Segment number, Bus number, Device number,
6295abccb5SBob Moore  *              and function code.
6395abccb5SBob Moore  *
6495abccb5SBob Moore  *              The PCI hardware dynamically configures PCI bus numbers
6595abccb5SBob Moore  *              depending on the bus topology discovered during system
6695abccb5SBob Moore  *              initialization. This function is invoked during configuration
6795abccb5SBob Moore  *              of a PCI_Config Operation Region in order to (possibly) update
6895abccb5SBob Moore  *              the Bus/Device/Function numbers in the pci_id with the actual
6995abccb5SBob Moore  *              values as determined by the hardware and operating system
7095abccb5SBob Moore  *              configuration.
7195abccb5SBob Moore  *
7295abccb5SBob Moore  *              The pci_id parameter is initially populated during the Operation
7395abccb5SBob Moore  *              Region initialization. This function is then called, and is
7495abccb5SBob Moore  *              will make any necessary modifications to the Bus, Device, or
7595abccb5SBob Moore  *              Function number PCI ID subfields as appropriate for the
7695abccb5SBob Moore  *              current hardware and OS configuration.
7795abccb5SBob Moore  *
7895abccb5SBob Moore  * NOTE:        Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id
7995abccb5SBob Moore  *              interface since this feature is OS-independent. This module
8095abccb5SBob Moore  *              specifically avoids any use of recursion by building a local
8195abccb5SBob Moore  *              temporary device list.
8295abccb5SBob Moore  *
8395abccb5SBob Moore  ******************************************************************************/
8495abccb5SBob Moore 
8595abccb5SBob Moore acpi_status
acpi_hw_derive_pci_id(struct acpi_pci_id * pci_id,acpi_handle root_pci_device,acpi_handle pci_region)8695abccb5SBob Moore acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
8795abccb5SBob Moore 		      acpi_handle root_pci_device, acpi_handle pci_region)
8895abccb5SBob Moore {
8995abccb5SBob Moore 	acpi_status status;
902900d56fSLv Zheng 	struct acpi_pci_device *list_head;
9195abccb5SBob Moore 
9295abccb5SBob Moore 	ACPI_FUNCTION_TRACE(hw_derive_pci_id);
9395abccb5SBob Moore 
9495abccb5SBob Moore 	if (!pci_id) {
9595abccb5SBob Moore 		return_ACPI_STATUS(AE_BAD_PARAMETER);
9695abccb5SBob Moore 	}
9795abccb5SBob Moore 
9895abccb5SBob Moore 	/* Build a list of PCI devices, from pci_region up to root_pci_device */
9995abccb5SBob Moore 
10095abccb5SBob Moore 	status =
10195abccb5SBob Moore 	    acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
10295abccb5SBob Moore 	if (ACPI_SUCCESS(status)) {
10395abccb5SBob Moore 
10495abccb5SBob Moore 		/* Walk the list, updating the PCI device/function/bus numbers */
10595abccb5SBob Moore 
10695abccb5SBob Moore 		status = acpi_hw_process_pci_list(pci_id, list_head);
10795abccb5SBob Moore 
108c28fa24bSDavid E. Box 		/* Delete the list */
10995abccb5SBob Moore 
11095abccb5SBob Moore 		acpi_hw_delete_pci_list(list_head);
111c28fa24bSDavid E. Box 	}
112c28fa24bSDavid E. Box 
11395abccb5SBob Moore 	return_ACPI_STATUS(status);
11495abccb5SBob Moore }
11595abccb5SBob Moore 
11695abccb5SBob Moore /*******************************************************************************
11795abccb5SBob Moore  *
11895abccb5SBob Moore  * FUNCTION:    acpi_hw_build_pci_list
11995abccb5SBob Moore  *
12095abccb5SBob Moore  * PARAMETERS:  root_pci_device     - A handle to a PCI device object. This
12195abccb5SBob Moore  *                                    object is guaranteed to be a PCI Root
12295abccb5SBob Moore  *                                    Bridge having a _HID value of either
12395abccb5SBob Moore  *                                    PNP0A03 or PNP0A08
12495abccb5SBob Moore  *              pci_region          - A handle to the PCI configuration space
12595abccb5SBob Moore  *                                    Operation Region
12695abccb5SBob Moore  *              return_list_head    - Where the PCI device list is returned
12795abccb5SBob Moore  *
12895abccb5SBob Moore  * RETURN:      Status
12995abccb5SBob Moore  *
13095abccb5SBob Moore  * DESCRIPTION: Builds a list of devices from the input PCI region up to the
13195abccb5SBob Moore  *              Root PCI device for this namespace subtree.
13295abccb5SBob Moore  *
13395abccb5SBob Moore  ******************************************************************************/
13495abccb5SBob Moore 
13595abccb5SBob Moore static acpi_status
acpi_hw_build_pci_list(acpi_handle root_pci_device,acpi_handle pci_region,struct acpi_pci_device ** return_list_head)13695abccb5SBob Moore acpi_hw_build_pci_list(acpi_handle root_pci_device,
13795abccb5SBob Moore 		       acpi_handle pci_region,
13895abccb5SBob Moore 		       struct acpi_pci_device **return_list_head)
13995abccb5SBob Moore {
14095abccb5SBob Moore 	acpi_handle current_device;
14195abccb5SBob Moore 	acpi_handle parent_device;
14295abccb5SBob Moore 	acpi_status status;
14395abccb5SBob Moore 	struct acpi_pci_device *list_element;
14495abccb5SBob Moore 
14595abccb5SBob Moore 	/*
14695abccb5SBob Moore 	 * Ascend namespace branch until the root_pci_device is reached, building
14795abccb5SBob Moore 	 * a list of device nodes. Loop will exit when either the PCI device is
14895abccb5SBob Moore 	 * found, or the root of the namespace is reached.
14995abccb5SBob Moore 	 */
1502900d56fSLv Zheng 	*return_list_head = NULL;
15195abccb5SBob Moore 	current_device = pci_region;
15295abccb5SBob Moore 	while (1) {
15395abccb5SBob Moore 		status = acpi_get_parent(current_device, &parent_device);
15495abccb5SBob Moore 		if (ACPI_FAILURE(status)) {
155c28fa24bSDavid E. Box 
156c28fa24bSDavid E. Box 			/* Must delete the list before exit */
157c28fa24bSDavid E. Box 
158c28fa24bSDavid E. Box 			acpi_hw_delete_pci_list(*return_list_head);
15995abccb5SBob Moore 			return (status);
16095abccb5SBob Moore 		}
16195abccb5SBob Moore 
16295abccb5SBob Moore 		/* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
16395abccb5SBob Moore 
16495abccb5SBob Moore 		if (parent_device == root_pci_device) {
16595abccb5SBob Moore 			return (AE_OK);
16695abccb5SBob Moore 		}
16795abccb5SBob Moore 
16895abccb5SBob Moore 		list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
16995abccb5SBob Moore 		if (!list_element) {
170c28fa24bSDavid E. Box 
171c28fa24bSDavid E. Box 			/* Must delete the list before exit */
172c28fa24bSDavid E. Box 
173c28fa24bSDavid E. Box 			acpi_hw_delete_pci_list(*return_list_head);
17495abccb5SBob Moore 			return (AE_NO_MEMORY);
17595abccb5SBob Moore 		}
17695abccb5SBob Moore 
17795abccb5SBob Moore 		/* Put new element at the head of the list */
17895abccb5SBob Moore 
1792900d56fSLv Zheng 		list_element->next = *return_list_head;
18095abccb5SBob Moore 		list_element->device = parent_device;
1812900d56fSLv Zheng 		*return_list_head = list_element;
18295abccb5SBob Moore 
18395abccb5SBob Moore 		current_device = parent_device;
18495abccb5SBob Moore 	}
18595abccb5SBob Moore }
18695abccb5SBob Moore 
18795abccb5SBob Moore /*******************************************************************************
18895abccb5SBob Moore  *
18995abccb5SBob Moore  * FUNCTION:    acpi_hw_process_pci_list
19095abccb5SBob Moore  *
19195abccb5SBob Moore  * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
19295abccb5SBob Moore  *                                    modified by this function.
19395abccb5SBob Moore  *              list_head           - Device list created by
19495abccb5SBob Moore  *                                    acpi_hw_build_pci_list
19595abccb5SBob Moore  *
19695abccb5SBob Moore  * RETURN:      Status
19795abccb5SBob Moore  *
19895abccb5SBob Moore  * DESCRIPTION: Walk downward through the PCI device list, getting the device
19995abccb5SBob Moore  *              info for each, via the PCI configuration space and updating
20095abccb5SBob Moore  *              the PCI ID as necessary. Deletes the list during traversal.
20195abccb5SBob Moore  *
20295abccb5SBob Moore  ******************************************************************************/
20395abccb5SBob Moore 
20495abccb5SBob Moore static acpi_status
acpi_hw_process_pci_list(struct acpi_pci_id * pci_id,struct acpi_pci_device * list_head)20595abccb5SBob Moore acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
20695abccb5SBob Moore 			 struct acpi_pci_device *list_head)
20795abccb5SBob Moore {
20895abccb5SBob Moore 	acpi_status status = AE_OK;
20995abccb5SBob Moore 	struct acpi_pci_device *info;
21095abccb5SBob Moore 	u16 bus_number;
21195abccb5SBob Moore 	u8 is_bridge = TRUE;
21295abccb5SBob Moore 
21395abccb5SBob Moore 	ACPI_FUNCTION_NAME(hw_process_pci_list);
21495abccb5SBob Moore 
21595abccb5SBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
21695abccb5SBob Moore 			  "Input PciId:  Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
21795abccb5SBob Moore 			  pci_id->segment, pci_id->bus, pci_id->device,
21895abccb5SBob Moore 			  pci_id->function));
21995abccb5SBob Moore 
22095abccb5SBob Moore 	bus_number = pci_id->bus;
22195abccb5SBob Moore 
22295abccb5SBob Moore 	/*
22395abccb5SBob Moore 	 * Descend down the namespace tree, collecting PCI device, function,
22495abccb5SBob Moore 	 * and bus numbers. bus_number is only important for PCI bridges.
22595abccb5SBob Moore 	 * Algorithm: As we descend the tree, use the last valid PCI device,
22695abccb5SBob Moore 	 * function, and bus numbers that are discovered, and assign them
22795abccb5SBob Moore 	 * to the PCI ID for the target device.
22895abccb5SBob Moore 	 */
22995abccb5SBob Moore 	info = list_head;
23095abccb5SBob Moore 	while (info) {
23195abccb5SBob Moore 		status = acpi_hw_get_pci_device_info(pci_id, info->device,
23295abccb5SBob Moore 						     &bus_number, &is_bridge);
23395abccb5SBob Moore 		if (ACPI_FAILURE(status)) {
23468aafc35SBob Moore 			return (status);
23595abccb5SBob Moore 		}
23695abccb5SBob Moore 
23795abccb5SBob Moore 		info = info->next;
23895abccb5SBob Moore 	}
23995abccb5SBob Moore 
24095abccb5SBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
24195abccb5SBob Moore 			  "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
24295abccb5SBob Moore 			  "Status %X BusNumber %X IsBridge %X\n",
24395abccb5SBob Moore 			  pci_id->segment, pci_id->bus, pci_id->device,
24495abccb5SBob Moore 			  pci_id->function, status, bus_number, is_bridge));
24595abccb5SBob Moore 
24668aafc35SBob Moore 	return (AE_OK);
24795abccb5SBob Moore }
24895abccb5SBob Moore 
24995abccb5SBob Moore /*******************************************************************************
25095abccb5SBob Moore  *
25195abccb5SBob Moore  * FUNCTION:    acpi_hw_delete_pci_list
25295abccb5SBob Moore  *
25395abccb5SBob Moore  * PARAMETERS:  list_head           - Device list created by
25495abccb5SBob Moore  *                                    acpi_hw_build_pci_list
25595abccb5SBob Moore  *
25695abccb5SBob Moore  * RETURN:      None
25795abccb5SBob Moore  *
25895abccb5SBob Moore  * DESCRIPTION: Free the entire PCI list.
25995abccb5SBob Moore  *
26095abccb5SBob Moore  ******************************************************************************/
26195abccb5SBob Moore 
acpi_hw_delete_pci_list(struct acpi_pci_device * list_head)26295abccb5SBob Moore static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
26395abccb5SBob Moore {
26495abccb5SBob Moore 	struct acpi_pci_device *next;
26595abccb5SBob Moore 	struct acpi_pci_device *previous;
26695abccb5SBob Moore 
26795abccb5SBob Moore 	next = list_head;
26895abccb5SBob Moore 	while (next) {
26995abccb5SBob Moore 		previous = next;
27095abccb5SBob Moore 		next = previous->next;
27195abccb5SBob Moore 		ACPI_FREE(previous);
27295abccb5SBob Moore 	}
27395abccb5SBob Moore }
27495abccb5SBob Moore 
27595abccb5SBob Moore /*******************************************************************************
27695abccb5SBob Moore  *
27795abccb5SBob Moore  * FUNCTION:    acpi_hw_get_pci_device_info
27895abccb5SBob Moore  *
27995abccb5SBob Moore  * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
28095abccb5SBob Moore  *                                    modified by this function.
28195abccb5SBob Moore  *              pci_device          - Handle for the PCI device object
28295abccb5SBob Moore  *              bus_number          - Where a PCI bridge bus number is returned
28395abccb5SBob Moore  *              is_bridge           - Return value, indicates if this PCI
28495abccb5SBob Moore  *                                    device is a PCI bridge
28595abccb5SBob Moore  *
28695abccb5SBob Moore  * RETURN:      Status
28795abccb5SBob Moore  *
28895abccb5SBob Moore  * DESCRIPTION: Get the device info for a single PCI device object. Get the
28995abccb5SBob Moore  *              _ADR (contains PCI device and function numbers), and for PCI
29095abccb5SBob Moore  *              bridge devices, get the bus number from PCI configuration
29195abccb5SBob Moore  *              space.
29295abccb5SBob Moore  *
29395abccb5SBob Moore  ******************************************************************************/
29495abccb5SBob Moore 
29595abccb5SBob Moore static acpi_status
acpi_hw_get_pci_device_info(struct acpi_pci_id * pci_id,acpi_handle pci_device,u16 * bus_number,u8 * is_bridge)29695abccb5SBob Moore acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
29795abccb5SBob Moore 			    acpi_handle pci_device,
29895abccb5SBob Moore 			    u16 *bus_number, u8 *is_bridge)
29995abccb5SBob Moore {
30095abccb5SBob Moore 	acpi_status status;
30195abccb5SBob Moore 	acpi_object_type object_type;
30295abccb5SBob Moore 	u64 return_value;
30395abccb5SBob Moore 	u64 pci_value;
30495abccb5SBob Moore 
30595abccb5SBob Moore 	/* We only care about objects of type Device */
30695abccb5SBob Moore 
30795abccb5SBob Moore 	status = acpi_get_type(pci_device, &object_type);
30895abccb5SBob Moore 	if (ACPI_FAILURE(status)) {
30995abccb5SBob Moore 		return (status);
31095abccb5SBob Moore 	}
31195abccb5SBob Moore 
31295abccb5SBob Moore 	if (object_type != ACPI_TYPE_DEVICE) {
31395abccb5SBob Moore 		return (AE_OK);
31495abccb5SBob Moore 	}
31595abccb5SBob Moore 
31695abccb5SBob Moore 	/* We need an _ADR. Ignore device if not present */
31795abccb5SBob Moore 
31895abccb5SBob Moore 	status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
31995abccb5SBob Moore 						 pci_device, &return_value);
32095abccb5SBob Moore 	if (ACPI_FAILURE(status)) {
32195abccb5SBob Moore 		return (AE_OK);
32295abccb5SBob Moore 	}
32395abccb5SBob Moore 
32495abccb5SBob Moore 	/*
32595abccb5SBob Moore 	 * From _ADR, get the PCI Device and Function and
32695abccb5SBob Moore 	 * update the PCI ID.
32795abccb5SBob Moore 	 */
32895abccb5SBob Moore 	pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
32995abccb5SBob Moore 	pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
33095abccb5SBob Moore 
33195abccb5SBob Moore 	/*
33295abccb5SBob Moore 	 * If the previous device was a bridge, use the previous
33395abccb5SBob Moore 	 * device bus number
33495abccb5SBob Moore 	 */
33595abccb5SBob Moore 	if (*is_bridge) {
33695abccb5SBob Moore 		pci_id->bus = *bus_number;
33795abccb5SBob Moore 	}
33895abccb5SBob Moore 
33995abccb5SBob Moore 	/*
34095abccb5SBob Moore 	 * Get the bus numbers from PCI Config space:
34195abccb5SBob Moore 	 *
34295abccb5SBob Moore 	 * First, get the PCI header_type
34395abccb5SBob Moore 	 */
34495abccb5SBob Moore 	*is_bridge = FALSE;
34595abccb5SBob Moore 	status = acpi_os_read_pci_configuration(pci_id,
34695abccb5SBob Moore 						PCI_CFG_HEADER_TYPE_REG,
34795abccb5SBob Moore 						&pci_value, 8);
34895abccb5SBob Moore 	if (ACPI_FAILURE(status)) {
34995abccb5SBob Moore 		return (status);
35095abccb5SBob Moore 	}
35195abccb5SBob Moore 
35295abccb5SBob Moore 	/* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
35395abccb5SBob Moore 
35495abccb5SBob Moore 	pci_value &= PCI_HEADER_TYPE_MASK;
35595abccb5SBob Moore 
35695abccb5SBob Moore 	if ((pci_value != PCI_TYPE_BRIDGE) &&
35795abccb5SBob Moore 	    (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
35895abccb5SBob Moore 		return (AE_OK);
35995abccb5SBob Moore 	}
36095abccb5SBob Moore 
36195abccb5SBob Moore 	/* Bridge: Get the Primary bus_number */
36295abccb5SBob Moore 
36395abccb5SBob Moore 	status = acpi_os_read_pci_configuration(pci_id,
36495abccb5SBob Moore 						PCI_CFG_PRIMARY_BUS_NUMBER_REG,
36595abccb5SBob Moore 						&pci_value, 8);
36695abccb5SBob Moore 	if (ACPI_FAILURE(status)) {
36795abccb5SBob Moore 		return (status);
36895abccb5SBob Moore 	}
36995abccb5SBob Moore 
37095abccb5SBob Moore 	*is_bridge = TRUE;
37195abccb5SBob Moore 	pci_id->bus = (u16)pci_value;
37295abccb5SBob Moore 
37395abccb5SBob Moore 	/* Bridge: Get the Secondary bus_number */
37495abccb5SBob Moore 
37595abccb5SBob Moore 	status = acpi_os_read_pci_configuration(pci_id,
37695abccb5SBob Moore 						PCI_CFG_SECONDARY_BUS_NUMBER_REG,
37795abccb5SBob Moore 						&pci_value, 8);
37895abccb5SBob Moore 	if (ACPI_FAILURE(status)) {
37995abccb5SBob Moore 		return (status);
38095abccb5SBob Moore 	}
38195abccb5SBob Moore 
38295abccb5SBob Moore 	*bus_number = (u16)pci_value;
38395abccb5SBob Moore 	return (AE_OK);
38495abccb5SBob Moore }
385