blob: 3dd60c96aa07398bb8072ccce5c3ea0545cc72c0 [file] [log] [blame]
Bob Moore95abccb2010-09-15 13:22:46 +08001/*******************************************************************************
2 *
3 * Module Name: hwpci - Obtain PCI bus, device, and function numbers
4 *
5 ******************************************************************************/
6
7/*
Bob Moorec8100dc2016-01-15 08:17:03 +08008 * Copyright (C) 2000 - 2016, Intel Corp.
Bob Moore95abccb2010-09-15 13:22:46 +08009 * 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;
Lv Zheng2900d562015-05-21 10:31:12 +0800126 struct acpi_pci_device *list_head;
Bob Moore95abccb2010-09-15 13:22:46 +0800127
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);
David E. Boxc28fa242014-04-30 10:04:20 +0800143
144 /* Delete the list */
145
146 acpi_hw_delete_pci_list(list_head);
Bob Moore95abccb2010-09-15 13:22:46 +0800147 }
148
Bob Moore95abccb2010-09-15 13:22:46 +0800149 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;
Bob Moore95abccb2010-09-15 13:22:46 +0800180
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 */
Lv Zheng2900d562015-05-21 10:31:12 +0800186 *return_list_head = NULL;
Bob Moore95abccb2010-09-15 13:22:46 +0800187 current_device = pci_region;
188 while (1) {
189 status = acpi_get_parent(current_device, &parent_device);
190 if (ACPI_FAILURE(status)) {
David E. Boxc28fa242014-04-30 10:04:20 +0800191
192 /* Must delete the list before exit */
193
194 acpi_hw_delete_pci_list(*return_list_head);
Bob Moore95abccb2010-09-15 13:22:46 +0800195 return (status);
196 }
197
198 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
199
200 if (parent_device == root_pci_device) {
Bob Moore95abccb2010-09-15 13:22:46 +0800201 return (AE_OK);
202 }
203
204 list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
205 if (!list_element) {
David E. Boxc28fa242014-04-30 10:04:20 +0800206
207 /* Must delete the list before exit */
208
209 acpi_hw_delete_pci_list(*return_list_head);
Bob Moore95abccb2010-09-15 13:22:46 +0800210 return (AE_NO_MEMORY);
211 }
212
213 /* Put new element at the head of the list */
214
Lv Zheng2900d562015-05-21 10:31:12 +0800215 list_element->next = *return_list_head;
Bob Moore95abccb2010-09-15 13:22:46 +0800216 list_element->device = parent_device;
Lv Zheng2900d562015-05-21 10:31:12 +0800217 *return_list_head = list_element;
Bob Moore95abccb2010-09-15 13:22:46 +0800218
219 current_device = parent_device;
220 }
221}
222
223/*******************************************************************************
224 *
225 * FUNCTION: acpi_hw_process_pci_list
226 *
227 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
228 * modified by this function.
229 * list_head - Device list created by
230 * acpi_hw_build_pci_list
231 *
232 * RETURN: Status
233 *
234 * DESCRIPTION: Walk downward through the PCI device list, getting the device
235 * info for each, via the PCI configuration space and updating
236 * the PCI ID as necessary. Deletes the list during traversal.
237 *
238 ******************************************************************************/
239
240static acpi_status
241acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
242 struct acpi_pci_device *list_head)
243{
244 acpi_status status = AE_OK;
245 struct acpi_pci_device *info;
246 u16 bus_number;
247 u8 is_bridge = TRUE;
248
249 ACPI_FUNCTION_NAME(hw_process_pci_list);
250
251 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
252 "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
253 pci_id->segment, pci_id->bus, pci_id->device,
254 pci_id->function));
255
256 bus_number = pci_id->bus;
257
258 /*
259 * Descend down the namespace tree, collecting PCI device, function,
260 * and bus numbers. bus_number is only important for PCI bridges.
261 * Algorithm: As we descend the tree, use the last valid PCI device,
262 * function, and bus numbers that are discovered, and assign them
263 * to the PCI ID for the target device.
264 */
265 info = list_head;
266 while (info) {
267 status = acpi_hw_get_pci_device_info(pci_id, info->device,
268 &bus_number, &is_bridge);
269 if (ACPI_FAILURE(status)) {
Bob Moore68aafc32012-10-31 02:26:01 +0000270 return (status);
Bob Moore95abccb2010-09-15 13:22:46 +0800271 }
272
273 info = info->next;
274 }
275
276 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
277 "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
278 "Status %X BusNumber %X IsBridge %X\n",
279 pci_id->segment, pci_id->bus, pci_id->device,
280 pci_id->function, status, bus_number, is_bridge));
281
Bob Moore68aafc32012-10-31 02:26:01 +0000282 return (AE_OK);
Bob Moore95abccb2010-09-15 13:22:46 +0800283}
284
285/*******************************************************************************
286 *
287 * FUNCTION: acpi_hw_delete_pci_list
288 *
289 * PARAMETERS: list_head - Device list created by
290 * acpi_hw_build_pci_list
291 *
292 * RETURN: None
293 *
294 * DESCRIPTION: Free the entire PCI list.
295 *
296 ******************************************************************************/
297
298static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
299{
300 struct acpi_pci_device *next;
301 struct acpi_pci_device *previous;
302
303 next = list_head;
304 while (next) {
305 previous = next;
306 next = previous->next;
307 ACPI_FREE(previous);
308 }
309}
310
311/*******************************************************************************
312 *
313 * FUNCTION: acpi_hw_get_pci_device_info
314 *
315 * PARAMETERS: pci_id - Initial values for the PCI ID. May be
316 * modified by this function.
317 * pci_device - Handle for the PCI device object
318 * bus_number - Where a PCI bridge bus number is returned
319 * is_bridge - Return value, indicates if this PCI
320 * device is a PCI bridge
321 *
322 * RETURN: Status
323 *
324 * DESCRIPTION: Get the device info for a single PCI device object. Get the
325 * _ADR (contains PCI device and function numbers), and for PCI
326 * bridge devices, get the bus number from PCI configuration
327 * space.
328 *
329 ******************************************************************************/
330
331static acpi_status
332acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
333 acpi_handle pci_device,
334 u16 *bus_number, u8 *is_bridge)
335{
336 acpi_status status;
337 acpi_object_type object_type;
338 u64 return_value;
339 u64 pci_value;
340
341 /* We only care about objects of type Device */
342
343 status = acpi_get_type(pci_device, &object_type);
344 if (ACPI_FAILURE(status)) {
345 return (status);
346 }
347
348 if (object_type != ACPI_TYPE_DEVICE) {
349 return (AE_OK);
350 }
351
352 /* We need an _ADR. Ignore device if not present */
353
354 status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
355 pci_device, &return_value);
356 if (ACPI_FAILURE(status)) {
357 return (AE_OK);
358 }
359
360 /*
361 * From _ADR, get the PCI Device and Function and
362 * update the PCI ID.
363 */
364 pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
365 pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
366
367 /*
368 * If the previous device was a bridge, use the previous
369 * device bus number
370 */
371 if (*is_bridge) {
372 pci_id->bus = *bus_number;
373 }
374
375 /*
376 * Get the bus numbers from PCI Config space:
377 *
378 * First, get the PCI header_type
379 */
380 *is_bridge = FALSE;
381 status = acpi_os_read_pci_configuration(pci_id,
382 PCI_CFG_HEADER_TYPE_REG,
383 &pci_value, 8);
384 if (ACPI_FAILURE(status)) {
385 return (status);
386 }
387
388 /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
389
390 pci_value &= PCI_HEADER_TYPE_MASK;
391
392 if ((pci_value != PCI_TYPE_BRIDGE) &&
393 (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
394 return (AE_OK);
395 }
396
397 /* Bridge: Get the Primary bus_number */
398
399 status = acpi_os_read_pci_configuration(pci_id,
400 PCI_CFG_PRIMARY_BUS_NUMBER_REG,
401 &pci_value, 8);
402 if (ACPI_FAILURE(status)) {
403 return (status);
404 }
405
406 *is_bridge = TRUE;
407 pci_id->bus = (u16)pci_value;
408
409 /* Bridge: Get the Secondary bus_number */
410
411 status = acpi_os_read_pci_configuration(pci_id,
412 PCI_CFG_SECONDARY_BUS_NUMBER_REG,
413 &pci_value, 8);
414 if (ACPI_FAILURE(status)) {
415 return (status);
416 }
417
418 *bus_number = (u16)pci_value;
419 return (AE_OK);
420}