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