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