]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
CommitLineData
9060e3ec 1/** @file\r
2 PCI emumeration support functions implementation for PCI Bus module.\r
3\r
0785c619 4Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>\r
25a26646 5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
f9c6b513 6Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>\r
9d510e61 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
9060e3ec 8\r
9**/\r
10\r
11#include "PciBus.h"\r
12\r
1436aea4
MK
13extern CHAR16 *mBarTypeStr[];\r
14extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;\r
8db6a82c 15\r
1436aea4
MK
16#define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL\r
17#define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL\r
18#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL\r
19#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL\r
8a93fa1e 20\r
9060e3ec 21/**\r
22 This routine is used to check whether the pci device is present.\r
23\r
24 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
25 @param Pci Output buffer for PCI device configuration space.\r
26 @param Bus PCI bus NO.\r
27 @param Device PCI device NO.\r
28 @param Func PCI Func NO.\r
29\r
30 @retval EFI_NOT_FOUND PCI device not present.\r
31 @retval EFI_SUCCESS PCI device is found.\r
32\r
33**/\r
34EFI_STATUS\r
35PciDevicePresent (\r
1436aea4
MK
36 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
37 OUT PCI_TYPE00 *Pci,\r
38 IN UINT8 Bus,\r
39 IN UINT8 Device,\r
40 IN UINT8 Func\r
9060e3ec 41 )\r
42{\r
43 UINT64 Address;\r
44 EFI_STATUS Status;\r
45\r
46 //\r
47 // Create PCI address map in terms of Bus, Device and Func\r
48 //\r
49 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
50\r
51 //\r
52 // Read the Vendor ID register\r
53 //\r
54 Status = PciRootBridgeIo->Pci.Read (\r
55 PciRootBridgeIo,\r
56 EfiPciWidthUint32,\r
57 Address,\r
58 1,\r
59 Pci\r
60 );\r
61\r
1436aea4 62 if (!EFI_ERROR (Status) && ((Pci->Hdr).VendorId != 0xffff)) {\r
9060e3ec 63 //\r
64 // Read the entire config header for the device\r
65 //\r
66 Status = PciRootBridgeIo->Pci.Read (\r
67 PciRootBridgeIo,\r
68 EfiPciWidthUint32,\r
69 Address,\r
70 sizeof (PCI_TYPE00) / sizeof (UINT32),\r
71 Pci\r
72 );\r
73\r
74 return EFI_SUCCESS;\r
75 }\r
76\r
77 return EFI_NOT_FOUND;\r
78}\r
79\r
80/**\r
81 Collect all the resource information under this root bridge.\r
82\r
83 A database that records all the information about pci device subject to this\r
84 root bridge will then be created.\r
85\r
86 @param Bridge Parent bridge instance.\r
fcdfcdbf 87 @param StartBusNumber Bus number of beginning.\r
9060e3ec 88\r
89 @retval EFI_SUCCESS PCI device is found.\r
90 @retval other Some error occurred when reading PCI bridge information.\r
91\r
92**/\r
93EFI_STATUS\r
94PciPciDeviceInfoCollector (\r
1436aea4
MK
95 IN PCI_IO_DEVICE *Bridge,\r
96 IN UINT8 StartBusNumber\r
9060e3ec 97 )\r
98{\r
1436aea4
MK
99 EFI_STATUS Status;\r
100 PCI_TYPE00 Pci;\r
101 UINT8 Device;\r
102 UINT8 Func;\r
103 UINT8 SecBus;\r
104 PCI_IO_DEVICE *PciIoDevice;\r
105 EFI_PCI_IO_PROTOCOL *PciIo;\r
9060e3ec 106\r
1436aea4
MK
107 Status = EFI_SUCCESS;\r
108 SecBus = 0;\r
9060e3ec 109\r
110 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
9060e3ec 111 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
9060e3ec 112 //\r
113 // Check to see whether PCI device is present\r
114 //\r
115 Status = PciDevicePresent (\r
116 Bridge->PciRootBridgeIo,\r
117 &Pci,\r
1436aea4
MK
118 (UINT8)StartBusNumber,\r
119 (UINT8)Device,\r
120 (UINT8)Func\r
9060e3ec 121 );\r
25a26646 122\r
1436aea4 123 if (EFI_ERROR (Status) && (Func == 0)) {\r
25a26646
JS
124 //\r
125 // go to next device if there is no Function 0\r
126 //\r
127 break;\r
128 }\r
129\r
9060e3ec 130 if (!EFI_ERROR (Status)) {\r
9060e3ec 131 //\r
132 // Call back to host bridge function\r
133 //\r
1436aea4 134 PreprocessController (Bridge, (UINT8)StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);\r
9060e3ec 135\r
136 //\r
137 // Collect all the information about the PCI device discovered\r
138 //\r
139 Status = PciSearchDevice (\r
140 Bridge,\r
141 &Pci,\r
1436aea4 142 (UINT8)StartBusNumber,\r
9060e3ec 143 Device,\r
144 Func,\r
145 &PciIoDevice\r
146 );\r
147\r
148 //\r
149 // Recursively scan PCI busses on the other side of PCI-PCI bridges\r
150 //\r
151 //\r
152 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {\r
9060e3ec 153 //\r
154 // If it is PPB, we need to get the secondary bus to continue the enumeration\r
155 //\r
1436aea4 156 PciIo = &(PciIoDevice->PciIo);\r
9060e3ec 157\r
1436aea4 158 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);\r
9060e3ec 159\r
160 if (EFI_ERROR (Status)) {\r
161 return Status;\r
162 }\r
163\r
c28306c3
MM
164 //\r
165 // Ensure secondary bus number is greater than the primary bus number to avoid\r
166 // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE\r
167 //\r
168 if (SecBus <= StartBusNumber) {\r
169 break;\r
170 }\r
171\r
9060e3ec 172 //\r
173 // Get resource padding for PPB\r
174 //\r
175 GetResourcePaddingPpb (PciIoDevice);\r
176\r
177 //\r
178 // Deep enumerate the next level bus\r
179 //\r
180 Status = PciPciDeviceInfoCollector (\r
181 PciIoDevice,\r
1436aea4 182 (UINT8)(SecBus)\r
9060e3ec 183 );\r
9060e3ec 184 }\r
185\r
1436aea4 186 if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {\r
9060e3ec 187 //\r
188 // Skip sub functions, this is not a multi function device\r
189 //\r
190 Func = PCI_MAX_FUNC;\r
191 }\r
192 }\r
9060e3ec 193 }\r
194 }\r
195\r
196 return EFI_SUCCESS;\r
197}\r
198\r
199/**\r
fcdfcdbf 200 Search required device and create PCI device instance.\r
9060e3ec 201\r
202 @param Bridge Parent bridge instance.\r
203 @param Pci Input PCI device information block.\r
204 @param Bus PCI bus NO.\r
205 @param Device PCI device NO.\r
206 @param Func PCI func NO.\r
207 @param PciDevice Output of searched PCI device instance.\r
208\r
209 @retval EFI_SUCCESS Successfully created PCI device instance.\r
210 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.\r
211\r
212**/\r
213EFI_STATUS\r
214PciSearchDevice (\r
1436aea4
MK
215 IN PCI_IO_DEVICE *Bridge,\r
216 IN PCI_TYPE00 *Pci,\r
217 IN UINT8 Bus,\r
218 IN UINT8 Device,\r
219 IN UINT8 Func,\r
220 OUT PCI_IO_DEVICE **PciDevice\r
9060e3ec 221 )\r
222{\r
1436aea4 223 PCI_IO_DEVICE *PciIoDevice;\r
cb8349f0 224 BOOLEAN IgnoreOptionRom;\r
9060e3ec 225\r
cb8349f0
MX
226 PciIoDevice = NULL;\r
227 IgnoreOptionRom = FALSE;\r
9060e3ec 228\r
8db6a82c 229 DEBUG ((\r
87000d77 230 DEBUG_INFO,\r
f9c6b513 231 "PciBus: Discovered %s @ [%02x|%02x|%02x] [VID = 0x%x, DID = 0x%0x]\n",\r
8db6a82c
RN
232 IS_PCI_BRIDGE (Pci) ? L"PPB" :\r
233 IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :\r
1436aea4
MK
234 L"PCI",\r
235 Bus,\r
236 Device,\r
f9c6b513
AC
237 Func,\r
238 Pci->Hdr.VendorId,\r
239 Pci->Hdr.DeviceId\r
8db6a82c
RN
240 ));\r
241\r
9060e3ec 242 if (!IS_PCI_BRIDGE (Pci)) {\r
9060e3ec 243 if (IS_CARDBUS_BRIDGE (Pci)) {\r
244 PciIoDevice = GatherP2CInfo (\r
245 Bridge,\r
246 Pci,\r
247 Bus,\r
248 Device,\r
249 Func\r
250 );\r
251 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
252 InitializeP2C (PciIoDevice);\r
253 }\r
254 } else {\r
9060e3ec 255 //\r
256 // Create private data for Pci Device\r
257 //\r
258 PciIoDevice = GatherDeviceInfo (\r
259 Bridge,\r
260 Pci,\r
261 Bus,\r
262 Device,\r
263 Func\r
264 );\r
9060e3ec 265 }\r
9060e3ec 266 } else {\r
9060e3ec 267 //\r
268 // Create private data for PPB\r
269 //\r
270 PciIoDevice = GatherPpbInfo (\r
271 Bridge,\r
272 Pci,\r
273 Bus,\r
274 Device,\r
275 Func\r
276 );\r
277\r
278 //\r
279 // Special initialization for PPB including making the PPB quiet\r
280 //\r
281 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
282 InitializePpb (PciIoDevice);\r
283 }\r
284 }\r
285\r
286 if (PciIoDevice == NULL) {\r
287 return EFI_OUT_OF_RESOURCES;\r
288 }\r
289\r
290 //\r
291 // Update the bar information for this PCI device so as to support some specific device\r
292 //\r
cb8349f0 293 UpdatePciInfo (PciIoDevice, &IgnoreOptionRom);\r
9060e3ec 294\r
295 if (PciIoDevice->DevicePath == NULL) {\r
296 return EFI_OUT_OF_RESOURCES;\r
297 }\r
298\r
299 //\r
300 // Detect this function has option rom\r
301 //\r
302 if (gFullEnumeration) {\r
cb8349f0 303 if (!IS_CARDBUS_BRIDGE (Pci) && !IgnoreOptionRom) {\r
9060e3ec 304 GetOpRomInfo (PciIoDevice);\r
9060e3ec 305 }\r
306\r
307 ResetPowerManagementFeature (PciIoDevice);\r
9060e3ec 308 }\r
309\r
310 //\r
311 // Insert it into a global tree for future reference\r
312 //\r
313 InsertPciDevice (Bridge, PciIoDevice);\r
314\r
315 //\r
316 // Determine PCI device attributes\r
317 //\r
318\r
319 if (PciDevice != NULL) {\r
320 *PciDevice = PciIoDevice;\r
321 }\r
322\r
323 return EFI_SUCCESS;\r
324}\r
325\r
f67bd32d
RN
326/**\r
327 Dump the PPB padding resource information.\r
328\r
329 @param PciIoDevice PCI IO instance.\r
330 @param ResourceType The desired resource type to dump.\r
331 PciBarTypeUnknown means to dump all types of resources.\r
332**/\r
333VOID\r
334DumpPpbPaddingResource (\r
1436aea4
MK
335 IN PCI_IO_DEVICE *PciIoDevice,\r
336 IN PCI_BAR_TYPE ResourceType\r
f67bd32d
RN
337 )\r
338{\r
1436aea4
MK
339 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
340 PCI_BAR_TYPE Type;\r
f67bd32d
RN
341\r
342 if (PciIoDevice->ResourcePaddingDescriptors == NULL) {\r
343 return;\r
344 }\r
345\r
1436aea4 346 if ((ResourceType == PciBarTypeIo16) || (ResourceType == PciBarTypeIo32)) {\r
f67bd32d
RN
347 ResourceType = PciBarTypeIo;\r
348 }\r
349\r
350 for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) {\r
f67bd32d 351 Type = PciBarTypeUnknown;\r
1436aea4 352 if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {\r
f67bd32d 353 Type = PciBarTypeIo;\r
1436aea4 354 } else if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {\r
f67bd32d
RN
355 if (Descriptor->AddrSpaceGranularity == 32) {\r
356 //\r
fcdfcdbf 357 // prefetchable\r
f67bd32d
RN
358 //\r
359 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {\r
360 Type = PciBarTypePMem32;\r
361 }\r
362\r
363 //\r
fcdfcdbf 364 // Non-prefetchable\r
f67bd32d
RN
365 //\r
366 if (Descriptor->SpecificFlag == 0) {\r
367 Type = PciBarTypeMem32;\r
368 }\r
369 }\r
370\r
371 if (Descriptor->AddrSpaceGranularity == 64) {\r
372 //\r
fcdfcdbf 373 // prefetchable\r
f67bd32d
RN
374 //\r
375 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {\r
376 Type = PciBarTypePMem64;\r
377 }\r
378\r
379 //\r
fcdfcdbf 380 // Non-prefetchable\r
f67bd32d
RN
381 //\r
382 if (Descriptor->SpecificFlag == 0) {\r
383 Type = PciBarTypeMem64;\r
384 }\r
385 }\r
386 }\r
387\r
388 if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) {\r
389 DEBUG ((\r
87000d77 390 DEBUG_INFO,\r
f67bd32d 391 " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",\r
1436aea4
MK
392 mBarTypeStr[Type],\r
393 Descriptor->AddrRangeMax,\r
394 Descriptor->AddrLen\r
f67bd32d
RN
395 ));\r
396 }\r
397 }\r
f67bd32d
RN
398}\r
399\r
8db6a82c
RN
400/**\r
401 Dump the PCI BAR information.\r
402\r
403 @param PciIoDevice PCI IO instance.\r
404**/\r
405VOID\r
406DumpPciBars (\r
1436aea4 407 IN PCI_IO_DEVICE *PciIoDevice\r
8db6a82c
RN
408 )\r
409{\r
1436aea4 410 UINTN Index;\r
8db6a82c
RN
411\r
412 for (Index = 0; Index < PCI_MAX_BAR; Index++) {\r
413 if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {\r
414 continue;\r
415 }\r
416\r
417 DEBUG ((\r
87000d77 418 DEBUG_INFO,\r
980050bc 419 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",\r
1436aea4
MK
420 Index,\r
421 mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)],\r
422 PciIoDevice->PciBar[Index].Alignment,\r
423 PciIoDevice->PciBar[Index].Length,\r
424 PciIoDevice->PciBar[Index].Offset\r
8db6a82c
RN
425 ));\r
426 }\r
427\r
428 for (Index = 0; Index < PCI_MAX_BAR; Index++) {\r
429 if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) {\r
430 continue;\r
431 }\r
432\r
433 DEBUG ((\r
87000d77 434 DEBUG_INFO,\r
980050bc 435 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",\r
1436aea4
MK
436 Index,\r
437 mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)],\r
438 PciIoDevice->VfPciBar[Index].Alignment,\r
439 PciIoDevice->VfPciBar[Index].Length,\r
440 PciIoDevice->VfPciBar[Index].Offset\r
8db6a82c
RN
441 ));\r
442 }\r
1436aea4 443\r
87000d77 444 DEBUG ((DEBUG_INFO, "\n"));\r
8db6a82c
RN
445}\r
446\r
9060e3ec 447/**\r
448 Create PCI device instance for PCI device.\r
449\r
450 @param Bridge Parent bridge instance.\r
451 @param Pci Input PCI device information block.\r
452 @param Bus PCI device Bus NO.\r
453 @param Device PCI device Device NO.\r
454 @param Func PCI device's func NO.\r
455\r
456 @return Created PCI device instance.\r
457\r
458**/\r
459PCI_IO_DEVICE *\r
460GatherDeviceInfo (\r
1436aea4
MK
461 IN PCI_IO_DEVICE *Bridge,\r
462 IN PCI_TYPE00 *Pci,\r
463 IN UINT8 Bus,\r
464 IN UINT8 Device,\r
465 IN UINT8 Func\r
9060e3ec 466 )\r
467{\r
1436aea4
MK
468 UINTN Offset;\r
469 UINTN BarIndex;\r
470 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 471\r
9060e3ec 472 PciIoDevice = CreatePciIoDevice (\r
d4048391 473 Bridge,\r
9060e3ec 474 Pci,\r
475 Bus,\r
476 Device,\r
477 Func\r
478 );\r
479\r
480 if (PciIoDevice == NULL) {\r
481 return NULL;\r
482 }\r
483\r
9060e3ec 484 //\r
485 // If it is a full enumeration, disconnect the device in advance\r
486 //\r
487 if (gFullEnumeration) {\r
9060e3ec 488 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
9060e3ec 489 }\r
490\r
491 //\r
492 // Start to parse the bars\r
493 //\r
494 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {\r
495 Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
496 }\r
497\r
498 //\r
499 // Parse the SR-IOV VF bars\r
500 //\r
1436aea4 501 if (PcdGetBool (PcdSrIovSupport) && (PciIoDevice->SrIovCapabilityOffset != 0)) {\r
9060e3ec 502 for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;\r
503 Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;\r
1436aea4
MK
504 BarIndex++)\r
505 {\r
9060e3ec 506 ASSERT (BarIndex < PCI_MAX_BAR);\r
507 Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);\r
508 }\r
509 }\r
8db6a82c 510\r
1436aea4
MK
511 DEBUG_CODE (\r
512 DumpPciBars (PciIoDevice);\r
513 );\r
9060e3ec 514 return PciIoDevice;\r
515}\r
516\r
517/**\r
518 Create PCI device instance for PCI-PCI bridge.\r
519\r
520 @param Bridge Parent bridge instance.\r
521 @param Pci Input PCI device information block.\r
522 @param Bus PCI device Bus NO.\r
523 @param Device PCI device Device NO.\r
524 @param Func PCI device's func NO.\r
525\r
526 @return Created PCI device instance.\r
527\r
528**/\r
529PCI_IO_DEVICE *\r
530GatherPpbInfo (\r
1436aea4
MK
531 IN PCI_IO_DEVICE *Bridge,\r
532 IN PCI_TYPE00 *Pci,\r
533 IN UINT8 Bus,\r
534 IN UINT8 Device,\r
535 IN UINT8 Func\r
9060e3ec 536 )\r
537{\r
1436aea4
MK
538 PCI_IO_DEVICE *PciIoDevice;\r
539 EFI_STATUS Status;\r
540 UINT8 Value;\r
541 EFI_PCI_IO_PROTOCOL *PciIo;\r
542 UINT8 Temp;\r
543 UINT32 PMemBaseLimit;\r
544 UINT16 PrefetchableMemoryBase;\r
545 UINT16 PrefetchableMemoryLimit;\r
9060e3ec 546\r
9060e3ec 547 PciIoDevice = CreatePciIoDevice (\r
d4048391 548 Bridge,\r
9060e3ec 549 Pci,\r
550 Bus,\r
551 Device,\r
552 Func\r
553 );\r
554\r
555 if (PciIoDevice == NULL) {\r
556 return NULL;\r
557 }\r
558\r
9060e3ec 559 if (gFullEnumeration) {\r
560 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
561\r
562 //\r
fcdfcdbf 563 // Initialize the bridge control register\r
9060e3ec 564 //\r
565 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);\r
9060e3ec 566 }\r
567\r
568 //\r
569 // PPB can have two BARs\r
570 //\r
571 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {\r
572 //\r
573 // Not 64-bit bar\r
574 //\r
575 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);\r
576 }\r
577\r
578 PciIo = &PciIoDevice->PciIo;\r
579\r
580 //\r
581 // Test whether it support 32 decode or not\r
582 //\r
583 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
584 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
585 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
586 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
587\r
588 if (Value != 0) {\r
589 if ((Value & 0x01) != 0) {\r
590 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
591 } else {\r
592 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;\r
593 }\r
594 }\r
595\r
1ef26783 596 //\r
597 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes\r
ed356b9e 598 // PCI bridge supporting non-standard I/O window alignment less than 4K.\r
1ef26783 599 //\r
600\r
601 PciIoDevice->BridgeIoAlignment = 0xFFF;\r
602 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {\r
603 //\r
604 // Check any bits of bit 3-1 of I/O Base Register are writable.\r
ed356b9e 605 // if so, it is assumed non-standard I/O window alignment is supported by this bridge.\r
1ef26783 606 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.\r
607 //\r
f00b5d83 608 Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));\r
1ef26783 609 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
610 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
611 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
f00b5d83 612 Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));\r
1ef26783 613 switch (Value) {\r
614 case BIT3:\r
615 PciIoDevice->BridgeIoAlignment = 0x7FF;\r
616 break;\r
617 case BIT3 | BIT2:\r
618 PciIoDevice->BridgeIoAlignment = 0x3FF;\r
619 break;\r
620 case BIT3 | BIT2 | BIT1:\r
621 PciIoDevice->BridgeIoAlignment = 0x1FF;\r
622 break;\r
623 }\r
624 }\r
625\r
9060e3ec 626 Status = BarExisted (\r
1436aea4
MK
627 PciIoDevice,\r
628 0x24,\r
629 NULL,\r
630 &PMemBaseLimit\r
631 );\r
9060e3ec 632\r
633 //\r
634 // Test if it supports 64 memory or not\r
635 //\r
07bcff9d 636 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit\r
637 // registers:\r
638 // 0 - the bridge supports only 32 bit addresses.\r
639 // 1 - the bridge supports 64-bit addresses.\r
640 //\r
1436aea4 641 PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);\r
571e9831 642 PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);\r
07bcff9d 643 if (!EFI_ERROR (Status) &&\r
1436aea4
MK
644 ((PrefetchableMemoryBase & 0x000f) == 0x0001) &&\r
645 ((PrefetchableMemoryLimit & 0x000f) == 0x0001))\r
646 {\r
9060e3ec 647 Status = BarExisted (\r
1436aea4
MK
648 PciIoDevice,\r
649 0x28,\r
650 NULL,\r
651 NULL\r
652 );\r
9060e3ec 653\r
654 if (!EFI_ERROR (Status)) {\r
655 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
656 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;\r
657 } else {\r
658 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
659 }\r
660 }\r
661\r
662 //\r
663 // Memory 32 code is required for ppb\r
664 //\r
665 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;\r
666\r
667 GetResourcePaddingPpb (PciIoDevice);\r
668\r
f67bd32d
RN
669 DEBUG_CODE (\r
670 DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown);\r
671 DumpPciBars (PciIoDevice);\r
1436aea4 672 );\r
8db6a82c 673\r
9060e3ec 674 return PciIoDevice;\r
675}\r
676\r
9060e3ec 677/**\r
678 Create PCI device instance for PCI Card bridge device.\r
679\r
680 @param Bridge Parent bridge instance.\r
681 @param Pci Input PCI device information block.\r
682 @param Bus PCI device Bus NO.\r
683 @param Device PCI device Device NO.\r
684 @param Func PCI device's func NO.\r
685\r
686 @return Created PCI device instance.\r
687\r
688**/\r
689PCI_IO_DEVICE *\r
690GatherP2CInfo (\r
1436aea4
MK
691 IN PCI_IO_DEVICE *Bridge,\r
692 IN PCI_TYPE00 *Pci,\r
693 IN UINT8 Bus,\r
694 IN UINT8 Device,\r
695 IN UINT8 Func\r
9060e3ec 696 )\r
697{\r
1436aea4 698 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 699\r
9060e3ec 700 PciIoDevice = CreatePciIoDevice (\r
d4048391 701 Bridge,\r
9060e3ec 702 Pci,\r
703 Bus,\r
704 Device,\r
705 Func\r
706 );\r
707\r
708 if (PciIoDevice == NULL) {\r
709 return NULL;\r
710 }\r
711\r
9060e3ec 712 if (gFullEnumeration) {\r
713 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
714\r
715 //\r
fcdfcdbf 716 // Initialize the bridge control register\r
9060e3ec 717 //\r
718 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);\r
719 }\r
720\r
721 //\r
722 // P2C only has one bar that is in 0x10\r
723 //\r
724 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);\r
725\r
726 //\r
727 // Read PciBar information from the bar register\r
728 //\r
729 GetBackPcCardBar (PciIoDevice);\r
730 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |\r
731 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |\r
732 EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
733\r
1436aea4
MK
734 DEBUG_CODE (\r
735 DumpPciBars (PciIoDevice);\r
736 );\r
8db6a82c 737\r
9060e3ec 738 return PciIoDevice;\r
739}\r
740\r
741/**\r
fcdfcdbf 742 Create device path for pci device.\r
9060e3ec 743\r
744 @param ParentDevicePath Parent bridge's path.\r
745 @param PciIoDevice Pci device instance.\r
746\r
747 @return Device path protocol instance for specific pci device.\r
748\r
749**/\r
750EFI_DEVICE_PATH_PROTOCOL *\r
751CreatePciDevicePath (\r
1436aea4
MK
752 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
753 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 754 )\r
755{\r
1436aea4 756 PCI_DEVICE_PATH PciNode;\r
9060e3ec 757\r
758 //\r
759 // Create PCI device path\r
760 //\r
1436aea4
MK
761 PciNode.Header.Type = HARDWARE_DEVICE_PATH;\r
762 PciNode.Header.SubType = HW_PCI_DP;\r
9060e3ec 763 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
764\r
765 PciNode.Device = PciIoDevice->DeviceNumber;\r
766 PciNode.Function = PciIoDevice->FunctionNumber;\r
767 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);\r
768\r
769 return PciIoDevice->DevicePath;\r
770}\r
771\r
772/**\r
773 Check whether the PCI IOV VF bar is existed or not.\r
774\r
775 @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
776 @param Offset The offset.\r
777 @param BarLengthValue The bar length value returned.\r
778 @param OriginalBarValue The original bar value returned.\r
779\r
780 @retval EFI_NOT_FOUND The bar doesn't exist.\r
781 @retval EFI_SUCCESS The bar exist.\r
782\r
783**/\r
784EFI_STATUS\r
785VfBarExisted (\r
1436aea4
MK
786 IN PCI_IO_DEVICE *PciIoDevice,\r
787 IN UINTN Offset,\r
788 OUT UINT32 *BarLengthValue,\r
789 OUT UINT32 *OriginalBarValue\r
9060e3ec 790 )\r
791{\r
1436aea4
MK
792 EFI_PCI_IO_PROTOCOL *PciIo;\r
793 UINT32 OriginalValue;\r
794 UINT32 Value;\r
795 EFI_TPL OldTpl;\r
9060e3ec 796\r
797 //\r
798 // Ensure it is called properly\r
799 //\r
800 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
801 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
802 return EFI_NOT_FOUND;\r
803 }\r
804\r
805 PciIo = &PciIoDevice->PciIo;\r
806\r
807 //\r
808 // Preserve the original value\r
809 //\r
810\r
811 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
812\r
813 //\r
814 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
815 //\r
816 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
817\r
818 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);\r
819 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);\r
820\r
821 //\r
822 // Write back the original value\r
823 //\r
824 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
825\r
826 //\r
827 // Restore TPL to its original level\r
828 //\r
829 gBS->RestoreTPL (OldTpl);\r
830\r
831 if (BarLengthValue != NULL) {\r
832 *BarLengthValue = Value;\r
833 }\r
834\r
835 if (OriginalBarValue != NULL) {\r
836 *OriginalBarValue = OriginalValue;\r
837 }\r
838\r
839 if (Value == 0) {\r
840 return EFI_NOT_FOUND;\r
841 } else {\r
842 return EFI_SUCCESS;\r
843 }\r
844}\r
845\r
846/**\r
847 Check whether the bar is existed or not.\r
848\r
849 @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
850 @param Offset The offset.\r
851 @param BarLengthValue The bar length value returned.\r
852 @param OriginalBarValue The original bar value returned.\r
853\r
854 @retval EFI_NOT_FOUND The bar doesn't exist.\r
855 @retval EFI_SUCCESS The bar exist.\r
856\r
857**/\r
858EFI_STATUS\r
859BarExisted (\r
1436aea4
MK
860 IN PCI_IO_DEVICE *PciIoDevice,\r
861 IN UINTN Offset,\r
862 OUT UINT32 *BarLengthValue,\r
863 OUT UINT32 *OriginalBarValue\r
9060e3ec 864 )\r
865{\r
1436aea4
MK
866 EFI_PCI_IO_PROTOCOL *PciIo;\r
867 UINT32 OriginalValue;\r
868 UINT32 Value;\r
869 EFI_TPL OldTpl;\r
9060e3ec 870\r
871 PciIo = &PciIoDevice->PciIo;\r
872\r
873 //\r
874 // Preserve the original value\r
875 //\r
1436aea4 876 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);\r
9060e3ec 877\r
878 //\r
879 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
880 //\r
881 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
882\r
1436aea4
MK
883 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &gAllOne);\r
884 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &Value);\r
9060e3ec 885\r
886 //\r
887 // Write back the original value\r
888 //\r
1436aea4 889 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);\r
9060e3ec 890\r
891 //\r
892 // Restore TPL to its original level\r
893 //\r
894 gBS->RestoreTPL (OldTpl);\r
895\r
896 if (BarLengthValue != NULL) {\r
897 *BarLengthValue = Value;\r
898 }\r
899\r
900 if (OriginalBarValue != NULL) {\r
901 *OriginalBarValue = OriginalValue;\r
902 }\r
903\r
904 if (Value == 0) {\r
905 return EFI_NOT_FOUND;\r
906 } else {\r
907 return EFI_SUCCESS;\r
908 }\r
909}\r
910\r
911/**\r
912 Test whether the device can support given attributes.\r
913\r
914 @param PciIoDevice Pci device instance.\r
915 @param Command Input command register value, and\r
916 returned supported register value.\r
fcdfcdbf 917 @param BridgeControl Input bridge control value for PPB or P2C, and\r
9060e3ec 918 returned supported bridge control value.\r
919 @param OldCommand Returned and stored old command register offset.\r
920 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.\r
921\r
922**/\r
923VOID\r
924PciTestSupportedAttribute (\r
1436aea4
MK
925 IN PCI_IO_DEVICE *PciIoDevice,\r
926 IN OUT UINT16 *Command,\r
927 IN OUT UINT16 *BridgeControl,\r
928 OUT UINT16 *OldCommand,\r
929 OUT UINT16 *OldBridgeControl\r
9060e3ec 930 )\r
931{\r
1436aea4
MK
932 EFI_TPL OldTpl;\r
933 UINT16 CommandValue;\r
9060e3ec 934\r
935 //\r
936 // Preserve the original value\r
937 //\r
938 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);\r
939\r
940 //\r
941 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
942 //\r
1436aea4 943 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
46b4606b 944 CommandValue = *Command | *OldCommand;\r
9060e3ec 945\r
46b4606b 946 PCI_SET_COMMAND_REGISTER (PciIoDevice, CommandValue);\r
947 PCI_READ_COMMAND_REGISTER (PciIoDevice, &CommandValue);\r
9060e3ec 948\r
46b4606b 949 *Command = *Command & CommandValue;\r
9060e3ec 950 //\r
951 // Write back the original value\r
952 //\r
953 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);\r
954\r
955 //\r
956 // Restore TPL to its original level\r
957 //\r
958 gBS->RestoreTPL (OldTpl);\r
959\r
960 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 961 //\r
962 // Preserve the original value\r
963 //\r
964 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);\r
965\r
966 //\r
967 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
968 //\r
969 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
970\r
971 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);\r
972 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);\r
973\r
974 //\r
975 // Write back the original value\r
976 //\r
977 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);\r
978\r
979 //\r
980 // Restore TPL to its original level\r
981 //\r
982 gBS->RestoreTPL (OldTpl);\r
9060e3ec 983 } else {\r
984 *OldBridgeControl = 0;\r
985 *BridgeControl = 0;\r
986 }\r
987}\r
988\r
989/**\r
990 Set the supported or current attributes of a PCI device.\r
991\r
992 @param PciIoDevice Structure pointer for PCI device.\r
993 @param Command Command register value.\r
994 @param BridgeControl Bridge control value for PPB or P2C.\r
995 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.\r
996\r
997**/\r
998VOID\r
999PciSetDeviceAttribute (\r
1436aea4
MK
1000 IN PCI_IO_DEVICE *PciIoDevice,\r
1001 IN UINT16 Command,\r
1002 IN UINT16 BridgeControl,\r
1003 IN UINTN Option\r
9060e3ec 1004 )\r
1005{\r
1006 UINT64 Attributes;\r
1007\r
1008 Attributes = 0;\r
1009\r
1010 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {\r
1011 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
1012 }\r
1013\r
1014 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {\r
1015 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
1016 }\r
1017\r
1018 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {\r
1019 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
1020 }\r
1021\r
1022 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {\r
1023 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
1024 }\r
1025\r
1026 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {\r
1027 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
1028 }\r
1029\r
1030 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {\r
1031 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
1032 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
1033 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
1034 }\r
1035\r
1036 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {\r
1037 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
1038 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;\r
1039 }\r
1040\r
1041 if (Option == EFI_SET_SUPPORTS) {\r
1436aea4
MK
1042 Attributes |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
1043 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |\r
1044 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |\r
1045 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
1046 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
1047 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
9060e3ec 1048\r
e0ee9d93 1049 if (IS_PCI_LPC (&PciIoDevice->Pci)) {\r
1436aea4
MK
1050 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
1051 Attributes |= (mReserveIsaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO : \\r
1052 (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);\r
9060e3ec 1053 }\r
1054\r
1055 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1056 //\r
1057 // For bridge, it should support IDE attributes\r
1058 //\r
1059 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
1060 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
e0ee9d93 1061\r
1062 if (mReserveVgaAliases) {\r
1063 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \\r
1064 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);\r
1065 } else {\r
1066 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \\r
1067 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);\r
1068 }\r
9060e3ec 1069 } else {\r
9060e3ec 1070 if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
1071 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
1072 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
1073 }\r
1074\r
1075 if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
1076 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
1436aea4
MK
1077 Attributes |= (mReserveVgaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO : \\r
1078 (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
9060e3ec 1079 }\r
1080 }\r
1081\r
1436aea4
MK
1082 PciIoDevice->Supports = Attributes;\r
1083 PciIoDevice->Supports &= ((PciIoDevice->Parent->Supports) | \\r
1084 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
1085 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER);\r
9060e3ec 1086 } else {\r
4ed4e19c 1087 //\r
1088 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were\r
1089 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.\r
1090 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize\r
1091 // fields is not from the the ROM BAR of the PCI controller.\r
1092 //\r
1093 if (!PciIoDevice->EmbeddedRom) {\r
1094 Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;\r
1095 }\r
1436aea4 1096\r
9060e3ec 1097 PciIoDevice->Attributes = Attributes;\r
1098 }\r
1099}\r
1100\r
1101/**\r
1102 Determine if the device can support Fast Back to Back attribute.\r
1103\r
1104 @param PciIoDevice Pci device instance.\r
1105 @param StatusIndex Status register value.\r
1106\r
1107 @retval EFI_SUCCESS This device support Fast Back to Back attribute.\r
1108 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.\r
1109\r
1110**/\r
1111EFI_STATUS\r
1112GetFastBackToBackSupport (\r
1436aea4
MK
1113 IN PCI_IO_DEVICE *PciIoDevice,\r
1114 IN UINT8 StatusIndex\r
9060e3ec 1115 )\r
1116{\r
1436aea4
MK
1117 EFI_PCI_IO_PROTOCOL *PciIo;\r
1118 EFI_STATUS Status;\r
1119 UINT32 StatusRegister;\r
9060e3ec 1120\r
1121 //\r
1122 // Read the status register\r
1123 //\r
1436aea4
MK
1124 PciIo = &PciIoDevice->PciIo;\r
1125 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
9060e3ec 1126 if (EFI_ERROR (Status)) {\r
1127 return EFI_UNSUPPORTED;\r
1128 }\r
1129\r
1130 //\r
1131 // Check the Fast B2B bit\r
1132 //\r
1133 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {\r
1134 return EFI_SUCCESS;\r
1135 } else {\r
1136 return EFI_UNSUPPORTED;\r
1137 }\r
1138}\r
1139\r
1140/**\r
1141 Process the option ROM for all the children of the specified parent PCI device.\r
1142 It can only be used after the first full Option ROM process.\r
1143\r
1144 @param PciIoDevice Pci device instance.\r
1145\r
1146**/\r
1147VOID\r
1148ProcessOptionRomLight (\r
1436aea4 1149 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 1150 )\r
1151{\r
1436aea4
MK
1152 PCI_IO_DEVICE *Temp;\r
1153 LIST_ENTRY *CurrentLink;\r
9060e3ec 1154\r
1155 //\r
1156 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1157 //\r
1158 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1159 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
9060e3ec 1160 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1161\r
1162 if (!IsListEmpty (&Temp->ChildList)) {\r
1163 ProcessOptionRomLight (Temp);\r
1164 }\r
1165\r
3f90ac3e 1166 Temp->AllOpRomProcessed = PciRomGetImageMapping (Temp);\r
9060e3ec 1167\r
1168 CurrentLink = CurrentLink->ForwardLink;\r
1169 }\r
1170}\r
1171\r
1172/**\r
1173 Determine the related attributes of all devices under a Root Bridge.\r
1174\r
1175 @param PciIoDevice PCI device instance.\r
1176\r
1177**/\r
1178EFI_STATUS\r
1179DetermineDeviceAttribute (\r
1436aea4 1180 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 1181 )\r
1182{\r
1436aea4
MK
1183 UINT16 Command;\r
1184 UINT16 BridgeControl;\r
1185 UINT16 OldCommand;\r
1186 UINT16 OldBridgeControl;\r
1187 BOOLEAN FastB2BSupport;\r
1188 PCI_IO_DEVICE *Temp;\r
1189 LIST_ENTRY *CurrentLink;\r
1190 EFI_STATUS Status;\r
9060e3ec 1191\r
1192 //\r
fcdfcdbf 1193 // For Root Bridge, just copy it by RootBridgeIo protocol\r
9060e3ec 1194 // so as to keep consistent with the actual attribute\r
1195 //\r
1196 if (PciIoDevice->Parent == NULL) {\r
1197 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
1436aea4
MK
1198 PciIoDevice->PciRootBridgeIo,\r
1199 &PciIoDevice->Supports,\r
1200 &PciIoDevice->Attributes\r
1201 );\r
9060e3ec 1202 if (EFI_ERROR (Status)) {\r
1203 return Status;\r
1204 }\r
1436aea4 1205\r
5a3a6aa7 1206 //\r
a8035b90 1207 // Assume the PCI Root Bridge supports DAC\r
5a3a6aa7 1208 //\r
6e1e5405 1209 PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
1436aea4
MK
1210 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
1211 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
9060e3ec 1212 } else {\r
9060e3ec 1213 //\r
1214 // Set the attributes to be checked for common PCI devices and PPB or P2C\r
1215 // Since some devices only support part of them, it is better to set the\r
1216 // attribute according to its command or bridge control register\r
1217 //\r
1218 Command = EFI_PCI_COMMAND_IO_SPACE |\r
1219 EFI_PCI_COMMAND_MEMORY_SPACE |\r
a8035b90 1220 EFI_PCI_COMMAND_BUS_MASTER |\r
9060e3ec 1221 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1222\r
1223 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
1224\r
1225 //\r
1226 // Test whether the device can support attributes above\r
1227 //\r
1228 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
1229\r
1230 //\r
1231 // Set the supported attributes for specified PCI device\r
1232 //\r
1233 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
1234\r
1235 //\r
1236 // Set the current attributes for specified PCI device\r
1237 //\r
1238 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
1239\r
1240 //\r
d9233654
RN
1241 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL\r
1242 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.\r
1243 if (!PciIoDevice->IsPciExp) {\r
1244 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
1245 }\r
9060e3ec 1246 }\r
1247\r
1248 FastB2BSupport = TRUE;\r
1249\r
1250 //\r
1251 // P2C can not support FB2B on the secondary side\r
1252 //\r
1253 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1254 FastB2BSupport = FALSE;\r
1255 }\r
1256\r
1257 //\r
1258 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1259 //\r
1260 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1261 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1436aea4
MK
1262 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1263 Status = DetermineDeviceAttribute (Temp);\r
9060e3ec 1264 if (EFI_ERROR (Status)) {\r
1265 return Status;\r
1266 }\r
1436aea4 1267\r
9060e3ec 1268 //\r
fcdfcdbf 1269 // Detect Fast Back to Back support for the device under the bridge\r
9060e3ec 1270 //\r
1271 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1272 if (FastB2BSupport && EFI_ERROR (Status)) {\r
1273 FastB2BSupport = FALSE;\r
1274 }\r
1275\r
1276 CurrentLink = CurrentLink->ForwardLink;\r
1277 }\r
1436aea4 1278\r
9060e3ec 1279 //\r
1280 // Set or clear Fast Back to Back bit for the whole bridge\r
1281 //\r
1282 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
9060e3ec 1283 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 1284 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1285\r
1286 if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1287 FastB2BSupport = FALSE;\r
1288 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1289 } else {\r
1290 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1291 }\r
1292 }\r
1293\r
1294 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1295 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1296 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1297 if (FastB2BSupport) {\r
1298 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1299 } else {\r
1300 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1301 }\r
1302\r
1303 CurrentLink = CurrentLink->ForwardLink;\r
1304 }\r
1305 }\r
1436aea4 1306\r
9060e3ec 1307 //\r
1308 // End for IsListEmpty\r
1309 //\r
1310 return EFI_SUCCESS;\r
1311}\r
1312\r
1313/**\r
1314 This routine is used to update the bar information for those incompatible PCI device.\r
1315\r
1316 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated\r
1317 Bar information.\r
cb8349f0 1318 @param IgnoreOptionRom Output If the option rom of incompatible device need to be ignored.\r
9060e3ec 1319\r
1320 @retval EFI_SUCCESS Successfully updated bar information.\r
1321 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.\r
1322\r
1323**/\r
1324EFI_STATUS\r
1325UpdatePciInfo (\r
cb8349f0
MX
1326 IN OUT PCI_IO_DEVICE *PciIoDevice,\r
1327 OUT BOOLEAN *IgnoreOptionRom\r
9060e3ec 1328 )\r
1329{\r
1436aea4
MK
1330 EFI_STATUS Status;\r
1331 UINTN BarIndex;\r
1332 BOOLEAN SetFlag;\r
1333 VOID *Configuration;\r
1334 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
9060e3ec 1335\r
1336 Configuration = NULL;\r
1337 Status = EFI_SUCCESS;\r
1338\r
ea669c1b 1339 if (gIncompatiblePciDeviceSupport == NULL) {\r
9060e3ec 1340 //\r
1341 // It can only be supported after the Incompatible PCI Device\r
1342 // Support Protocol has been installed\r
1343 //\r
1344 Status = gBS->LocateProtocol (\r
1345 &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
1346 NULL,\r
1436aea4 1347 (VOID **)&gIncompatiblePciDeviceSupport\r
9060e3ec 1348 );\r
1349 }\r
9060e3ec 1350\r
1436aea4
MK
1351 if (Status == EFI_SUCCESS) {\r
1352 //\r
1353 // Check whether the device belongs to incompatible devices from protocol or not\r
1354 // If it is , then get its special requirement in the ACPI table\r
1355 //\r
1356 Status = gIncompatiblePciDeviceSupport->CheckDevice (\r
1357 gIncompatiblePciDeviceSupport,\r
1358 PciIoDevice->Pci.Hdr.VendorId,\r
1359 PciIoDevice->Pci.Hdr.DeviceId,\r
1360 PciIoDevice->Pci.Hdr.RevisionID,\r
1361 PciIoDevice->Pci.Device.SubsystemVendorID,\r
1362 PciIoDevice->Pci.Device.SubsystemID,\r
1363 &Configuration\r
1364 );\r
9060e3ec 1365 }\r
1366\r
1436aea4 1367 if (EFI_ERROR (Status) || (Configuration == NULL)) {\r
9060e3ec 1368 return EFI_UNSUPPORTED;\r
1369 }\r
1370\r
1371 //\r
1372 // Update PCI device information from the ACPI table\r
1373 //\r
1436aea4 1374 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;\r
9060e3ec 1375\r
1376 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
9060e3ec 1377 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1378 //\r
1379 // The format is not support\r
1380 //\r
1381 break;\r
1382 }\r
1383\r
cb8349f0
MX
1384 //\r
1385 // According to "Table 20. ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage"\r
1386 // in PI Spec 1.7, Type-specific flags can be set to 0 when Address Translation\r
1387 // Offset == 6 to skip device option ROM (do not probe option rom BAR).\r
1388 //\r
1389 if (((Ptr->AddrTranslationOffset == PCI_MAX_BAR) && (Ptr->SpecificFlag == 0))) {\r
1390 *IgnoreOptionRom = TRUE;\r
1391 Ptr++;\r
1392 continue;\r
1393 }\r
1394\r
063bcff7
RN
1395 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {\r
1396 if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&\r
1397 (Ptr->AddrTranslationOffset != MAX_UINT8) &&\r
1398 (Ptr->AddrTranslationOffset != BarIndex)\r
1436aea4
MK
1399 )\r
1400 {\r
063bcff7
RN
1401 //\r
1402 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).\r
1403 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.\r
1404 // Comparing against MAX_UINT8 is to keep backward compatibility.\r
1405 //\r
1406 continue;\r
1407 }\r
9060e3ec 1408\r
9060e3ec 1409 SetFlag = FALSE;\r
1410 switch (Ptr->ResType) {\r
1436aea4 1411 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
05070c1b
RN
1412\r
1413 //\r
1436aea4 1414 // Make sure the bar is memory type\r
05070c1b 1415 //\r
1436aea4
MK
1416 if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeMem)) {\r
1417 SetFlag = TRUE;\r
1418\r
1419 //\r
1420 // Ignored if granularity is 0.\r
1421 // Ignored if PCI BAR is I/O or 32-bit memory.\r
1422 // If PCI BAR is 64-bit memory and granularity is 32, then\r
1423 // the PCI BAR resource is allocated below 4GB.\r
1424 // If PCI BAR is 64-bit memory and granularity is 64, then\r
1425 // the PCI BAR resource is allocated above 4GB.\r
1426 //\r
1427 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {\r
1428 switch (Ptr->AddrSpaceGranularity) {\r
1429 case 32:\r
1430 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1431 case 64:\r
1432 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1433 break;\r
1434 default:\r
1435 break;\r
1436 }\r
05070c1b 1437 }\r
05070c1b 1438\r
1436aea4
MK
1439 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {\r
1440 switch (Ptr->AddrSpaceGranularity) {\r
1441 case 32:\r
1442 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1443 case 64:\r
1444 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1445 break;\r
1446 default:\r
1447 break;\r
1448 }\r
05070c1b
RN
1449 }\r
1450 }\r
9060e3ec 1451\r
1436aea4 1452 break;\r
9060e3ec 1453\r
1436aea4
MK
1454 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1455\r
1456 //\r
1457 // Make sure the bar is IO type\r
1458 //\r
1459 if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeIo)) {\r
1460 SetFlag = TRUE;\r
1461 }\r
1462\r
1463 break;\r
9060e3ec 1464 }\r
1465\r
1466 if (SetFlag) {\r
9060e3ec 1467 //\r
1468 // Update the new alignment for the device\r
1469 //\r
1470 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1471\r
1472 //\r
1473 // Update the new length for the device\r
1474 //\r
8a93fa1e 1475 if (Ptr->AddrLen != 0) {\r
9060e3ec 1476 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1477 }\r
1478 }\r
1479 }\r
1480\r
1481 Ptr++;\r
1482 }\r
1483\r
1484 FreePool (Configuration);\r
1485\r
1486 return EFI_SUCCESS;\r
1487}\r
1488\r
1489/**\r
1490 This routine will update the alignment with the new alignment.\r
8a93fa1e
RN
1491 Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep\r
1492 backward compatibility.\r
9060e3ec 1493\r
1494 @param Alignment Input Old alignment. Output updated alignment.\r
1495 @param NewAlignment New alignment.\r
1496\r
1497**/\r
1498VOID\r
1499SetNewAlign (\r
1436aea4
MK
1500 IN OUT UINT64 *Alignment,\r
1501 IN UINT64 NewAlignment\r
9060e3ec 1502 )\r
1503{\r
1504 UINT64 OldAlignment;\r
1505 UINTN ShiftBit;\r
1506\r
1507 //\r
1508 // The new alignment is the same as the original,\r
1509 // so skip it\r
1510 //\r
8a93fa1e 1511 if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {\r
1436aea4 1512 return;\r
9060e3ec 1513 }\r
1436aea4 1514\r
9060e3ec 1515 //\r
1516 // Check the validity of the parameter\r
1517 //\r
1436aea4
MK
1518 if ((NewAlignment != EVEN_ALIGN) &&\r
1519 (NewAlignment != SQUAD_ALIGN) &&\r
1520 (NewAlignment != DQUAD_ALIGN))\r
1521 {\r
9060e3ec 1522 *Alignment = NewAlignment;\r
1436aea4 1523 return;\r
9060e3ec 1524 }\r
1525\r
1436aea4
MK
1526 OldAlignment = (*Alignment) + 1;\r
1527 ShiftBit = 0;\r
9060e3ec 1528\r
1529 //\r
1530 // Get the first non-zero hex value of the length\r
1531 //\r
1532 while ((OldAlignment & 0x0F) == 0x00) {\r
1533 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1436aea4 1534 ShiftBit += 4;\r
9060e3ec 1535 }\r
1536\r
1537 //\r
1538 // Adjust the alignment to even, quad or double quad boundary\r
1539 //\r
8a93fa1e 1540 if (NewAlignment == EVEN_ALIGN) {\r
9060e3ec 1541 if ((OldAlignment & 0x01) != 0) {\r
1542 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1543 }\r
8a93fa1e 1544 } else if (NewAlignment == SQUAD_ALIGN) {\r
9060e3ec 1545 if ((OldAlignment & 0x03) != 0) {\r
1546 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1547 }\r
8a93fa1e 1548 } else if (NewAlignment == DQUAD_ALIGN) {\r
9060e3ec 1549 if ((OldAlignment & 0x07) != 0) {\r
1550 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1551 }\r
1552 }\r
1553\r
1554 //\r
1555 // Update the old value\r
1556 //\r
1436aea4
MK
1557 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1558 *Alignment = NewAlignment;\r
9060e3ec 1559\r
1436aea4 1560 return;\r
9060e3ec 1561}\r
1562\r
1563/**\r
1564 Parse PCI IOV VF bar information and fill them into PCI device instance.\r
1565\r
1566 @param PciIoDevice Pci device instance.\r
1567 @param Offset Bar offset.\r
1568 @param BarIndex Bar index.\r
1569\r
1570 @return Next bar offset.\r
1571\r
1572**/\r
1573UINTN\r
1574PciIovParseVfBar (\r
1575 IN PCI_IO_DEVICE *PciIoDevice,\r
1576 IN UINTN Offset,\r
1577 IN UINTN BarIndex\r
1578 )\r
1579{\r
1580 UINT32 Value;\r
1581 UINT32 OriginalValue;\r
1582 UINT32 Mask;\r
9060e3ec 1583 EFI_STATUS Status;\r
1584\r
1585 //\r
1586 // Ensure it is called properly\r
1587 //\r
1588 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
1589 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
1590 return 0;\r
1591 }\r
1592\r
1593 OriginalValue = 0;\r
1594 Value = 0;\r
1595\r
1596 Status = VfBarExisted (\r
1436aea4
MK
1597 PciIoDevice,\r
1598 Offset,\r
1599 &Value,\r
1600 &OriginalValue\r
1601 );\r
9060e3ec 1602\r
1603 if (EFI_ERROR (Status)) {\r
1604 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1605 PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
1606 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1607\r
1608 //\r
1609 // Scan all the BARs anyway\r
1610 //\r
1436aea4 1611 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;\r
9060e3ec 1612 return Offset + 4;\r
1613 }\r
1614\r
1436aea4 1615 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;\r
aa75dfec 1616 if ((Value & 0x01) != 0) {\r
9060e3ec 1617 //\r
1618 // Device I/Os. Impossible\r
1619 //\r
1620 ASSERT (FALSE);\r
1621 return Offset + 4;\r
9060e3ec 1622 } else {\r
1436aea4 1623 Mask = 0xfffffff0;\r
9060e3ec 1624\r
1625 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1626\r
1627 switch (Value & 0x07) {\r
1436aea4
MK
1628 //\r
1629 // memory space; anywhere in 32 bit address space\r
1630 //\r
1631 case 0x00:\r
1632 if ((Value & 0x08) != 0) {\r
1633 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
1634 } else {\r
1635 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
1636 }\r
9060e3ec 1637\r
1436aea4
MK
1638 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1639 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1640\r
1641 //\r
1642 // Adjust Length\r
1643 //\r
1644 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1645 //\r
1646 // Adjust Alignment\r
1647 //\r
1648 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1649 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1650 }\r
9060e3ec 1651\r
1436aea4 1652 break;\r
9060e3ec 1653\r
1654 //\r
1436aea4 1655 // memory space; anywhere in 64 bit address space\r
9060e3ec 1656 //\r
1436aea4
MK
1657 case 0x04:\r
1658 if ((Value & 0x08) != 0) {\r
1659 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
1660 } else {\r
1661 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
1662 }\r
9060e3ec 1663\r
1436aea4
MK
1664 //\r
1665 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1666 // is regarded as an extension for the first bar. As a result\r
1667 // the sizing will be conducted on combined 64 bit value\r
1668 // Here just store the masked first 32bit value for future size\r
1669 // calculation\r
1670 //\r
1671 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
1672 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
9060e3ec 1673\r
1436aea4
MK
1674 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1675 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1676 }\r
9060e3ec 1677\r
1436aea4
MK
1678 //\r
1679 // Increment the offset to point to next DWORD\r
1680 //\r
1681 Offset += 4;\r
9060e3ec 1682\r
1436aea4
MK
1683 Status = VfBarExisted (\r
1684 PciIoDevice,\r
1685 Offset,\r
1686 &Value,\r
1687 &OriginalValue\r
1688 );\r
9060e3ec 1689\r
1436aea4
MK
1690 if (EFI_ERROR (Status)) {\r
1691 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1692 return Offset + 4;\r
1693 }\r
9060e3ec 1694\r
1436aea4
MK
1695 //\r
1696 // Fix the length to support some special 64 bit BAR\r
1697 //\r
1698 Value |= ((UINT32)-1 << HighBitSet32 (Value));\r
9060e3ec 1699\r
1436aea4
MK
1700 //\r
1701 // Calculate the size of 64bit bar\r
1702 //\r
1703 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);\r
9060e3ec 1704\r
1436aea4
MK
1705 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);\r
1706 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
1707 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
9060e3ec 1708\r
1436aea4
MK
1709 //\r
1710 // Adjust Length\r
1711 //\r
1712 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1713 //\r
1714 // Adjust Alignment\r
1715 //\r
1716 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1717 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1718 }\r
9060e3ec 1719\r
1436aea4 1720 break;\r
9060e3ec 1721\r
1722 //\r
1436aea4 1723 // reserved\r
9060e3ec 1724 //\r
1436aea4
MK
1725 default:\r
1726 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1727 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1728 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
9060e3ec 1729\r
1436aea4
MK
1730 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1731 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1732 }\r
9060e3ec 1733\r
1436aea4 1734 break;\r
9060e3ec 1735 }\r
1736 }\r
d1102dba 1737\r
9060e3ec 1738 //\r
1739 // Check the length again so as to keep compatible with some special bars\r
1740 //\r
1741 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
1742 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1743 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1744 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1745 }\r
d1102dba 1746\r
9060e3ec 1747 //\r
1748 // Increment number of bar\r
1749 //\r
1750 return Offset + 4;\r
1751}\r
1752\r
1753/**\r
1754 Parse PCI bar information and fill them into PCI device instance.\r
1755\r
1756 @param PciIoDevice Pci device instance.\r
1757 @param Offset Bar offset.\r
1758 @param BarIndex Bar index.\r
1759\r
1760 @return Next bar offset.\r
1761\r
1762**/\r
1763UINTN\r
1764PciParseBar (\r
1765 IN PCI_IO_DEVICE *PciIoDevice,\r
1766 IN UINTN Offset,\r
1767 IN UINTN BarIndex\r
1768 )\r
1769{\r
1770 UINT32 Value;\r
1771 UINT32 OriginalValue;\r
1772 UINT32 Mask;\r
9060e3ec 1773 EFI_STATUS Status;\r
1774\r
1775 OriginalValue = 0;\r
1776 Value = 0;\r
1777\r
1778 Status = BarExisted (\r
1779 PciIoDevice,\r
1780 Offset,\r
1781 &Value,\r
1782 &OriginalValue\r
1783 );\r
1784\r
1785 if (EFI_ERROR (Status)) {\r
1786 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1787 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1788 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1789\r
1790 //\r
1791 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1792 //\r
1436aea4 1793 PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset;\r
9060e3ec 1794 return Offset + 4;\r
1795 }\r
1796\r
05070c1b 1797 PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;\r
1436aea4 1798 PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset;\r
9060e3ec 1799 if ((Value & 0x01) != 0) {\r
1800 //\r
1801 // Device I/Os\r
1802 //\r
1803 Mask = 0xfffffffc;\r
1804\r
1805 if ((Value & 0xFFFF0000) != 0) {\r
1806 //\r
1807 // It is a IO32 bar\r
1808 //\r
1809 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1810 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1811 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1812 } else {\r
1813 //\r
1814 // It is a IO16 bar\r
1815 //\r
1816 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1817 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1818 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1819 }\r
1436aea4 1820\r
9060e3ec 1821 //\r
fcdfcdbf 1822 // Workaround. Some platforms implement IO bar with 0 length\r
9060e3ec 1823 // Need to treat it as no-bar\r
1824 //\r
1825 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1436aea4 1826 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE)0;\r
9060e3ec 1827 }\r
1828\r
1436aea4 1829 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
9060e3ec 1830 } else {\r
1436aea4 1831 Mask = 0xfffffff0;\r
9060e3ec 1832\r
1833 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1834\r
1835 switch (Value & 0x07) {\r
1436aea4
MK
1836 //\r
1837 // memory space; anywhere in 32 bit address space\r
1838 //\r
1839 case 0x00:\r
1840 if ((Value & 0x08) != 0) {\r
1841 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1842 } else {\r
1843 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1844 }\r
9060e3ec 1845\r
1436aea4
MK
1846 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1847 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1848 //\r
1849 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1850 //\r
1851 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1852 } else {\r
1853 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1854 }\r
1855\r
1856 break;\r
1857\r
1858 //\r
1859 // memory space; anywhere in 64 bit address space\r
1860 //\r
1861 case 0x04:\r
1862 if ((Value & 0x08) != 0) {\r
1863 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1864 } else {\r
1865 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1866 }\r
9060e3ec 1867\r
9060e3ec 1868 //\r
1436aea4
MK
1869 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1870 // is regarded as an extension for the first bar. As a result\r
1871 // the sizing will be conducted on combined 64 bit value\r
1872 // Here just store the masked first 32bit value for future size\r
1873 // calculation\r
9060e3ec 1874 //\r
1436aea4 1875 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
9060e3ec 1876 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1877\r
1436aea4
MK
1878 //\r
1879 // Increment the offset to point to next DWORD\r
1880 //\r
1881 Offset += 4;\r
9060e3ec 1882\r
1436aea4
MK
1883 Status = BarExisted (\r
1884 PciIoDevice,\r
1885 Offset,\r
1886 &Value,\r
1887 &OriginalValue\r
1888 );\r
9060e3ec 1889\r
1436aea4
MK
1890 if (EFI_ERROR (Status)) {\r
1891 //\r
1892 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
1893 //\r
1894 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1895 //\r
1896 // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
1897 //\r
1898 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1899 return Offset + 4;\r
1900 }\r
1901 }\r
9060e3ec 1902\r
1436aea4
MK
1903 //\r
1904 // Fix the length to support some special 64 bit BAR\r
1905 //\r
1906 if (Value == 0) {\r
1907 DEBUG ((DEBUG_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));\r
1908 Value = (UINT32)-1;\r
1909 } else {\r
1910 Value |= ((UINT32)(-1) << HighBitSet32 (Value));\r
1911 }\r
9060e3ec 1912\r
9060e3ec 1913 //\r
1436aea4 1914 // Calculate the size of 64bit bar\r
9060e3ec 1915 //\r
1436aea4
MK
1916 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);\r
1917\r
1918 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);\r
1919 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1920 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
9060e3ec 1921 //\r
1436aea4 1922 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
9060e3ec 1923 //\r
1436aea4
MK
1924 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1925 } else {\r
1926 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1927 }\r
9060e3ec 1928\r
1436aea4 1929 break;\r
9060e3ec 1930\r
1931 //\r
1436aea4 1932 // reserved\r
9060e3ec 1933 //\r
1436aea4
MK
1934 default:\r
1935 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1936 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1937 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1938 //\r
1939 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1940 //\r
1941 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1942 } else {\r
1943 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1944 }\r
9060e3ec 1945\r
1436aea4 1946 break;\r
9060e3ec 1947 }\r
1948 }\r
1949\r
1950 //\r
1951 // Check the length again so as to keep compatible with some special bars\r
1952 //\r
1953 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1954 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1955 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1956 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1957 }\r
1958\r
1959 //\r
1960 // Increment number of bar\r
1961 //\r
1962 return Offset + 4;\r
1963}\r
1964\r
1965/**\r
1966 This routine is used to initialize the bar of a PCI device.\r
1967\r
1968 @param PciIoDevice Pci device instance.\r
1969\r
1970 @note It can be called typically when a device is going to be rejected.\r
1971\r
1972**/\r
1973VOID\r
1974InitializePciDevice (\r
1436aea4 1975 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 1976 )\r
1977{\r
1436aea4
MK
1978 EFI_PCI_IO_PROTOCOL *PciIo;\r
1979 UINT8 Offset;\r
9060e3ec 1980\r
1981 PciIo = &(PciIoDevice->PciIo);\r
1982\r
1983 //\r
1984 // Put all the resource apertures\r
1985 // Resource base is set to all ones so as to indicate its resource\r
fcdfcdbf 1986 // has not been allocated\r
9060e3ec 1987 //\r
1988 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1989 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1990 }\r
1991}\r
1992\r
1993/**\r
1994 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1995\r
1996 @param PciIoDevice PCI-PCI bridge device instance.\r
1997\r
1998**/\r
1999VOID\r
2000InitializePpb (\r
1436aea4 2001 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 2002 )\r
2003{\r
1436aea4 2004 EFI_PCI_IO_PROTOCOL *PciIo;\r
9060e3ec 2005\r
2006 PciIo = &(PciIoDevice->PciIo);\r
2007\r
2008 //\r
2009 // Put all the resource apertures including IO16\r
2010 // Io32, pMem32, pMem64 to quiescent state\r
2011 // Resource base all ones, Resource limit all zeros\r
2012 //\r
2013 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
2014 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
2015\r
2016 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
2017 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
2018\r
2019 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
2020 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
2021\r
2022 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
2023 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
2024\r
2025 //\r
2026 // Don't support use io32 as for now\r
2027 //\r
2028 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
2029 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
2030\r
2031 //\r
2032 // Force Interrupt line to zero for cards that come up randomly\r
2033 //\r
2034 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2035}\r
2036\r
2037/**\r
2038 This routine is used to initialize the bar of a PCI Card Bridge device.\r
2039\r
2040 @param PciIoDevice PCI Card bridge device.\r
2041\r
2042**/\r
2043VOID\r
2044InitializeP2C (\r
1436aea4 2045 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 2046 )\r
2047{\r
1436aea4 2048 EFI_PCI_IO_PROTOCOL *PciIo;\r
9060e3ec 2049\r
2050 PciIo = &(PciIoDevice->PciIo);\r
2051\r
2052 //\r
2053 // Put all the resource apertures including IO16\r
2054 // Io32, pMem32, pMem64 to quiescent state(\r
2055 // Resource base all ones, Resource limit all zeros\r
2056 //\r
2057 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
2058 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
2059\r
2060 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
2061 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
2062\r
2063 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
2064 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
2065\r
2066 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
2067 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
2068\r
2069 //\r
2070 // Force Interrupt line to zero for cards that come up randomly\r
2071 //\r
2072 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2073}\r
2074\r
1e947f9b 2075/**\r
995d8b85
JY
2076 Authenticate the PCI device by using DeviceSecurityProtocol.\r
2077\r
2078 @param PciIoDevice PCI device.\r
2079\r
2080 @retval EFI_SUCCESS The device passes the authentication.\r
2081 @return not EFI_SUCCESS The device failes the authentication or\r
2082 unexpected error happen during authentication.\r
1e947f9b 2083**/\r
995d8b85
JY
2084EFI_STATUS\r
2085AuthenticatePciDevice (\r
1436aea4 2086 IN PCI_IO_DEVICE *PciIoDevice\r
995d8b85
JY
2087 )\r
2088{\r
2089 EDKII_DEVICE_IDENTIFIER DeviceIdentifier;\r
2090 EFI_STATUS Status;\r
2091\r
2092 if (mDeviceSecurityProtocol != NULL) {\r
2093 //\r
2094 // Prepare the parameter\r
2095 //\r
2096 DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;\r
2097 CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid);\r
2098 DeviceIdentifier.DeviceHandle = NULL;\r
1436aea4
MK
2099 Status = gBS->InstallMultipleProtocolInterfaces (\r
2100 &DeviceIdentifier.DeviceHandle,\r
2101 &gEfiDevicePathProtocolGuid,\r
2102 PciIoDevice->DevicePath,\r
2103 &gEdkiiDeviceIdentifierTypePciGuid,\r
2104 &PciIoDevice->PciIo,\r
2105 NULL\r
2106 );\r
2107 if (EFI_ERROR (Status)) {\r
995d8b85
JY
2108 return Status;\r
2109 }\r
2110\r
2111 //\r
2112 // Do DeviceAuthentication\r
2113 //\r
2114 Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier);\r
2115 //\r
2116 // Always uninstall, because they are only for Authentication.\r
2117 // No need to check return Status.\r
2118 //\r
2119 gBS->UninstallMultipleProtocolInterfaces (\r
1436aea4
MK
2120 DeviceIdentifier.DeviceHandle,\r
2121 &gEfiDevicePathProtocolGuid,\r
2122 PciIoDevice->DevicePath,\r
2123 &gEdkiiDeviceIdentifierTypePciGuid,\r
2124 &PciIoDevice->PciIo,\r
2125 NULL\r
2126 );\r
995d8b85
JY
2127 return Status;\r
2128 }\r
2129\r
2130 //\r
2131 // Device Security Protocol is not found, just return success\r
2132 //\r
2133 return EFI_SUCCESS;\r
2134}\r
2135\r
c095122d
RN
2136/**\r
2137 Checks if PCI device is Root Bridge.\r
2138\r
2139 @param PciIoDevice Instance of PCI device\r
2140\r
2141 @retval TRUE Device is Root Bridge\r
2142 @retval FALSE Device is not Root Bridge\r
2143\r
2144**/\r
2145BOOLEAN\r
2146IsRootBridge (\r
2147 IN PCI_IO_DEVICE *PciIoDevice\r
2148 )\r
2149{\r
2150 if (PciIoDevice->Parent == NULL) {\r
2151 return TRUE;\r
2152 } else {\r
2153 return FALSE;\r
2154 }\r
2155}\r
2156\r
9060e3ec 2157/**\r
fcdfcdbf 2158 Create and initialize general PCI I/O device instance for\r
9060e3ec 2159 PCI device/bridge device/hotplug bridge device.\r
2160\r
fcdfcdbf 2161 @param Bridge Parent bridge instance.\r
9060e3ec 2162 @param Pci Input Pci information block.\r
2163 @param Bus Device Bus NO.\r
2164 @param Device Device device NO.\r
2165 @param Func Device func NO.\r
2166\r
2167 @return Instance of PCI device. NULL means no instance created.\r
2168\r
2169**/\r
2170PCI_IO_DEVICE *\r
2171CreatePciIoDevice (\r
1436aea4
MK
2172 IN PCI_IO_DEVICE *Bridge,\r
2173 IN PCI_TYPE00 *Pci,\r
2174 IN UINT8 Bus,\r
2175 IN UINT8 Device,\r
2176 IN UINT8 Func\r
9060e3ec 2177 )\r
2178{\r
d4048391 2179 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 2180 EFI_PCI_IO_PROTOCOL *PciIo;\r
2181 EFI_STATUS Status;\r
2182\r
2183 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
2184 if (PciIoDevice == NULL) {\r
2185 return NULL;\r
2186 }\r
2187\r
1436aea4
MK
2188 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
2189 PciIoDevice->Handle = NULL;\r
2190 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2191 PciIoDevice->DevicePath = NULL;\r
2192 PciIoDevice->BusNumber = Bus;\r
2193 PciIoDevice->DeviceNumber = Device;\r
2194 PciIoDevice->FunctionNumber = Func;\r
2195 PciIoDevice->Decodes = 0;\r
9060e3ec 2196\r
2197 if (gFullEnumeration) {\r
2198 PciIoDevice->Allocated = FALSE;\r
2199 } else {\r
2200 PciIoDevice->Allocated = TRUE;\r
2201 }\r
2202\r
1436aea4
MK
2203 PciIoDevice->Registered = FALSE;\r
2204 PciIoDevice->Attributes = 0;\r
2205 PciIoDevice->Supports = 0;\r
2206 PciIoDevice->BusOverride = FALSE;\r
2207 PciIoDevice->AllOpRomProcessed = FALSE;\r
9060e3ec 2208\r
1436aea4 2209 PciIoDevice->IsPciExp = FALSE;\r
9060e3ec 2210\r
2211 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
2212\r
2213 //\r
2214 // Initialize the PCI I/O instance structure\r
2215 //\r
2216 InitializePciIoInstance (PciIoDevice);\r
2217 InitializePciDriverOverrideInstance (PciIoDevice);\r
2218 InitializePciLoadFile2 (PciIoDevice);\r
2219 PciIo = &PciIoDevice->PciIo;\r
2220\r
b0bc24af
AW
2221 //\r
2222 // Create a device path for this PCI device and store it into its private data\r
2223 //\r
2224 CreatePciDevicePath (\r
2225 Bridge->DevicePath,\r
2226 PciIoDevice\r
2227 );\r
2228\r
9060e3ec 2229 //\r
2230 // Detect if PCI Express Device\r
2231 //\r
2232 PciIoDevice->PciExpressCapabilityOffset = 0;\r
1436aea4
MK
2233 Status = LocateCapabilityRegBlock (\r
2234 PciIoDevice,\r
2235 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
2236 &PciIoDevice->PciExpressCapabilityOffset,\r
2237 NULL\r
2238 );\r
9060e3ec 2239 if (!EFI_ERROR (Status)) {\r
2240 PciIoDevice->IsPciExp = TRUE;\r
2241 }\r
2242\r
995d8b85
JY
2243 //\r
2244 // Now we can do the authentication check for the device.\r
2245 //\r
2246 Status = AuthenticatePciDevice (PciIoDevice);\r
2247 //\r
2248 // If authentication fails, skip this device.\r
2249 //\r
1436aea4 2250 if (EFI_ERROR (Status)) {\r
995d8b85
JY
2251 if (PciIoDevice->DevicePath != NULL) {\r
2252 FreePool (PciIoDevice->DevicePath);\r
2253 }\r
1436aea4 2254\r
995d8b85
JY
2255 FreePool (PciIoDevice);\r
2256 return NULL;\r
2257 }\r
2258\r
c095122d
RN
2259 //\r
2260 // Check if device's parent is not Root Bridge\r
2261 //\r
2262 if (PcdGetBool (PcdAriSupport) && !IsRootBridge (Bridge)) {\r
d4048391 2263 //\r
2264 // Check if the device is an ARI device.\r
2265 //\r
2266 Status = LocatePciExpressCapabilityRegBlock (\r
2267 PciIoDevice,\r
2268 EFI_PCIE_CAPABILITY_ID_ARI,\r
2269 &PciIoDevice->AriCapabilityOffset,\r
2270 NULL\r
2271 );\r
2272 if (!EFI_ERROR (Status)) {\r
2273 //\r
2274 // We need to enable ARI feature before calculate BusReservation,\r
2275 // because FirstVFOffset and VFStride may change after that.\r
2276 //\r
2277 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
2278 UINT32 Data32;\r
9060e3ec 2279\r
d4048391 2280 //\r
2281 // Check if its parent supports ARI forwarding.\r
2282 //\r
2283 ParentPciIo = &Bridge->PciIo;\r
2284 ParentPciIo->Pci.Read (\r
1436aea4
MK
2285 ParentPciIo,\r
2286 EfiPciIoWidthUint32,\r
2287 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
2288 1,\r
2289 &Data32\r
2290 );\r
d4048391 2291 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
8fc06b6e 2292 PciIoDevice->IsAriEnabled = TRUE;\r
d4048391 2293 //\r
2294 // ARI forward support in bridge, so enable it.\r
2295 //\r
2296 ParentPciIo->Pci.Read (\r
1436aea4
MK
2297 ParentPciIo,\r
2298 EfiPciIoWidthUint32,\r
2299 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2300 1,\r
2301 &Data32\r
2302 );\r
d4048391 2303 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2304 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2305 ParentPciIo->Pci.Write (\r
1436aea4
MK
2306 ParentPciIo,\r
2307 EfiPciIoWidthUint32,\r
2308 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2309 1,\r
2310 &Data32\r
2311 );\r
d4048391 2312 DEBUG ((\r
87000d77 2313 DEBUG_INFO,\r
8db6a82c
RN
2314 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",\r
2315 Bridge->BusNumber,\r
2316 Bridge->DeviceNumber,\r
2317 Bridge->FunctionNumber\r
d4048391 2318 ));\r
2319 }\r
2320 }\r
9060e3ec 2321\r
87000d77 2322 DEBUG ((DEBUG_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));\r
d4048391 2323 }\r
9060e3ec 2324 }\r
2325\r
2326 //\r
d4048391 2327 // Initialization for SR-IOV\r
9060e3ec 2328 //\r
9060e3ec 2329\r
d4048391 2330 if (PcdGetBool (PcdSrIovSupport)) {\r
2331 Status = LocatePciExpressCapabilityRegBlock (\r
2332 PciIoDevice,\r
2333 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2334 &PciIoDevice->SrIovCapabilityOffset,\r
2335 NULL\r
2336 );\r
2337 if (!EFI_ERROR (Status)) {\r
1436aea4
MK
2338 UINT32 SupportedPageSize;\r
2339 UINT16 VFStride;\r
2340 UINT16 FirstVFOffset;\r
2341 UINT16 Data16;\r
2342 UINT32 PFRid;\r
2343 UINT32 LastVF;\r
d4048391 2344\r
2345 //\r
2346 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2347 //\r
1436aea4 2348 if (PcdGetBool (PcdAriSupport) && (PciIoDevice->AriCapabilityOffset != 0)) {\r
d4048391 2349 PciIo->Pci.Read (\r
2350 PciIo,\r
2351 EfiPciIoWidthUint16,\r
2352 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2353 1,\r
2354 &Data16\r
2355 );\r
2356 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2357 PciIo->Pci.Write (\r
2358 PciIo,\r
2359 EfiPciIoWidthUint16,\r
2360 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2361 1,\r
2362 &Data16\r
2363 );\r
2364 }\r
9060e3ec 2365\r
d4048391 2366 //\r
2367 // Calculate SystemPageSize\r
2368 //\r
9060e3ec 2369\r
d4048391 2370 PciIo->Pci.Read (\r
2371 PciIo,\r
2372 EfiPciIoWidthUint32,\r
2373 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2374 1,\r
8db6a82c 2375 &SupportedPageSize\r
d4048391 2376 );\r
8db6a82c 2377 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);\r
d4048391 2378 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2379\r
2380 PciIo->Pci.Write (\r
2381 PciIo,\r
2382 EfiPciIoWidthUint32,\r
2383 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2384 1,\r
2385 &PciIoDevice->SystemPageSize\r
2386 );\r
d4048391 2387 //\r
2388 // Adjust SystemPageSize for Alignment usage later\r
2389 //\r
2390 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2391\r
d4048391 2392 //\r
2393 // Calculate BusReservation for PCI IOV\r
2394 //\r
9060e3ec 2395\r
d4048391 2396 //\r
2397 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2398 //\r
2399 PciIo->Pci.Read (\r
2400 PciIo,\r
2401 EfiPciIoWidthUint16,\r
2402 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2403 1,\r
2404 &FirstVFOffset\r
2405 );\r
d4048391 2406 PciIo->Pci.Read (\r
2407 PciIo,\r
2408 EfiPciIoWidthUint16,\r
2409 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2410 1,\r
2411 &PciIoDevice->InitialVFs\r
2412 );\r
d4048391 2413 PciIo->Pci.Read (\r
2414 PciIo,\r
2415 EfiPciIoWidthUint16,\r
2416 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2417 1,\r
2418 &VFStride\r
2419 );\r
d4048391 2420 //\r
2421 // Calculate LastVF\r
2422 //\r
de103f19
FN
2423 if (PciIoDevice->InitialVFs == 0) {\r
2424 PciIoDevice->ReservedBusNum = 0;\r
2425 } else {\r
2426 PFRid = EFI_PCI_RID (Bus, Device, Func);\r
2427 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2428\r
de103f19
FN
2429 //\r
2430 // Calculate ReservedBusNum for this PF\r
2431 //\r
4aa7e66c 2432 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus);\r
de103f19 2433 }\r
8db6a82c 2434\r
d4048391 2435 DEBUG ((\r
87000d77 2436 DEBUG_INFO,\r
8db6a82c 2437 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",\r
1436aea4
MK
2438 SupportedPageSize,\r
2439 PciIoDevice->SystemPageSize >> 12,\r
2440 FirstVFOffset\r
d4048391 2441 ));\r
d4048391 2442 DEBUG ((\r
87000d77 2443 DEBUG_INFO,\r
8db6a82c 2444 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",\r
1436aea4
MK
2445 PciIoDevice->InitialVFs,\r
2446 PciIoDevice->ReservedBusNum,\r
2447 PciIoDevice->SrIovCapabilityOffset\r
d4048391 2448 ));\r
2449 }\r
9060e3ec 2450 }\r
2451\r
d4048391 2452 if (PcdGetBool (PcdMrIovSupport)) {\r
2453 Status = LocatePciExpressCapabilityRegBlock (\r
2454 PciIoDevice,\r
2455 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2456 &PciIoDevice->MrIovCapabilityOffset,\r
2457 NULL\r
2458 );\r
2459 if (!EFI_ERROR (Status)) {\r
87000d77 2460 DEBUG ((DEBUG_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));\r
d4048391 2461 }\r
2462 }\r
9060e3ec 2463\r
0785c619
LH
2464 PciIoDevice->ResizableBarOffset = 0;\r
2465 if (PcdGetBool (PcdPcieResizableBarSupport)) {\r
2466 Status = LocatePciExpressCapabilityRegBlock (\r
2467 PciIoDevice,\r
2468 PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID,\r
2469 &PciIoDevice->ResizableBarOffset,\r
2470 NULL\r
2471 );\r
2472 if (!EFI_ERROR (Status)) {\r
1436aea4
MK
2473 PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl;\r
2474 UINT32 Offset;\r
0785c619 2475 Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)\r
1436aea4 2476 + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY),\r
0785c619 2477 PciIo->Pci.Read (\r
1436aea4
MK
2478 PciIo,\r
2479 EfiPciIoWidthUint8,\r
2480 Offset,\r
2481 sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL),\r
2482 &ResizableBarControl\r
2483 );\r
0785c619
LH
2484 PciIoDevice->ResizableBarNumber = ResizableBarControl.Bits.ResizableBarNumber;\r
2485 PciProgramResizableBar (PciIoDevice, PciResizableBarMax);\r
2486 }\r
2487 }\r
2488\r
9060e3ec 2489 //\r
2490 // Initialize the reserved resource list\r
2491 //\r
2492 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2493\r
2494 //\r
2495 // Initialize the driver list\r
2496 //\r
2497 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2498\r
2499 //\r
2500 // Initialize the child list\r
2501 //\r
2502 InitializeListHead (&PciIoDevice->ChildList);\r
2503\r
2504 return PciIoDevice;\r
2505}\r
2506\r
2507/**\r
2508 This routine is used to enumerate entire pci bus system\r
2509 in a given platform.\r
2510\r
2511 It is only called on the second start on the same Root Bridge.\r
2512\r
2513 @param Controller Parent bridge handler.\r
2514\r
2515 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2516 @retval other Some error occurred when enumerating the pci bus system.\r
2517\r
2518**/\r
2519EFI_STATUS\r
2520PciEnumeratorLight (\r
1436aea4 2521 IN EFI_HANDLE Controller\r
9060e3ec 2522 )\r
2523{\r
1436aea4
MK
2524 EFI_STATUS Status;\r
2525 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2526 PCI_IO_DEVICE *RootBridgeDev;\r
2527 UINT16 MinBus;\r
2528 UINT16 MaxBus;\r
2529 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
9060e3ec 2530\r
2531 MinBus = 0;\r
2532 MaxBus = PCI_MAX_BUS;\r
2533 Descriptors = NULL;\r
2534\r
2535 //\r
2536 // If this root bridge has been already enumerated, then return successfully\r
2537 //\r
2538 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2539 return EFI_SUCCESS;\r
2540 }\r
2541\r
2542 //\r
2543 // Open pci root bridge io protocol\r
2544 //\r
2545 Status = gBS->OpenProtocol (\r
2546 Controller,\r
2547 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 2548 (VOID **)&PciRootBridgeIo,\r
9060e3ec 2549 gPciBusDriverBinding.DriverBindingHandle,\r
2550 Controller,\r
2551 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2552 );\r
1436aea4 2553 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
9060e3ec 2554 return Status;\r
2555 }\r
2556\r
1436aea4 2557 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)&Descriptors);\r
9060e3ec 2558\r
2559 if (EFI_ERROR (Status)) {\r
2560 return Status;\r
2561 }\r
2562\r
2563 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
9060e3ec 2564 //\r
2565 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2566 //\r
2567 RootBridgeDev = CreateRootBridge (Controller);\r
2568\r
2569 if (RootBridgeDev == NULL) {\r
2570 Descriptors++;\r
2571 continue;\r
2572 }\r
2573\r
2574 //\r
fcdfcdbf 2575 // Record the root bridge-io protocol\r
9060e3ec 2576 //\r
2577 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2578\r
2579 Status = PciPciDeviceInfoCollector (\r
2580 RootBridgeDev,\r
1436aea4 2581 (UINT8)MinBus\r
9060e3ec 2582 );\r
2583\r
2584 if (!EFI_ERROR (Status)) {\r
9060e3ec 2585 //\r
2586 // Remove those PCI devices which are rejected when full enumeration\r
2587 //\r
2588 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2589\r
2590 //\r
2591 // Process option rom light\r
2592 //\r
2593 ProcessOptionRomLight (RootBridgeDev);\r
2594\r
2595 //\r
2596 // Determine attributes for all devices under this root bridge\r
2597 //\r
2598 DetermineDeviceAttribute (RootBridgeDev);\r
2599\r
2600 //\r
2601 // If successfully, insert the node into device pool\r
2602 //\r
2603 InsertRootBridge (RootBridgeDev);\r
2604 } else {\r
9060e3ec 2605 //\r
fcdfcdbf 2606 // If unsuccessfully, destroy the entire node\r
9060e3ec 2607 //\r
2608 DestroyRootBridge (RootBridgeDev);\r
2609 }\r
2610\r
2611 Descriptors++;\r
2612 }\r
2613\r
2614 return EFI_SUCCESS;\r
2615}\r
2616\r
2617/**\r
2618 Get bus range from PCI resource descriptor list.\r
2619\r
2620 @param Descriptors A pointer to the address space descriptor.\r
2621 @param MinBus The min bus returned.\r
2622 @param MaxBus The max bus returned.\r
2623 @param BusRange The bus range returned.\r
2624\r
2625 @retval EFI_SUCCESS Successfully got bus range.\r
2626 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2627\r
2628**/\r
2629EFI_STATUS\r
2630PciGetBusRange (\r
2631 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2632 OUT UINT16 *MinBus,\r
2633 OUT UINT16 *MaxBus,\r
2634 OUT UINT16 *BusRange\r
2635 )\r
2636{\r
2637 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2638 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2639 if (MinBus != NULL) {\r
1436aea4 2640 *MinBus = (UINT16)(*Descriptors)->AddrRangeMin;\r
9060e3ec 2641 }\r
2642\r
2643 if (MaxBus != NULL) {\r
1436aea4 2644 *MaxBus = (UINT16)(*Descriptors)->AddrRangeMax;\r
9060e3ec 2645 }\r
2646\r
2647 if (BusRange != NULL) {\r
1436aea4 2648 *BusRange = (UINT16)(*Descriptors)->AddrLen;\r
9060e3ec 2649 }\r
2650\r
2651 return EFI_SUCCESS;\r
2652 }\r
2653\r
2654 (*Descriptors)++;\r
2655 }\r
2656\r
2657 return EFI_NOT_FOUND;\r
2658}\r
2659\r
2660/**\r
2661 This routine can be used to start the root bridge.\r
2662\r
2663 @param RootBridgeDev Pci device instance.\r
2664\r
2665 @retval EFI_SUCCESS This device started.\r
2666 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2667\r
2668**/\r
2669EFI_STATUS\r
2670StartManagingRootBridge (\r
1436aea4 2671 IN PCI_IO_DEVICE *RootBridgeDev\r
9060e3ec 2672 )\r
2673{\r
1436aea4
MK
2674 EFI_HANDLE RootBridgeHandle;\r
2675 EFI_STATUS Status;\r
2676 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
9060e3ec 2677\r
2678 //\r
2679 // Get the root bridge handle\r
2680 //\r
2681 RootBridgeHandle = RootBridgeDev->Handle;\r
2682 PciRootBridgeIo = NULL;\r
2683\r
2684 //\r
2685 // Get the pci root bridge io protocol\r
2686 //\r
2687 Status = gBS->OpenProtocol (\r
2688 RootBridgeHandle,\r
2689 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 2690 (VOID **)&PciRootBridgeIo,\r
9060e3ec 2691 gPciBusDriverBinding.DriverBindingHandle,\r
2692 RootBridgeHandle,\r
2693 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2694 );\r
2695\r
1436aea4 2696 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
9060e3ec 2697 return Status;\r
2698 }\r
2699\r
2700 //\r
2701 // Store the PciRootBridgeIo protocol into root bridge private data\r
2702 //\r
2703 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2704\r
2705 return EFI_SUCCESS;\r
9060e3ec 2706}\r
2707\r
2708/**\r
2709 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2710\r
2711 @param PciIoDevice Pci device instance.\r
2712\r
2713 @retval TRUE This device should be rejected.\r
2714 @retval FALSE This device shouldn't be rejected.\r
2715\r
2716**/\r
2717BOOLEAN\r
2718IsPciDeviceRejected (\r
1436aea4 2719 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 2720 )\r
2721{\r
2722 EFI_STATUS Status;\r
2723 UINT32 TestValue;\r
2724 UINT32 OldValue;\r
2725 UINT32 Mask;\r
2726 UINT8 BarOffset;\r
2727\r
2728 //\r
2729 // PPB should be skip!\r
2730 //\r
2731 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2732 return FALSE;\r
2733 }\r
2734\r
2735 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2736 //\r
2737 // Only test base registers for P2C\r
2738 //\r
2739 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
1436aea4
MK
2740 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2741 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
9060e3ec 2742 if (EFI_ERROR (Status)) {\r
2743 continue;\r
2744 }\r
2745\r
2746 TestValue = TestValue & Mask;\r
2747 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2748 //\r
2749 // The bar isn't programed, so it should be rejected\r
2750 //\r
2751 return TRUE;\r
2752 }\r
2753 }\r
2754\r
2755 return FALSE;\r
2756 }\r
2757\r
2758 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2759 //\r
2760 // Test PCI devices\r
2761 //\r
2762 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2763 if (EFI_ERROR (Status)) {\r
2764 continue;\r
2765 }\r
2766\r
2767 if ((TestValue & 0x01) != 0) {\r
9060e3ec 2768 //\r
2769 // IO Bar\r
2770 //\r
2771 Mask = 0xFFFFFFFC;\r
2772 TestValue = TestValue & Mask;\r
2773 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2774 return TRUE;\r
2775 }\r
9060e3ec 2776 } else {\r
9060e3ec 2777 //\r
2778 // Mem Bar\r
2779 //\r
2780 Mask = 0xFFFFFFF0;\r
2781 TestValue = TestValue & Mask;\r
2782\r
2783 if ((TestValue & 0x07) == 0x04) {\r
9060e3ec 2784 //\r
2785 // Mem64 or PMem64\r
2786 //\r
2787 BarOffset += sizeof (UINT32);\r
2788 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
9060e3ec 2789 //\r
2790 // Test its high 32-Bit BAR\r
2791 //\r
2792 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2793 if (TestValue == OldValue) {\r
2794 return TRUE;\r
2795 }\r
2796 }\r
9060e3ec 2797 } else {\r
9060e3ec 2798 //\r
2799 // Mem32 or PMem32\r
2800 //\r
2801 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2802 return TRUE;\r
2803 }\r
2804 }\r
2805 }\r
2806 }\r
2807\r
2808 return FALSE;\r
2809}\r
2810\r
2811/**\r
2812 Reset all bus number from specific bridge.\r
2813\r
2814 @param Bridge Parent specific bridge.\r
2815 @param StartBusNumber Start bus number.\r
2816\r
2817**/\r
2818VOID\r
2819ResetAllPpbBusNumber (\r
1436aea4
MK
2820 IN PCI_IO_DEVICE *Bridge,\r
2821 IN UINT8 StartBusNumber\r
9060e3ec 2822 )\r
2823{\r
1436aea4
MK
2824 EFI_STATUS Status;\r
2825 PCI_TYPE00 Pci;\r
2826 UINT8 Device;\r
2827 UINT32 Register;\r
2828 UINT8 Func;\r
2829 UINT64 Address;\r
2830 UINT8 SecondaryBus;\r
2831 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
9060e3ec 2832\r
2833 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2834\r
2835 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2836 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
9060e3ec 2837 //\r
2838 // Check to see whether a pci device is present\r
2839 //\r
2840 Status = PciDevicePresent (\r
2841 PciRootBridgeIo,\r
2842 &Pci,\r
2843 StartBusNumber,\r
2844 Device,\r
2845 Func\r
2846 );\r
2847\r
1436aea4 2848 if (EFI_ERROR (Status) && (Func == 0)) {\r
25a26646
JS
2849 //\r
2850 // go to next device if there is no Function 0\r
2851 //\r
2852 break;\r
2853 }\r
2854\r
9060e3ec 2855 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
1436aea4
MK
2856 Register = 0;\r
2857 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2858 Status = PciRootBridgeIo->Pci.Read (\r
2859 PciRootBridgeIo,\r
2860 EfiPciWidthUint32,\r
2861 Address,\r
2862 1,\r
2863 &Register\r
2864 );\r
9060e3ec 2865 SecondaryBus = (UINT8)(Register >> 8);\r
2866\r
2867 if (SecondaryBus != 0) {\r
2868 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2869 }\r
2870\r
2871 //\r
2872 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2873 //\r
2874 Register &= 0xFF000000;\r
1436aea4
MK
2875 Status = PciRootBridgeIo->Pci.Write (\r
2876 PciRootBridgeIo,\r
2877 EfiPciWidthUint32,\r
2878 Address,\r
2879 1,\r
2880 &Register\r
2881 );\r
9060e3ec 2882 }\r
2883\r
1436aea4 2884 if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {\r
9060e3ec 2885 //\r
2886 // Skip sub functions, this is not a multi function device\r
2887 //\r
2888 Func = PCI_MAX_FUNC;\r
2889 }\r
2890 }\r
2891 }\r
2892}\r