1/*******************************************************************************
2 *
3 * Module Name: hwpci - Obtain PCI bus, device, and function numbers
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, 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		/* Delete the list */
145
146		acpi_hw_delete_pci_list(list_head);
147	}
148
149	return_ACPI_STATUS(status);
150}
151
152/*******************************************************************************
153 *
154 * FUNCTION:    acpi_hw_build_pci_list
155 *
156 * PARAMETERS:  root_pci_device     - A handle to a PCI device object. This
157 *                                    object is guaranteed to be a PCI Root
158 *                                    Bridge having a _HID value of either
159 *                                    PNP0A03 or PNP0A08
160 *              pci_region          - A handle to the PCI configuration space
161 *                                    Operation Region
162 *              return_list_head    - Where the PCI device list is returned
163 *
164 * RETURN:      Status
165 *
166 * DESCRIPTION: Builds a list of devices from the input PCI region up to the
167 *              Root PCI device for this namespace subtree.
168 *
169 ******************************************************************************/
170
171static acpi_status
172acpi_hw_build_pci_list(acpi_handle root_pci_device,
173		       acpi_handle pci_region,
174		       struct acpi_pci_device **return_list_head)
175{
176	acpi_handle current_device;
177	acpi_handle parent_device;
178	acpi_status status;
179	struct acpi_pci_device *list_element;
180	struct acpi_pci_device *list_head = NULL;
181
182	/*
183	 * Ascend namespace branch until the root_pci_device is reached, building
184	 * a list of device nodes. Loop will exit when either the PCI device is
185	 * found, or the root of the namespace is reached.
186	 */
187	current_device = pci_region;
188	while (1) {
189		status = acpi_get_parent(current_device, &parent_device);
190		if (ACPI_FAILURE(status)) {
191
192			/* Must delete the list before exit */
193
194			acpi_hw_delete_pci_list(*return_list_head);
195			return (status);
196		}
197
198		/* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
199
200		if (parent_device == root_pci_device) {
201			*return_list_head = list_head;
202			return (AE_OK);
203		}
204
205		list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
206		if (!list_element) {
207
208			/* Must delete the list before exit */
209
210			acpi_hw_delete_pci_list(*return_list_head);
211			return (AE_NO_MEMORY);
212		}
213
214		/* Put new element at the head of the list */
215
216		list_element->next = list_head;
217		list_element->device = parent_device;
218		list_head = list_element;
219
220		current_device = parent_device;
221	}
222}
223
224/*******************************************************************************
225 *
226 * FUNCTION:    acpi_hw_process_pci_list
227 *
228 * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
229 *                                    modified by this function.
230 *              list_head           - Device list created by
231 *                                    acpi_hw_build_pci_list
232 *
233 * RETURN:      Status
234 *
235 * DESCRIPTION: Walk downward through the PCI device list, getting the device
236 *              info for each, via the PCI configuration space and updating
237 *              the PCI ID as necessary. Deletes the list during traversal.
238 *
239 ******************************************************************************/
240
241static acpi_status
242acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
243			 struct acpi_pci_device *list_head)
244{
245	acpi_status status = AE_OK;
246	struct acpi_pci_device *info;
247	u16 bus_number;
248	u8 is_bridge = TRUE;
249
250	ACPI_FUNCTION_NAME(hw_process_pci_list);
251
252	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
253			  "Input PciId:  Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
254			  pci_id->segment, pci_id->bus, pci_id->device,
255			  pci_id->function));
256
257	bus_number = pci_id->bus;
258
259	/*
260	 * Descend down the namespace tree, collecting PCI device, function,
261	 * and bus numbers. bus_number is only important for PCI bridges.
262	 * Algorithm: As we descend the tree, use the last valid PCI device,
263	 * function, and bus numbers that are discovered, and assign them
264	 * to the PCI ID for the target device.
265	 */
266	info = list_head;
267	while (info) {
268		status = acpi_hw_get_pci_device_info(pci_id, info->device,
269						     &bus_number, &is_bridge);
270		if (ACPI_FAILURE(status)) {
271			return (status);
272		}
273
274		info = info->next;
275	}
276
277	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
278			  "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
279			  "Status %X BusNumber %X IsBridge %X\n",
280			  pci_id->segment, pci_id->bus, pci_id->device,
281			  pci_id->function, status, bus_number, is_bridge));
282
283	return (AE_OK);
284}
285
286/*******************************************************************************
287 *
288 * FUNCTION:    acpi_hw_delete_pci_list
289 *
290 * PARAMETERS:  list_head           - Device list created by
291 *                                    acpi_hw_build_pci_list
292 *
293 * RETURN:      None
294 *
295 * DESCRIPTION: Free the entire PCI list.
296 *
297 ******************************************************************************/
298
299static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
300{
301	struct acpi_pci_device *next;
302	struct acpi_pci_device *previous;
303
304	next = list_head;
305	while (next) {
306		previous = next;
307		next = previous->next;
308		ACPI_FREE(previous);
309	}
310}
311
312/*******************************************************************************
313 *
314 * FUNCTION:    acpi_hw_get_pci_device_info
315 *
316 * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
317 *                                    modified by this function.
318 *              pci_device          - Handle for the PCI device object
319 *              bus_number          - Where a PCI bridge bus number is returned
320 *              is_bridge           - Return value, indicates if this PCI
321 *                                    device is a PCI bridge
322 *
323 * RETURN:      Status
324 *
325 * DESCRIPTION: Get the device info for a single PCI device object. Get the
326 *              _ADR (contains PCI device and function numbers), and for PCI
327 *              bridge devices, get the bus number from PCI configuration
328 *              space.
329 *
330 ******************************************************************************/
331
332static acpi_status
333acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
334			    acpi_handle pci_device,
335			    u16 *bus_number, u8 *is_bridge)
336{
337	acpi_status status;
338	acpi_object_type object_type;
339	u64 return_value;
340	u64 pci_value;
341
342	/* We only care about objects of type Device */
343
344	status = acpi_get_type(pci_device, &object_type);
345	if (ACPI_FAILURE(status)) {
346		return (status);
347	}
348
349	if (object_type != ACPI_TYPE_DEVICE) {
350		return (AE_OK);
351	}
352
353	/* We need an _ADR. Ignore device if not present */
354
355	status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
356						 pci_device, &return_value);
357	if (ACPI_FAILURE(status)) {
358		return (AE_OK);
359	}
360
361	/*
362	 * From _ADR, get the PCI Device and Function and
363	 * update the PCI ID.
364	 */
365	pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
366	pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
367
368	/*
369	 * If the previous device was a bridge, use the previous
370	 * device bus number
371	 */
372	if (*is_bridge) {
373		pci_id->bus = *bus_number;
374	}
375
376	/*
377	 * Get the bus numbers from PCI Config space:
378	 *
379	 * First, get the PCI header_type
380	 */
381	*is_bridge = FALSE;
382	status = acpi_os_read_pci_configuration(pci_id,
383						PCI_CFG_HEADER_TYPE_REG,
384						&pci_value, 8);
385	if (ACPI_FAILURE(status)) {
386		return (status);
387	}
388
389	/* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
390
391	pci_value &= PCI_HEADER_TYPE_MASK;
392
393	if ((pci_value != PCI_TYPE_BRIDGE) &&
394	    (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
395		return (AE_OK);
396	}
397
398	/* Bridge: Get the Primary bus_number */
399
400	status = acpi_os_read_pci_configuration(pci_id,
401						PCI_CFG_PRIMARY_BUS_NUMBER_REG,
402						&pci_value, 8);
403	if (ACPI_FAILURE(status)) {
404		return (status);
405	}
406
407	*is_bridge = TRUE;
408	pci_id->bus = (u16)pci_value;
409
410	/* Bridge: Get the Secondary bus_number */
411
412	status = acpi_os_read_pci_configuration(pci_id,
413						PCI_CFG_SECONDARY_BUS_NUMBER_REG,
414						&pci_value, 8);
415	if (ACPI_FAILURE(status)) {
416		return (status);
417	}
418
419	*bus_number = (u16)pci_value;
420	return (AE_OK);
421}
422