]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
MdeModulePkg: Issues reported by ECC in EDK2.
[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
fcdfcdbf 4Copyright (c) 2006 - 2019, 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
RN
233 DEBUG ((\r
234 EFI_D_INFO,\r
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
401 EFI_D_INFO,\r
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
428 EFI_D_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
441 EFI_D_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
447 DEBUG ((EFI_D_INFO, "\n"));\r
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
936\r
937 //\r
938 // Preserve the original value\r
939 //\r
940 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);\r
941\r
942 //\r
943 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
944 //\r
945 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
946\r
947 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);\r
948 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);\r
949\r
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
961\r
962 //\r
963 // Preserve the original value\r
964 //\r
965 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);\r
966\r
967 //\r
968 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
969 //\r
970 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
971\r
972 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);\r
973 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);\r
974\r
975 //\r
976 // Write back the original value\r
977 //\r
978 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);\r
979\r
980 //\r
981 // Restore TPL to its original level\r
982 //\r
983 gBS->RestoreTPL (OldTpl);\r
984\r
985 } else {\r
986 *OldBridgeControl = 0;\r
987 *BridgeControl = 0;\r
988 }\r
989}\r
990\r
991/**\r
992 Set the supported or current attributes of a PCI device.\r
993\r
994 @param PciIoDevice Structure pointer for PCI device.\r
995 @param Command Command register value.\r
996 @param BridgeControl Bridge control value for PPB or P2C.\r
997 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.\r
998\r
999**/\r
1000VOID\r
1001PciSetDeviceAttribute (\r
1002 IN PCI_IO_DEVICE *PciIoDevice,\r
1003 IN UINT16 Command,\r
1004 IN UINT16 BridgeControl,\r
1005 IN UINTN Option\r
1006 )\r
1007{\r
1008 UINT64 Attributes;\r
1009\r
1010 Attributes = 0;\r
1011\r
1012 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {\r
1013 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
1014 }\r
1015\r
1016 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {\r
1017 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
1018 }\r
1019\r
1020 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {\r
1021 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
1022 }\r
1023\r
1024 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {\r
1025 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
1026 }\r
1027\r
1028 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {\r
1029 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
1030 }\r
1031\r
1032 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {\r
1033 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
1034 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
1035 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
1036 }\r
1037\r
1038 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {\r
1039 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
1040 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;\r
1041 }\r
1042\r
1043 if (Option == EFI_SET_SUPPORTS) {\r
1044\r
6e1e5405 1045 Attributes |= (UINT64) (EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
9060e3ec 1046 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |\r
1047 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |\r
1048 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
1049 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
6e1e5405 1050 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
9060e3ec 1051\r
e0ee9d93 1052 if (IS_PCI_LPC (&PciIoDevice->Pci)) {\r
1053 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
980050bc
RN
1054 Attributes |= (mReserveIsaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO : \\r
1055 (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);\r
9060e3ec 1056 }\r
1057\r
1058 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1059 //\r
1060 // For bridge, it should support IDE attributes\r
1061 //\r
1062 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
1063 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
e0ee9d93 1064\r
1065 if (mReserveVgaAliases) {\r
1066 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \\r
1067 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);\r
1068 } else {\r
1069 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \\r
1070 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);\r
1071 }\r
9060e3ec 1072 } else {\r
1073\r
1074 if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
1075 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
1076 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
1077 }\r
1078\r
1079 if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
1080 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
980050bc
RN
1081 Attributes |= (mReserveVgaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO : \\r
1082 (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
9060e3ec 1083 }\r
1084 }\r
1085\r
1086 PciIoDevice->Supports = Attributes;\r
1087 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \\r
1088 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
1089 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );\r
1090\r
1091 } else {\r
4ed4e19c 1092 //\r
1093 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were\r
1094 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.\r
1095 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize\r
1096 // fields is not from the the ROM BAR of the PCI controller.\r
1097 //\r
1098 if (!PciIoDevice->EmbeddedRom) {\r
1099 Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;\r
1100 }\r
9060e3ec 1101 PciIoDevice->Attributes = Attributes;\r
1102 }\r
1103}\r
1104\r
1105/**\r
1106 Determine if the device can support Fast Back to Back attribute.\r
1107\r
1108 @param PciIoDevice Pci device instance.\r
1109 @param StatusIndex Status register value.\r
1110\r
1111 @retval EFI_SUCCESS This device support Fast Back to Back attribute.\r
1112 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.\r
1113\r
1114**/\r
1115EFI_STATUS\r
1116GetFastBackToBackSupport (\r
1117 IN PCI_IO_DEVICE *PciIoDevice,\r
1118 IN UINT8 StatusIndex\r
1119 )\r
1120{\r
1121 EFI_PCI_IO_PROTOCOL *PciIo;\r
1122 EFI_STATUS Status;\r
1123 UINT32 StatusRegister;\r
1124\r
1125 //\r
1126 // Read the status register\r
1127 //\r
1128 PciIo = &PciIoDevice->PciIo;\r
1129 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
1130 if (EFI_ERROR (Status)) {\r
1131 return EFI_UNSUPPORTED;\r
1132 }\r
1133\r
1134 //\r
1135 // Check the Fast B2B bit\r
1136 //\r
1137 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {\r
1138 return EFI_SUCCESS;\r
1139 } else {\r
1140 return EFI_UNSUPPORTED;\r
1141 }\r
1142}\r
1143\r
1144/**\r
1145 Process the option ROM for all the children of the specified parent PCI device.\r
1146 It can only be used after the first full Option ROM process.\r
1147\r
1148 @param PciIoDevice Pci device instance.\r
1149\r
1150**/\r
1151VOID\r
1152ProcessOptionRomLight (\r
1153 IN PCI_IO_DEVICE *PciIoDevice\r
1154 )\r
1155{\r
1156 PCI_IO_DEVICE *Temp;\r
1157 LIST_ENTRY *CurrentLink;\r
1158\r
1159 //\r
1160 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1161 //\r
1162 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1163 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1164\r
1165 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1166\r
1167 if (!IsListEmpty (&Temp->ChildList)) {\r
1168 ProcessOptionRomLight (Temp);\r
1169 }\r
1170\r
1171 PciRomGetImageMapping (Temp);\r
1172\r
1173 //\r
1174 // The OpRom has already been processed in the first round\r
1175 //\r
1176 Temp->AllOpRomProcessed = TRUE;\r
1177\r
1178 CurrentLink = CurrentLink->ForwardLink;\r
1179 }\r
1180}\r
1181\r
1182/**\r
1183 Determine the related attributes of all devices under a Root Bridge.\r
1184\r
1185 @param PciIoDevice PCI device instance.\r
1186\r
1187**/\r
1188EFI_STATUS\r
1189DetermineDeviceAttribute (\r
1190 IN PCI_IO_DEVICE *PciIoDevice\r
1191 )\r
1192{\r
1193 UINT16 Command;\r
1194 UINT16 BridgeControl;\r
1195 UINT16 OldCommand;\r
1196 UINT16 OldBridgeControl;\r
1197 BOOLEAN FastB2BSupport;\r
1198 PCI_IO_DEVICE *Temp;\r
1199 LIST_ENTRY *CurrentLink;\r
1200 EFI_STATUS Status;\r
1201\r
1202 //\r
fcdfcdbf 1203 // For Root Bridge, just copy it by RootBridgeIo protocol\r
9060e3ec 1204 // so as to keep consistent with the actual attribute\r
1205 //\r
1206 if (PciIoDevice->Parent == NULL) {\r
1207 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
1208 PciIoDevice->PciRootBridgeIo,\r
1209 &PciIoDevice->Supports,\r
1210 &PciIoDevice->Attributes\r
1211 );\r
1212 if (EFI_ERROR (Status)) {\r
1213 return Status;\r
1214 }\r
5a3a6aa7 1215 //\r
a8035b90 1216 // Assume the PCI Root Bridge supports DAC\r
5a3a6aa7 1217 //\r
6e1e5405 1218 PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
5a3a6aa7 1219 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
a8035b90 1220 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
7afa5ea8 1221\r
9060e3ec 1222 } else {\r
1223\r
1224 //\r
1225 // Set the attributes to be checked for common PCI devices and PPB or P2C\r
1226 // Since some devices only support part of them, it is better to set the\r
1227 // attribute according to its command or bridge control register\r
1228 //\r
1229 Command = EFI_PCI_COMMAND_IO_SPACE |\r
1230 EFI_PCI_COMMAND_MEMORY_SPACE |\r
a8035b90 1231 EFI_PCI_COMMAND_BUS_MASTER |\r
9060e3ec 1232 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1233\r
1234 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
1235\r
1236 //\r
1237 // Test whether the device can support attributes above\r
1238 //\r
1239 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
1240\r
1241 //\r
1242 // Set the supported attributes for specified PCI device\r
1243 //\r
1244 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
1245\r
1246 //\r
1247 // Set the current attributes for specified PCI device\r
1248 //\r
1249 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
1250\r
1251 //\r
d9233654
RN
1252 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL\r
1253 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.\r
1254 if (!PciIoDevice->IsPciExp) {\r
1255 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
1256 }\r
9060e3ec 1257 }\r
1258\r
1259 FastB2BSupport = TRUE;\r
1260\r
1261 //\r
1262 // P2C can not support FB2B on the secondary side\r
1263 //\r
1264 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1265 FastB2BSupport = FALSE;\r
1266 }\r
1267\r
1268 //\r
1269 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1270 //\r
1271 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1272 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1273\r
1274 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1275 Status = DetermineDeviceAttribute (Temp);\r
1276 if (EFI_ERROR (Status)) {\r
1277 return Status;\r
1278 }\r
1279 //\r
fcdfcdbf 1280 // Detect Fast Back to Back support for the device under the bridge\r
9060e3ec 1281 //\r
1282 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1283 if (FastB2BSupport && EFI_ERROR (Status)) {\r
1284 FastB2BSupport = FALSE;\r
1285 }\r
1286\r
1287 CurrentLink = CurrentLink->ForwardLink;\r
1288 }\r
1289 //\r
1290 // Set or clear Fast Back to Back bit for the whole bridge\r
1291 //\r
1292 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
1293\r
1294 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1295\r
1296 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1297\r
1298 if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1299 FastB2BSupport = FALSE;\r
1300 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1301 } else {\r
1302 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1303 }\r
1304 }\r
1305\r
1306 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1307 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1308 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1309 if (FastB2BSupport) {\r
1310 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1311 } else {\r
1312 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1313 }\r
1314\r
1315 CurrentLink = CurrentLink->ForwardLink;\r
1316 }\r
1317 }\r
1318 //\r
1319 // End for IsListEmpty\r
1320 //\r
1321 return EFI_SUCCESS;\r
1322}\r
1323\r
1324/**\r
1325 This routine is used to update the bar information for those incompatible PCI device.\r
1326\r
1327 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated\r
1328 Bar information.\r
1329\r
1330 @retval EFI_SUCCESS Successfully updated bar information.\r
1331 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.\r
1332\r
1333**/\r
1334EFI_STATUS\r
1335UpdatePciInfo (\r
1336 IN OUT PCI_IO_DEVICE *PciIoDevice\r
1337 )\r
1338{\r
1339 EFI_STATUS Status;\r
eb470e05 1340 UINTN BarIndex;\r
9060e3ec 1341 BOOLEAN SetFlag;\r
1342 VOID *Configuration;\r
1343 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1344\r
1345 Configuration = NULL;\r
1346 Status = EFI_SUCCESS;\r
1347\r
ea669c1b 1348 if (gIncompatiblePciDeviceSupport == NULL) {\r
9060e3ec 1349 //\r
1350 // It can only be supported after the Incompatible PCI Device\r
1351 // Support Protocol has been installed\r
1352 //\r
1353 Status = gBS->LocateProtocol (\r
1354 &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
1355 NULL,\r
ea669c1b 1356 (VOID **) &gIncompatiblePciDeviceSupport\r
9060e3ec 1357 );\r
1358 }\r
1359 if (Status == EFI_SUCCESS) {\r
1360 //\r
1361 // Check whether the device belongs to incompatible devices from protocol or not\r
1362 // If it is , then get its special requirement in the ACPI table\r
1363 //\r
ea669c1b
RN
1364 Status = gIncompatiblePciDeviceSupport->CheckDevice (\r
1365 gIncompatiblePciDeviceSupport,\r
1366 PciIoDevice->Pci.Hdr.VendorId,\r
1367 PciIoDevice->Pci.Hdr.DeviceId,\r
1368 PciIoDevice->Pci.Hdr.RevisionID,\r
1369 PciIoDevice->Pci.Device.SubsystemVendorID,\r
1370 PciIoDevice->Pci.Device.SubsystemID,\r
1371 &Configuration\r
1372 );\r
9060e3ec 1373\r
1374 }\r
1375\r
1376 if (EFI_ERROR (Status) || Configuration == NULL ) {\r
1377 return EFI_UNSUPPORTED;\r
1378 }\r
1379\r
1380 //\r
1381 // Update PCI device information from the ACPI table\r
1382 //\r
1383 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1384\r
1385 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1386\r
1387 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1388 //\r
1389 // The format is not support\r
1390 //\r
1391 break;\r
1392 }\r
1393\r
063bcff7
RN
1394 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {\r
1395 if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&\r
1396 (Ptr->AddrTranslationOffset != MAX_UINT8) &&\r
1397 (Ptr->AddrTranslationOffset != BarIndex)\r
1398 ) {\r
1399 //\r
1400 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).\r
1401 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.\r
1402 // Comparing against MAX_UINT8 is to keep backward compatibility.\r
1403 //\r
1404 continue;\r
1405 }\r
9060e3ec 1406\r
9060e3ec 1407 SetFlag = FALSE;\r
1408 switch (Ptr->ResType) {\r
1409 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1410\r
1411 //\r
1412 // Make sure the bar is memory type\r
1413 //\r
1414 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {\r
1415 SetFlag = TRUE;\r
05070c1b
RN
1416\r
1417 //\r
1418 // Ignored if granularity is 0.\r
1419 // Ignored if PCI BAR is I/O or 32-bit memory.\r
1420 // If PCI BAR is 64-bit memory and granularity is 32, then\r
1421 // the PCI BAR resource is allocated below 4GB.\r
1422 // If PCI BAR is 64-bit memory and granularity is 64, then\r
1423 // the PCI BAR resource is allocated above 4GB.\r
1424 //\r
1425 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {\r
1426 switch (Ptr->AddrSpaceGranularity) {\r
1427 case 32:\r
1428 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1429 case 64:\r
1430 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1431 break;\r
1432 default:\r
1433 break;\r
1434 }\r
1435 }\r
1436\r
1437 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {\r
1438 switch (Ptr->AddrSpaceGranularity) {\r
1439 case 32:\r
1440 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1441 case 64:\r
1442 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1443 break;\r
1444 default:\r
1445 break;\r
1446 }\r
1447 }\r
9060e3ec 1448 }\r
1449 break;\r
1450\r
1451 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1452\r
1453 //\r
1454 // Make sure the bar is IO type\r
1455 //\r
1456 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
1457 SetFlag = TRUE;\r
1458 }\r
1459 break;\r
1460 }\r
1461\r
1462 if (SetFlag) {\r
1463\r
1464 //\r
1465 // Update the new alignment for the device\r
1466 //\r
1467 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1468\r
1469 //\r
1470 // Update the new length for the device\r
1471 //\r
8a93fa1e 1472 if (Ptr->AddrLen != 0) {\r
9060e3ec 1473 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1474 }\r
1475 }\r
1476 }\r
1477\r
1478 Ptr++;\r
1479 }\r
1480\r
1481 FreePool (Configuration);\r
1482\r
1483 return EFI_SUCCESS;\r
1484}\r
1485\r
1486/**\r
1487 This routine will update the alignment with the new alignment.\r
8a93fa1e
RN
1488 Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep\r
1489 backward compatibility.\r
9060e3ec 1490\r
1491 @param Alignment Input Old alignment. Output updated alignment.\r
1492 @param NewAlignment New alignment.\r
1493\r
1494**/\r
1495VOID\r
1496SetNewAlign (\r
1497 IN OUT UINT64 *Alignment,\r
1498 IN UINT64 NewAlignment\r
1499 )\r
1500{\r
1501 UINT64 OldAlignment;\r
1502 UINTN ShiftBit;\r
1503\r
1504 //\r
1505 // The new alignment is the same as the original,\r
1506 // so skip it\r
1507 //\r
8a93fa1e 1508 if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {\r
9060e3ec 1509 return ;\r
1510 }\r
1511 //\r
1512 // Check the validity of the parameter\r
1513 //\r
8a93fa1e
RN
1514 if (NewAlignment != EVEN_ALIGN &&\r
1515 NewAlignment != SQUAD_ALIGN &&\r
1516 NewAlignment != DQUAD_ALIGN ) {\r
9060e3ec 1517 *Alignment = NewAlignment;\r
1518 return ;\r
1519 }\r
1520\r
1521 OldAlignment = (*Alignment) + 1;\r
1522 ShiftBit = 0;\r
1523\r
1524 //\r
1525 // Get the first non-zero hex value of the length\r
1526 //\r
1527 while ((OldAlignment & 0x0F) == 0x00) {\r
1528 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1529 ShiftBit += 4;\r
1530 }\r
1531\r
1532 //\r
1533 // Adjust the alignment to even, quad or double quad boundary\r
1534 //\r
8a93fa1e 1535 if (NewAlignment == EVEN_ALIGN) {\r
9060e3ec 1536 if ((OldAlignment & 0x01) != 0) {\r
1537 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1538 }\r
8a93fa1e 1539 } else if (NewAlignment == SQUAD_ALIGN) {\r
9060e3ec 1540 if ((OldAlignment & 0x03) != 0) {\r
1541 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1542 }\r
8a93fa1e 1543 } else if (NewAlignment == DQUAD_ALIGN) {\r
9060e3ec 1544 if ((OldAlignment & 0x07) != 0) {\r
1545 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1546 }\r
1547 }\r
1548\r
1549 //\r
1550 // Update the old value\r
1551 //\r
1552 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1553 *Alignment = NewAlignment;\r
1554\r
1555 return ;\r
1556}\r
1557\r
1558/**\r
1559 Parse PCI IOV VF bar information and fill them into PCI device instance.\r
1560\r
1561 @param PciIoDevice Pci device instance.\r
1562 @param Offset Bar offset.\r
1563 @param BarIndex Bar index.\r
1564\r
1565 @return Next bar offset.\r
1566\r
1567**/\r
1568UINTN\r
1569PciIovParseVfBar (\r
1570 IN PCI_IO_DEVICE *PciIoDevice,\r
1571 IN UINTN Offset,\r
1572 IN UINTN BarIndex\r
1573 )\r
1574{\r
1575 UINT32 Value;\r
1576 UINT32 OriginalValue;\r
1577 UINT32 Mask;\r
9060e3ec 1578 EFI_STATUS Status;\r
1579\r
1580 //\r
1581 // Ensure it is called properly\r
1582 //\r
1583 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
1584 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
1585 return 0;\r
1586 }\r
1587\r
1588 OriginalValue = 0;\r
1589 Value = 0;\r
1590\r
1591 Status = VfBarExisted (\r
1592 PciIoDevice,\r
1593 Offset,\r
1594 &Value,\r
1595 &OriginalValue\r
1596 );\r
1597\r
1598 if (EFI_ERROR (Status)) {\r
1599 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1600 PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
1601 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1602\r
1603 //\r
1604 // Scan all the BARs anyway\r
1605 //\r
d4048391 1606 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
9060e3ec 1607 return Offset + 4;\r
1608 }\r
1609\r
d4048391 1610 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
aa75dfec 1611 if ((Value & 0x01) != 0) {\r
9060e3ec 1612 //\r
1613 // Device I/Os. Impossible\r
1614 //\r
1615 ASSERT (FALSE);\r
1616 return Offset + 4;\r
1617\r
1618 } else {\r
1619\r
1620 Mask = 0xfffffff0;\r
1621\r
1622 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1623\r
1624 switch (Value & 0x07) {\r
1625\r
1626 //\r
1627 //memory space; anywhere in 32 bit address space\r
1628 //\r
1629 case 0x00:\r
aa75dfec 1630 if ((Value & 0x08) != 0) {\r
9060e3ec 1631 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
1632 } else {\r
1633 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
1634 }\r
1635\r
1636 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1637 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1638\r
1639 //\r
1640 // Adjust Length\r
1641 //\r
1642 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1643 //\r
1644 // Adjust Alignment\r
1645 //\r
1646 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1647 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1648 }\r
1649\r
1650 break;\r
1651\r
1652 //\r
1653 // memory space; anywhere in 64 bit address space\r
1654 //\r
1655 case 0x04:\r
aa75dfec 1656 if ((Value & 0x08) != 0) {\r
9060e3ec 1657 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
1658 } else {\r
1659 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
1660 }\r
1661\r
1662 //\r
1663 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1664 // is regarded as an extension for the first bar. As a result\r
1665 // the sizing will be conducted on combined 64 bit value\r
1666 // Here just store the masked first 32bit value for future size\r
1667 // calculation\r
1668 //\r
1669 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
1670 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1671\r
1672 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1673 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1674 }\r
1675\r
1676 //\r
1677 // Increment the offset to point to next DWORD\r
1678 //\r
1679 Offset += 4;\r
1680\r
1681 Status = VfBarExisted (\r
1682 PciIoDevice,\r
1683 Offset,\r
1684 &Value,\r
1685 &OriginalValue\r
1686 );\r
1687\r
1688 if (EFI_ERROR (Status)) {\r
1689 return Offset + 4;\r
1690 }\r
1691\r
1692 //\r
fcdfcdbf 1693 // Fix the length to support some special 64 bit BAR\r
9060e3ec 1694 //\r
c0394e04 1695 Value |= ((UINT32) -1 << HighBitSet32 (Value));\r
9060e3ec 1696\r
1697 //\r
1698 // Calculate the size of 64bit bar\r
1699 //\r
1700 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1701\r
1702 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1703 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
1704 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1705\r
1706 //\r
1707 // Adjust Length\r
1708 //\r
1709 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1710 //\r
1711 // Adjust Alignment\r
1712 //\r
1713 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1714 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1715 }\r
1716\r
1717 break;\r
1718\r
1719 //\r
1720 // reserved\r
1721 //\r
1722 default:\r
1723 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1724 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1725 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1726\r
1727 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1728 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1729 }\r
1730\r
1731 break;\r
1732 }\r
1733 }\r
d1102dba 1734\r
9060e3ec 1735 //\r
1736 // Check the length again so as to keep compatible with some special bars\r
1737 //\r
1738 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
1739 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1740 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1741 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1742 }\r
d1102dba 1743\r
9060e3ec 1744 //\r
1745 // Increment number of bar\r
1746 //\r
1747 return Offset + 4;\r
1748}\r
1749\r
1750/**\r
1751 Parse PCI bar information and fill them into PCI device instance.\r
1752\r
1753 @param PciIoDevice Pci device instance.\r
1754 @param Offset Bar offset.\r
1755 @param BarIndex Bar index.\r
1756\r
1757 @return Next bar offset.\r
1758\r
1759**/\r
1760UINTN\r
1761PciParseBar (\r
1762 IN PCI_IO_DEVICE *PciIoDevice,\r
1763 IN UINTN Offset,\r
1764 IN UINTN BarIndex\r
1765 )\r
1766{\r
1767 UINT32 Value;\r
1768 UINT32 OriginalValue;\r
1769 UINT32 Mask;\r
9060e3ec 1770 EFI_STATUS Status;\r
1771\r
1772 OriginalValue = 0;\r
1773 Value = 0;\r
1774\r
1775 Status = BarExisted (\r
1776 PciIoDevice,\r
1777 Offset,\r
1778 &Value,\r
1779 &OriginalValue\r
1780 );\r
1781\r
1782 if (EFI_ERROR (Status)) {\r
1783 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1784 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1785 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1786\r
1787 //\r
1788 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1789 //\r
1790 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1791 return Offset + 4;\r
1792 }\r
1793\r
05070c1b 1794 PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;\r
9060e3ec 1795 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1796 if ((Value & 0x01) != 0) {\r
1797 //\r
1798 // Device I/Os\r
1799 //\r
1800 Mask = 0xfffffffc;\r
1801\r
1802 if ((Value & 0xFFFF0000) != 0) {\r
1803 //\r
1804 // It is a IO32 bar\r
1805 //\r
1806 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1807 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1808 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1809\r
1810 } else {\r
1811 //\r
1812 // It is a IO16 bar\r
1813 //\r
1814 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1815 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1816 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1817\r
1818 }\r
1819 //\r
fcdfcdbf 1820 // Workaround. Some platforms implement IO bar with 0 length\r
9060e3ec 1821 // Need to treat it as no-bar\r
1822 //\r
1823 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1824 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1825 }\r
1826\r
9060e3ec 1827 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1828\r
1829 } else {\r
1830\r
1831 Mask = 0xfffffff0;\r
1832\r
1833 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1834\r
1835 switch (Value & 0x07) {\r
1836\r
1837 //\r
1838 //memory space; anywhere in 32 bit address space\r
1839 //\r
1840 case 0x00:\r
1841 if ((Value & 0x08) != 0) {\r
1842 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1843 } else {\r
1844 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1845 }\r
1846\r
1847 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1848 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1849 //\r
1850 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1851 //\r
1852 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1853 } else {\r
1854 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\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
1867\r
1868 //\r
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
1874 //\r
1875 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1876 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1877\r
1878 //\r
1879 // Increment the offset to point to next DWORD\r
1880 //\r
1881 Offset += 4;\r
1882\r
1883 Status = BarExisted (\r
1884 PciIoDevice,\r
1885 Offset,\r
1886 &Value,\r
1887 &OriginalValue\r
1888 );\r
1889\r
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
5c13180c 1899 return Offset + 4;\r
9060e3ec 1900 }\r
9060e3ec 1901 }\r
1902\r
1903 //\r
fcdfcdbf 1904 // Fix the length to support some special 64 bit BAR\r
9060e3ec 1905 //\r
5c13180c
RN
1906 if (Value == 0) {\r
1907 DEBUG ((EFI_D_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
1913 //\r
1914 // Calculate the size of 64bit bar\r
1915 //\r
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
1921 //\r
1922 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1923 //\r
1924 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1925 } else {\r
1926 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1927 }\r
1928\r
1929 break;\r
1930\r
1931 //\r
1932 // reserved\r
1933 //\r
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
1945 break;\r
1946 }\r
1947 }\r
1948\r
1949 //\r
1950 // Check the length again so as to keep compatible with some special bars\r
1951 //\r
1952 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1953 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1954 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1955 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1956 }\r
1957\r
1958 //\r
1959 // Increment number of bar\r
1960 //\r
1961 return Offset + 4;\r
1962}\r
1963\r
1964/**\r
1965 This routine is used to initialize the bar of a PCI device.\r
1966\r
1967 @param PciIoDevice Pci device instance.\r
1968\r
1969 @note It can be called typically when a device is going to be rejected.\r
1970\r
1971**/\r
1972VOID\r
1973InitializePciDevice (\r
1974 IN PCI_IO_DEVICE *PciIoDevice\r
1975 )\r
1976{\r
1977 EFI_PCI_IO_PROTOCOL *PciIo;\r
1978 UINT8 Offset;\r
1979\r
1980 PciIo = &(PciIoDevice->PciIo);\r
1981\r
1982 //\r
1983 // Put all the resource apertures\r
1984 // Resource base is set to all ones so as to indicate its resource\r
fcdfcdbf 1985 // has not been allocated\r
9060e3ec 1986 //\r
1987 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1988 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1989 }\r
1990}\r
1991\r
1992/**\r
1993 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1994\r
1995 @param PciIoDevice PCI-PCI bridge device instance.\r
1996\r
1997**/\r
1998VOID\r
1999InitializePpb (\r
2000 IN PCI_IO_DEVICE *PciIoDevice\r
2001 )\r
2002{\r
2003 EFI_PCI_IO_PROTOCOL *PciIo;\r
2004\r
2005 PciIo = &(PciIoDevice->PciIo);\r
2006\r
2007 //\r
2008 // Put all the resource apertures including IO16\r
2009 // Io32, pMem32, pMem64 to quiescent state\r
2010 // Resource base all ones, Resource limit all zeros\r
2011 //\r
2012 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
2013 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
2014\r
2015 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
2016 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
2017\r
2018 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
2019 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
2020\r
2021 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
2022 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
2023\r
2024 //\r
2025 // Don't support use io32 as for now\r
2026 //\r
2027 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
2028 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
2029\r
2030 //\r
2031 // Force Interrupt line to zero for cards that come up randomly\r
2032 //\r
2033 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2034}\r
2035\r
2036/**\r
2037 This routine is used to initialize the bar of a PCI Card Bridge device.\r
2038\r
2039 @param PciIoDevice PCI Card bridge device.\r
2040\r
2041**/\r
2042VOID\r
2043InitializeP2C (\r
2044 IN PCI_IO_DEVICE *PciIoDevice\r
2045 )\r
2046{\r
2047 EFI_PCI_IO_PROTOCOL *PciIo;\r
2048\r
2049 PciIo = &(PciIoDevice->PciIo);\r
2050\r
2051 //\r
2052 // Put all the resource apertures including IO16\r
2053 // Io32, pMem32, pMem64 to quiescent state(\r
2054 // Resource base all ones, Resource limit all zeros\r
2055 //\r
2056 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
2057 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
2058\r
2059 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
2060 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
2061\r
2062 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
2063 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
2064\r
2065 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
2066 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
2067\r
2068 //\r
2069 // Force Interrupt line to zero for cards that come up randomly\r
2070 //\r
2071 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2072}\r
2073\r
1e947f9b 2074/**\r
995d8b85
JY
2075 Authenticate the PCI device by using DeviceSecurityProtocol.\r
2076\r
2077 @param PciIoDevice PCI device.\r
2078\r
2079 @retval EFI_SUCCESS The device passes the authentication.\r
2080 @return not EFI_SUCCESS The device failes the authentication or\r
2081 unexpected error happen during authentication.\r
1e947f9b 2082**/\r
995d8b85
JY
2083EFI_STATUS\r
2084AuthenticatePciDevice (\r
2085 IN PCI_IO_DEVICE *PciIoDevice\r
2086 )\r
2087{\r
2088 EDKII_DEVICE_IDENTIFIER DeviceIdentifier;\r
2089 EFI_STATUS Status;\r
2090\r
2091 if (mDeviceSecurityProtocol != NULL) {\r
2092 //\r
2093 // Prepare the parameter\r
2094 //\r
2095 DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;\r
2096 CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid);\r
2097 DeviceIdentifier.DeviceHandle = NULL;\r
2098 Status = gBS->InstallMultipleProtocolInterfaces (\r
2099 &DeviceIdentifier.DeviceHandle,\r
2100 &gEfiDevicePathProtocolGuid,\r
2101 PciIoDevice->DevicePath,\r
2102 &gEdkiiDeviceIdentifierTypePciGuid,\r
2103 &PciIoDevice->PciIo,\r
2104 NULL\r
2105 );\r
2106 if (EFI_ERROR(Status)) {\r
2107 return Status;\r
2108 }\r
2109\r
2110 //\r
2111 // Do DeviceAuthentication\r
2112 //\r
2113 Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier);\r
2114 //\r
2115 // Always uninstall, because they are only for Authentication.\r
2116 // No need to check return Status.\r
2117 //\r
2118 gBS->UninstallMultipleProtocolInterfaces (\r
2119 DeviceIdentifier.DeviceHandle,\r
2120 &gEfiDevicePathProtocolGuid,\r
2121 PciIoDevice->DevicePath,\r
2122 &gEdkiiDeviceIdentifierTypePciGuid,\r
2123 &PciIoDevice->PciIo,\r
2124 NULL\r
2125 );\r
2126 return Status;\r
2127 }\r
2128\r
2129 //\r
2130 // Device Security Protocol is not found, just return success\r
2131 //\r
2132 return EFI_SUCCESS;\r
2133}\r
2134\r
9060e3ec 2135/**\r
fcdfcdbf 2136 Create and initialize general PCI I/O device instance for\r
9060e3ec 2137 PCI device/bridge device/hotplug bridge device.\r
2138\r
fcdfcdbf 2139 @param Bridge Parent bridge instance.\r
9060e3ec 2140 @param Pci Input Pci information block.\r
2141 @param Bus Device Bus NO.\r
2142 @param Device Device device NO.\r
2143 @param Func Device func NO.\r
2144\r
2145 @return Instance of PCI device. NULL means no instance created.\r
2146\r
2147**/\r
2148PCI_IO_DEVICE *\r
2149CreatePciIoDevice (\r
d4048391 2150 IN PCI_IO_DEVICE *Bridge,\r
9060e3ec 2151 IN PCI_TYPE00 *Pci,\r
2152 IN UINT8 Bus,\r
2153 IN UINT8 Device,\r
2154 IN UINT8 Func\r
2155 )\r
2156{\r
d4048391 2157 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 2158 EFI_PCI_IO_PROTOCOL *PciIo;\r
2159 EFI_STATUS Status;\r
2160\r
2161 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
2162 if (PciIoDevice == NULL) {\r
2163 return NULL;\r
2164 }\r
2165\r
2166 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
2167 PciIoDevice->Handle = NULL;\r
d4048391 2168 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
9060e3ec 2169 PciIoDevice->DevicePath = NULL;\r
2170 PciIoDevice->BusNumber = Bus;\r
2171 PciIoDevice->DeviceNumber = Device;\r
2172 PciIoDevice->FunctionNumber = Func;\r
2173 PciIoDevice->Decodes = 0;\r
2174\r
2175 if (gFullEnumeration) {\r
2176 PciIoDevice->Allocated = FALSE;\r
2177 } else {\r
2178 PciIoDevice->Allocated = TRUE;\r
2179 }\r
2180\r
2181 PciIoDevice->Registered = FALSE;\r
2182 PciIoDevice->Attributes = 0;\r
2183 PciIoDevice->Supports = 0;\r
2184 PciIoDevice->BusOverride = FALSE;\r
2185 PciIoDevice->AllOpRomProcessed = FALSE;\r
2186\r
2187 PciIoDevice->IsPciExp = FALSE;\r
2188\r
2189 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
2190\r
2191 //\r
2192 // Initialize the PCI I/O instance structure\r
2193 //\r
2194 InitializePciIoInstance (PciIoDevice);\r
2195 InitializePciDriverOverrideInstance (PciIoDevice);\r
2196 InitializePciLoadFile2 (PciIoDevice);\r
2197 PciIo = &PciIoDevice->PciIo;\r
2198\r
b0bc24af
AW
2199 //\r
2200 // Create a device path for this PCI device and store it into its private data\r
2201 //\r
2202 CreatePciDevicePath (\r
2203 Bridge->DevicePath,\r
2204 PciIoDevice\r
2205 );\r
2206\r
9060e3ec 2207 //\r
2208 // Detect if PCI Express Device\r
2209 //\r
2210 PciIoDevice->PciExpressCapabilityOffset = 0;\r
2211 Status = LocateCapabilityRegBlock (\r
2212 PciIoDevice,\r
2213 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
2214 &PciIoDevice->PciExpressCapabilityOffset,\r
2215 NULL\r
2216 );\r
2217 if (!EFI_ERROR (Status)) {\r
2218 PciIoDevice->IsPciExp = TRUE;\r
2219 }\r
2220\r
995d8b85
JY
2221 //\r
2222 // Now we can do the authentication check for the device.\r
2223 //\r
2224 Status = AuthenticatePciDevice (PciIoDevice);\r
2225 //\r
2226 // If authentication fails, skip this device.\r
2227 //\r
2228 if (EFI_ERROR(Status)) {\r
2229 if (PciIoDevice->DevicePath != NULL) {\r
2230 FreePool (PciIoDevice->DevicePath);\r
2231 }\r
2232 FreePool (PciIoDevice);\r
2233 return NULL;\r
2234 }\r
2235\r
d4048391 2236 if (PcdGetBool (PcdAriSupport)) {\r
2237 //\r
2238 // Check if the device is an ARI device.\r
2239 //\r
2240 Status = LocatePciExpressCapabilityRegBlock (\r
2241 PciIoDevice,\r
2242 EFI_PCIE_CAPABILITY_ID_ARI,\r
2243 &PciIoDevice->AriCapabilityOffset,\r
2244 NULL\r
2245 );\r
2246 if (!EFI_ERROR (Status)) {\r
2247 //\r
2248 // We need to enable ARI feature before calculate BusReservation,\r
2249 // because FirstVFOffset and VFStride may change after that.\r
2250 //\r
2251 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
2252 UINT32 Data32;\r
9060e3ec 2253\r
d4048391 2254 //\r
2255 // Check if its parent supports ARI forwarding.\r
2256 //\r
2257 ParentPciIo = &Bridge->PciIo;\r
2258 ParentPciIo->Pci.Read (\r
d1102dba 2259 ParentPciIo,\r
d4048391 2260 EfiPciIoWidthUint32,\r
2261 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
2262 1,\r
2263 &Data32\r
2264 );\r
2265 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
2266 //\r
2267 // ARI forward support in bridge, so enable it.\r
2268 //\r
2269 ParentPciIo->Pci.Read (\r
2270 ParentPciIo,\r
2271 EfiPciIoWidthUint32,\r
2272 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2273 1,\r
2274 &Data32\r
2275 );\r
2276 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2277 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2278 ParentPciIo->Pci.Write (\r
2279 ParentPciIo,\r
2280 EfiPciIoWidthUint32,\r
2281 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2282 1,\r
2283 &Data32\r
2284 );\r
2285 DEBUG ((\r
2286 EFI_D_INFO,\r
8db6a82c
RN
2287 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",\r
2288 Bridge->BusNumber,\r
2289 Bridge->DeviceNumber,\r
2290 Bridge->FunctionNumber\r
d4048391 2291 ));\r
2292 }\r
2293 }\r
9060e3ec 2294\r
8db6a82c 2295 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));\r
d4048391 2296 }\r
9060e3ec 2297 }\r
2298\r
2299 //\r
d4048391 2300 // Initialization for SR-IOV\r
9060e3ec 2301 //\r
9060e3ec 2302\r
d4048391 2303 if (PcdGetBool (PcdSrIovSupport)) {\r
2304 Status = LocatePciExpressCapabilityRegBlock (\r
2305 PciIoDevice,\r
2306 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2307 &PciIoDevice->SrIovCapabilityOffset,\r
2308 NULL\r
2309 );\r
2310 if (!EFI_ERROR (Status)) {\r
8db6a82c 2311 UINT32 SupportedPageSize;\r
d4048391 2312 UINT16 VFStride;\r
2313 UINT16 FirstVFOffset;\r
2314 UINT16 Data16;\r
2315 UINT32 PFRid;\r
2316 UINT32 LastVF;\r
2317\r
2318 //\r
2319 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2320 //\r
2321 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {\r
2322 PciIo->Pci.Read (\r
2323 PciIo,\r
2324 EfiPciIoWidthUint16,\r
2325 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2326 1,\r
2327 &Data16\r
2328 );\r
2329 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2330 PciIo->Pci.Write (\r
2331 PciIo,\r
2332 EfiPciIoWidthUint16,\r
2333 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2334 1,\r
2335 &Data16\r
2336 );\r
2337 }\r
9060e3ec 2338\r
d4048391 2339 //\r
2340 // Calculate SystemPageSize\r
2341 //\r
9060e3ec 2342\r
d4048391 2343 PciIo->Pci.Read (\r
2344 PciIo,\r
2345 EfiPciIoWidthUint32,\r
2346 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2347 1,\r
8db6a82c 2348 &SupportedPageSize\r
d4048391 2349 );\r
8db6a82c 2350 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);\r
d4048391 2351 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2352\r
2353 PciIo->Pci.Write (\r
2354 PciIo,\r
2355 EfiPciIoWidthUint32,\r
2356 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2357 1,\r
2358 &PciIoDevice->SystemPageSize\r
2359 );\r
d4048391 2360 //\r
2361 // Adjust SystemPageSize for Alignment usage later\r
2362 //\r
2363 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2364\r
d4048391 2365 //\r
2366 // Calculate BusReservation for PCI IOV\r
2367 //\r
9060e3ec 2368\r
d4048391 2369 //\r
2370 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2371 //\r
2372 PciIo->Pci.Read (\r
2373 PciIo,\r
2374 EfiPciIoWidthUint16,\r
2375 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2376 1,\r
2377 &FirstVFOffset\r
2378 );\r
d4048391 2379 PciIo->Pci.Read (\r
2380 PciIo,\r
2381 EfiPciIoWidthUint16,\r
2382 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2383 1,\r
2384 &PciIoDevice->InitialVFs\r
2385 );\r
d4048391 2386 PciIo->Pci.Read (\r
2387 PciIo,\r
2388 EfiPciIoWidthUint16,\r
2389 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2390 1,\r
2391 &VFStride\r
2392 );\r
d4048391 2393 //\r
2394 // Calculate LastVF\r
2395 //\r
2396 PFRid = EFI_PCI_RID(Bus, Device, Func);\r
2397 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2398\r
d4048391 2399 //\r
2400 // Calculate ReservedBusNum for this PF\r
2401 //\r
2402 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
8db6a82c 2403\r
d4048391 2404 DEBUG ((\r
2405 EFI_D_INFO,\r
8db6a82c
RN
2406 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",\r
2407 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset\r
d4048391 2408 ));\r
d4048391 2409 DEBUG ((\r
2410 EFI_D_INFO,\r
8db6a82c
RN
2411 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",\r
2412 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset\r
d4048391 2413 ));\r
2414 }\r
9060e3ec 2415 }\r
2416\r
d4048391 2417 if (PcdGetBool (PcdMrIovSupport)) {\r
2418 Status = LocatePciExpressCapabilityRegBlock (\r
2419 PciIoDevice,\r
2420 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2421 &PciIoDevice->MrIovCapabilityOffset,\r
2422 NULL\r
2423 );\r
2424 if (!EFI_ERROR (Status)) {\r
8db6a82c 2425 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));\r
d4048391 2426 }\r
2427 }\r
9060e3ec 2428\r
2429 //\r
2430 // Initialize the reserved resource list\r
2431 //\r
2432 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2433\r
2434 //\r
2435 // Initialize the driver list\r
2436 //\r
2437 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2438\r
2439 //\r
2440 // Initialize the child list\r
2441 //\r
2442 InitializeListHead (&PciIoDevice->ChildList);\r
2443\r
2444 return PciIoDevice;\r
2445}\r
2446\r
2447/**\r
2448 This routine is used to enumerate entire pci bus system\r
2449 in a given platform.\r
2450\r
2451 It is only called on the second start on the same Root Bridge.\r
2452\r
2453 @param Controller Parent bridge handler.\r
2454\r
2455 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2456 @retval other Some error occurred when enumerating the pci bus system.\r
2457\r
2458**/\r
2459EFI_STATUS\r
2460PciEnumeratorLight (\r
2461 IN EFI_HANDLE Controller\r
2462 )\r
2463{\r
2464\r
2465 EFI_STATUS Status;\r
2466 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2467 PCI_IO_DEVICE *RootBridgeDev;\r
2468 UINT16 MinBus;\r
2469 UINT16 MaxBus;\r
2470 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
2471\r
2472 MinBus = 0;\r
2473 MaxBus = PCI_MAX_BUS;\r
2474 Descriptors = NULL;\r
2475\r
2476 //\r
2477 // If this root bridge has been already enumerated, then return successfully\r
2478 //\r
2479 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2480 return EFI_SUCCESS;\r
2481 }\r
2482\r
2483 //\r
2484 // Open pci root bridge io protocol\r
2485 //\r
2486 Status = gBS->OpenProtocol (\r
2487 Controller,\r
2488 &gEfiPciRootBridgeIoProtocolGuid,\r
2489 (VOID **) &PciRootBridgeIo,\r
2490 gPciBusDriverBinding.DriverBindingHandle,\r
2491 Controller,\r
2492 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2493 );\r
2494 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2495 return Status;\r
2496 }\r
2497\r
2498 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
2499\r
2500 if (EFI_ERROR (Status)) {\r
2501 return Status;\r
2502 }\r
2503\r
2504 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
2505\r
2506 //\r
2507 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2508 //\r
2509 RootBridgeDev = CreateRootBridge (Controller);\r
2510\r
2511 if (RootBridgeDev == NULL) {\r
2512 Descriptors++;\r
2513 continue;\r
2514 }\r
2515\r
2516 //\r
fcdfcdbf 2517 // Record the root bridge-io protocol\r
9060e3ec 2518 //\r
2519 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2520\r
2521 Status = PciPciDeviceInfoCollector (\r
2522 RootBridgeDev,\r
2523 (UINT8) MinBus\r
2524 );\r
2525\r
2526 if (!EFI_ERROR (Status)) {\r
2527\r
2528 //\r
2529 // Remove those PCI devices which are rejected when full enumeration\r
2530 //\r
2531 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2532\r
2533 //\r
2534 // Process option rom light\r
2535 //\r
2536 ProcessOptionRomLight (RootBridgeDev);\r
2537\r
2538 //\r
2539 // Determine attributes for all devices under this root bridge\r
2540 //\r
2541 DetermineDeviceAttribute (RootBridgeDev);\r
2542\r
2543 //\r
2544 // If successfully, insert the node into device pool\r
2545 //\r
2546 InsertRootBridge (RootBridgeDev);\r
2547 } else {\r
2548\r
2549 //\r
fcdfcdbf 2550 // If unsuccessfully, destroy the entire node\r
9060e3ec 2551 //\r
2552 DestroyRootBridge (RootBridgeDev);\r
2553 }\r
2554\r
2555 Descriptors++;\r
2556 }\r
2557\r
2558 return EFI_SUCCESS;\r
2559}\r
2560\r
2561/**\r
2562 Get bus range from PCI resource descriptor list.\r
2563\r
2564 @param Descriptors A pointer to the address space descriptor.\r
2565 @param MinBus The min bus returned.\r
2566 @param MaxBus The max bus returned.\r
2567 @param BusRange The bus range returned.\r
2568\r
2569 @retval EFI_SUCCESS Successfully got bus range.\r
2570 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2571\r
2572**/\r
2573EFI_STATUS\r
2574PciGetBusRange (\r
2575 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2576 OUT UINT16 *MinBus,\r
2577 OUT UINT16 *MaxBus,\r
2578 OUT UINT16 *BusRange\r
2579 )\r
2580{\r
2581 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2582 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2583 if (MinBus != NULL) {\r
2584 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
2585 }\r
2586\r
2587 if (MaxBus != NULL) {\r
2588 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
2589 }\r
2590\r
2591 if (BusRange != NULL) {\r
2592 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
2593 }\r
2594\r
2595 return EFI_SUCCESS;\r
2596 }\r
2597\r
2598 (*Descriptors)++;\r
2599 }\r
2600\r
2601 return EFI_NOT_FOUND;\r
2602}\r
2603\r
2604/**\r
2605 This routine can be used to start the root bridge.\r
2606\r
2607 @param RootBridgeDev Pci device instance.\r
2608\r
2609 @retval EFI_SUCCESS This device started.\r
2610 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2611\r
2612**/\r
2613EFI_STATUS\r
2614StartManagingRootBridge (\r
2615 IN PCI_IO_DEVICE *RootBridgeDev\r
2616 )\r
2617{\r
2618 EFI_HANDLE RootBridgeHandle;\r
2619 EFI_STATUS Status;\r
2620 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2621\r
2622 //\r
2623 // Get the root bridge handle\r
2624 //\r
2625 RootBridgeHandle = RootBridgeDev->Handle;\r
2626 PciRootBridgeIo = NULL;\r
2627\r
2628 //\r
2629 // Get the pci root bridge io protocol\r
2630 //\r
2631 Status = gBS->OpenProtocol (\r
2632 RootBridgeHandle,\r
2633 &gEfiPciRootBridgeIoProtocolGuid,\r
2634 (VOID **) &PciRootBridgeIo,\r
2635 gPciBusDriverBinding.DriverBindingHandle,\r
2636 RootBridgeHandle,\r
2637 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2638 );\r
2639\r
2640 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2641 return Status;\r
2642 }\r
2643\r
2644 //\r
2645 // Store the PciRootBridgeIo protocol into root bridge private data\r
2646 //\r
2647 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2648\r
2649 return EFI_SUCCESS;\r
2650\r
2651}\r
2652\r
2653/**\r
2654 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2655\r
2656 @param PciIoDevice Pci device instance.\r
2657\r
2658 @retval TRUE This device should be rejected.\r
2659 @retval FALSE This device shouldn't be rejected.\r
2660\r
2661**/\r
2662BOOLEAN\r
2663IsPciDeviceRejected (\r
2664 IN PCI_IO_DEVICE *PciIoDevice\r
2665 )\r
2666{\r
2667 EFI_STATUS Status;\r
2668 UINT32 TestValue;\r
2669 UINT32 OldValue;\r
2670 UINT32 Mask;\r
2671 UINT8 BarOffset;\r
2672\r
2673 //\r
2674 // PPB should be skip!\r
2675 //\r
2676 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2677 return FALSE;\r
2678 }\r
2679\r
2680 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2681 //\r
2682 // Only test base registers for P2C\r
2683 //\r
2684 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
2685\r
2686 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2687 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2688 if (EFI_ERROR (Status)) {\r
2689 continue;\r
2690 }\r
2691\r
2692 TestValue = TestValue & Mask;\r
2693 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2694 //\r
2695 // The bar isn't programed, so it should be rejected\r
2696 //\r
2697 return TRUE;\r
2698 }\r
2699 }\r
2700\r
2701 return FALSE;\r
2702 }\r
2703\r
2704 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2705 //\r
2706 // Test PCI devices\r
2707 //\r
2708 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2709 if (EFI_ERROR (Status)) {\r
2710 continue;\r
2711 }\r
2712\r
2713 if ((TestValue & 0x01) != 0) {\r
2714\r
2715 //\r
2716 // IO Bar\r
2717 //\r
2718 Mask = 0xFFFFFFFC;\r
2719 TestValue = TestValue & Mask;\r
2720 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2721 return TRUE;\r
2722 }\r
2723\r
2724 } else {\r
2725\r
2726 //\r
2727 // Mem Bar\r
2728 //\r
2729 Mask = 0xFFFFFFF0;\r
2730 TestValue = TestValue & Mask;\r
2731\r
2732 if ((TestValue & 0x07) == 0x04) {\r
2733\r
2734 //\r
2735 // Mem64 or PMem64\r
2736 //\r
2737 BarOffset += sizeof (UINT32);\r
2738 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2739\r
2740 //\r
2741 // Test its high 32-Bit BAR\r
2742 //\r
2743 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2744 if (TestValue == OldValue) {\r
2745 return TRUE;\r
2746 }\r
2747 }\r
2748\r
2749 } else {\r
2750\r
2751 //\r
2752 // Mem32 or PMem32\r
2753 //\r
2754 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2755 return TRUE;\r
2756 }\r
2757 }\r
2758 }\r
2759 }\r
2760\r
2761 return FALSE;\r
2762}\r
2763\r
2764/**\r
2765 Reset all bus number from specific bridge.\r
2766\r
2767 @param Bridge Parent specific bridge.\r
2768 @param StartBusNumber Start bus number.\r
2769\r
2770**/\r
2771VOID\r
2772ResetAllPpbBusNumber (\r
2773 IN PCI_IO_DEVICE *Bridge,\r
2774 IN UINT8 StartBusNumber\r
2775 )\r
2776{\r
2777 EFI_STATUS Status;\r
2778 PCI_TYPE00 Pci;\r
2779 UINT8 Device;\r
2780 UINT32 Register;\r
2781 UINT8 Func;\r
2782 UINT64 Address;\r
2783 UINT8 SecondaryBus;\r
2784 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2785\r
2786 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2787\r
2788 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2789 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2790\r
2791 //\r
2792 // Check to see whether a pci device is present\r
2793 //\r
2794 Status = PciDevicePresent (\r
2795 PciRootBridgeIo,\r
2796 &Pci,\r
2797 StartBusNumber,\r
2798 Device,\r
2799 Func\r
2800 );\r
2801\r
25a26646
JS
2802 if (EFI_ERROR (Status) && Func == 0) {\r
2803 //\r
2804 // go to next device if there is no Function 0\r
2805 //\r
2806 break;\r
2807 }\r
2808\r
9060e3ec 2809 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
2810\r
2811 Register = 0;\r
2812 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2813 Status = PciRootBridgeIo->Pci.Read (\r
2814 PciRootBridgeIo,\r
2815 EfiPciWidthUint32,\r
2816 Address,\r
2817 1,\r
2818 &Register\r
2819 );\r
2820 SecondaryBus = (UINT8)(Register >> 8);\r
2821\r
2822 if (SecondaryBus != 0) {\r
2823 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2824 }\r
2825\r
2826 //\r
2827 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2828 //\r
2829 Register &= 0xFF000000;\r
2830 Status = PciRootBridgeIo->Pci.Write (\r
2831 PciRootBridgeIo,\r
2832 EfiPciWidthUint32,\r
2833 Address,\r
2834 1,\r
2835 &Register\r
2836 );\r
2837 }\r
2838\r
2839 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2840 //\r
2841 // Skip sub functions, this is not a multi function device\r
2842 //\r
2843 Func = PCI_MAX_FUNC;\r
2844 }\r
2845 }\r
2846 }\r
2847}\r
2848\r