public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Jeremy Linton <lintonrjeremy@gmail.com>
To: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: "Pete Batard" <pete@akeo.ie>,
	"Jeremy Linton" <jeremy.linton@arm.com>,
	edk2-devel-groups-io <devel@edk2.groups.io>,
	"Leif Lindholm" <leif.lindholm@linaro.org>,
	"Philippe Mathieu-Daudé" <philmd@redhat.com>
Subject: Re: [edk2-platforms][PATCH 2/4] Silicon/Bcm27xx: Add segment library to handle nonstandard ECAM
Date: Thu, 12 Dec 2019 16:15:54 -0600	[thread overview]
Message-ID: <CAEFTgixaNwF9Pawwor7yBV=9NP+Vtx7q+OvV=tENeTNz9ZqymQ@mail.gmail.com> (raw)
In-Reply-To: <CAKv+Gu-wfUWfSzBv27bqxj8M=bYj25-pDyTddDpEe-1Rei3r5A@mail.gmail.com>

Hi,

On Thu, Dec 12, 2019 at 7:35 AM Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
>
> On Thu, 12 Dec 2019 at 11:55, Pete Batard <pete@akeo.ie> wrote:
> >
> > From: Jeremy Linton <lintonrjeremy@gmail.com>
> >
> > Signed-off-by: Pete Batard <pete@akeo.ie>
> > ---
> >  Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.c   | 1432 ++++++++++++++++++++
> >  Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.inf |   34 +
> >  2 files changed, 1466 insertions(+)
> >
> > diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.c b/Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.c
> > new file mode 100644
> > index 000000000000..78232d233c5a
> > --- /dev/null
> > +++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.c
> > @@ -0,0 +1,1432 @@
> > +/** @file
> > + *
> > + * PCI Segment Library for Bcm2711 (RPi4) SoC
> > + *
> > + * Copyright (c) 2019, Jeremy Linton
> > + * Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
> > + * Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > + **/
> > +
> > +#include <Base.h>
> > +
> > +#include <Library/BaseLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/IoLib.h>
> > +#include <Library/PcdLib.h>
> > +#include <Library/PciSegmentLib.h>
> > +#include <IndustryStandard/Bcm2711.h>
> > +
> > +typedef enum {
> > +  PciCfgWidthUint8 = 0,
> > +  PciCfgWidthUint16,
> > +  PciCfgWidthUint32,
> > +  PciCfgWidthMax
> > +} PCI_CFG_WIDTH;
> > +
> > +/*
> > + * This PCIe config space is unusual...
> > + * The root port is the first bytes of the register space (offset 0)
> > + * The individual devices are then selected by computing their BDF index
> > + * and writing that into the CFG_INDEX register (offset 0x9000)
> > + * the "ECAM" data is then read/writeable at CFG_DATA (offset 0x8000)
> > + */
> > +
> > +#define EFI_PCI_ADDR_BUS(bus) ((bus>>20) & 0xFF)    /* Note PCI_SEGMENT_LIB_ADDRESS */
> > +#define EFI_PCI_ADDR_DEV(dev) ((dev>>15) & 0x1F)
> > +#define EFI_PCI_ADDR_FUN(fun) ((fun>>12) & 0x07)
> > +
> > +/**
> > +  Assert the validity of a PCI Segment address.
> > +  A valid PCI Segment address should not contain 1's in bits 28..31 and 48..63
> > +
> > +  @param  A The address to validate.
> > +  @param  M Additional bits to assert to be zero.
> > +
> > +**/
> > +#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A,M) \
> > +  ASSERT (((A) & (0xffff0000f0000000ULL | (M))) == 0)
> > +
> > +/**
> > +  Internal worker function to obtain config space base address.
> > +
> > +  @param  Address The address that encodes the PCI Bus, Device, Function and
> > +                  Register.
> > +
> > +  @return The value read from the PCI configuration register.
> > +
> > +**/
> > +
> > +STATIC
> > +UINT64
> > +PciSegmentLibGetConfigBase (
> > +  IN  UINT64                      Address
> > +  )
> > +{
> > +  STATIC UINT64 LastAccess = 0;     /* Avoid repeat CFG_INDEX updates */
>
> This doesn't look safe to me in the face of concurrency: what happens
> if the timer interrupt fires in the middle of this routine, and
> executes an event callback that accesses the PCI config space of
> another device? I'm not saying this is likely to happen, but we have
> to deal with it nonetheless.

No, I think your right, I had a comment around here about it not being
safe (aka you get the wrong config space), but I removed it.

OTOH, wasn't sure if it could happen in this code path.

>
> I think the only safe way is to perform the entire access with TPL set
> to TPL_HIGH_LEVEL, i.e., raise it before calling
> PciSegmentLibGetConfigBase() in each routine, and drop it after
> performing the access.

That is easy enough.


>
>
> > +  UINT64        Base;
> > +  UINT64        Offset;
> > +
> > +  Base = PCIE_REG_BASE;
> > +  Offset = Address & 0xFFF;         /* Pick off the 4k register offset */
> > +  Address &= 0xFFFFF000;            /* Clear the offset leave only the BDF */
> > +
> > +  /* The root port is at the base of the PCIe register space */
> > +  if (Address != 0) {
> > +    /* The current device is at CFG_DATA */
> > +    Base += PCIE_EXT_CFG_DATA;
> > +    if (LastAccess != Address) {
> > +      UINT32 dev = EFI_PCI_ADDR_DEV (Address);
> > +      /*
> > +       * Scan things out directly rather than translating the "bus" to a device, etc..
> > +       * only we need to limit each bus to a single device.
> > +       */
> > +      if (dev < 1) {
> > +          MmioWrite32 (PCIE_REG_BASE + PCIE_EXT_CFG_INDEX, Address);
> > +          LastAccess = Address;
> > +      } else {
> > +          LastAccess = 0;
> > +          return 0xFFFFFFFF;
> > +      }
> > +    }
> > +  }
> > +  return Base + Offset;
> > +}
> > +
> > +/**
> > +  Internal worker function to read a PCI configuration register.
> > +
> > +  @param  Address The address that encodes the PCI Bus, Device, Function and
> > +                  Register.
> > +  @param  Width   The width of data to read
> > +
> > +  @return The value read from the PCI configuration register.
> > +
> > +**/
> > +STATIC
> > +UINT32
> > +PciSegmentLibReadWorker (
> > +  IN  UINT64                      Address,
> > +  IN  PCI_CFG_WIDTH               Width
> > +  )
> > +{
> > +  UINT64    Base;
> > +  UINT64    Ret = 0;
> > +
> > +  Base = PciSegmentLibGetConfigBase (Address);
> > +
> > +  if (Base==0xFFFFFFFF)
> > +    return Base;
> > +
> > +  switch (Width) {
> > +  case PciCfgWidthUint8:
> > +    Ret = MmioRead8 (Base);
> > +    break;
> > +  case PciCfgWidthUint16:
> > +    Ret = MmioRead16 (Base);
> > +    break;
> > +  case PciCfgWidthUint32:
> > +    Ret = MmioRead32 (Base);
> > +    break;
> > +  default:
> > +    ASSERT (FALSE);
> > +  }
> > +  return Ret;
> > +}
> > +
> > +/**
> > +  Internal worker function to writes a PCI configuration register.
> > +
> > +  @param  Address The address that encodes the PCI Bus, Device, Function and
> > +                  Register.
> > +  @param  Width   The width of data to write
> > +  @param  Data    The value to write.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +STATIC
> > +UINT32
> > +PciSegmentLibWriteWorker (
> > +  IN  UINT64                      Address,
> > +  IN  PCI_CFG_WIDTH               Width,
> > +  IN  UINT32                      Data
> > +  )
> > +{
> > +  UINT64    Base;
> > +
> > +  Base = PciSegmentLibGetConfigBase (Address);
> > +
> > +  switch (Width) {
> > +  case PciCfgWidthUint8:
> > +    MmioWrite8 (Base, Data);
> > +    break;
> > +  case PciCfgWidthUint16:
> > +    MmioWrite16 (Base, Data);
> > +    break;
> > +  case PciCfgWidthUint32:
> > +    MmioWrite32 (Base, Data);
> > +    break;
> > +  default:
> > +    ASSERT (FALSE);
> > +  }
> > +  return Data;
> > +}
> > +
> > +/**
> > +  Register a PCI device so PCI configuration registers may be accessed after
> > +  SetVirtualAddressMap().
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +
> > +  @param  Address The address that encodes the PCI Bus, Device, Function and
> > +                  Register.
> > +
> > +  @retval RETURN_SUCCESS           The PCI device was registered for runtime access.
> > +  @retval RETURN_UNSUPPORTED       An attempt was made to call this function
> > +                                   after ExitBootServices().
> > +  @retval RETURN_UNSUPPORTED       The resources required to access the PCI device
> > +                                   at runtime could not be mapped.
> > +  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
> > +                                   complete the registration.
> > +
> > +**/
> > +RETURN_STATUS
> > +EFIAPI
> > +PciSegmentRegisterForRuntimeAccess (
> > +  IN UINTN  Address
> > +  )
> > +{
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
> > +  return RETURN_UNSUPPORTED;
> > +}
> > +
> > +/**
> > +  Reads an 8-bit PCI configuration register.
> > +
> > +  Reads and returns the 8-bit PCI configuration register specified by Address.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
> > +                    and Register.
> > +
> > +  @return The 8-bit PCI configuration register specified by Address.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentRead8 (
> > +  IN UINT64                    Address
> > +  )
> > +{
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
> > +
> > +  return (UINT8) PciSegmentLibReadWorker (Address, PciCfgWidthUint8);
> > +}
> > +
> > +/**
> > +  Writes an 8-bit PCI configuration register.
> > +
> > +  Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
> > +  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +
> > +  @param  Address     The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  Value       The value to write.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentWrite8 (
> > +  IN UINT64                    Address,
> > +  IN UINT8                     Value
> > +  )
> > +{
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
> > +
> > +  return (UINT8) PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value);
> > +}
> > +
> > +/**
> > +  Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
> > +
> > +  Reads the 8-bit PCI configuration register specified by Address,
> > +  performs a bitwise OR between the read result and the value specified by OrData,
> > +  and writes the result to the 8-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentOr8 (
> > +  IN UINT64                    Address,
> > +  IN UINT8                     OrData
> > +  )
> > +{
> > +  return PciSegmentWrite8 (Address, (UINT8) (PciSegmentRead8 (Address) | OrData));
> > +}
> > +
> > +/**
> > +  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
> > +
> > +  Reads the 8-bit PCI configuration register specified by Address,
> > +  performs a bitwise AND between the read result and the value specified by AndData,
> > +  and writes the result to the 8-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +  If any reserved bits in Address are set, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentAnd8 (
> > +  IN UINT64                    Address,
> > +  IN UINT8                     AndData
> > +  )
> > +{
> > +  return PciSegmentWrite8 (Address, (UINT8) (PciSegmentRead8 (Address) & AndData));
> > +}
> > +
> > +/**
> > +  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
> > +  followed a  bitwise OR with another 8-bit value.
> > +
> > +  Reads the 8-bit PCI configuration register specified by Address,
> > +  performs a bitwise AND between the read result and the value specified by AndData,
> > +  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
> > +  and writes the result to the 8-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  AndData    The value to AND with the PCI configuration register.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentAndThenOr8 (
> > +  IN UINT64                    Address,
> > +  IN UINT8                     AndData,
> > +  IN UINT8                     OrData
> > +  )
> > +{
> > +  return PciSegmentWrite8 (Address, (UINT8) ((PciSegmentRead8 (Address) & AndData) | OrData));
> > +}
> > +
> > +/**
> > +  Reads a bit field of a PCI configuration register.
> > +
> > +  Reads the bit field in an 8-bit PCI configuration register. The bit field is
> > +  specified by the StartBit and the EndBit. The value of the bit field is
> > +  returned.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 7, then ASSERT().
> > +  If EndBit is greater than 7, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to read.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..7.
> > +
> > +  @return The value of the bit field read from the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentBitFieldRead8 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit
> > +  )
> > +{
> > +  return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit);
> > +}
> > +
> > +/**
> > +  Writes a bit field to a PCI configuration register.
> > +
> > +  Writes Value to the bit field of the PCI configuration register. The bit
> > +  field is specified by the StartBit and the EndBit. All other bits in the
> > +  destination PCI configuration register are preserved. The new value of the
> > +  8-bit register is returned.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 7, then ASSERT().
> > +  If EndBit is greater than 7, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  Value     The new value of the bit field.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentBitFieldWrite8 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT8                     Value
> > +  )
> > +{
> > +  return PciSegmentWrite8 (
> > +           Address,
> > +           BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Value)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
> > +  writes the result back to the bit field in the 8-bit port.
> > +
> > +  Reads the 8-bit PCI configuration register specified by Address, performs a
> > +  bitwise OR between the read result and the value specified by
> > +  OrData, and writes the result to the 8-bit PCI configuration register
> > +  specified by Address. The value written to the PCI configuration register is
> > +  returned. This function must guarantee that all PCI read and write operations
> > +  are serialized. Extra left bits in OrData are stripped.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 7, then ASSERT().
> > +  If EndBit is greater than 7, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentBitFieldOr8 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT8                     OrData
> > +  )
> > +{
> > +  return PciSegmentWrite8 (
> > +           Address,
> > +           BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
> > +  AND, and writes the result back to the bit field in the 8-bit register.
> > +
> > +  Reads the 8-bit PCI configuration register specified by Address, performs a
> > +  bitwise AND between the read result and the value specified by AndData, and
> > +  writes the result to the 8-bit PCI configuration register specified by
> > +  Address. The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are
> > +  serialized. Extra left bits in AndData are stripped.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 7, then ASSERT().
> > +  If EndBit is greater than 7, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentBitFieldAnd8 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT8                     AndData
> > +  )
> > +{
> > +  return PciSegmentWrite8 (
> > +           Address,
> > +           BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
> > +  bitwise OR, and writes the result back to the bit field in the
> > +  8-bit port.
> > +
> > +  Reads the 8-bit PCI configuration register specified by Address, performs a
> > +  bitwise AND followed by a bitwise OR between the read result and
> > +  the value specified by AndData, and writes the result to the 8-bit PCI
> > +  configuration register specified by Address. The value written to the PCI
> > +  configuration register is returned. This function must guarantee that all PCI
> > +  read and write operations are serialized. Extra left bits in both AndData and
> > +  OrData are stripped.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 7, then ASSERT().
> > +  If EndBit is greater than 7, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..7.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +  @param  OrData    The value to OR with the result of the AND operation.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT8
> > +EFIAPI
> > +PciSegmentBitFieldAndThenOr8 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT8                     AndData,
> > +  IN UINT8                     OrData
> > +  )
> > +{
> > +  return PciSegmentWrite8 (
> > +           Address,
> > +           BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData, OrData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a 16-bit PCI configuration register.
> > +
> > +  Reads and returns the 16-bit PCI configuration register specified by Address.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +
> > +  @return The 16-bit PCI configuration register specified by Address.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentRead16 (
> > +  IN UINT64                    Address
> > +  )
> > +{
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
> > +
> > +  return (UINT16) PciSegmentLibReadWorker (Address, PciCfgWidthUint16);
> > +}
> > +
> > +/**
> > +  Writes a 16-bit PCI configuration register.
> > +
> > +  Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
> > +  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +
> > +  @param  Address     The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  Value       The value to write.
> > +
> > +  @return The parameter of Value.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentWrite16 (
> > +  IN UINT64                    Address,
> > +  IN UINT16                    Value
> > +  )
> > +{
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
> > +
> > +  return (UINT16) PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Value);
> > +}
> > +
> > +/**
> > +  Performs a bitwise OR of a 16-bit PCI configuration register with
> > +  a 16-bit value.
> > +
> > +  Reads the 16-bit PCI configuration register specified by Address, performs a
> > +  bitwise OR between the read result and the value specified by
> > +  OrData, and writes the result to the 16-bit PCI configuration register
> > +  specified by Address. The value written to the PCI configuration register is
> > +  returned. This function must guarantee that all PCI read and write operations
> > +  are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +
> > +  @param  Address The address that encodes the PCI Segment, Bus, Device, Function and
> > +                  Register.
> > +  @param  OrData  The value to OR with the PCI configuration register.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentOr16 (
> > +  IN UINT64                    Address,
> > +  IN UINT16                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) | OrData));
> > +}
> > +
> > +/**
> > +  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
> > +
> > +  Reads the 16-bit PCI configuration register specified by Address,
> > +  performs a bitwise AND between the read result and the value specified by AndData,
> > +  and writes the result to the 16-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentAnd16 (
> > +  IN UINT64                    Address,
> > +  IN UINT16                    AndData
> > +  )
> > +{
> > +  return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) & AndData));
> > +}
> > +
> > +/**
> > +  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
> > +  followed a  bitwise OR with another 16-bit value.
> > +
> > +  Reads the 16-bit PCI configuration register specified by Address,
> > +  performs a bitwise AND between the read result and the value specified by AndData,
> > +  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
> > +  and writes the result to the 16-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentAndThenOr16 (
> > +  IN UINT64                    Address,
> > +  IN UINT16                    AndData,
> > +  IN UINT16                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite16 (Address, (UINT16) ((PciSegmentRead16 (Address) & AndData) | OrData));
> > +}
> > +
> > +/**
> > +  Reads a bit field of a PCI configuration register.
> > +
> > +  Reads the bit field in a 16-bit PCI configuration register. The bit field is
> > +  specified by the StartBit and the EndBit. The value of the bit field is
> > +  returned.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +  If StartBit is greater than 15, then ASSERT().
> > +  If EndBit is greater than 15, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to read.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..15.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..15.
> > +
> > +  @return The value of the bit field read from the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentBitFieldRead16 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit
> > +  )
> > +{
> > +  return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit);
> > +}
> > +
> > +/**
> > +  Writes a bit field to a PCI configuration register.
> > +
> > +  Writes Value to the bit field of the PCI configuration register. The bit
> > +  field is specified by the StartBit and the EndBit. All other bits in the
> > +  destination PCI configuration register are preserved. The new value of the
> > +  16-bit register is returned.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +  If StartBit is greater than 15, then ASSERT().
> > +  If EndBit is greater than 15, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..15.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..15.
> > +  @param  Value     The new value of the bit field.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentBitFieldWrite16 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT16                    Value
> > +  )
> > +{
> > +  return PciSegmentWrite16 (
> > +           Address,
> > +           BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, Value)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads the 16-bit PCI configuration register specified by Address,
> > +  performs a bitwise OR between the read result and the value specified by OrData,
> > +  and writes the result to the 16-bit PCI configuration register specified by Address.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +  If StartBit is greater than 15, then ASSERT().
> > +  If EndBit is greater than 15, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..15.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..15.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentBitFieldOr16 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT16                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite16 (
> > +           Address,
> > +           BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR,
> > +  and writes the result back to the bit field in the 16-bit port.
> > +
> > +  Reads the 16-bit PCI configuration register specified by Address,
> > +  performs a bitwise OR between the read result and the value specified by OrData,
> > +  and writes the result to the 16-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +  Extra left bits in OrData are stripped.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> > +  If StartBit is greater than 7, then ASSERT().
> > +  If EndBit is greater than 7, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    The ordinal of the least significant bit in a byte is bit 0.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    The ordinal of the most significant bit in a byte is bit 7.
> > +  @param  AndData   The value to AND with the read value from the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentBitFieldAnd16 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT16                    AndData
> > +  )
> > +{
> > +  return PciSegmentWrite16 (
> > +           Address,
> > +           BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
> > +  bitwise OR, and writes the result back to the bit field in the
> > +  16-bit port.
> > +
> > +  Reads the 16-bit PCI configuration register specified by Address, performs a
> > +  bitwise AND followed by a bitwise OR between the read result and
> > +  the value specified by AndData, and writes the result to the 16-bit PCI
> > +  configuration register specified by Address. The value written to the PCI
> > +  configuration register is returned. This function must guarantee that all PCI
> > +  read and write operations are serialized. Extra left bits in both AndData and
> > +  OrData are stripped.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 15, then ASSERT().
> > +  If EndBit is greater than 15, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..15.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..15.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +  @param  OrData    The value to OR with the result of the AND operation.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT16
> > +EFIAPI
> > +PciSegmentBitFieldAndThenOr16 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT16                    AndData,
> > +  IN UINT16                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite16 (
> > +           Address,
> > +           BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData, OrData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a 32-bit PCI configuration register.
> > +
> > +  Reads and returns the 32-bit PCI configuration register specified by Address.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
> > +                    and Register.
> > +
> > +  @return The 32-bit PCI configuration register specified by Address.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentRead32 (
> > +  IN UINT64                    Address
> > +  )
> > +{
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
> > +
> > +  return PciSegmentLibReadWorker (Address, PciCfgWidthUint32);
> > +}
> > +
> > +/**
> > +  Writes a 32-bit PCI configuration register.
> > +
> > +  Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
> > +  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +
> > +  @param  Address     The address that encodes the PCI Segment, Bus, Device,
> > +                      Function, and Register.
> > +  @param  Value       The value to write.
> > +
> > +  @return The parameter of Value.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentWrite32 (
> > +  IN UINT64                    Address,
> > +  IN UINT32                    Value
> > +  )
> > +{
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
> > +
> > +  return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value);
> > +}
> > +
> > +/**
> > +  Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
> > +
> > +  Reads the 32-bit PCI configuration register specified by Address,
> > +  performs a bitwise OR between the read result and the value specified by OrData,
> > +  and writes the result to the 32-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentOr32 (
> > +  IN UINT64                    Address,
> > +  IN UINT32                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData);
> > +}
> > +
> > +/**
> > +  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
> > +
> > +  Reads the 32-bit PCI configuration register specified by Address,
> > +  performs a bitwise AND between the read result and the value specified by AndData,
> > +  and writes the result to the 32-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
> > +                    and Register.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentAnd32 (
> > +  IN UINT64                    Address,
> > +  IN UINT32                    AndData
> > +  )
> > +{
> > +  return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData);
> > +}
> > +
> > +/**
> > +  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
> > +  followed a  bitwise OR with another 32-bit value.
> > +
> > +  Reads the 32-bit PCI configuration register specified by Address,
> > +  performs a bitwise AND between the read result and the value specified by AndData,
> > +  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
> > +  and writes the result to the 32-bit PCI configuration register specified by Address.
> > +  The value written to the PCI configuration register is returned.
> > +  This function must guarantee that all PCI read and write operations are serialized.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +
> > +  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
> > +                    and Register.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written to the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentAndThenOr32 (
> > +  IN UINT64                    Address,
> > +  IN UINT32                    AndData,
> > +  IN UINT32                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData);
> > +}
> > +
> > +/**
> > +  Reads a bit field of a PCI configuration register.
> > +
> > +  Reads the bit field in a 32-bit PCI configuration register. The bit field is
> > +  specified by the StartBit and the EndBit. The value of the bit field is
> > +  returned.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +  If StartBit is greater than 31, then ASSERT().
> > +  If EndBit is greater than 31, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to read.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..31.
> > +
> > +  @return The value of the bit field read from the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentBitFieldRead32 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit
> > +  )
> > +{
> > +  return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit);
> > +}
> > +
> > +/**
> > +  Writes a bit field to a PCI configuration register.
> > +
> > +  Writes Value to the bit field of the PCI configuration register. The bit
> > +  field is specified by the StartBit and the EndBit. All other bits in the
> > +  destination PCI configuration register are preserved. The new value of the
> > +  32-bit register is returned.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +  If StartBit is greater than 31, then ASSERT().
> > +  If EndBit is greater than 31, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  Value     The new value of the bit field.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentBitFieldWrite32 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT32                    Value
> > +  )
> > +{
> > +  return PciSegmentWrite32 (
> > +           Address,
> > +           BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, Value)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
> > +  writes the result back to the bit field in the 32-bit port.
> > +
> > +  Reads the 32-bit PCI configuration register specified by Address, performs a
> > +  bitwise OR between the read result and the value specified by
> > +  OrData, and writes the result to the 32-bit PCI configuration register
> > +  specified by Address. The value written to the PCI configuration register is
> > +  returned. This function must guarantee that all PCI read and write operations
> > +  are serialized. Extra left bits in OrData are stripped.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 31, then ASSERT().
> > +  If EndBit is greater than 31, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  OrData    The value to OR with the PCI configuration register.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentBitFieldOr32 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT32                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite32 (
> > +           Address,
> > +           BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
> > +  AND, and writes the result back to the bit field in the 32-bit register.
> > +
> > +
> > +  Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
> > +  AND between the read result and the value specified by AndData, and writes the result
> > +  to the 32-bit PCI configuration register specified by Address. The value written to
> > +  the PCI configuration register is returned.  This function must guarantee that all PCI
> > +  read and write operations are serialized.  Extra left bits in AndData are stripped.
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> > +  If StartBit is greater than 31, then ASSERT().
> > +  If EndBit is greater than 31, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentBitFieldAnd32 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT32                    AndData
> > +  )
> > +{
> > +  return PciSegmentWrite32 (
> > +           Address,
> > +           BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
> > +  bitwise OR, and writes the result back to the bit field in the
> > +  32-bit port.
> > +
> > +  Reads the 32-bit PCI configuration register specified by Address, performs a
> > +  bitwise AND followed by a bitwise OR between the read result and
> > +  the value specified by AndData, and writes the result to the 32-bit PCI
> > +  configuration register specified by Address. The value written to the PCI
> > +  configuration register is returned. This function must guarantee that all PCI
> > +  read and write operations are serialized. Extra left bits in both AndData and
> > +  OrData are stripped.
> > +
> > +  If any reserved bits in Address are set, then ASSERT().
> > +  If StartBit is greater than 31, then ASSERT().
> > +  If EndBit is greater than 31, then ASSERT().
> > +  If EndBit is less than StartBit, then ASSERT().
> > +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> > +
> > +  @param  Address   The PCI configuration register to write.
> > +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> > +                    Range 0..31.
> > +  @param  AndData   The value to AND with the PCI configuration register.
> > +  @param  OrData    The value to OR with the result of the AND operation.
> > +
> > +  @return The value written back to the PCI configuration register.
> > +
> > +**/
> > +UINT32
> > +EFIAPI
> > +PciSegmentBitFieldAndThenOr32 (
> > +  IN UINT64                    Address,
> > +  IN UINTN                     StartBit,
> > +  IN UINTN                     EndBit,
> > +  IN UINT32                    AndData,
> > +  IN UINT32                    OrData
> > +  )
> > +{
> > +  return PciSegmentWrite32 (
> > +           Address,
> > +           BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData, OrData)
> > +           );
> > +}
> > +
> > +/**
> > +  Reads a range of PCI configuration registers into a caller supplied buffer.
> > +
> > +  Reads the range of PCI configuration registers specified by StartAddress and
> > +  Size into the buffer specified by Buffer. This function only allows the PCI
> > +  configuration registers from a single PCI function to be read. Size is
> > +  returned. When possible 32-bit PCI configuration read cycles are used to read
> > +  from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
> > +  and 16-bit PCI configuration read cycles may be used at the beginning and the
> > +  end of the range.
> > +
> > +  If any reserved bits in StartAddress are set, then ASSERT().
> > +  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
> > +  If Size > 0 and Buffer is NULL, then ASSERT().
> > +
> > +  @param  StartAddress  The starting address that encodes the PCI Segment, Bus,
> > +                        Device, Function and Register.
> > +  @param  Size          The size in bytes of the transfer.
> > +  @param  Buffer        The pointer to a buffer receiving the data read.
> > +
> > +  @return Size
> > +
> > +**/
> > +UINTN
> > +EFIAPI
> > +PciSegmentReadBuffer (
> > +  IN  UINT64                   StartAddress,
> > +  IN  UINTN                    Size,
> > +  OUT VOID                     *Buffer
> > +  )
> > +{
> > +  UINTN                             ReturnValue;
> > +
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
> > +  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
> > +
> > +  if (Size == 0) {
> > +    return Size;
> > +  }
> > +
> > +  ASSERT (Buffer != NULL);
> > +
> > +  //
> > +  // Save Size for return
> > +  //
> > +  ReturnValue = Size;
> > +
> > +  if ((StartAddress & BIT0) != 0) {
> > +    //
> > +    // Read a byte if StartAddress is byte aligned
> > +    //
> > +    *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
> > +    StartAddress += sizeof (UINT8);
> > +    Size -= sizeof (UINT8);
> > +    Buffer = (UINT8*)Buffer + 1;
> > +  }
> > +
> > +  if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) {
> > +    //
> > +    // Read a word if StartAddress is word aligned
> > +    //
> > +    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
> > +    StartAddress += sizeof (UINT16);
> > +    Size -= sizeof (UINT16);
> > +    Buffer = (UINT16*)Buffer + 1;
> > +  }
> > +
> > +  while (Size >= sizeof (UINT32)) {
> > +    //
> > +    // Read as many double words as possible
> > +    //
> > +    WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress));
> > +    StartAddress += sizeof (UINT32);
> > +    Size -= sizeof (UINT32);
> > +    Buffer = (UINT32*)Buffer + 1;
> > +  }
> > +
> > +  if (Size >= sizeof (UINT16)) {
> > +    //
> > +    // Read the last remaining word if exist
> > +    //
> > +    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
> > +    StartAddress += sizeof (UINT16);
> > +    Size -= sizeof (UINT16);
> > +    Buffer = (UINT16*)Buffer + 1;
> > +  }
> > +
> > +  if (Size >= sizeof (UINT8)) {
> > +    //
> > +    // Read the last remaining byte if exist
> > +    //
> > +    *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
> > +  }
> > +
> > +  return ReturnValue;
> > +}
> > +
> > +
> > +/**
> > +  Copies the data in a caller supplied buffer to a specified range of PCI
> > +  configuration space.
> > +
> > +  Writes the range of PCI configuration registers specified by StartAddress and
> > +  Size from the buffer specified by Buffer. This function only allows the PCI
> > +  configuration registers from a single PCI function to be written. Size is
> > +  returned. When possible 32-bit PCI configuration write cycles are used to
> > +  write from StartAdress to StartAddress + Size. Due to alignment restrictions,
> > +  8-bit and 16-bit PCI configuration write cycles may be used at the beginning
> > +  and the end of the range.
> > +
> > +  If any reserved bits in StartAddress are set, then ASSERT().
> > +  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
> > +  If Size > 0 and Buffer is NULL, then ASSERT().
> > +
> > +  @param  StartAddress  The starting address that encodes the PCI Segment, Bus,
> > +                        Device, Function and Register.
> > +  @param  Size          The size in bytes of the transfer.
> > +  @param  Buffer        The pointer to a buffer containing the data to write.
> > +
> > +  @return The parameter of Size.
> > +
> > +**/
> > +UINTN
> > +EFIAPI
> > +PciSegmentWriteBuffer (
> > +  IN UINT64                    StartAddress,
> > +  IN UINTN                     Size,
> > +  IN VOID                      *Buffer
> > +  )
> > +{
> > +  UINTN                             ReturnValue;
> > +
> > +  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
> > +  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
> > +
> > +  if (Size == 0) {
> > +    return 0;
> > +  }
> > +
> > +  ASSERT (Buffer != NULL);
> > +
> > +  // The Bcm/Rpi has a single cfg which can be mapped
> > +  // to any given device on the bus, which means we need to remap
> > +  // it basically everytime a new config access is done
> > +
> > +  //
> > +  // Save Size for return
> > +  //
> > +  ReturnValue = Size;
> > +
> > +  if ((StartAddress & BIT0) != 0) {
> > +    //
> > +    // Write a byte if StartAddress is byte aligned
> > +    //
> > +    PciSegmentWrite8 (StartAddress, *(UINT8*)Buffer);
> > +    StartAddress += sizeof (UINT8);
> > +    Size -= sizeof (UINT8);
> > +    Buffer = (UINT8*)Buffer + 1;
> > +  }
> > +
> > +  if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) {
> > +    //
> > +    // Write a word if StartAddress is word aligned
> > +    //
> > +    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
> > +    StartAddress += sizeof (UINT16);
> > +    Size -= sizeof (UINT16);
> > +    Buffer = (UINT16*)Buffer + 1;
> > +  }
> > +
> > +  while (Size >= sizeof (UINT32)) {
> > +    //
> > +    // Write as many double words as possible
> > +    //
> > +    PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer));
> > +    StartAddress += sizeof (UINT32);
> > +    Size -= sizeof (UINT32);
> > +    Buffer = (UINT32*)Buffer + 1;
> > +  }
> > +
> > +  if (Size >= sizeof (UINT16)) {
> > +    //
> > +    // Write the last remaining word if exist
> > +    //
> > +    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
> > +    StartAddress += sizeof (UINT16);
> > +    Size -= sizeof (UINT16);
> > +    Buffer = (UINT16*)Buffer + 1;
> > +  }
> > +
> > +  if (Size >= sizeof (UINT8)) {
> > +    //
> > +    // Write the last remaining byte if exist
> > +    //
> > +    PciSegmentWrite8 (StartAddress, *(UINT8*)Buffer);
> > +  }
> > +
> > +  return ReturnValue;
> > +}
> > diff --git a/Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.inf b/Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.inf
> > new file mode 100644
> > index 000000000000..2ee38c06368a
> > --- /dev/null
> > +++ b/Silicon/Broadcom/Bcm27xx/Library/Bcm2711PciSegmentLib/PciSegmentLib.inf
> > @@ -0,0 +1,34 @@
> > +## @file
> > +# PCI Segment Library for Bcm2711 (RPi4) SoC
> > +#
> > +# Copyright (c) 2019, Jeremy Linton
> > +# Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
> > +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x0001001B
> > +  BASE_NAME                      = PciSegmentLib
> > +  FILE_GUID                      = 74fe3f9e-0040-11ea-a7bf-5254005675a0
> > +  MODULE_TYPE                    = BASE
> > +  VERSION_STRING                 = 1.0
> > +  LIBRARY_CLASS                  = PciSegmentLib
> > +
> > +[Sources]
> > +  PciSegmentLib.c
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
> > +
> > +[LibraryClasses]
> > +  BaseLib
> > +  DebugLib
> > +  IoLib
> > +  PcdLib
> > +
> > +[FixedPcd]
> > +  gBcm27xxTokenSpaceGuid.PcdBcm27xxPciRegBase
> > --
> > 2.21.0.windows.1
> >

  reply	other threads:[~2019-12-12 22:16 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-12 10:54 [edk2-platforms][PATCH 0/4] Platform/RPi4: Add PCIe and xHCI support Pete Batard
2019-12-12 10:54 ` [edk2-platforms][PATCH 1/4] Silicon/Bcm27xx: Add PCIe constants to Bcm2711.h Pete Batard
2019-12-12 10:55 ` [edk2-platforms][PATCH 2/4] Silicon/Bcm27xx: Add segment library to handle nonstandard ECAM Pete Batard
2019-12-12 13:35   ` Ard Biesheuvel
2019-12-12 22:15     ` Jeremy Linton [this message]
2019-12-12 10:55 ` [edk2-platforms][PATCH 3/4] Silicon/Bcm27xx: Add PCIe host bridge config library Pete Batard
2019-12-12 10:55 ` [edk2-platforms][PATCH 4/4] Platform/RPi4: Build the PCIe and xHCI drivers into the firmware Pete Batard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAEFTgixaNwF9Pawwor7yBV=9NP+Vtx7q+OvV=tENeTNz9ZqymQ@mail.gmail.com' \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox