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