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