kernel: Sync ACPICA with Intel's version 20140424.
[dragonfly.git] / sys / contrib / dev / acpica / source / components / hardware / hwpci.c
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 #define __HWPCI_C__
45
46 #include "acpi.h"
47 #include "accommon.h"
48
49
50 #define _COMPONENT          ACPI_NAMESPACE
51         ACPI_MODULE_NAME    ("hwpci")
52
53
54 /* PCI configuration space values */
55
56 #define PCI_CFG_HEADER_TYPE_REG             0x0E
57 #define PCI_CFG_PRIMARY_BUS_NUMBER_REG      0x18
58 #define PCI_CFG_SECONDARY_BUS_NUMBER_REG    0x19
59
60 /* PCI header values */
61
62 #define PCI_HEADER_TYPE_MASK                0x7F
63 #define PCI_TYPE_BRIDGE                     0x01
64 #define PCI_TYPE_CARDBUS_BRIDGE             0x02
65
66 typedef struct acpi_pci_device
67 {
68     ACPI_HANDLE             Device;
69     struct acpi_pci_device  *Next;
70
71 } ACPI_PCI_DEVICE;
72
73
74 /* Local prototypes */
75
76 static ACPI_STATUS
77 AcpiHwBuildPciList (
78     ACPI_HANDLE             RootPciDevice,
79     ACPI_HANDLE             PciRegion,
80     ACPI_PCI_DEVICE         **ReturnListHead);
81
82 static ACPI_STATUS
83 AcpiHwProcessPciList (
84     ACPI_PCI_ID             *PciId,
85     ACPI_PCI_DEVICE         *ListHead);
86
87 static void
88 AcpiHwDeletePciList (
89     ACPI_PCI_DEVICE         *ListHead);
90
91 static ACPI_STATUS
92 AcpiHwGetPciDeviceInfo (
93     ACPI_PCI_ID             *PciId,
94     ACPI_HANDLE             PciDevice,
95     UINT16                  *BusNumber,
96     BOOLEAN                 *IsBridge);
97
98
99 /*******************************************************************************
100  *
101  * FUNCTION:    AcpiHwDerivePciId
102  *
103  * PARAMETERS:  PciId               - Initial values for the PCI ID. May be
104  *                                    modified by this function.
105  *              RootPciDevice       - A handle to a PCI device object. This
106  *                                    object must be a PCI Root Bridge having a
107  *                                    _HID value of either PNP0A03 or PNP0A08
108  *              PciRegion           - A handle to a PCI configuration space
109  *                                    Operation Region being initialized
110  *
111  * RETURN:      Status
112  *
113  * DESCRIPTION: This function derives a full PCI ID for a PCI device,
114  *              consisting of a Segment number, Bus number, Device number,
115  *              and function code.
116  *
117  *              The PCI hardware dynamically configures PCI bus numbers
118  *              depending on the bus topology discovered during system
119  *              initialization. This function is invoked during configuration
120  *              of a PCI_Config Operation Region in order to (possibly) update
121  *              the Bus/Device/Function numbers in the PciId with the actual
122  *              values as determined by the hardware and operating system
123  *              configuration.
124  *
125  *              The PciId parameter is initially populated during the Operation
126  *              Region initialization. This function is then called, and is
127  *              will make any necessary modifications to the Bus, Device, or
128  *              Function number PCI ID subfields as appropriate for the
129  *              current hardware and OS configuration.
130  *
131  * NOTE:        Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId
132  *              interface since this feature is OS-independent. This module
133  *              specifically avoids any use of recursion by building a local
134  *              temporary device list.
135  *
136  ******************************************************************************/
137
138 ACPI_STATUS
139 AcpiHwDerivePciId (
140     ACPI_PCI_ID             *PciId,
141     ACPI_HANDLE             RootPciDevice,
142     ACPI_HANDLE             PciRegion)
143 {
144     ACPI_STATUS             Status;
145     ACPI_PCI_DEVICE         *ListHead = NULL;
146
147
148     ACPI_FUNCTION_TRACE (HwDerivePciId);
149
150
151     if (!PciId)
152     {
153         return_ACPI_STATUS (AE_BAD_PARAMETER);
154     }
155
156     /* Build a list of PCI devices, from PciRegion up to RootPciDevice */
157
158     Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead);
159     if (ACPI_SUCCESS (Status))
160     {
161         /* Walk the list, updating the PCI device/function/bus numbers */
162
163         Status = AcpiHwProcessPciList (PciId, ListHead);
164
165         /* Delete the list */
166
167         AcpiHwDeletePciList (ListHead);
168     }
169
170     return_ACPI_STATUS (Status);
171 }
172
173
174 /*******************************************************************************
175  *
176  * FUNCTION:    AcpiHwBuildPciList
177  *
178  * PARAMETERS:  RootPciDevice       - A handle to a PCI device object. This
179  *                                    object is guaranteed to be a PCI Root
180  *                                    Bridge having a _HID value of either
181  *                                    PNP0A03 or PNP0A08
182  *              PciRegion           - A handle to the PCI configuration space
183  *                                    Operation Region
184  *              ReturnListHead      - Where the PCI device list is returned
185  *
186  * RETURN:      Status
187  *
188  * DESCRIPTION: Builds a list of devices from the input PCI region up to the
189  *              Root PCI device for this namespace subtree.
190  *
191  ******************************************************************************/
192
193 static ACPI_STATUS
194 AcpiHwBuildPciList (
195     ACPI_HANDLE             RootPciDevice,
196     ACPI_HANDLE             PciRegion,
197     ACPI_PCI_DEVICE         **ReturnListHead)
198 {
199     ACPI_HANDLE             CurrentDevice;
200     ACPI_HANDLE             ParentDevice;
201     ACPI_STATUS             Status;
202     ACPI_PCI_DEVICE         *ListElement;
203     ACPI_PCI_DEVICE         *ListHead = NULL;
204
205
206     /*
207      * Ascend namespace branch until the RootPciDevice is reached, building
208      * a list of device nodes. Loop will exit when either the PCI device is
209      * found, or the root of the namespace is reached.
210      */
211     CurrentDevice = PciRegion;
212     while (1)
213     {
214         Status = AcpiGetParent (CurrentDevice, &ParentDevice);
215         if (ACPI_FAILURE (Status))
216         {
217             /* Must delete the list before exit */
218
219             AcpiHwDeletePciList (*ReturnListHead);
220             return (Status);
221         }
222
223         /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
224
225         if (ParentDevice == RootPciDevice)
226         {
227             *ReturnListHead = ListHead;
228             return (AE_OK);
229         }
230
231         ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE));
232         if (!ListElement)
233         {
234             /* Must delete the list before exit */
235
236             AcpiHwDeletePciList (*ReturnListHead);
237             return (AE_NO_MEMORY);
238         }
239
240         /* Put new element at the head of the list */
241
242         ListElement->Next = ListHead;
243         ListElement->Device = ParentDevice;
244         ListHead = ListElement;
245
246         CurrentDevice = ParentDevice;
247     }
248 }
249
250
251 /*******************************************************************************
252  *
253  * FUNCTION:    AcpiHwProcessPciList
254  *
255  * PARAMETERS:  PciId               - Initial values for the PCI ID. May be
256  *                                    modified by this function.
257  *              ListHead            - Device list created by
258  *                                    AcpiHwBuildPciList
259  *
260  * RETURN:      Status
261  *
262  * DESCRIPTION: Walk downward through the PCI device list, getting the device
263  *              info for each, via the PCI configuration space and updating
264  *              the PCI ID as necessary. Deletes the list during traversal.
265  *
266  ******************************************************************************/
267
268 static ACPI_STATUS
269 AcpiHwProcessPciList (
270     ACPI_PCI_ID             *PciId,
271     ACPI_PCI_DEVICE         *ListHead)
272 {
273     ACPI_STATUS             Status = AE_OK;
274     ACPI_PCI_DEVICE         *Info;
275     UINT16                  BusNumber;
276     BOOLEAN                 IsBridge = TRUE;
277
278
279     ACPI_FUNCTION_NAME (HwProcessPciList);
280
281
282     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
283         "Input PciId:  Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
284         PciId->Segment, PciId->Bus, PciId->Device, PciId->Function));
285
286     BusNumber = PciId->Bus;
287
288     /*
289      * Descend down the namespace tree, collecting PCI device, function,
290      * and bus numbers. BusNumber is only important for PCI bridges.
291      * Algorithm: As we descend the tree, use the last valid PCI device,
292      * function, and bus numbers that are discovered, and assign them
293      * to the PCI ID for the target device.
294      */
295     Info = ListHead;
296     while (Info)
297     {
298         Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device,
299             &BusNumber, &IsBridge);
300         if (ACPI_FAILURE (Status))
301         {
302             return (Status);
303         }
304
305         Info = Info->Next;
306     }
307
308     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
309         "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
310         "Status %X BusNumber %X IsBridge %X\n",
311         PciId->Segment, PciId->Bus, PciId->Device, PciId->Function,
312         Status, BusNumber, IsBridge));
313
314     return (AE_OK);
315 }
316
317
318 /*******************************************************************************
319  *
320  * FUNCTION:    AcpiHwDeletePciList
321  *
322  * PARAMETERS:  ListHead            - Device list created by
323  *                                    AcpiHwBuildPciList
324  *
325  * RETURN:      None
326  *
327  * DESCRIPTION: Free the entire PCI list.
328  *
329  ******************************************************************************/
330
331 static void
332 AcpiHwDeletePciList (
333     ACPI_PCI_DEVICE         *ListHead)
334 {
335     ACPI_PCI_DEVICE         *Next;
336     ACPI_PCI_DEVICE         *Previous;
337
338
339     Next = ListHead;
340     while (Next)
341     {
342         Previous = Next;
343         Next = Previous->Next;
344         ACPI_FREE (Previous);
345     }
346 }
347
348
349 /*******************************************************************************
350  *
351  * FUNCTION:    AcpiHwGetPciDeviceInfo
352  *
353  * PARAMETERS:  PciId               - Initial values for the PCI ID. May be
354  *                                    modified by this function.
355  *              PciDevice           - Handle for the PCI device object
356  *              BusNumber           - Where a PCI bridge bus number is returned
357  *              IsBridge            - Return value, indicates if this PCI
358  *                                    device is a PCI bridge
359  *
360  * RETURN:      Status
361  *
362  * DESCRIPTION: Get the device info for a single PCI device object. Get the
363  *              _ADR (contains PCI device and function numbers), and for PCI
364  *              bridge devices, get the bus number from PCI configuration
365  *              space.
366  *
367  ******************************************************************************/
368
369 static ACPI_STATUS
370 AcpiHwGetPciDeviceInfo (
371     ACPI_PCI_ID             *PciId,
372     ACPI_HANDLE             PciDevice,
373     UINT16                  *BusNumber,
374     BOOLEAN                 *IsBridge)
375 {
376     ACPI_STATUS             Status;
377     ACPI_OBJECT_TYPE        ObjectType;
378     UINT64                  ReturnValue;
379     UINT64                  PciValue;
380
381
382     /* We only care about objects of type Device */
383
384     Status = AcpiGetType (PciDevice, &ObjectType);
385     if (ACPI_FAILURE (Status))
386     {
387         return (Status);
388     }
389
390     if (ObjectType != ACPI_TYPE_DEVICE)
391     {
392         return (AE_OK);
393     }
394
395     /* We need an _ADR. Ignore device if not present */
396
397     Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR,
398         PciDevice, &ReturnValue);
399     if (ACPI_FAILURE (Status))
400     {
401         return (AE_OK);
402     }
403
404     /*
405      * From _ADR, get the PCI Device and Function and
406      * update the PCI ID.
407      */
408     PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue));
409     PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue));
410
411     /*
412      * If the previous device was a bridge, use the previous
413      * device bus number
414      */
415     if (*IsBridge)
416     {
417         PciId->Bus = *BusNumber;
418     }
419
420     /*
421      * Get the bus numbers from PCI Config space:
422      *
423      * First, get the PCI HeaderType
424      */
425     *IsBridge = FALSE;
426     Status = AcpiOsReadPciConfiguration (PciId,
427         PCI_CFG_HEADER_TYPE_REG, &PciValue, 8);
428     if (ACPI_FAILURE (Status))
429     {
430         return (Status);
431     }
432
433     /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */
434
435     PciValue &= PCI_HEADER_TYPE_MASK;
436
437     if ((PciValue != PCI_TYPE_BRIDGE) &&
438         (PciValue != PCI_TYPE_CARDBUS_BRIDGE))
439     {
440         return (AE_OK);
441     }
442
443     /* Bridge: Get the Primary BusNumber */
444
445     Status = AcpiOsReadPciConfiguration (PciId,
446         PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8);
447     if (ACPI_FAILURE (Status))
448     {
449         return (Status);
450     }
451
452     *IsBridge = TRUE;
453     PciId->Bus = (UINT16) PciValue;
454
455     /* Bridge: Get the Secondary BusNumber */
456
457     Status = AcpiOsReadPciConfiguration (PciId,
458         PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8);
459     if (ACPI_FAILURE (Status))
460     {
461         return (Status);
462     }
463
464     *BusNumber = (UINT16) PciValue;
465     return (AE_OK);
466 }