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