Home | History | Annotate | Download | only in PciBusDxe
      1 /** @file
      2   EFI PCI IO protocol functions implementation for PCI Bus module.
      3 
      4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PciBus.h"
     16 
     17 //
     18 // Pci Io Protocol Interface
     19 //
     20 EFI_PCI_IO_PROTOCOL  mPciIoInterface = {
     21   PciIoPollMem,
     22   PciIoPollIo,
     23   {
     24     PciIoMemRead,
     25     PciIoMemWrite
     26   },
     27   {
     28     PciIoIoRead,
     29     PciIoIoWrite
     30   },
     31   {
     32     PciIoConfigRead,
     33     PciIoConfigWrite
     34   },
     35   PciIoCopyMem,
     36   PciIoMap,
     37   PciIoUnmap,
     38   PciIoAllocateBuffer,
     39   PciIoFreeBuffer,
     40   PciIoFlush,
     41   PciIoGetLocation,
     42   PciIoAttributes,
     43   PciIoGetBarAttributes,
     44   PciIoSetBarAttributes,
     45   0,
     46   NULL
     47 };
     48 
     49 /**
     50   Initializes a PCI I/O Instance.
     51 
     52   @param PciIoDevice    Pci device instance.
     53 
     54 **/
     55 VOID
     56 InitializePciIoInstance (
     57   IN PCI_IO_DEVICE               *PciIoDevice
     58   )
     59 {
     60   CopyMem (&PciIoDevice->PciIo, &mPciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));
     61 }
     62 
     63 /**
     64   Verifies access to a PCI Base Address Register (BAR).
     65 
     66   @param PciIoDevice  Pci device instance.
     67   @param BarIndex     The BAR index of the standard PCI Configuration header to use as the
     68                       base address for the memory or I/O operation to perform.
     69   @param Type         Operation type could be memory or I/O.
     70   @param Width        Signifies the width of the memory or I/O operations.
     71   @param Count        The number of memory or I/O operations to perform.
     72   @param Offset       The offset within the PCI configuration space for the PCI controller.
     73 
     74   @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
     75   @retval EFI_SUCCESS           Successfully verified.
     76 
     77 **/
     78 EFI_STATUS
     79 PciIoVerifyBarAccess (
     80   IN PCI_IO_DEVICE                   *PciIoDevice,
     81   IN UINT8                           BarIndex,
     82   IN PCI_BAR_TYPE                    Type,
     83   IN IN EFI_PCI_IO_PROTOCOL_WIDTH    Width,
     84   IN IN UINTN                        Count,
     85   IN UINT64                          *Offset
     86   )
     87 {
     88   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
     89     return EFI_INVALID_PARAMETER;
     90   }
     91 
     92   if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
     93     return EFI_SUCCESS;
     94   }
     95 
     96   //
     97   // BarIndex 0-5 is legal
     98   //
     99   if (BarIndex >= PCI_MAX_BAR) {
    100     return EFI_INVALID_PARAMETER;
    101   }
    102 
    103   if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
    104     return EFI_INVALID_PARAMETER;
    105   }
    106 
    107   //
    108   // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
    109   // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
    110   //
    111   if (Width >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) {
    112     Count = 1;
    113   }
    114 
    115   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
    116 
    117   if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {
    118     return EFI_INVALID_PARAMETER;
    119   }
    120 
    121   *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;
    122 
    123   return EFI_SUCCESS;
    124 }
    125 
    126 /**
    127   Verifies access to a PCI Configuration Header.
    128 
    129   @param PciIoDevice  Pci device instance.
    130   @param Width        Signifies the width of the memory or I/O operations.
    131   @param Count        The number of memory or I/O operations to perform.
    132   @param Offset       The offset within the PCI configuration space for the PCI controller.
    133 
    134   @retval EFI_INVALID_PARAMETER  Invalid Width
    135   @retval EFI_UNSUPPORTED        Offset overflowed.
    136   @retval EFI_SUCCESS            Successfully verified.
    137 
    138 **/
    139 EFI_STATUS
    140 PciIoVerifyConfigAccess (
    141   IN PCI_IO_DEVICE              *PciIoDevice,
    142   IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    143   IN UINTN                      Count,
    144   IN UINT64                     *Offset
    145   )
    146 {
    147   UINT64  ExtendOffset;
    148 
    149   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    150     return EFI_INVALID_PARAMETER;
    151   }
    152 
    153   //
    154   // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
    155   //
    156   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
    157 
    158   if (PciIoDevice->IsPciExp) {
    159     if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {
    160       return EFI_UNSUPPORTED;
    161     }
    162 
    163     ExtendOffset  = LShiftU64 (*Offset, 32);
    164     *Offset       = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
    165     *Offset       = (*Offset) | ExtendOffset;
    166 
    167   } else {
    168     if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {
    169       return EFI_UNSUPPORTED;
    170     }
    171 
    172     *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
    173   }
    174 
    175   return EFI_SUCCESS;
    176 }
    177 
    178 /**
    179   Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
    180   satisfied or after a defined duration.
    181 
    182   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    183   @param  Width                 Signifies the width of the memory or I/O operations.
    184   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    185                                 base address for the memory operation to perform.
    186   @param  Offset                The offset within the selected BAR to start the memory operation.
    187   @param  Mask                  Mask used for the polling criteria.
    188   @param  Value                 The comparison value used for the polling exit criteria.
    189   @param  Delay                 The number of 100 ns units to poll.
    190   @param  Result                Pointer to the last value read from the memory location.
    191 
    192   @retval EFI_SUCCESS           The last data returned from the access matched the poll exit criteria.
    193   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    194   @retval EFI_UNSUPPORTED       Offset is not valid for the BarIndex of this PCI controller.
    195   @retval EFI_TIMEOUT           Delay expired before a match occurred.
    196   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    197   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    198 
    199 **/
    200 EFI_STATUS
    201 EFIAPI
    202 PciIoPollMem (
    203   IN  EFI_PCI_IO_PROTOCOL        *This,
    204   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    205   IN  UINT8                      BarIndex,
    206   IN  UINT64                     Offset,
    207   IN  UINT64                     Mask,
    208   IN  UINT64                     Value,
    209   IN  UINT64                     Delay,
    210   OUT UINT64                     *Result
    211   )
    212 {
    213   EFI_STATUS    Status;
    214   PCI_IO_DEVICE *PciIoDevice;
    215 
    216   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    217 
    218   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    219     return EFI_INVALID_PARAMETER;
    220   }
    221 
    222   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);
    223   if (EFI_ERROR (Status)) {
    224     return EFI_UNSUPPORTED;
    225   }
    226 
    227   if (Width > EfiPciIoWidthUint64) {
    228     return EFI_INVALID_PARAMETER;
    229   }
    230 
    231   //
    232   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    233   //
    234   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    235     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    236       Status  = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
    237       if (EFI_ERROR (Status)) {
    238         return Status;
    239       }
    240       if ((*Result & Mask) == Value || Delay == 0) {
    241         return EFI_SUCCESS;
    242       }
    243       do {
    244         //
    245         // Stall 10 us = 100 * 100ns
    246         //
    247         gBS->Stall (10);
    248 
    249         Status  = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
    250         if (EFI_ERROR (Status)) {
    251           return Status;
    252         }
    253         if ((*Result & Mask) == Value) {
    254           return EFI_SUCCESS;
    255         }
    256         if (Delay <= 100) {
    257           return EFI_TIMEOUT;
    258         }
    259         Delay -= 100;
    260       } while (TRUE);
    261     }
    262   }
    263 
    264   Status = PciIoDevice->PciRootBridgeIo->PollMem (
    265                                            PciIoDevice->PciRootBridgeIo,
    266                                            (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    267                                            Offset,
    268                                            Mask,
    269                                            Value,
    270                                            Delay,
    271                                            Result
    272                                            );
    273 
    274   if (EFI_ERROR (Status)) {
    275     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    276       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    277       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
    278       PciIoDevice->DevicePath
    279       );
    280   }
    281 
    282   return Status;
    283 }
    284 
    285 /**
    286   Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
    287   satisfied or after a defined duration.
    288 
    289   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    290   @param  Width                 Signifies the width of the memory or I/O operations.
    291   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    292                                 base address for the memory operation to perform.
    293   @param  Offset                The offset within the selected BAR to start the memory operation.
    294   @param  Mask                  Mask used for the polling criteria.
    295   @param  Value                 The comparison value used for the polling exit criteria.
    296   @param  Delay                 The number of 100 ns units to poll.
    297   @param  Result                Pointer to the last value read from the memory location.
    298 
    299   @retval EFI_SUCCESS           The last data returned from the access matched the poll exit criteria.
    300   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    301   @retval EFI_UNSUPPORTED       Offset is not valid for the BarIndex of this PCI controller.
    302   @retval EFI_TIMEOUT           Delay expired before a match occurred.
    303   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    304   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    305 
    306 **/
    307 EFI_STATUS
    308 EFIAPI
    309 PciIoPollIo (
    310   IN  EFI_PCI_IO_PROTOCOL        *This,
    311   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    312   IN  UINT8                      BarIndex,
    313   IN  UINT64                     Offset,
    314   IN  UINT64                     Mask,
    315   IN  UINT64                     Value,
    316   IN  UINT64                     Delay,
    317   OUT UINT64                     *Result
    318   )
    319 {
    320   EFI_STATUS    Status;
    321   PCI_IO_DEVICE *PciIoDevice;
    322 
    323   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    324 
    325   if ((UINT32)Width > EfiPciIoWidthUint64) {
    326     return EFI_INVALID_PARAMETER;
    327   }
    328 
    329   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);
    330   if (EFI_ERROR (Status)) {
    331     return EFI_UNSUPPORTED;
    332   }
    333 
    334   //
    335   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    336   //
    337   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    338     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    339       Status  = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
    340       if (EFI_ERROR (Status)) {
    341         return Status;
    342       }
    343       if ((*Result & Mask) == Value || Delay == 0) {
    344         return EFI_SUCCESS;
    345       }
    346       do {
    347         //
    348         // Stall 10 us = 100 * 100ns
    349         //
    350         gBS->Stall (10);
    351 
    352         Status  = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
    353         if (EFI_ERROR (Status)) {
    354           return Status;
    355         }
    356         if ((*Result & Mask) == Value) {
    357           return EFI_SUCCESS;
    358         }
    359         if (Delay <= 100) {
    360           return EFI_TIMEOUT;
    361         }
    362         Delay -= 100;
    363       } while (TRUE);
    364     }
    365   }
    366 
    367   Status = PciIoDevice->PciRootBridgeIo->PollIo (
    368                                            PciIoDevice->PciRootBridgeIo,
    369                                            (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    370                                            Offset,
    371                                            Mask,
    372                                            Value,
    373                                            Delay,
    374                                            Result
    375                                            );
    376 
    377   if (EFI_ERROR (Status)) {
    378     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    379       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    380       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
    381       PciIoDevice->DevicePath
    382       );
    383   }
    384 
    385   return Status;
    386 }
    387 
    388 /**
    389   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    390 
    391   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    392   @param  Width                 Signifies the width of the memory or I/O operations.
    393   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    394                                 base address for the memory or I/O operation to perform.
    395   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    396   @param  Count                 The number of memory or I/O operations to perform.
    397   @param  Buffer                For read operations, the destination buffer to store the results. For write
    398                                 operations, the source buffer to write data from.
    399 
    400   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    401   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    402   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    403                                 valid for the PCI BAR specified by BarIndex.
    404   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    405   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    406 
    407 **/
    408 EFI_STATUS
    409 EFIAPI
    410 PciIoMemRead (
    411   IN     EFI_PCI_IO_PROTOCOL        *This,
    412   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    413   IN     UINT8                      BarIndex,
    414   IN     UINT64                     Offset,
    415   IN     UINTN                      Count,
    416   IN OUT VOID                       *Buffer
    417   )
    418 {
    419   EFI_STATUS    Status;
    420   PCI_IO_DEVICE *PciIoDevice;
    421 
    422   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    423 
    424   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    425     return EFI_INVALID_PARAMETER;
    426   }
    427 
    428   if (Buffer == NULL) {
    429     return EFI_INVALID_PARAMETER;
    430   }
    431 
    432   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
    433   if (EFI_ERROR (Status)) {
    434     return EFI_UNSUPPORTED;
    435   }
    436 
    437   //
    438   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    439   //
    440   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    441     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    442       Count *=  (UINTN)(1 << (Width & 0x03));
    443       Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
    444     }
    445   }
    446 
    447 
    448   Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
    449                                               PciIoDevice->PciRootBridgeIo,
    450                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    451                                               Offset,
    452                                               Count,
    453                                               Buffer
    454                                               );
    455 
    456   if (EFI_ERROR (Status)) {
    457     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    458       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    459       EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
    460       PciIoDevice->DevicePath
    461       );
    462   }
    463 
    464   return Status;
    465 }
    466 
    467 /**
    468   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    469 
    470   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    471   @param  Width                 Signifies the width of the memory or I/O operations.
    472   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    473                                 base address for the memory or I/O operation to perform.
    474   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    475   @param  Count                 The number of memory or I/O operations to perform.
    476   @param  Buffer                For read operations, the destination buffer to store the results. For write
    477                                 operations, the source buffer to write data from.
    478 
    479   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    480   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    481   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    482                                 valid for the PCI BAR specified by BarIndex.
    483   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    484   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    485 
    486 **/
    487 EFI_STATUS
    488 EFIAPI
    489 PciIoMemWrite (
    490   IN     EFI_PCI_IO_PROTOCOL        *This,
    491   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    492   IN     UINT8                      BarIndex,
    493   IN     UINT64                     Offset,
    494   IN     UINTN                      Count,
    495   IN OUT VOID                       *Buffer
    496   )
    497 {
    498   EFI_STATUS    Status;
    499   PCI_IO_DEVICE *PciIoDevice;
    500 
    501   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    502 
    503   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    504     return EFI_INVALID_PARAMETER;
    505   }
    506 
    507   if (Buffer == NULL) {
    508     return EFI_INVALID_PARAMETER;
    509   }
    510 
    511   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
    512   if (EFI_ERROR (Status)) {
    513     return EFI_UNSUPPORTED;
    514   }
    515 
    516   //
    517   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    518   //
    519   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    520     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    521       Count *=  (UINTN)(1 << (Width & 0x03));
    522       Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
    523     }
    524   }
    525 
    526   Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
    527                                               PciIoDevice->PciRootBridgeIo,
    528                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    529                                               Offset,
    530                                               Count,
    531                                               Buffer
    532                                               );
    533 
    534   if (EFI_ERROR (Status)) {
    535     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    536       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    537       EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
    538       PciIoDevice->DevicePath
    539       );
    540   }
    541 
    542   return Status;
    543 }
    544 
    545 /**
    546   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    547 
    548   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    549   @param  Width                 Signifies the width of the memory or I/O operations.
    550   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    551                                 base address for the memory or I/O operation to perform.
    552   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    553   @param  Count                 The number of memory or I/O operations to perform.
    554   @param  Buffer                For read operations, the destination buffer to store the results. For write
    555                                 operations, the source buffer to write data from.
    556 
    557   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    558   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    559   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    560                                 valid for the PCI BAR specified by BarIndex.
    561   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    562   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    563 
    564 **/
    565 EFI_STATUS
    566 EFIAPI
    567 PciIoIoRead (
    568   IN     EFI_PCI_IO_PROTOCOL        *This,
    569   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    570   IN     UINT8                      BarIndex,
    571   IN     UINT64                     Offset,
    572   IN     UINTN                      Count,
    573   IN OUT VOID                       *Buffer
    574   )
    575 {
    576   EFI_STATUS    Status;
    577   PCI_IO_DEVICE *PciIoDevice;
    578 
    579   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    580 
    581   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    582     return EFI_INVALID_PARAMETER;
    583   }
    584 
    585   if (Buffer == NULL) {
    586     return EFI_INVALID_PARAMETER;
    587   }
    588 
    589   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
    590   if (EFI_ERROR (Status)) {
    591     return EFI_UNSUPPORTED;
    592   }
    593 
    594   //
    595   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    596   //
    597   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    598     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    599       Count *=  (UINTN)(1 << (Width & 0x03));
    600       Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
    601     }
    602   }
    603 
    604   Status = PciIoDevice->PciRootBridgeIo->Io.Read (
    605                                               PciIoDevice->PciRootBridgeIo,
    606                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    607                                               Offset,
    608                                               Count,
    609                                               Buffer
    610                                               );
    611 
    612   if (EFI_ERROR (Status)) {
    613     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    614       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    615       EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
    616       PciIoDevice->DevicePath
    617       );
    618   }
    619 
    620   return Status;
    621 }
    622 
    623 /**
    624   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    625 
    626   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    627   @param  Width                 Signifies the width of the memory or I/O operations.
    628   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    629                                 base address for the memory or I/O operation to perform.
    630   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    631   @param  Count                 The number of memory or I/O operations to perform.
    632   @param  Buffer                For read operations, the destination buffer to store the results. For write
    633                                 operations, the source buffer to write data from.
    634 
    635   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    636   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    637   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    638                                 valid for the PCI BAR specified by BarIndex.
    639   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    640   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    641 
    642 **/
    643 EFI_STATUS
    644 EFIAPI
    645 PciIoIoWrite (
    646   IN     EFI_PCI_IO_PROTOCOL        *This,
    647   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    648   IN     UINT8                      BarIndex,
    649   IN     UINT64                     Offset,
    650   IN     UINTN                      Count,
    651   IN OUT VOID                       *Buffer
    652   )
    653 {
    654   EFI_STATUS    Status;
    655   PCI_IO_DEVICE *PciIoDevice;
    656 
    657   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    658 
    659   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    660     return EFI_INVALID_PARAMETER;
    661   }
    662 
    663   if (Buffer == NULL) {
    664     return EFI_INVALID_PARAMETER;
    665   }
    666 
    667   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
    668   if (EFI_ERROR (Status)) {
    669     return EFI_UNSUPPORTED;
    670   }
    671 
    672   //
    673   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    674   //
    675   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    676     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    677       Count *=  (UINTN)(1 << (Width & 0x03));
    678       Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
    679     }
    680   }
    681 
    682   Status = PciIoDevice->PciRootBridgeIo->Io.Write (
    683                                               PciIoDevice->PciRootBridgeIo,
    684                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    685                                               Offset,
    686                                               Count,
    687                                               Buffer
    688                                               );
    689 
    690   if (EFI_ERROR (Status)) {
    691     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    692       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    693       EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
    694       PciIoDevice->DevicePath
    695       );
    696   }
    697 
    698   return Status;
    699 }
    700 
    701 /**
    702   Enable a PCI driver to access PCI controller registers in PCI configuration space.
    703 
    704   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    705   @param  Width                 Signifies the width of the memory operations.
    706   @param  Offset                The offset within the PCI configuration space for the PCI controller.
    707   @param  Count                 The number of PCI configuration operations to perform.
    708   @param  Buffer                For read operations, the destination buffer to store the results. For write
    709                                 operations, the source buffer to write data from.
    710 
    711 
    712   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    713   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    714                                 valid for the PCI configuration header of the PCI controller.
    715   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    716   @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
    717 
    718 **/
    719 EFI_STATUS
    720 EFIAPI
    721 PciIoConfigRead (
    722   IN     EFI_PCI_IO_PROTOCOL        *This,
    723   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    724   IN     UINT32                     Offset,
    725   IN     UINTN                      Count,
    726   IN OUT VOID                       *Buffer
    727   )
    728 {
    729   EFI_STATUS    Status;
    730   PCI_IO_DEVICE *PciIoDevice;
    731   UINT64        Address;
    732 
    733   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    734 
    735   Address     = Offset;
    736   Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
    737   if (EFI_ERROR (Status)) {
    738     return Status;
    739   }
    740 
    741   //
    742   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    743   //
    744   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    745     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    746       Count *=  (UINTN)(1 << (Width & 0x03));
    747       Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
    748     }
    749   }
    750 
    751   Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
    752                                                PciIoDevice->PciRootBridgeIo,
    753                                                (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    754                                                Address,
    755                                                Count,
    756                                                Buffer
    757                                                );
    758 
    759   if (EFI_ERROR (Status)) {
    760     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    761       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    762       EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
    763       PciIoDevice->DevicePath
    764       );
    765   }
    766 
    767   return Status;
    768 }
    769 
    770 /**
    771   Enable a PCI driver to access PCI controller registers in PCI configuration space.
    772 
    773   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    774   @param  Width                 Signifies the width of the memory operations.
    775   @param  Offset                The offset within the PCI configuration space for the PCI controller.
    776   @param  Count                 The number of PCI configuration operations to perform.
    777   @param  Buffer                For read operations, the destination buffer to store the results. For write
    778                                 operations, the source buffer to write data from.
    779 
    780 
    781   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    782   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    783                                 valid for the PCI configuration header of the PCI controller.
    784   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    785   @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
    786 
    787 **/
    788 EFI_STATUS
    789 EFIAPI
    790 PciIoConfigWrite (
    791   IN     EFI_PCI_IO_PROTOCOL        *This,
    792   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    793   IN     UINT32                     Offset,
    794   IN     UINTN                      Count,
    795   IN OUT VOID                       *Buffer
    796   )
    797 {
    798   EFI_STATUS    Status;
    799   PCI_IO_DEVICE *PciIoDevice;
    800   UINT64        Address;
    801 
    802   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    803 
    804   Address     = Offset;
    805   Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
    806   if (EFI_ERROR (Status)) {
    807     return Status;
    808   }
    809 
    810   //
    811   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    812   //
    813   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    814     if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
    815       Count *=  (UINTN)(1 << (Width & 0x03));
    816       Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
    817     }
    818   }
    819 
    820   Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
    821                                               PciIoDevice->PciRootBridgeIo,
    822                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    823                                               Address,
    824                                               Count,
    825                                               Buffer
    826                                               );
    827 
    828   if (EFI_ERROR (Status)) {
    829     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    830       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    831       EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
    832       PciIoDevice->DevicePath
    833       );
    834   }
    835 
    836   return Status;
    837 }
    838 
    839 /**
    840   Enables a PCI driver to copy one region of PCI memory space to another region of PCI
    841   memory space.
    842 
    843   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    844   @param  Width                 Signifies the width of the memory operations.
    845   @param  DestBarIndex          The BAR index in the standard PCI Configuration header to use as the
    846                                 base address for the memory operation to perform.
    847   @param  DestOffset            The destination offset within the BAR specified by DestBarIndex to
    848                                 start the memory writes for the copy operation.
    849   @param  SrcBarIndex           The BAR index in the standard PCI Configuration header to use as the
    850                                 base address for the memory operation to perform.
    851   @param  SrcOffset             The source offset within the BAR specified by SrcBarIndex to start
    852                                 the memory reads for the copy operation.
    853   @param  Count                 The number of memory operations to perform. Bytes moved is Width
    854                                 size * Count, starting at DestOffset and SrcOffset.
    855 
    856   @retval EFI_SUCCESS           The data was copied from one memory region to another memory region.
    857   @retval EFI_UNSUPPORTED       DestBarIndex not valid for this PCI controller.
    858   @retval EFI_UNSUPPORTED       SrcBarIndex not valid for this PCI controller.
    859   @retval EFI_UNSUPPORTED       The address range specified by DestOffset, Width, and Count
    860                                 is not valid for the PCI BAR specified by DestBarIndex.
    861   @retval EFI_UNSUPPORTED       The address range specified by SrcOffset, Width, and Count is
    862                                 not valid for the PCI BAR specified by SrcBarIndex.
    863   @retval EFI_INVALID_PARAMETER Width is invalid.
    864   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    865 
    866 **/
    867 EFI_STATUS
    868 EFIAPI
    869 PciIoCopyMem (
    870   IN EFI_PCI_IO_PROTOCOL              *This,
    871   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    872   IN     UINT8                        DestBarIndex,
    873   IN     UINT64                       DestOffset,
    874   IN     UINT8                        SrcBarIndex,
    875   IN     UINT64                       SrcOffset,
    876   IN     UINTN                        Count
    877   )
    878 {
    879   EFI_STATUS    Status;
    880   PCI_IO_DEVICE *PciIoDevice;
    881 
    882   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    883 
    884   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    885     return EFI_INVALID_PARAMETER;
    886   }
    887 
    888   if (Width == EfiPciIoWidthFifoUint8  ||
    889       Width == EfiPciIoWidthFifoUint16 ||
    890       Width == EfiPciIoWidthFifoUint32 ||
    891       Width == EfiPciIoWidthFifoUint64 ||
    892       Width == EfiPciIoWidthFillUint8  ||
    893       Width == EfiPciIoWidthFillUint16 ||
    894       Width == EfiPciIoWidthFillUint32 ||
    895       Width == EfiPciIoWidthFillUint64) {
    896     return EFI_INVALID_PARAMETER;
    897   }
    898 
    899   Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);
    900   if (EFI_ERROR (Status)) {
    901     return EFI_UNSUPPORTED;
    902   }
    903 
    904   Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);
    905   if (EFI_ERROR (Status)) {
    906     return EFI_UNSUPPORTED;
    907   }
    908 
    909   //
    910   // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
    911   //
    912   if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
    913     if ((SrcOffset & ((1 << (Width & 0x03)) - 1)) != 0 || (DestOffset & ((1 << (Width & 0x03)) - 1)) != 0) {
    914       Count *=  (UINTN)(1 << (Width & 0x03));
    915       Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
    916     }
    917   }
    918 
    919   Status = PciIoDevice->PciRootBridgeIo->CopyMem (
    920                                           PciIoDevice->PciRootBridgeIo,
    921                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
    922                                           DestOffset,
    923                                           SrcOffset,
    924                                           Count
    925                                           );
    926 
    927   if (EFI_ERROR (Status)) {
    928     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    929       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    930       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
    931       PciIoDevice->DevicePath
    932       );
    933   }
    934 
    935   return Status;
    936 }
    937 
    938 /**
    939   Provides the PCI controller-specific addresses needed to access system memory.
    940 
    941   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    942   @param  Operation             Indicates if the bus master is going to read or write to system memory.
    943   @param  HostAddress           The system memory address to map to the PCI controller.
    944   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
    945                                 that were mapped.
    946   @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
    947                                 access the hosts HostAddress.
    948   @param  Mapping               A resulting value to pass to Unmap().
    949 
    950   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
    951   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
    952   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    953   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    954   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
    955 
    956 **/
    957 EFI_STATUS
    958 EFIAPI
    959 PciIoMap (
    960   IN     EFI_PCI_IO_PROTOCOL            *This,
    961   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
    962   IN     VOID                           *HostAddress,
    963   IN OUT UINTN                          *NumberOfBytes,
    964   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
    965   OUT    VOID                           **Mapping
    966   )
    967 {
    968   EFI_STATUS    Status;
    969   PCI_IO_DEVICE *PciIoDevice;
    970 
    971   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
    972 
    973   if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
    974     return EFI_INVALID_PARAMETER;
    975   }
    976 
    977   if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
    978     return EFI_INVALID_PARAMETER;
    979   }
    980 
    981   if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
    982     Operation = (EFI_PCI_IO_PROTOCOL_OPERATION) (Operation + EfiPciOperationBusMasterRead64);
    983   }
    984 
    985   Status = PciIoDevice->PciRootBridgeIo->Map (
    986                                           PciIoDevice->PciRootBridgeIo,
    987                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,
    988                                           HostAddress,
    989                                           NumberOfBytes,
    990                                           DeviceAddress,
    991                                           Mapping
    992                                           );
    993 
    994   if (EFI_ERROR (Status)) {
    995     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    996       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    997       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
    998       PciIoDevice->DevicePath
    999       );
   1000   }
   1001 
   1002   return Status;
   1003 }
   1004 
   1005 /**
   1006   Completes the Map() operation and releases any corresponding resources.
   1007 
   1008   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1009   @param  Mapping               The mapping value returned from Map().
   1010 
   1011   @retval EFI_SUCCESS           The range was unmapped.
   1012   @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
   1013 
   1014 **/
   1015 EFI_STATUS
   1016 EFIAPI
   1017 PciIoUnmap (
   1018   IN  EFI_PCI_IO_PROTOCOL  *This,
   1019   IN  VOID                 *Mapping
   1020   )
   1021 {
   1022   EFI_STATUS    Status;
   1023   PCI_IO_DEVICE *PciIoDevice;
   1024 
   1025   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1026 
   1027   Status = PciIoDevice->PciRootBridgeIo->Unmap (
   1028                                           PciIoDevice->PciRootBridgeIo,
   1029                                           Mapping
   1030                                           );
   1031 
   1032   if (EFI_ERROR (Status)) {
   1033     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1034       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1035       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
   1036       PciIoDevice->DevicePath
   1037       );
   1038   }
   1039 
   1040   return Status;
   1041 }
   1042 
   1043 /**
   1044   Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
   1045   mapping.
   1046 
   1047   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1048   @param  Type                  This parameter is not used and must be ignored.
   1049   @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
   1050                                 EfiRuntimeServicesData.
   1051   @param  Pages                 The number of pages to allocate.
   1052   @param  HostAddress           A pointer to store the base system memory address of the
   1053                                 allocated range.
   1054   @param  Attributes            The requested bit mask of attributes for the allocated range.
   1055 
   1056   @retval EFI_SUCCESS           The requested memory pages were allocated.
   1057   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
   1058                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
   1059   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1060   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
   1061 
   1062 **/
   1063 EFI_STATUS
   1064 EFIAPI
   1065 PciIoAllocateBuffer (
   1066   IN  EFI_PCI_IO_PROTOCOL   *This,
   1067   IN  EFI_ALLOCATE_TYPE     Type,
   1068   IN  EFI_MEMORY_TYPE       MemoryType,
   1069   IN  UINTN                 Pages,
   1070   OUT VOID                  **HostAddress,
   1071   IN  UINT64                Attributes
   1072   )
   1073 {
   1074   EFI_STATUS    Status;
   1075   PCI_IO_DEVICE *PciIoDevice;
   1076 
   1077   if ((Attributes &
   1078       (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) != 0){
   1079     return EFI_UNSUPPORTED;
   1080   }
   1081 
   1082   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1083 
   1084   if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
   1085     Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
   1086   }
   1087 
   1088   Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
   1089                                           PciIoDevice->PciRootBridgeIo,
   1090                                           Type,
   1091                                           MemoryType,
   1092                                           Pages,
   1093                                           HostAddress,
   1094                                           Attributes
   1095                                           );
   1096 
   1097   if (EFI_ERROR (Status)) {
   1098     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1099       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1100       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
   1101       PciIoDevice->DevicePath
   1102       );
   1103   }
   1104 
   1105   return Status;
   1106 }
   1107 
   1108 /**
   1109   Frees memory that was allocated with AllocateBuffer().
   1110 
   1111   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1112   @param  Pages                 The number of pages to free.
   1113   @param  HostAddress           The base system memory address of the allocated range.
   1114 
   1115   @retval EFI_SUCCESS           The requested memory pages were freed.
   1116   @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
   1117                                 was not allocated with AllocateBuffer().
   1118 
   1119 **/
   1120 EFI_STATUS
   1121 EFIAPI
   1122 PciIoFreeBuffer (
   1123   IN  EFI_PCI_IO_PROTOCOL   *This,
   1124   IN  UINTN                 Pages,
   1125   IN  VOID                  *HostAddress
   1126   )
   1127 {
   1128   EFI_STATUS    Status;
   1129   PCI_IO_DEVICE *PciIoDevice;
   1130 
   1131   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1132 
   1133   Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
   1134                                           PciIoDevice->PciRootBridgeIo,
   1135                                           Pages,
   1136                                           HostAddress
   1137                                           );
   1138 
   1139   if (EFI_ERROR (Status)) {
   1140     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1141       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1142       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
   1143       PciIoDevice->DevicePath
   1144       );
   1145   }
   1146 
   1147   return Status;
   1148 }
   1149 
   1150 /**
   1151   Flushes all PCI posted write transactions from a PCI host bridge to system memory.
   1152 
   1153   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1154 
   1155   @retval EFI_SUCCESS           The PCI posted write transactions were flushed from the PCI host
   1156                                 bridge to system memory.
   1157   @retval EFI_DEVICE_ERROR      The PCI posted write transactions were not flushed from the PCI
   1158                                 host bridge due to a hardware error.
   1159 
   1160 **/
   1161 EFI_STATUS
   1162 EFIAPI
   1163 PciIoFlush (
   1164   IN  EFI_PCI_IO_PROTOCOL  *This
   1165   )
   1166 {
   1167   EFI_STATUS    Status;
   1168   PCI_IO_DEVICE *PciIoDevice;
   1169 
   1170   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1171 
   1172   Status = PciIoDevice->PciRootBridgeIo->Flush (
   1173                                            PciIoDevice->PciRootBridgeIo
   1174                                            );
   1175   if (EFI_ERROR (Status)) {
   1176     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1177       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1178       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
   1179       PciIoDevice->DevicePath
   1180       );
   1181   }
   1182 
   1183   return Status;
   1184 }
   1185 
   1186 /**
   1187   Retrieves this PCI controller's current PCI bus number, device number, and function number.
   1188 
   1189   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1190   @param  SegmentNumber         The PCI controller's current PCI segment number.
   1191   @param  BusNumber             The PCI controller's current PCI bus number.
   1192   @param  DeviceNumber          The PCI controller's current PCI device number.
   1193   @param  FunctionNumber        The PCI controller's current PCI function number.
   1194 
   1195   @retval EFI_SUCCESS           The PCI controller location was returned.
   1196   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1197 
   1198 **/
   1199 EFI_STATUS
   1200 EFIAPI
   1201 PciIoGetLocation (
   1202   IN  EFI_PCI_IO_PROTOCOL  *This,
   1203   OUT UINTN                *Segment,
   1204   OUT UINTN                *Bus,
   1205   OUT UINTN                *Device,
   1206   OUT UINTN                *Function
   1207   )
   1208 {
   1209   PCI_IO_DEVICE *PciIoDevice;
   1210 
   1211   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1212 
   1213   if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {
   1214     return EFI_INVALID_PARAMETER;
   1215   }
   1216 
   1217   *Segment  = PciIoDevice->PciRootBridgeIo->SegmentNumber;
   1218   *Bus      = PciIoDevice->BusNumber;
   1219   *Device   = PciIoDevice->DeviceNumber;
   1220   *Function = PciIoDevice->FunctionNumber;
   1221 
   1222   return EFI_SUCCESS;
   1223 }
   1224 
   1225 /**
   1226   Check BAR type for PCI resource.
   1227 
   1228   @param PciIoDevice   PCI device instance.
   1229   @param BarIndex      The BAR index of the standard PCI Configuration header to use as the
   1230                        base address for the memory or I/O operation to perform.
   1231   @param BarType       Memory or I/O.
   1232 
   1233   @retval TRUE         Pci device's bar type is same with input BarType.
   1234   @retval TRUE         Pci device's bar type is not same with input BarType.
   1235 
   1236 **/
   1237 BOOLEAN
   1238 CheckBarType (
   1239   IN PCI_IO_DEVICE          *PciIoDevice,
   1240   IN UINT8                  BarIndex,
   1241   IN PCI_BAR_TYPE           BarType
   1242   )
   1243 {
   1244   switch (BarType) {
   1245 
   1246   case PciBarTypeMem:
   1247 
   1248     if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32  &&
   1249         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
   1250         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
   1251         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64    ) {
   1252       return FALSE;
   1253     }
   1254 
   1255     return TRUE;
   1256 
   1257   case PciBarTypeIo:
   1258     if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
   1259         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
   1260       return FALSE;
   1261     }
   1262 
   1263     return TRUE;
   1264 
   1265   default:
   1266     break;
   1267   }
   1268 
   1269   return FALSE;
   1270 }
   1271 
   1272 /**
   1273   Set/Disable new attributes to a Root Bridge.
   1274 
   1275   @param  PciIoDevice  Pci device instance.
   1276   @param  Attributes   New attribute want to be set.
   1277   @param  Operation    Set or Disable.
   1278 
   1279   @retval  EFI_UNSUPPORTED  If root bridge does not support change attribute.
   1280   @retval  EFI_SUCCESS      Successfully set new attributs.
   1281 
   1282 **/
   1283 EFI_STATUS
   1284 ModifyRootBridgeAttributes (
   1285   IN  PCI_IO_DEVICE                            *PciIoDevice,
   1286   IN  UINT64                                   Attributes,
   1287   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
   1288   )
   1289 {
   1290   UINT64      PciRootBridgeSupports;
   1291   UINT64      PciRootBridgeAttributes;
   1292   UINT64      NewPciRootBridgeAttributes;
   1293   EFI_STATUS  Status;
   1294 
   1295   //
   1296   // Get the current attributes of this PCI device's PCI Root Bridge
   1297   //
   1298   Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
   1299                                           PciIoDevice->PciRootBridgeIo,
   1300                                           &PciRootBridgeSupports,
   1301                                           &PciRootBridgeAttributes
   1302                                           );
   1303   if (EFI_ERROR (Status)) {
   1304     return EFI_UNSUPPORTED;
   1305   }
   1306 
   1307   //
   1308   // Mask off attributes not supported by PCI root bridge.
   1309   //
   1310   Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
   1311                           EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
   1312                           EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
   1313 
   1314   //
   1315   // Record the new attribute of the Root Bridge
   1316   //
   1317   if (Operation == EfiPciIoAttributeOperationEnable) {
   1318     NewPciRootBridgeAttributes = PciRootBridgeAttributes | Attributes;
   1319   } else {
   1320     NewPciRootBridgeAttributes = PciRootBridgeAttributes & (~Attributes);
   1321   }
   1322 
   1323   //
   1324   // Call the PCI Root Bridge to attempt to modify the attributes
   1325   //
   1326   if ((NewPciRootBridgeAttributes ^ PciRootBridgeAttributes) != 0) {
   1327 
   1328     Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
   1329                                             PciIoDevice->PciRootBridgeIo,
   1330                                             NewPciRootBridgeAttributes,
   1331                                             NULL,
   1332                                             NULL
   1333                                             );
   1334     if (EFI_ERROR (Status)) {
   1335       //
   1336       // The PCI Root Bridge could not modify the attributes, so return the error.
   1337       //
   1338       return EFI_UNSUPPORTED;
   1339     }
   1340   }
   1341 
   1342   //
   1343   // Also update the attributes for this Root Bridge structure
   1344   //
   1345   PciIoDevice->Attributes = NewPciRootBridgeAttributes;
   1346 
   1347   return EFI_SUCCESS;
   1348 }
   1349 
   1350 /**
   1351   Check whether this device can be enable/disable to snoop.
   1352 
   1353   @param PciIoDevice  Pci device instance.
   1354   @param Operation    Enable/Disable.
   1355 
   1356   @retval EFI_UNSUPPORTED  Pci device is not GFX device or not support snoop.
   1357   @retval EFI_SUCCESS      Snoop can be supported.
   1358 
   1359 **/
   1360 EFI_STATUS
   1361 SupportPaletteSnoopAttributes (
   1362   IN PCI_IO_DEVICE                            *PciIoDevice,
   1363   IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
   1364   )
   1365 {
   1366   PCI_IO_DEVICE *Temp;
   1367   UINT16        VGACommand;
   1368 
   1369   //
   1370   // Snoop attribute can be only modified by GFX
   1371   //
   1372   if (!IS_PCI_GFX (&PciIoDevice->Pci)) {
   1373     return EFI_UNSUPPORTED;
   1374   }
   1375 
   1376   //
   1377   // Get the boot VGA on the same segement
   1378   //
   1379   Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
   1380 
   1381   if (Temp == NULL) {
   1382     //
   1383     // If there is no VGA device on the segement, set
   1384     // this graphics card to decode the palette range
   1385     //
   1386     return EFI_SUCCESS;
   1387   }
   1388 
   1389   //
   1390   // Check these two agents are on the same path
   1391   //
   1392   if (!PciDevicesOnTheSamePath (Temp, PciIoDevice)) {
   1393     //
   1394     // they are not on the same path, so snoop can be enabled or disabled
   1395     //
   1396     return EFI_SUCCESS;
   1397   }
   1398   //
   1399   // Check if they are on the same bus
   1400   //
   1401   if (Temp->Parent == PciIoDevice->Parent) {
   1402 
   1403     PCI_READ_COMMAND_REGISTER (Temp, &VGACommand);
   1404 
   1405     //
   1406     // If they are on the same bus, either one can
   1407     // be set to snoop, the other set to decode
   1408     //
   1409     if ((VGACommand & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
   1410       //
   1411       // VGA has set to snoop, so GFX can be only set to disable snoop
   1412       //
   1413       if (Operation == EfiPciIoAttributeOperationEnable) {
   1414         return EFI_UNSUPPORTED;
   1415       }
   1416     } else {
   1417       //
   1418       // VGA has disabled to snoop, so GFX can be only enabled
   1419       //
   1420       if (Operation == EfiPciIoAttributeOperationDisable) {
   1421         return EFI_UNSUPPORTED;
   1422       }
   1423     }
   1424 
   1425     return EFI_SUCCESS;
   1426   }
   1427 
   1428   //
   1429   // If they are on  the same path but on the different bus
   1430   // The first agent is set to snoop, the second one set to
   1431   // decode
   1432   //
   1433 
   1434   if (Temp->BusNumber < PciIoDevice->BusNumber) {
   1435     //
   1436     // GFX should be set to decode
   1437     //
   1438     if (Operation == EfiPciIoAttributeOperationDisable) {
   1439       PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
   1440       Temp->Attributes |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
   1441     } else {
   1442       return EFI_UNSUPPORTED;
   1443     }
   1444 
   1445   } else {
   1446     //
   1447     // GFX should be set to snoop
   1448     //
   1449     if (Operation == EfiPciIoAttributeOperationEnable) {
   1450       PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
   1451       Temp->Attributes &= (~(UINT64)EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
   1452     } else {
   1453       return EFI_UNSUPPORTED;
   1454     }
   1455 
   1456   }
   1457 
   1458   return EFI_SUCCESS;
   1459 }
   1460 
   1461 /**
   1462   Performs an operation on the attributes that this PCI controller supports. The operations include
   1463   getting the set of supported attributes, retrieving the current attributes, setting the current
   1464   attributes, enabling attributes, and disabling attributes.
   1465 
   1466   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1467   @param  Operation             The operation to perform on the attributes for this PCI controller.
   1468   @param  Attributes            The mask of attributes that are used for Set, Enable, and Disable
   1469                                 operations.
   1470   @param  Result                A pointer to the result mask of attributes that are returned for the Get
   1471                                 and Supported operations.
   1472 
   1473   @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.
   1474   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1475   @retval EFI_UNSUPPORTED       one or more of the bits set in
   1476                                 Attributes are not supported by this PCI controller or one of
   1477                                 its parent bridges when Operation is Set, Enable or Disable.
   1478 
   1479 **/
   1480 EFI_STATUS
   1481 EFIAPI
   1482 PciIoAttributes (
   1483   IN EFI_PCI_IO_PROTOCOL                       * This,
   1484   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
   1485   IN  UINT64                                   Attributes,
   1486   OUT UINT64                                   *Result OPTIONAL
   1487   )
   1488 {
   1489   EFI_STATUS    Status;
   1490 
   1491   PCI_IO_DEVICE *PciIoDevice;
   1492   PCI_IO_DEVICE *UpStreamBridge;
   1493   PCI_IO_DEVICE *Temp;
   1494 
   1495   UINT64        Supports;
   1496   UINT64        UpStreamAttributes;
   1497   UINT16        BridgeControl;
   1498   UINT16        Command;
   1499 
   1500   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1501 
   1502   switch (Operation) {
   1503   case EfiPciIoAttributeOperationGet:
   1504     if (Result == NULL) {
   1505       return EFI_INVALID_PARAMETER;
   1506     }
   1507 
   1508     *Result = PciIoDevice->Attributes;
   1509     return EFI_SUCCESS;
   1510 
   1511   case EfiPciIoAttributeOperationSupported:
   1512     if (Result == NULL) {
   1513       return EFI_INVALID_PARAMETER;
   1514     }
   1515 
   1516     *Result = PciIoDevice->Supports;
   1517     return EFI_SUCCESS;
   1518 
   1519   case EfiPciIoAttributeOperationSet:
   1520     Status = PciIoDevice->PciIo.Attributes (
   1521                                   &(PciIoDevice->PciIo),
   1522                                   EfiPciIoAttributeOperationEnable,
   1523                                   Attributes,
   1524                                   NULL
   1525                                   );
   1526     if (EFI_ERROR (Status)) {
   1527       return EFI_UNSUPPORTED;
   1528     }
   1529 
   1530     Status = PciIoDevice->PciIo.Attributes (
   1531                                   &(PciIoDevice->PciIo),
   1532                                   EfiPciIoAttributeOperationDisable,
   1533                                   (~Attributes) & (PciIoDevice->Supports),
   1534                                   NULL
   1535                                   );
   1536     if (EFI_ERROR (Status)) {
   1537       return EFI_UNSUPPORTED;
   1538     }
   1539 
   1540     return EFI_SUCCESS;
   1541 
   1542   case EfiPciIoAttributeOperationEnable:
   1543   case EfiPciIoAttributeOperationDisable:
   1544     break;
   1545 
   1546   default:
   1547     return EFI_INVALID_PARAMETER;
   1548   }
   1549   //
   1550   // Just a trick for ENABLE attribute
   1551   // EFI_PCI_DEVICE_ENABLE is not defined in UEFI spec, which is the internal usage.
   1552   // So, this logic doesn't confrom to UEFI spec, which should be removed.
   1553   // But this trick logic is still kept for some binary drivers that depend on it.
   1554   //
   1555   if ((Attributes & EFI_PCI_DEVICE_ENABLE) == EFI_PCI_DEVICE_ENABLE) {
   1556     Attributes &= (PciIoDevice->Supports);
   1557 
   1558     //
   1559     // Raise the EFI_P_PC_ENABLE Status code
   1560     //
   1561     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1562       EFI_PROGRESS_CODE,
   1563       EFI_IO_BUS_PCI | EFI_P_PC_ENABLE,
   1564       PciIoDevice->DevicePath
   1565       );
   1566   }
   1567 
   1568   //
   1569   // Check VGA and VGA16, they can not be set at the same time
   1570   //
   1571   if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) != 0) {
   1572     if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
   1573       return EFI_UNSUPPORTED;
   1574     }
   1575   }
   1576 
   1577   //
   1578   // If no attributes can be supported, then return.
   1579   // Otherwise, set the attributes that it can support.
   1580   //
   1581   Supports = (PciIoDevice->Supports) & Attributes;
   1582   if (Supports != Attributes) {
   1583     return EFI_UNSUPPORTED;
   1584   }
   1585 
   1586   //
   1587   // For Root Bridge, just call RootBridgeIo to set attributes;
   1588   //
   1589   if (PciIoDevice->Parent == NULL) {
   1590     Status = ModifyRootBridgeAttributes (PciIoDevice, Attributes, Operation);
   1591     return Status;
   1592   }
   1593 
   1594   Command       = 0;
   1595   BridgeControl = 0;
   1596 
   1597   //
   1598   // For PPB & P2C, set relevant attribute bits
   1599   //
   1600   if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
   1601 
   1602     if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
   1603       BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA;
   1604     }
   1605 
   1606     if ((Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) != 0) {
   1607       BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA;
   1608     }
   1609 
   1610     if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
   1611       Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
   1612     }
   1613 
   1614     if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
   1615       BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA_16;
   1616     }
   1617 
   1618   } else {
   1619     //
   1620     // Do with the attributes on VGA
   1621     // Only for VGA's legacy resource, we just can enable once.
   1622     //
   1623     if ((Attributes &
   1624         (EFI_PCI_IO_ATTRIBUTE_VGA_IO    |
   1625          EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |
   1626          EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY)) != 0) {
   1627       //
   1628       // Check if a VGA has been enabled before enabling a new one
   1629       //
   1630       if (Operation == EfiPciIoAttributeOperationEnable) {
   1631         //
   1632         // Check if there have been an active VGA device on the same segment
   1633         //
   1634         Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
   1635         if (Temp != NULL && Temp != PciIoDevice) {
   1636           //
   1637           // An active VGA has been detected, so can not enable another
   1638           //
   1639           return EFI_UNSUPPORTED;
   1640         }
   1641       }
   1642     }
   1643 
   1644     //
   1645     // Do with the attributes on GFX
   1646     //
   1647     if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
   1648 
   1649       if (Operation == EfiPciIoAttributeOperationEnable) {
   1650         //
   1651         // Check if snoop can be enabled in current configuration
   1652         //
   1653         Status = SupportPaletteSnoopAttributes (PciIoDevice, Operation);
   1654 
   1655         if (EFI_ERROR (Status)) {
   1656 
   1657           //
   1658           // Enable operation is forbidden, so mask the bit in attributes
   1659           // so as to keep consistent with the actual Status
   1660           //
   1661           // Attributes &= (~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
   1662           //
   1663           //
   1664           //
   1665           return EFI_UNSUPPORTED;
   1666 
   1667         }
   1668       }
   1669 
   1670       //
   1671       // It can be supported, so get ready to set the bit
   1672       //
   1673       Command |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
   1674     }
   1675   }
   1676 
   1677   if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
   1678     Command |= EFI_PCI_COMMAND_IO_SPACE;
   1679   }
   1680 
   1681   if ((Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) != 0) {
   1682     Command |= EFI_PCI_COMMAND_MEMORY_SPACE;
   1683   }
   1684 
   1685   if ((Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) != 0) {
   1686     Command |= EFI_PCI_COMMAND_BUS_MASTER;
   1687   }
   1688   //
   1689   // The upstream bridge should be also set to revelant attribute
   1690   // expect for IO, Mem and BusMaster
   1691   //
   1692   UpStreamAttributes = Attributes &
   1693                        (~(EFI_PCI_IO_ATTRIBUTE_IO     |
   1694                           EFI_PCI_IO_ATTRIBUTE_MEMORY |
   1695                           EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
   1696                           )
   1697                         );
   1698   UpStreamBridge = PciIoDevice->Parent;
   1699 
   1700   if (Operation == EfiPciIoAttributeOperationEnable) {
   1701     //
   1702     // Enable relevant attributes to command register and bridge control register
   1703     //
   1704     Status = PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, Command);
   1705     if (BridgeControl != 0) {
   1706       Status = PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
   1707     }
   1708 
   1709     PciIoDevice->Attributes |= Attributes;
   1710 
   1711     //
   1712     // Enable attributes of the upstream bridge
   1713     //
   1714     Status = UpStreamBridge->PciIo.Attributes (
   1715                                     &(UpStreamBridge->PciIo),
   1716                                     EfiPciIoAttributeOperationEnable,
   1717                                     UpStreamAttributes,
   1718                                     NULL
   1719                                     );
   1720   } else {
   1721 
   1722     //
   1723     // Disable relevant attributes to command register and bridge control register
   1724     //
   1725     Status = PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, Command);
   1726     if (BridgeControl != 0) {
   1727       Status = PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
   1728     }
   1729 
   1730     PciIoDevice->Attributes &= (~Attributes);
   1731     Status = EFI_SUCCESS;
   1732 
   1733   }
   1734 
   1735   if (EFI_ERROR (Status)) {
   1736     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1737       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1738       EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
   1739       PciIoDevice->DevicePath
   1740       );
   1741   }
   1742 
   1743   return Status;
   1744 }
   1745 
   1746 /**
   1747   Retrieve the AddrTranslationOffset from RootBridgeIo for the
   1748   specified range.
   1749 
   1750   @param RootBridgeIo    Root Bridge IO instance.
   1751   @param AddrRangeMin    The base address of the MMIO.
   1752   @param AddrLen         The length of the MMIO.
   1753 
   1754   @retval The AddrTranslationOffset from RootBridgeIo for the
   1755           specified range, or (UINT64) -1 if the range is not
   1756           found in RootBridgeIo.
   1757 **/
   1758 UINT64
   1759 GetMmioAddressTranslationOffset (
   1760   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *RootBridgeIo,
   1761   UINT64                            AddrRangeMin,
   1762   UINT64                            AddrLen
   1763   )
   1764 {
   1765   EFI_STATUS                        Status;
   1766   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
   1767 
   1768   Status = RootBridgeIo->Configuration (
   1769                            RootBridgeIo,
   1770                            (VOID **) &Configuration
   1771                            );
   1772   if (EFI_ERROR (Status)) {
   1773     return (UINT64) -1;
   1774   }
   1775 
   1776   while (Configuration->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
   1777     if ((Configuration->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
   1778         (Configuration->AddrRangeMin <= AddrRangeMin) &&
   1779         (Configuration->AddrRangeMin + Configuration->AddrLen >= AddrRangeMin + AddrLen)
   1780         ) {
   1781       return Configuration->AddrTranslationOffset;
   1782     }
   1783     Configuration++;
   1784   }
   1785 
   1786   //
   1787   // The resource occupied by BAR should be in the range reported by RootBridge.
   1788   //
   1789   ASSERT (FALSE);
   1790   return (UINT64) -1;
   1791 }
   1792 
   1793 /**
   1794   Gets the attributes that this PCI controller supports setting on a BAR using
   1795   SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
   1796 
   1797   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1798   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
   1799                                 base address for resource range. The legal range for this field is 0..5.
   1800   @param  Supports              A pointer to the mask of attributes that this PCI controller supports
   1801                                 setting for this BAR with SetBarAttributes().
   1802   @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current
   1803                                 configuration of this BAR of the PCI controller.
   1804 
   1805   @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI
   1806                                 controller supports are returned in Supports. If Resources
   1807                                 is not NULL, then the ACPI 2.0 resource descriptors that the PCI
   1808                                 controller is currently using are returned in Resources.
   1809   @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
   1810   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
   1811   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate
   1812                                 Resources.
   1813 
   1814 **/
   1815 EFI_STATUS
   1816 EFIAPI
   1817 PciIoGetBarAttributes (
   1818   IN EFI_PCI_IO_PROTOCOL             * This,
   1819   IN  UINT8                          BarIndex,
   1820   OUT UINT64                         *Supports, OPTIONAL
   1821   OUT VOID                           **Resources OPTIONAL
   1822   )
   1823 {
   1824   PCI_IO_DEVICE                     *PciIoDevice;
   1825   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
   1826   EFI_ACPI_END_TAG_DESCRIPTOR       *End;
   1827 
   1828   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1829 
   1830   if (Supports == NULL && Resources == NULL) {
   1831     return EFI_INVALID_PARAMETER;
   1832   }
   1833 
   1834   if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
   1835     return EFI_UNSUPPORTED;
   1836   }
   1837 
   1838   //
   1839   // This driver does not support modifications to the WRITE_COMBINE or
   1840   // CACHED attributes for BAR ranges.
   1841   //
   1842   if (Supports != NULL) {
   1843     *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
   1844   }
   1845 
   1846   if (Resources != NULL) {
   1847     Descriptor = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
   1848     if (Descriptor == NULL) {
   1849       return EFI_OUT_OF_RESOURCES;
   1850     }
   1851 
   1852     *Resources   = Descriptor;
   1853 
   1854     Descriptor->Desc         = ACPI_ADDRESS_SPACE_DESCRIPTOR;
   1855     Descriptor->Len          = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
   1856     Descriptor->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
   1857     Descriptor->AddrLen      = PciIoDevice->PciBar[BarIndex].Length;
   1858     Descriptor->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
   1859 
   1860     switch (PciIoDevice->PciBar[BarIndex].BarType) {
   1861     case PciBarTypeIo16:
   1862     case PciBarTypeIo32:
   1863       //
   1864       // Io
   1865       //
   1866       Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
   1867       break;
   1868 
   1869     case PciBarTypePMem32:
   1870       //
   1871       // prefechable
   1872       //
   1873       Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
   1874       //
   1875       // Fall through
   1876       //
   1877     case PciBarTypeMem32:
   1878       //
   1879       // Mem
   1880       //
   1881       Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
   1882       //
   1883       // 32 bit
   1884       //
   1885       Descriptor->AddrSpaceGranularity = 32;
   1886       break;
   1887 
   1888     case PciBarTypePMem64:
   1889       //
   1890       // prefechable
   1891       //
   1892       Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
   1893       //
   1894       // Fall through
   1895       //
   1896     case PciBarTypeMem64:
   1897       //
   1898       // Mem
   1899       //
   1900       Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
   1901       //
   1902       // 64 bit
   1903       //
   1904       Descriptor->AddrSpaceGranularity = 64;
   1905       break;
   1906 
   1907     default:
   1908       break;
   1909     }
   1910 
   1911     //
   1912     // put the checksum
   1913     //
   1914     End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
   1915     End->Desc     = ACPI_END_TAG_DESCRIPTOR;
   1916     End->Checksum = 0;
   1917 
   1918     //
   1919     // Get the Address Translation Offset
   1920     //
   1921     if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
   1922       Descriptor->AddrTranslationOffset = GetMmioAddressTranslationOffset (
   1923                                             PciIoDevice->PciRootBridgeIo,
   1924                                             Descriptor->AddrRangeMin,
   1925                                             Descriptor->AddrLen
   1926                                             );
   1927       if (Descriptor->AddrTranslationOffset == (UINT64) -1) {
   1928         FreePool (Descriptor);
   1929         return EFI_UNSUPPORTED;
   1930       }
   1931     }
   1932   }
   1933 
   1934   return EFI_SUCCESS;
   1935 }
   1936 
   1937 /**
   1938   Sets the attributes for a range of a BAR on a PCI controller.
   1939 
   1940   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1941   @param  Attributes            The mask of attributes to set for the resource range specified by
   1942                                 BarIndex, Offset, and Length.
   1943   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
   1944                                 base address for resource range. The legal range for this field is 0..5.
   1945   @param  Offset                A pointer to the BAR relative base address of the resource range to be
   1946                                 modified by the attributes specified by Attributes.
   1947   @param  Length                A pointer to the length of the resource range to be modified by the
   1948                                 attributes specified by Attributes.
   1949 
   1950   @retval EFI_SUCCESS           The set of attributes specified by Attributes for the resource
   1951                                 range specified by BarIndex, Offset, and Length were
   1952                                 set on the PCI controller, and the actual resource range is returned
   1953                                 in Offset and Length.
   1954   @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
   1955   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
   1956   @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set the attributes on the
   1957                                 resource range specified by BarIndex, Offset, and
   1958                                 Length.
   1959 
   1960 **/
   1961 EFI_STATUS
   1962 EFIAPI
   1963 PciIoSetBarAttributes (
   1964   IN EFI_PCI_IO_PROTOCOL              *This,
   1965   IN     UINT64                       Attributes,
   1966   IN     UINT8                        BarIndex,
   1967   IN OUT UINT64                       *Offset,
   1968   IN OUT UINT64                       *Length
   1969   )
   1970 {
   1971   EFI_STATUS    Status;
   1972   PCI_IO_DEVICE *PciIoDevice;
   1973   UINT64        NonRelativeOffset;
   1974   UINT64        Supports;
   1975 
   1976   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
   1977 
   1978   //
   1979   // Make sure Offset and Length are not NULL
   1980   //
   1981   if (Offset == NULL || Length == NULL) {
   1982     return EFI_INVALID_PARAMETER;
   1983   }
   1984 
   1985   if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
   1986     return EFI_UNSUPPORTED;
   1987   }
   1988   //
   1989   // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
   1990   // If Attributes is not 0, then return EFI_UNSUPPORTED.
   1991   //
   1992   Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
   1993 
   1994   if (Attributes != (Attributes & Supports)) {
   1995     return EFI_UNSUPPORTED;
   1996   }
   1997   //
   1998   // Attributes must be supported.  Make sure the BAR range describd by BarIndex, Offset, and
   1999   // Length are valid for this PCI device.
   2000   //
   2001   NonRelativeOffset = *Offset;
   2002   Status = PciIoVerifyBarAccess (
   2003             PciIoDevice,
   2004             BarIndex,
   2005             PciBarTypeMem,
   2006             EfiPciIoWidthUint8,
   2007             (UINT32) *Length,
   2008             &NonRelativeOffset
   2009             );
   2010   if (EFI_ERROR (Status)) {
   2011     return EFI_UNSUPPORTED;
   2012   }
   2013 
   2014   return EFI_SUCCESS;
   2015 }
   2016 
   2017 /**
   2018   Program parent bridge's attribute recurrently.
   2019 
   2020   @param PciIoDevice  Child Pci device instance
   2021   @param Operation    The operation to perform on the attributes for this PCI controller.
   2022   @param Attributes   The mask of attributes that are used for Set, Enable, and Disable
   2023                       operations.
   2024 
   2025   @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.
   2026   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   2027   @retval EFI_UNSUPPORTED       one or more of the bits set in
   2028                                 Attributes are not supported by this PCI controller or one of
   2029                                 its parent bridges when Operation is Set, Enable or Disable.
   2030 
   2031 **/
   2032 EFI_STATUS
   2033 UpStreamBridgesAttributes (
   2034   IN PCI_IO_DEVICE                            *PciIoDevice,
   2035   IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
   2036   IN UINT64                                   Attributes
   2037   )
   2038 {
   2039   PCI_IO_DEVICE       *Parent;
   2040   EFI_PCI_IO_PROTOCOL *PciIo;
   2041 
   2042   Parent = PciIoDevice->Parent;
   2043 
   2044   while (Parent != NULL && IS_PCI_BRIDGE (&Parent->Pci)) {
   2045 
   2046     //
   2047     // Get the PciIo Protocol
   2048     //
   2049     PciIo = &Parent->PciIo;
   2050 
   2051     PciIo->Attributes (PciIo, Operation, Attributes, NULL);
   2052 
   2053     Parent = Parent->Parent;
   2054   }
   2055 
   2056   return EFI_SUCCESS;
   2057 }
   2058 
   2059 /**
   2060   Test whether two Pci devices has same parent bridge.
   2061 
   2062   @param PciDevice1  The first pci device for testing.
   2063   @param PciDevice2  The second pci device for testing.
   2064 
   2065   @retval TRUE       Two Pci device has the same parent bridge.
   2066   @retval FALSE      Two Pci device has not the same parent bridge.
   2067 
   2068 **/
   2069 BOOLEAN
   2070 PciDevicesOnTheSamePath (
   2071   IN PCI_IO_DEVICE        *PciDevice1,
   2072   IN PCI_IO_DEVICE        *PciDevice2
   2073   )
   2074 {
   2075   BOOLEAN   Existed1;
   2076   BOOLEAN   Existed2;
   2077 
   2078   if (PciDevice1->Parent == PciDevice2->Parent) {
   2079     return TRUE;
   2080   }
   2081 
   2082   Existed1 = PciDeviceExisted (PciDevice1->Parent, PciDevice2);
   2083   Existed2 = PciDeviceExisted (PciDevice2->Parent, PciDevice1);
   2084 
   2085   return (BOOLEAN) (Existed1 || Existed2);
   2086 }
   2087 
   2088