Home | History | Annotate | Download | only in PciHostBridgeLib
      1 /** @file
      2   Scan the entire PCI bus for root bridges to support coreboot UEFI payload.
      3 
      4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials are licensed and made available
      7   under the terms and conditions of the BSD License which accompanies this
      8   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, WITHOUT
     12   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <PiDxe.h>
     17 #include <IndustryStandard/Pci.h>
     18 #include <Protocol/PciHostBridgeResourceAllocation.h>
     19 #include <Protocol/PciRootBridgeIo.h>
     20 #include <Library/BaseMemoryLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/MemoryAllocationLib.h>
     23 #include <Library/PciHostBridgeLib.h>
     24 #include <Library/PciLib.h>
     25 #include "PciHostBridge.h"
     26 
     27 /**
     28   Adjust the collected PCI resource.
     29 
     30   @param[in]  Io               IO aperture.
     31 
     32   @param[in]  Mem              MMIO aperture.
     33 
     34   @param[in]  MemAbove4G       MMIO aperture above 4G.
     35 
     36   @param[in]  PMem             Prefetchable MMIO aperture.
     37 
     38   @param[in]  PMemAbove4G      Prefetchable MMIO aperture above 4G.
     39 **/
     40 VOID
     41 AdjustRootBridgeResource (
     42   IN  PCI_ROOT_BRIDGE_APERTURE *Io,
     43   IN  PCI_ROOT_BRIDGE_APERTURE *Mem,
     44   IN  PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
     45   IN  PCI_ROOT_BRIDGE_APERTURE *PMem,
     46   IN  PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G
     47 )
     48 {
     49   UINT64  Mask;
     50 
     51   //
     52   // For now try to downgrade everything into MEM32 since
     53   // - coreboot does not assign resource above 4GB
     54   // - coreboot might allocate interleaved MEM32 and PMEM32 resource
     55   //   in some cases
     56   //
     57   if (PMem->Base < Mem->Base) {
     58     Mem->Base = PMem->Base;
     59   }
     60 
     61   if (PMem->Limit > Mem->Limit) {
     62     Mem->Limit = PMem->Limit;
     63   }
     64 
     65   PMem->Base  = MAX_UINT64;
     66   PMem->Limit = 0;
     67 
     68   if (MemAbove4G->Base < 0x100000000ULL) {
     69     if (MemAbove4G->Base < Mem->Base) {
     70       Mem->Base  = MemAbove4G->Base;
     71     }
     72     if (MemAbove4G->Limit > Mem->Limit) {
     73       Mem->Limit = MemAbove4G->Limit;
     74     }
     75     MemAbove4G->Base  = MAX_UINT64;
     76     MemAbove4G->Limit = 0;
     77   }
     78 
     79   if (PMemAbove4G->Base < 0x100000000ULL) {
     80     if (PMemAbove4G->Base < Mem->Base) {
     81       Mem->Base  = PMemAbove4G->Base;
     82     }
     83     if (PMemAbove4G->Limit > Mem->Limit) {
     84       Mem->Limit = PMemAbove4G->Limit;
     85     }
     86     PMemAbove4G->Base  = MAX_UINT64;
     87     PMemAbove4G->Limit = 0;
     88   }
     89 
     90   //
     91   // Align IO  resource at 4K  boundary
     92   //
     93   Mask        = 0xFFFULL;
     94   Io->Limit   = ((Io->Limit + Mask) & ~Mask) - 1;
     95   if (Io->Base != MAX_UINT64) {
     96     Io->Base &= ~Mask;
     97   }
     98 
     99   //
    100   // Align MEM resource at 1MB boundary
    101   //
    102   Mask        = 0xFFFFFULL;
    103   Mem->Limit  = ((Mem->Limit + Mask) & ~Mask) - 1;
    104   if (Mem->Base != MAX_UINT64) {
    105     Mem->Base &= ~Mask;
    106   }
    107 }
    108 
    109 /**
    110   Probe a bar is existed or not.
    111 
    112   @param[in]    Address           PCI address for the BAR.
    113   @param[out]   OriginalValue     The original bar value returned.
    114   @param[out]   Value             The probed bar value returned.
    115 **/
    116 STATIC
    117 VOID
    118 PcatPciRootBridgeBarExisted (
    119   IN  UINT64                         Address,
    120   OUT UINT32                         *OriginalValue,
    121   OUT UINT32                         *Value
    122 )
    123 {
    124   UINTN   PciAddress;
    125 
    126   PciAddress = (UINTN)Address;
    127 
    128   //
    129   // Preserve the original value
    130   //
    131   *OriginalValue = PciRead32 (PciAddress);
    132 
    133   //
    134   // Disable timer interrupt while the BAR is probed
    135   //
    136   DisableInterrupts ();
    137 
    138   PciWrite32 (PciAddress, 0xFFFFFFFF);
    139   *Value = PciRead32 (PciAddress);
    140   PciWrite32 (PciAddress, *OriginalValue);
    141 
    142   //
    143   // Enable interrupt
    144   //
    145   EnableInterrupts ();
    146 }
    147 
    148 /**
    149   Parse PCI bar and collect the assigned PCI resouce information.
    150 
    151   @param[in]  Command          Supported attributes.
    152 
    153   @param[in]  Bus              PCI bus number.
    154 
    155   @param[in]  Device           PCI device number.
    156 
    157   @param[in]  Function         PCI function number.
    158 
    159   @param[in]  BarOffsetBase    PCI bar start offset.
    160 
    161   @param[in]  BarOffsetEnd     PCI bar end offset.
    162 
    163   @param[in]  Io               IO aperture.
    164 
    165   @param[in]  Mem              MMIO aperture.
    166 
    167   @param[in]  MemAbove4G       MMIO aperture above 4G.
    168 
    169   @param[in]  PMem             Prefetchable MMIO aperture.
    170 
    171   @param[in]  PMemAbove4G      Prefetchable MMIO aperture above 4G.
    172 **/
    173 STATIC
    174 VOID
    175 PcatPciRootBridgeParseBars (
    176   IN UINT16                         Command,
    177   IN UINTN                          Bus,
    178   IN UINTN                          Device,
    179   IN UINTN                          Function,
    180   IN UINTN                          BarOffsetBase,
    181   IN UINTN                          BarOffsetEnd,
    182   IN PCI_ROOT_BRIDGE_APERTURE       *Io,
    183   IN PCI_ROOT_BRIDGE_APERTURE       *Mem,
    184   IN PCI_ROOT_BRIDGE_APERTURE       *MemAbove4G,
    185   IN PCI_ROOT_BRIDGE_APERTURE       *PMem,
    186   IN PCI_ROOT_BRIDGE_APERTURE       *PMemAbove4G
    187 
    188 )
    189 {
    190   UINT32                            OriginalValue;
    191   UINT32                            Value;
    192   UINT32                            OriginalUpperValue;
    193   UINT32                            UpperValue;
    194   UINT64                            Mask;
    195   UINTN                             Offset;
    196   UINTN                             LowBit;
    197   UINT64                            Base;
    198   UINT64                            Length;
    199   UINT64                            Limit;
    200   PCI_ROOT_BRIDGE_APERTURE          *MemAperture;
    201 
    202   for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) {
    203     PcatPciRootBridgeBarExisted (
    204       PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
    205       &OriginalValue, &Value
    206     );
    207     if (Value == 0) {
    208       continue;
    209     }
    210     if ((Value & BIT0) == BIT0) {
    211       //
    212       // IO Bar
    213       //
    214       if (Command & EFI_PCI_COMMAND_IO_SPACE) {
    215         Mask = 0xfffffffc;
    216         Base = OriginalValue & Mask;
    217         Length = ((~(Value & Mask)) & Mask) + 0x04;
    218         if (!(Value & 0xFFFF0000)) {
    219           Length &= 0x0000FFFF;
    220         }
    221         Limit = Base + Length - 1;
    222 
    223         if ((Base > 0) && (Base < Limit)) {
    224           if (Io->Base > Base) {
    225             Io->Base = Base;
    226           }
    227           if (Io->Limit < Limit) {
    228             Io->Limit = Limit;
    229           }
    230         }
    231       }
    232     } else {
    233       //
    234       // Mem Bar
    235       //
    236       if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {
    237 
    238         Mask = 0xfffffff0;
    239         Base = OriginalValue & Mask;
    240         Length = Value & Mask;
    241 
    242         if ((Value & (BIT1 | BIT2)) == 0) {
    243           //
    244           // 32bit
    245           //
    246           Length = ((~Length) + 1) & 0xffffffff;
    247 
    248           if ((Value & BIT3) == BIT3) {
    249             MemAperture = PMem;
    250           } else {
    251             MemAperture = Mem;
    252           }
    253         } else {
    254           //
    255           // 64bit
    256           //
    257           Offset += 4;
    258           PcatPciRootBridgeBarExisted (
    259             PCI_LIB_ADDRESS (Bus, Device, Function, Offset),
    260             &OriginalUpperValue,
    261             &UpperValue
    262           );
    263 
    264           Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32);
    265           Length = Length | LShiftU64 ((UINT64) UpperValue, 32);
    266           if (Length != 0) {
    267             LowBit = LowBitSet64 (Length);
    268             Length = LShiftU64 (1ULL, LowBit);
    269           }
    270 
    271           if ((Value & BIT3) == BIT3) {
    272             MemAperture = PMemAbove4G;
    273           } else {
    274             MemAperture = MemAbove4G;
    275           }
    276         }
    277 
    278         Limit = Base + Length - 1;
    279         if ((Base > 0) && (Base < Limit)) {
    280           if (MemAperture->Base > Base) {
    281             MemAperture->Base = Base;
    282           }
    283           if (MemAperture->Limit < Limit) {
    284             MemAperture->Limit = Limit;
    285           }
    286         }
    287       }
    288     }
    289   }
    290 }
    291 
    292 /**
    293   Scan for all root bridges in platform.
    294 
    295   @param[out] NumberOfRootBridges  Number of root bridges detected
    296 
    297   @retval     Pointer to the allocated PCI_ROOT_BRIDGE structure array.
    298 **/
    299 PCI_ROOT_BRIDGE *
    300 ScanForRootBridges (
    301   OUT UINTN      *NumberOfRootBridges
    302 )
    303 {
    304   UINTN      PrimaryBus;
    305   UINTN      SubBus;
    306   UINT8      Device;
    307   UINT8      Function;
    308   UINTN      NumberOfDevices;
    309   UINTN      Address;
    310   PCI_TYPE01 Pci;
    311   UINT64     Attributes;
    312   UINT64     Base;
    313   UINT64     Limit;
    314   UINT64     Value;
    315   PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture;
    316   PCI_ROOT_BRIDGE *RootBridges;
    317   UINTN      BarOffsetEnd;
    318 
    319 
    320   *NumberOfRootBridges = 0;
    321   RootBridges = NULL;
    322 
    323   //
    324   // After scanning all the PCI devices on the PCI root bridge's primary bus,
    325   // update the Primary Bus Number for the next PCI root bridge to be this PCI
    326   // root bridge's subordinate bus number + 1.
    327   //
    328   for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) {
    329     SubBus = PrimaryBus;
    330     Attributes = 0;
    331     Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64;
    332     Io.Limit = Mem.Limit = MemAbove4G.Limit = PMem.Limit = PMemAbove4G.Limit = 0;
    333     //
    334     // Scan all the PCI devices on the primary bus of the PCI root bridge
    335     //
    336     for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {
    337 
    338       for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
    339 
    340         //
    341         // Compute the PCI configuration address of the PCI device to probe
    342         //
    343         Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0);
    344 
    345         //
    346         // Read the Vendor ID from the PCI Configuration Header
    347         //
    348         if (PciRead16 (Address) == MAX_UINT16) {
    349           if (Function == 0) {
    350             //
    351             // If the PCI Configuration Read fails, or a PCI device does not
    352             // exist, then skip this entire PCI device
    353             //
    354             break;
    355           } else {
    356             //
    357             // If PCI function != 0, VendorId == 0xFFFF, we continue to search
    358             // PCI function.
    359             //
    360             continue;
    361           }
    362         }
    363 
    364         //
    365         // Read the entire PCI Configuration Header
    366         //
    367         PciReadBuffer (Address, sizeof (Pci), &Pci);
    368 
    369         //
    370         // Increment the number of PCI device found on the primary bus of the
    371         // PCI root bridge
    372         //
    373         NumberOfDevices++;
    374 
    375         //
    376         // Look for devices with the VGA Palette Snoop enabled in the COMMAND
    377         // register of the PCI Config Header
    378         //
    379         if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
    380           Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
    381           Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
    382         }
    383 
    384         BarOffsetEnd = 0;
    385 
    386         //
    387         // PCI-PCI Bridge
    388         //
    389         if (IS_PCI_BRIDGE (&Pci)) {
    390           //
    391           // Get the Bus range that the PPB is decoding
    392           //
    393           if (Pci.Bridge.SubordinateBus > SubBus) {
    394             //
    395             // If the suborinate bus number of the PCI-PCI bridge is greater
    396             // than the PCI root bridge's current subordinate bus number,
    397             // then update the PCI root bridge's subordinate bus number
    398             //
    399             SubBus = Pci.Bridge.SubordinateBus;
    400           }
    401 
    402           //
    403           // Get the I/O range that the PPB is decoding
    404           //
    405           Value = Pci.Bridge.IoBase & 0x0f;
    406           Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8;
    407           Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff;
    408           if (Value == BIT0) {
    409             Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16);
    410             Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16);
    411           }
    412           if ((Base > 0) && (Base < Limit)) {
    413             if (Io.Base > Base) {
    414               Io.Base = Base;
    415             }
    416             if (Io.Limit < Limit) {
    417               Io.Limit = Limit;
    418             }
    419           }
    420 
    421           //
    422           // Get the Memory range that the PPB is decoding
    423           //
    424           Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16;
    425           Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
    426           if ((Base > 0) && (Base < Limit)) {
    427             if (Mem.Base > Base) {
    428               Mem.Base = Base;
    429             }
    430             if (Mem.Limit < Limit) {
    431               Mem.Limit = Limit;
    432             }
    433           }
    434 
    435           //
    436           // Get the Prefetchable Memory range that the PPB is decoding
    437           //
    438           Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f;
    439           Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16;
    440           Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0)
    441                    << 16) | 0xfffff;
    442           MemAperture = &PMem;
    443           if (Value == BIT0) {
    444             Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32);
    445             Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32);
    446             MemAperture = &PMemAbove4G;
    447           }
    448           if ((Base > 0) && (Base < Limit)) {
    449             if (MemAperture->Base > Base) {
    450               MemAperture->Base = Base;
    451             }
    452             if (MemAperture->Limit < Limit) {
    453               MemAperture->Limit = Limit;
    454             }
    455           }
    456 
    457           //
    458           // Look at the PPB Configuration for legacy decoding attributes
    459           //
    460           if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA)
    461               == EFI_PCI_BRIDGE_CONTROL_ISA) {
    462             Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
    463             Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
    464             Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
    465           }
    466           if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA)
    467               == EFI_PCI_BRIDGE_CONTROL_VGA) {
    468             Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
    469             Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
    470             Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
    471             if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16)
    472                 != 0) {
    473               Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
    474               Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
    475             }
    476           }
    477 
    478           BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]);
    479         } else {
    480           //
    481           // Parse the BARs of the PCI device to get what I/O Ranges, Memory
    482           // Ranges, and Prefetchable Memory Ranges the device is decoding
    483           //
    484           if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
    485             BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]);
    486           }
    487         }
    488 
    489         PcatPciRootBridgeParseBars (
    490           Pci.Hdr.Command,
    491           PrimaryBus,
    492           Device,
    493           Function,
    494           OFFSET_OF (PCI_TYPE00, Device.Bar),
    495           BarOffsetEnd,
    496           &Io,
    497           &Mem, &MemAbove4G,
    498           &PMem, &PMemAbove4G
    499         );
    500 
    501         //
    502         // See if the PCI device is an IDE controller
    503         //
    504         if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE,
    505                        PCI_CLASS_MASS_STORAGE_IDE)) {
    506           if (Pci.Hdr.ClassCode[0] & 0x80) {
    507             Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
    508             Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
    509           }
    510           if (Pci.Hdr.ClassCode[0] & 0x01) {
    511             Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
    512           }
    513           if (Pci.Hdr.ClassCode[0] & 0x04) {
    514             Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
    515           }
    516         }
    517 
    518         //
    519         // See if the PCI device is a legacy VGA controller or
    520         // a standard VGA controller
    521         //
    522         if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) ||
    523             IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA)
    524            ) {
    525           Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
    526           Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
    527           Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
    528           Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
    529           Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16;
    530         }
    531 
    532         //
    533         // See if the PCI Device is a PCI - ISA or PCI - EISA
    534         // or ISA_POSITIVIE_DECODE Bridge device
    535         //
    536         if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
    537           if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA ||
    538               Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA ||
    539               Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) {
    540             Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
    541             Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16;
    542             Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
    543           }
    544         }
    545 
    546         //
    547         // If this device is not a multi function device, then skip the rest
    548         // of this PCI device
    549         //
    550         if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
    551           break;
    552         }
    553       }
    554     }
    555 
    556     //
    557     // If at least one PCI device was found on the primary bus of this PCI
    558     // root bridge, then the PCI root bridge exists.
    559     //
    560     if (NumberOfDevices > 0) {
    561       RootBridges = ReallocatePool (
    562                       (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE),
    563                       (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE),
    564                       RootBridges
    565                     );
    566       ASSERT (RootBridges != NULL);
    567 
    568       AdjustRootBridgeResource (&Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G);
    569 
    570       InitRootBridge (
    571         Attributes, Attributes, 0,
    572         (UINT8) PrimaryBus, (UINT8) SubBus,
    573         &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G,
    574         &RootBridges[*NumberOfRootBridges]
    575       );
    576       RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE;
    577       //
    578       // Increment the index for the next PCI Root Bridge
    579       //
    580       (*NumberOfRootBridges)++;
    581     }
    582   }
    583 
    584   return RootBridges;
    585 }
    586