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
> >
next prev parent 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