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