__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout OvmfPkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
		
			
				
	
	
		
			1087 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1087 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Work with PCI capabilities in PCI config space.
 | 
						|
 | 
						|
  Provides functions to parse capabilities lists, and to locate, describe, read
 | 
						|
  and write capabilities. PCI config space access is abstracted away.
 | 
						|
 | 
						|
  Copyright (C) 2018, Red Hat, Inc.
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
**/
 | 
						|
 | 
						|
#include <IndustryStandard/PciExpress21.h>
 | 
						|
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
 | 
						|
#include "BasePciCapLib.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Compare a standalone PCI_CAP_KEY against a PCI_CAP containing an embedded
 | 
						|
  PCI_CAP_KEY.
 | 
						|
 | 
						|
  @param[in] PciCapKey  Pointer to the bare PCI_CAP_KEY.
 | 
						|
 | 
						|
  @param[in] PciCap     Pointer to the PCI_CAP with the embedded PCI_CAP_KEY.
 | 
						|
 | 
						|
  @retval <0  If PciCapKey compares less than PciCap->Key.
 | 
						|
 | 
						|
  @retval  0  If PciCapKey compares equal to PciCap->Key.
 | 
						|
 | 
						|
  @retval >0  If PciCapKey compares greater than PciCap->Key.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
INTN
 | 
						|
EFIAPI
 | 
						|
ComparePciCapKey (
 | 
						|
  IN CONST VOID  *PciCapKey,
 | 
						|
  IN CONST VOID  *PciCap
 | 
						|
  )
 | 
						|
{
 | 
						|
  CONST PCI_CAP_KEY  *Key1;
 | 
						|
  CONST PCI_CAP_KEY  *Key2;
 | 
						|
 | 
						|
  Key1 = PciCapKey;
 | 
						|
  Key2 = &((CONST PCI_CAP *)PciCap)->Key;
 | 
						|
 | 
						|
  if (Key1->Domain < Key2->Domain) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Key1->Domain > Key2->Domain) {
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Key1->CapId < Key2->CapId) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Key1->CapId > Key2->CapId) {
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Key1->Instance < Key2->Instance) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Key1->Instance > Key2->Instance) {
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compare two PCI_CAP objects based on PCI_CAP.Key.
 | 
						|
 | 
						|
  @param[in] PciCap1  Pointer to the first PCI_CAP.
 | 
						|
 | 
						|
  @param[in] PciCap2  Pointer to the second PCI_CAP.
 | 
						|
 | 
						|
  @retval <0  If PciCap1 compares less than PciCap2.
 | 
						|
 | 
						|
  @retval  0  If PciCap1 compares equal to PciCap2.
 | 
						|
 | 
						|
  @retval >0  If PciCap1 compares greater than PciCap2.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
INTN
 | 
						|
EFIAPI
 | 
						|
ComparePciCap (
 | 
						|
  IN CONST VOID  *PciCap1,
 | 
						|
  IN CONST VOID  *PciCap2
 | 
						|
  )
 | 
						|
{
 | 
						|
  CONST PCI_CAP_KEY  *PciCap1Key;
 | 
						|
 | 
						|
  PciCap1Key = &((CONST PCI_CAP *)PciCap1)->Key;
 | 
						|
  return ComparePciCapKey (PciCap1Key, PciCap2);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compare the standalone UINT16 config space offset of a capability header
 | 
						|
  against a PCI_CAP containing an embedded Offset.
 | 
						|
 | 
						|
  @param[in] CapHdrOffset  Pointer to the bare UINT16 config space offset.
 | 
						|
 | 
						|
  @param[in] PciCap        Pointer to the PCI_CAP with the embedded Offset.
 | 
						|
 | 
						|
  @retval <0  If CapHdrOffset compares less than PciCap->Offset.
 | 
						|
 | 
						|
  @retval  0  If CapHdrOffset compares equal to PciCap->Offset.
 | 
						|
 | 
						|
  @retval >0  If CapHdrOffset compares greater than PciCap->Offset.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
INTN
 | 
						|
EFIAPI
 | 
						|
ComparePciCapOffsetKey (
 | 
						|
  IN CONST VOID  *CapHdrOffset,
 | 
						|
  IN CONST VOID  *PciCap
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  Offset1;
 | 
						|
  UINT16  Offset2;
 | 
						|
 | 
						|
  Offset1 = *(CONST UINT16 *)CapHdrOffset;
 | 
						|
  Offset2 = ((CONST PCI_CAP *)PciCap)->Offset;
 | 
						|
  //
 | 
						|
  // Note: both Offset1 and Offset2 are promoted to INT32 below, and the
 | 
						|
  // subtraction takes place between INT32 values.
 | 
						|
  //
 | 
						|
  return Offset1 - Offset2;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compare two PCI_CAP objects based on PCI_CAP.Offset.
 | 
						|
 | 
						|
  @param[in] PciCap1  Pointer to the first PCI_CAP.
 | 
						|
 | 
						|
  @param[in] PciCap2  Pointer to the second PCI_CAP.
 | 
						|
 | 
						|
  @retval <0  If PciCap1 compares less than PciCap2.
 | 
						|
 | 
						|
  @retval  0  If PciCap1 compares equal to PciCap2.
 | 
						|
 | 
						|
  @retval >0  If PciCap1 compares greater than PciCap2.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
INTN
 | 
						|
EFIAPI
 | 
						|
ComparePciCapOffset (
 | 
						|
  IN CONST VOID  *PciCap1,
 | 
						|
  IN CONST VOID  *PciCap2
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  Offset1;
 | 
						|
  UINT16  Offset2;
 | 
						|
 | 
						|
  Offset1 = ((CONST PCI_CAP *)PciCap1)->Offset;
 | 
						|
  Offset2 = ((CONST PCI_CAP *)PciCap2)->Offset;
 | 
						|
  //
 | 
						|
  // Note: both Offset1 and Offset2 are promoted to INT32 below, and the
 | 
						|
  // subtraction takes place between INT32 values.
 | 
						|
  //
 | 
						|
  return Offset1 - Offset2;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Insert a new instance of the PCI capability given by (Domain, CapId) in
 | 
						|
  CapList.
 | 
						|
 | 
						|
  @param[in,out] CapList        The PCI_CAP_LIST into which the new PCI_CAP
 | 
						|
                                should be inserted. CapList will own the new
 | 
						|
                                PCI_CAP structure.
 | 
						|
 | 
						|
  @param[in,out] CapHdrOffsets  Link the new PCI_CAP structure into the
 | 
						|
                                (non-owning) CapHdrOffsets collection as well.
 | 
						|
                                CapHdrOffsets orders the PCI_CAP structures
 | 
						|
                                based on the PCI_CAP.Offset member, and enables
 | 
						|
                                the calculation of PCI_CAP.MaxSizeHint.
 | 
						|
 | 
						|
  @param[in] Domain             Whether the capability is normal or extended.
 | 
						|
 | 
						|
  @param[in] CapId              Capability ID (specific to Domain).
 | 
						|
 | 
						|
  @param[in] Offset             Config space offset at which the standard
 | 
						|
                                header of the capability starts. The caller is
 | 
						|
                                responsible for ensuring that Offset be DWORD
 | 
						|
                                aligned. The caller is also responsible for
 | 
						|
                                ensuring that Offset be within the config space
 | 
						|
                                identified by Domain.
 | 
						|
 | 
						|
  @param[in] Version            The version number of the capability. The
 | 
						|
                                caller is responsible for passing 0 as Version
 | 
						|
                                if Domain is PciCapNormal.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS           Insertion successful.
 | 
						|
 | 
						|
  @retval RETURN_OUT_OF_RESOURCES  Memory allocation failed.
 | 
						|
 | 
						|
  @retval RETURN_DEVICE_ERROR      A PCI_CAP with Offset is already linked by
 | 
						|
                                   CapHdrOffsets. This indicates a loop in the
 | 
						|
                                   capabilities list being parsed.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
InsertPciCap (
 | 
						|
  IN OUT PCI_CAP_LIST        *CapList,
 | 
						|
  IN OUT ORDERED_COLLECTION  *CapHdrOffsets,
 | 
						|
  IN     PCI_CAP_DOMAIN      Domain,
 | 
						|
  IN     UINT16              CapId,
 | 
						|
  IN     UINT16              Offset,
 | 
						|
  IN     UINT8               Version
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_CAP                   *PciCap;
 | 
						|
  RETURN_STATUS             Status;
 | 
						|
  ORDERED_COLLECTION_ENTRY  *PciCapEntry;
 | 
						|
  PCI_CAP                   *InstanceZero;
 | 
						|
 | 
						|
  ASSERT ((Offset & 0x3) == 0);
 | 
						|
  ASSERT (
 | 
						|
    Offset < (Domain == PciCapNormal ?
 | 
						|
              PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET)
 | 
						|
    );
 | 
						|
  ASSERT (Domain == PciCapExtended || Version == 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Set InstanceZero to suppress incorrect compiler/analyzer warnings.
 | 
						|
  //
 | 
						|
  InstanceZero = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate PciCap, and populate it assuming it is the first occurrence of
 | 
						|
  // (Domain, CapId). Note that PciCap->MaxSizeHint is not assigned the final
 | 
						|
  // value just yet.
 | 
						|
  //
 | 
						|
  PciCap = AllocatePool (sizeof *PciCap);
 | 
						|
  if (PciCap == NULL) {
 | 
						|
    return RETURN_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  PciCap->Key.Domain                     = Domain;
 | 
						|
  PciCap->Key.CapId                      = CapId;
 | 
						|
  PciCap->Key.Instance                   = 0;
 | 
						|
  PciCap->NumInstancesUnion.NumInstances = 1;
 | 
						|
  PciCap->Offset                         = Offset;
 | 
						|
  PciCap->MaxSizeHint                    = 0;
 | 
						|
  PciCap->Version                        = Version;
 | 
						|
 | 
						|
  //
 | 
						|
  // Add PciCap to CapList.
 | 
						|
  //
 | 
						|
  Status = OrderedCollectionInsert (
 | 
						|
             CapList->Capabilities,
 | 
						|
             &PciCapEntry,
 | 
						|
             PciCap
 | 
						|
             );
 | 
						|
  if (RETURN_ERROR (Status)) {
 | 
						|
    if (Status == RETURN_OUT_OF_RESOURCES) {
 | 
						|
      goto FreePciCap;
 | 
						|
    }
 | 
						|
 | 
						|
    ASSERT (Status == RETURN_ALREADY_STARTED);
 | 
						|
    //
 | 
						|
    // PciCap is not the first instance of (Domain, CapId). Add it as a new
 | 
						|
    // instance, taking the current instance count from Instance#0. Note that
 | 
						|
    // we don't bump the instance count maintained in Instance#0 just yet, to
 | 
						|
    // keep rollback on errors simple.
 | 
						|
    //
 | 
						|
    InstanceZero                           = OrderedCollectionUserStruct (PciCapEntry);
 | 
						|
    PciCap->Key.Instance                   = InstanceZero->NumInstancesUnion.NumInstances;
 | 
						|
    PciCap->NumInstancesUnion.InstanceZero = InstanceZero;
 | 
						|
 | 
						|
    ASSERT (PciCap->Key.Instance > 0);
 | 
						|
    Status = OrderedCollectionInsert (
 | 
						|
               CapList->Capabilities,
 | 
						|
               &PciCapEntry,
 | 
						|
               PciCap
 | 
						|
               );
 | 
						|
    if (Status == RETURN_OUT_OF_RESOURCES) {
 | 
						|
      goto FreePciCap;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // At this point, PciCap has been inserted in CapList->Capabilities, either
 | 
						|
  // with Instance==0 or with Instance>0. PciCapEntry is the iterator that
 | 
						|
  // links PciCap.
 | 
						|
  //
 | 
						|
  ASSERT_RETURN_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Link PciCap into CapHdrOffsets too, to order it globally based on config
 | 
						|
  // space offset. Note that partial overlaps between capability headers is not
 | 
						|
  // possible: Offset is DWORD aligned, normal capability headers are 16-bit
 | 
						|
  // wide, and extended capability headers are 32-bit wide. Therefore any two
 | 
						|
  // capability headers either are distinct or start at the same offset
 | 
						|
  // (implying a loop in the respective capabilities list).
 | 
						|
  //
 | 
						|
  Status = OrderedCollectionInsert (CapHdrOffsets, NULL, PciCap);
 | 
						|
  if (RETURN_ERROR (Status)) {
 | 
						|
    if (Status == RETURN_ALREADY_STARTED) {
 | 
						|
      //
 | 
						|
      // Loop found; map return status accordingly.
 | 
						|
      //
 | 
						|
      Status = RETURN_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    goto DeletePciCapFromCapList;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Now we can bump the instance count maintained in Instance#0, if PciCap is
 | 
						|
  // not the first instance of (Domain, CapId).
 | 
						|
  //
 | 
						|
  if (PciCap->Key.Instance > 0) {
 | 
						|
    //
 | 
						|
    // Suppress invalid "nullptr dereference" compiler/analyzer warnings: the
 | 
						|
    // only way for "PciCap->Key.Instance" to be positive here is for it to
 | 
						|
    // have been assigned *from* dereferencing "InstanceZero" above.
 | 
						|
    //
 | 
						|
    ASSERT (InstanceZero != NULL);
 | 
						|
 | 
						|
    InstanceZero->NumInstancesUnion.NumInstances++;
 | 
						|
  }
 | 
						|
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
 | 
						|
DeletePciCapFromCapList:
 | 
						|
  OrderedCollectionDelete (CapList->Capabilities, PciCapEntry, NULL);
 | 
						|
 | 
						|
FreePciCap:
 | 
						|
  FreePool (PciCap);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate the MaxSizeHint member for a PCI_CAP object.
 | 
						|
 | 
						|
  CalculatePciCapMaxSizeHint() may only be called once all capability instances
 | 
						|
  have been successfully processed by InsertPciCap().
 | 
						|
 | 
						|
  @param[in,out] PciCap  The PCI_CAP object for which to calculate the
 | 
						|
                         MaxSizeHint member. The caller is responsible for
 | 
						|
                         passing a PCI_CAP object that has been created by a
 | 
						|
                         successful invocation of InsertPciCap().
 | 
						|
 | 
						|
  @param[in] NextPciCap  If NextPciCap is NULL, then the caller is responsible
 | 
						|
                         for PciCap to represent the capability instance with
 | 
						|
                         the highest header offset in all config space. If
 | 
						|
                         NextPciCap is not NULL, then the caller is responsible
 | 
						|
                         for (a) having created NextPciCap with a successful
 | 
						|
                         invocation of InsertPciCap(), and (b) NextPciCap being
 | 
						|
                         the direct successor of PciCap in config space offset
 | 
						|
                         order, as ordered by ComparePciCapOffset().
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
CalculatePciCapMaxSizeHint (
 | 
						|
  IN OUT PCI_CAP  *PciCap,
 | 
						|
  IN     PCI_CAP  *NextPciCap OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  ConfigSpaceSize;
 | 
						|
 | 
						|
  ConfigSpaceSize = (PciCap->Key.Domain == PciCapNormal ?
 | 
						|
                     PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET);
 | 
						|
  //
 | 
						|
  // The following is guaranteed by the interface contract on
 | 
						|
  // CalculatePciCapMaxSizeHint().
 | 
						|
  //
 | 
						|
  ASSERT (NextPciCap == NULL || PciCap->Offset < NextPciCap->Offset);
 | 
						|
  //
 | 
						|
  // The following is guaranteed by the interface contract on InsertPciCap().
 | 
						|
  //
 | 
						|
  ASSERT (PciCap->Offset < ConfigSpaceSize);
 | 
						|
  //
 | 
						|
  // Thus we can safely subtract PciCap->Offset from either of
 | 
						|
  // - ConfigSpaceSize
 | 
						|
  // - and NextPciCap->Offset (if NextPciCap is not NULL).
 | 
						|
  //
 | 
						|
  // PciCap extends from PciCap->Offset to NextPciCap->Offset (if any), except
 | 
						|
  // it cannot cross config space boundary.
 | 
						|
  //
 | 
						|
  if ((NextPciCap == NULL) || (NextPciCap->Offset >= ConfigSpaceSize)) {
 | 
						|
    PciCap->MaxSizeHint = ConfigSpaceSize - PciCap->Offset;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  PciCap->MaxSizeHint = NextPciCap->Offset - PciCap->Offset;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Debug dump a PCI_CAP_LIST object at the DEBUG_VERBOSE level.
 | 
						|
 | 
						|
  @param[in] CapList  The PCI_CAP_LIST object to dump.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
DebugDumpPciCapList (
 | 
						|
  IN PCI_CAP_LIST  *CapList
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEBUG_CODE_BEGIN ();
 | 
						|
  ORDERED_COLLECTION_ENTRY  *PciCapEntry;
 | 
						|
 | 
						|
  for (PciCapEntry = OrderedCollectionMin (CapList->Capabilities);
 | 
						|
       PciCapEntry != NULL;
 | 
						|
       PciCapEntry = OrderedCollectionNext (PciCapEntry))
 | 
						|
  {
 | 
						|
    PCI_CAP        *PciCap;
 | 
						|
    RETURN_STATUS  Status;
 | 
						|
    PCI_CAP_INFO   Info;
 | 
						|
 | 
						|
    PciCap = OrderedCollectionUserStruct (PciCapEntry);
 | 
						|
    Status = PciCapGetInfo (PciCap, &Info);
 | 
						|
    //
 | 
						|
    // PciCapGetInfo() cannot fail in this library instance.
 | 
						|
    //
 | 
						|
    ASSERT_RETURN_ERROR (Status);
 | 
						|
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_VERBOSE,
 | 
						|
      "%a:%a: %a 0x%04x %03u/%03u v0x%x @0x%03x+0x%03x\n",
 | 
						|
      gEfiCallerBaseName,
 | 
						|
      __func__,
 | 
						|
      (Info.Domain == PciCapNormal ? "Norm" : "Extd"),
 | 
						|
      Info.CapId,
 | 
						|
      Info.Instance,
 | 
						|
      Info.NumInstances,
 | 
						|
      Info.Version,
 | 
						|
      Info.Offset,
 | 
						|
      Info.MaxSizeHint
 | 
						|
      ));
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE_END ();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Empty a collection of PCI_CAP structures, optionally releasing the referenced
 | 
						|
  PCI_CAP structures themselves. Release the collection at last.
 | 
						|
 | 
						|
  @param[in,out] PciCapCollection  The collection to empty and release.
 | 
						|
 | 
						|
  @param[in] FreePciCap            TRUE if the PCI_CAP structures linked by
 | 
						|
                                   PciCapCollection should be released. When
 | 
						|
                                   FALSE, the caller is responsible for
 | 
						|
                                   retaining at least one reference to each
 | 
						|
                                   PCI_CAP structure originally linked by
 | 
						|
                                   PciCapCollection.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
EmptyAndUninitPciCapCollection (
 | 
						|
  IN OUT ORDERED_COLLECTION  *PciCapCollection,
 | 
						|
  IN     BOOLEAN             FreePciCap
 | 
						|
  )
 | 
						|
{
 | 
						|
  ORDERED_COLLECTION_ENTRY  *PciCapEntry;
 | 
						|
  ORDERED_COLLECTION_ENTRY  *NextEntry;
 | 
						|
 | 
						|
  for (PciCapEntry = OrderedCollectionMin (PciCapCollection);
 | 
						|
       PciCapEntry != NULL;
 | 
						|
       PciCapEntry = NextEntry)
 | 
						|
  {
 | 
						|
    PCI_CAP  *PciCap;
 | 
						|
 | 
						|
    NextEntry = OrderedCollectionNext (PciCapEntry);
 | 
						|
    OrderedCollectionDelete (PciCapCollection, PciCapEntry, (VOID **)&PciCap);
 | 
						|
    if (FreePciCap) {
 | 
						|
      FreePool (PciCap);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  OrderedCollectionUninit (PciCapCollection);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parse the capabilities lists (both normal and extended, as applicable) of a
 | 
						|
  PCI device.
 | 
						|
 | 
						|
  If the PCI device has no capabilities, that per se will not fail
 | 
						|
  PciCapListInit(); an empty capabilities list will be represented.
 | 
						|
 | 
						|
  If the PCI device is found to be PCI Express, then an attempt will be made to
 | 
						|
  parse the extended capabilities list as well. If the first extended config
 | 
						|
  space access -- via PciDevice->ReadConfig() with SourceOffset=0x100 and
 | 
						|
  Size=4 -- fails, that per se will not fail PciCapListInit(); the device will
 | 
						|
  be assumed to have no extended capabilities.
 | 
						|
 | 
						|
  @param[in] PciDevice  Implementation-specific unique representation of the
 | 
						|
                        PCI device in the PCI hierarchy.
 | 
						|
 | 
						|
  @param[out] CapList   Opaque data structure that holds an in-memory
 | 
						|
                        representation of the parsed capabilities lists of
 | 
						|
                        PciDevice.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS           The capabilities lists have been parsed from
 | 
						|
                                   config space.
 | 
						|
 | 
						|
  @retval RETURN_OUT_OF_RESOURCES  Memory allocation failed.
 | 
						|
 | 
						|
  @retval RETURN_DEVICE_ERROR      A loop or some other kind of invalid pointer
 | 
						|
                                   was detected in the capabilities lists of
 | 
						|
                                   PciDevice.
 | 
						|
 | 
						|
  @return                          Error codes propagated from
 | 
						|
                                   PciDevice->ReadConfig().
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
PciCapListInit (
 | 
						|
  IN  PCI_CAP_DEV   *PciDevice,
 | 
						|
  OUT PCI_CAP_LIST  **CapList
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_CAP_LIST              *OutCapList;
 | 
						|
  RETURN_STATUS             Status;
 | 
						|
  ORDERED_COLLECTION        *CapHdrOffsets;
 | 
						|
  UINT16                    PciStatusReg;
 | 
						|
  BOOLEAN                   DeviceIsExpress;
 | 
						|
  ORDERED_COLLECTION_ENTRY  *OffsetEntry;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate the output structure.
 | 
						|
  //
 | 
						|
  OutCapList = AllocatePool (sizeof *OutCapList);
 | 
						|
  if (OutCapList == NULL) {
 | 
						|
    return RETURN_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The OutCapList->Capabilities collection owns the PCI_CAP structures and
 | 
						|
  // orders them based on PCI_CAP.Key.
 | 
						|
  //
 | 
						|
  OutCapList->Capabilities = OrderedCollectionInit (
 | 
						|
                               ComparePciCap,
 | 
						|
                               ComparePciCapKey
 | 
						|
                               );
 | 
						|
  if (OutCapList->Capabilities == NULL) {
 | 
						|
    Status = RETURN_OUT_OF_RESOURCES;
 | 
						|
    goto FreeOutCapList;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The (temporary) CapHdrOffsets collection only references PCI_CAP
 | 
						|
  // structures, and orders them based on PCI_CAP.Offset.
 | 
						|
  //
 | 
						|
  CapHdrOffsets = OrderedCollectionInit (
 | 
						|
                    ComparePciCapOffset,
 | 
						|
                    ComparePciCapOffsetKey
 | 
						|
                    );
 | 
						|
  if (CapHdrOffsets == NULL) {
 | 
						|
    Status = RETURN_OUT_OF_RESOURCES;
 | 
						|
    goto FreeCapabilities;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Whether the device is PCI Express depends on the normal capability with
 | 
						|
  // identifier EFI_PCI_CAPABILITY_ID_PCIEXP.
 | 
						|
  //
 | 
						|
  DeviceIsExpress = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether a normal capabilities list is present. If there's none,
 | 
						|
  // that's not an error; we'll just return OutCapList->Capabilities empty.
 | 
						|
  //
 | 
						|
  Status = PciDevice->ReadConfig (
 | 
						|
                        PciDevice,
 | 
						|
                        PCI_PRIMARY_STATUS_OFFSET,
 | 
						|
                        &PciStatusReg,
 | 
						|
                        sizeof PciStatusReg
 | 
						|
                        );
 | 
						|
  if (RETURN_ERROR (Status)) {
 | 
						|
    goto FreeCapHdrOffsets;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((PciStatusReg & EFI_PCI_STATUS_CAPABILITY) != 0) {
 | 
						|
    UINT8  NormalCapHdrOffset;
 | 
						|
 | 
						|
    //
 | 
						|
    // Fetch the start offset of the normal capabilities list.
 | 
						|
    //
 | 
						|
    Status = PciDevice->ReadConfig (
 | 
						|
                          PciDevice,
 | 
						|
                          PCI_CAPBILITY_POINTER_OFFSET,
 | 
						|
                          &NormalCapHdrOffset,
 | 
						|
                          sizeof NormalCapHdrOffset
 | 
						|
                          );
 | 
						|
    if (RETURN_ERROR (Status)) {
 | 
						|
      goto FreeCapHdrOffsets;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Traverse the normal capabilities list.
 | 
						|
    //
 | 
						|
    NormalCapHdrOffset &= 0xFC;
 | 
						|
    while (NormalCapHdrOffset > 0) {
 | 
						|
      EFI_PCI_CAPABILITY_HDR  NormalCapHdr;
 | 
						|
 | 
						|
      Status = PciDevice->ReadConfig (
 | 
						|
                            PciDevice,
 | 
						|
                            NormalCapHdrOffset,
 | 
						|
                            &NormalCapHdr,
 | 
						|
                            sizeof NormalCapHdr
 | 
						|
                            );
 | 
						|
      if (RETURN_ERROR (Status)) {
 | 
						|
        goto FreeCapHdrOffsets;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = InsertPciCap (
 | 
						|
                 OutCapList,
 | 
						|
                 CapHdrOffsets,
 | 
						|
                 PciCapNormal,
 | 
						|
                 NormalCapHdr.CapabilityID,
 | 
						|
                 NormalCapHdrOffset,
 | 
						|
                 0
 | 
						|
                 );
 | 
						|
      if (RETURN_ERROR (Status)) {
 | 
						|
        goto FreeCapHdrOffsets;
 | 
						|
      }
 | 
						|
 | 
						|
      if (NormalCapHdr.CapabilityID == EFI_PCI_CAPABILITY_ID_PCIEXP) {
 | 
						|
        DeviceIsExpress = TRUE;
 | 
						|
      }
 | 
						|
 | 
						|
      NormalCapHdrOffset = NormalCapHdr.NextItemPtr & 0xFC;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If the device has been found PCI Express, attempt to traverse the extended
 | 
						|
  // capabilities list. It starts right after the normal config space.
 | 
						|
  //
 | 
						|
  if (DeviceIsExpress) {
 | 
						|
    UINT16  ExtendedCapHdrOffset;
 | 
						|
 | 
						|
    ExtendedCapHdrOffset = PCI_MAX_CONFIG_OFFSET;
 | 
						|
    while (ExtendedCapHdrOffset > 0) {
 | 
						|
      PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER  ExtendedCapHdr;
 | 
						|
 | 
						|
      Status = PciDevice->ReadConfig (
 | 
						|
                            PciDevice,
 | 
						|
                            ExtendedCapHdrOffset,
 | 
						|
                            &ExtendedCapHdr,
 | 
						|
                            sizeof ExtendedCapHdr
 | 
						|
                            );
 | 
						|
      //
 | 
						|
      // If the first extended config space access fails, assume the device has
 | 
						|
      // no extended capabilities. If the first extended config space access
 | 
						|
      // succeeds but we read an "all bits zero" extended capability header,
 | 
						|
      // that means (by spec) the device has no extended capabilities.
 | 
						|
      //
 | 
						|
      if ((ExtendedCapHdrOffset == PCI_MAX_CONFIG_OFFSET) &&
 | 
						|
          (RETURN_ERROR (Status) ||
 | 
						|
           IsZeroBuffer (&ExtendedCapHdr, sizeof ExtendedCapHdr)))
 | 
						|
      {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      if (RETURN_ERROR (Status)) {
 | 
						|
        goto FreeCapHdrOffsets;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = InsertPciCap (
 | 
						|
                 OutCapList,
 | 
						|
                 CapHdrOffsets,
 | 
						|
                 PciCapExtended,
 | 
						|
                 (UINT16)ExtendedCapHdr.CapabilityId,
 | 
						|
                 ExtendedCapHdrOffset,
 | 
						|
                 (UINT8)ExtendedCapHdr.CapabilityVersion
 | 
						|
                 );
 | 
						|
      if (RETURN_ERROR (Status)) {
 | 
						|
        goto FreeCapHdrOffsets;
 | 
						|
      }
 | 
						|
 | 
						|
      ExtendedCapHdrOffset = ExtendedCapHdr.NextCapabilityOffset & 0xFFC;
 | 
						|
      if ((ExtendedCapHdrOffset > 0) &&
 | 
						|
          (ExtendedCapHdrOffset < PCI_MAX_CONFIG_OFFSET))
 | 
						|
      {
 | 
						|
        //
 | 
						|
        // Invalid capability pointer.
 | 
						|
        //
 | 
						|
        Status = RETURN_DEVICE_ERROR;
 | 
						|
        goto FreeCapHdrOffsets;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Both capabilities lists have been parsed; compute the PCI_CAP.MaxSizeHint
 | 
						|
  // members if at least one capability has been found. In parallel, evacuate
 | 
						|
  // the CapHdrOffsets collection.
 | 
						|
  //
 | 
						|
  // At first, set OffsetEntry to the iterator of the PCI_CAP object with the
 | 
						|
  // lowest Offset (if such exists).
 | 
						|
  //
 | 
						|
  OffsetEntry = OrderedCollectionMin (CapHdrOffsets);
 | 
						|
  if (OffsetEntry != NULL) {
 | 
						|
    ORDERED_COLLECTION_ENTRY  *NextOffsetEntry;
 | 
						|
    PCI_CAP                   *PciCap;
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize NextOffsetEntry to the iterator of the PCI_CAP object with
 | 
						|
    // the second lowest Offset (if such exists).
 | 
						|
    //
 | 
						|
    NextOffsetEntry = OrderedCollectionNext (OffsetEntry);
 | 
						|
    //
 | 
						|
    // Calculate MaxSizeHint for all PCI_CAP objects except the one with the
 | 
						|
    // highest Offset.
 | 
						|
    //
 | 
						|
    while (NextOffsetEntry != NULL) {
 | 
						|
      PCI_CAP  *NextPciCap;
 | 
						|
 | 
						|
      OrderedCollectionDelete (CapHdrOffsets, OffsetEntry, (VOID **)&PciCap);
 | 
						|
      NextPciCap = OrderedCollectionUserStruct (NextOffsetEntry);
 | 
						|
      CalculatePciCapMaxSizeHint (PciCap, NextPciCap);
 | 
						|
 | 
						|
      OffsetEntry     = NextOffsetEntry;
 | 
						|
      NextOffsetEntry = OrderedCollectionNext (OffsetEntry);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Calculate MaxSizeHint for the PCI_CAP object with the highest Offset.
 | 
						|
    //
 | 
						|
    OrderedCollectionDelete (CapHdrOffsets, OffsetEntry, (VOID **)&PciCap);
 | 
						|
    CalculatePciCapMaxSizeHint (PciCap, NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (OrderedCollectionIsEmpty (CapHdrOffsets));
 | 
						|
  OrderedCollectionUninit (CapHdrOffsets);
 | 
						|
 | 
						|
  DebugDumpPciCapList (OutCapList);
 | 
						|
  *CapList = OutCapList;
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
 | 
						|
FreeCapHdrOffsets:
 | 
						|
  EmptyAndUninitPciCapCollection (CapHdrOffsets, FALSE);
 | 
						|
 | 
						|
FreeCapabilities:
 | 
						|
  EmptyAndUninitPciCapCollection (OutCapList->Capabilities, TRUE);
 | 
						|
 | 
						|
FreeOutCapList:
 | 
						|
  FreePool (OutCapList);
 | 
						|
 | 
						|
  ASSERT (RETURN_ERROR (Status));
 | 
						|
  DEBUG ((
 | 
						|
    DEBUG_ERROR,
 | 
						|
    "%a:%a: %r\n",
 | 
						|
    gEfiCallerBaseName,
 | 
						|
    __func__,
 | 
						|
    Status
 | 
						|
    ));
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Free the resources used by CapList.
 | 
						|
 | 
						|
  @param[in] CapList  The PCI_CAP_LIST object to free, originally produced by
 | 
						|
                      PciCapListInit().
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PciCapListUninit (
 | 
						|
  IN PCI_CAP_LIST  *CapList
 | 
						|
  )
 | 
						|
{
 | 
						|
  EmptyAndUninitPciCapCollection (CapList->Capabilities, TRUE);
 | 
						|
  FreePool (CapList);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Locate a capability instance in the parsed capabilities lists.
 | 
						|
 | 
						|
  @param[in] CapList   The PCI_CAP_LIST object produced by PciCapListInit().
 | 
						|
 | 
						|
  @param[in] Domain    Distinguishes whether CapId is 8-bit wide and
 | 
						|
                       interpreted in normal config space, or 16-bit wide and
 | 
						|
                       interpreted in extended config space. Capability ID
 | 
						|
                       definitions are relative to domain.
 | 
						|
 | 
						|
  @param[in] CapId     Capability identifier to look up.
 | 
						|
 | 
						|
  @param[in] Instance  Domain and CapId may identify a multi-instance
 | 
						|
                       capability. When Instance is zero, the first instance of
 | 
						|
                       the capability is located (in list traversal order --
 | 
						|
                       which may not mean increasing config space offset
 | 
						|
                       order). Higher Instance values locate subsequent
 | 
						|
                       instances of the same capability (in list traversal
 | 
						|
                       order).
 | 
						|
 | 
						|
  @param[out] Cap      The capability instance that matches the search
 | 
						|
                       criteria. Cap is owned by CapList and becomes invalid
 | 
						|
                       when CapList is freed with PciCapListUninit().
 | 
						|
                       PciCapListFindCap() may be called with Cap set to NULL,
 | 
						|
                       in order to test the existence of a specific capability
 | 
						|
                       instance.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS    The capability instance identified by (Domain,
 | 
						|
                            CapId, Instance) has been found.
 | 
						|
 | 
						|
  @retval RETURN_NOT_FOUND  The requested (Domain, CapId, Instance) capability
 | 
						|
                            instance does not exist.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
PciCapListFindCap (
 | 
						|
  IN  PCI_CAP_LIST    *CapList,
 | 
						|
  IN  PCI_CAP_DOMAIN  Domain,
 | 
						|
  IN  UINT16          CapId,
 | 
						|
  IN  UINT16          Instance,
 | 
						|
  OUT PCI_CAP         **Cap    OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_CAP_KEY               Key;
 | 
						|
  ORDERED_COLLECTION_ENTRY  *PciCapEntry;
 | 
						|
 | 
						|
  Key.Domain   = Domain;
 | 
						|
  Key.CapId    = CapId;
 | 
						|
  Key.Instance = Instance;
 | 
						|
 | 
						|
  PciCapEntry = OrderedCollectionFind (CapList->Capabilities, &Key);
 | 
						|
  if (PciCapEntry == NULL) {
 | 
						|
    return RETURN_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Cap != NULL) {
 | 
						|
    *Cap = OrderedCollectionUserStruct (PciCapEntry);
 | 
						|
  }
 | 
						|
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Locate the first instance of the capability given by (Domain, CapId) such
 | 
						|
  that the instance's Version is greater than or equal to MinVersion.
 | 
						|
 | 
						|
  This is a convenience function that may save client code calls to
 | 
						|
  PciCapListFindCap() and PciCapGetInfo().
 | 
						|
 | 
						|
  @param[in] CapList     The PCI_CAP_LIST object produced by PciCapListInit().
 | 
						|
 | 
						|
  @param[in] Domain      Distinguishes whether CapId is 8-bit wide and
 | 
						|
                         interpreted in normal config space, or 16-bit wide and
 | 
						|
                         interpreted in extended config space. Capability ID
 | 
						|
                         definitions are relative to domain.
 | 
						|
 | 
						|
  @param[in] CapId       Capability identifier to look up.
 | 
						|
 | 
						|
  @param[in] MinVersion  The minimum version that the capability instance is
 | 
						|
                         required to have. Note that all capability instances
 | 
						|
                         in Domain=PciCapNormal have Version=0.
 | 
						|
 | 
						|
  @param[out] Cap        The first capability instance that matches the search
 | 
						|
                         criteria. Cap is owned by CapList and becomes invalid
 | 
						|
                         when CapList is freed with PciCapListUninit().
 | 
						|
                         PciCapListFindCapVersion() may be called with Cap set
 | 
						|
                         to NULL, in order just to test whether the search
 | 
						|
                         criteria are satisfiable.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS    The first capability instance matching (Domain,
 | 
						|
                            CapId, MinVersion) has been located.
 | 
						|
 | 
						|
  @retval RETURN_NOT_FOUND  No capability instance matches (Domain, CapId,
 | 
						|
                            MinVersion).
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
PciCapListFindCapVersion (
 | 
						|
  IN  PCI_CAP_LIST    *CapList,
 | 
						|
  IN  PCI_CAP_DOMAIN  Domain,
 | 
						|
  IN  UINT16          CapId,
 | 
						|
  IN  UINT8           MinVersion,
 | 
						|
  OUT PCI_CAP         **Cap      OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_CAP_KEY               Key;
 | 
						|
  ORDERED_COLLECTION_ENTRY  *PciCapEntry;
 | 
						|
 | 
						|
  //
 | 
						|
  // Start the version checks at Instance#0 of (Domain, CapId).
 | 
						|
  //
 | 
						|
  Key.Domain   = Domain;
 | 
						|
  Key.CapId    = CapId;
 | 
						|
  Key.Instance = 0;
 | 
						|
 | 
						|
  for (PciCapEntry = OrderedCollectionFind (CapList->Capabilities, &Key);
 | 
						|
       PciCapEntry != NULL;
 | 
						|
       PciCapEntry = OrderedCollectionNext (PciCapEntry))
 | 
						|
  {
 | 
						|
    PCI_CAP  *PciCap;
 | 
						|
 | 
						|
    PciCap = OrderedCollectionUserStruct (PciCapEntry);
 | 
						|
    //
 | 
						|
    // PCI_CAP.Key ordering keeps instances of the same (Domain, CapId)
 | 
						|
    // adjacent to each other, so stop searching if either Domain or CapId
 | 
						|
    // changes.
 | 
						|
    //
 | 
						|
    if ((PciCap->Key.Domain != Domain) || (PciCap->Key.CapId != CapId)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (PciCap->Version >= MinVersion) {
 | 
						|
      //
 | 
						|
      // Match found.
 | 
						|
      //
 | 
						|
      if (Cap != NULL) {
 | 
						|
        *Cap = PciCap;
 | 
						|
      }
 | 
						|
 | 
						|
      return RETURN_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return RETURN_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get information about a PCI Capability instance.
 | 
						|
 | 
						|
  @param[in] Cap    The capability instance to get info about, located with
 | 
						|
                    PciCapListFindCap*().
 | 
						|
 | 
						|
  @param[out] Info  A PCI_CAP_INFO structure that describes the properties of
 | 
						|
                    Cap.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS  Fields of Info have been set.
 | 
						|
 | 
						|
  @return                 Unspecified error codes, if filling in Info failed
 | 
						|
                          for some reason.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
PciCapGetInfo (
 | 
						|
  IN  PCI_CAP       *Cap,
 | 
						|
  OUT PCI_CAP_INFO  *Info
 | 
						|
  )
 | 
						|
{
 | 
						|
  PCI_CAP  *InstanceZero;
 | 
						|
 | 
						|
  ASSERT (Info != NULL);
 | 
						|
 | 
						|
  InstanceZero = (Cap->Key.Instance == 0 ? Cap :
 | 
						|
                  Cap->NumInstancesUnion.InstanceZero);
 | 
						|
 | 
						|
  Info->Domain       = Cap->Key.Domain;
 | 
						|
  Info->CapId        = Cap->Key.CapId;
 | 
						|
  Info->NumInstances = InstanceZero->NumInstancesUnion.NumInstances;
 | 
						|
  Info->Instance     = Cap->Key.Instance;
 | 
						|
  Info->Offset       = Cap->Offset;
 | 
						|
  Info->MaxSizeHint  = Cap->MaxSizeHint;
 | 
						|
  Info->Version      = Cap->Version;
 | 
						|
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read a slice of a capability instance.
 | 
						|
 | 
						|
  The function performs as few config space accesses as possible (without
 | 
						|
  attempting 64-bit wide accesses). PciCapRead() performs bounds checking on
 | 
						|
  SourceOffsetInCap and Size, and only invokes PciDevice->ReadConfig() if the
 | 
						|
  requested transfer falls within Cap.
 | 
						|
 | 
						|
  @param[in] PciDevice           Implementation-specific unique representation
 | 
						|
                                 of the PCI device in the PCI hierarchy.
 | 
						|
 | 
						|
  @param[in] Cap                 The capability instance to read, located with
 | 
						|
                                 PciCapListFindCap*().
 | 
						|
 | 
						|
  @param[in] SourceOffsetInCap   Source offset relative to the capability
 | 
						|
                                 header to start reading from. A zero value
 | 
						|
                                 refers to the first byte of the capability
 | 
						|
                                 header.
 | 
						|
 | 
						|
  @param[out] DestinationBuffer  Buffer to store the read data to.
 | 
						|
 | 
						|
  @param[in] Size                The number of bytes to transfer.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS          Size bytes have been transferred from Cap to
 | 
						|
                                  DestinationBuffer.
 | 
						|
 | 
						|
  @retval RETURN_BAD_BUFFER_SIZE  Reading Size bytes starting from
 | 
						|
                                  SourceOffsetInCap would not (entirely) be
 | 
						|
                                  contained within Cap, as suggested by
 | 
						|
                                  PCI_CAP_INFO.MaxSizeHint. No bytes have been
 | 
						|
                                  read.
 | 
						|
 | 
						|
  @return                         Error codes propagated from
 | 
						|
                                  PciDevice->ReadConfig(). Fewer than Size
 | 
						|
                                  bytes may have been read.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
PciCapRead (
 | 
						|
  IN  PCI_CAP_DEV  *PciDevice,
 | 
						|
  IN  PCI_CAP      *Cap,
 | 
						|
  IN  UINT16       SourceOffsetInCap,
 | 
						|
  OUT VOID         *DestinationBuffer,
 | 
						|
  IN  UINT16       Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Note: all UINT16 values are promoted to INT32 below, and addition and
 | 
						|
  // comparison take place between INT32 values.
 | 
						|
  //
 | 
						|
  if (SourceOffsetInCap + Size > Cap->MaxSizeHint) {
 | 
						|
    return RETURN_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  return PciDevice->ReadConfig (
 | 
						|
                      PciDevice,
 | 
						|
                      Cap->Offset + SourceOffsetInCap,
 | 
						|
                      DestinationBuffer,
 | 
						|
                      Size
 | 
						|
                      );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Write a slice of a capability instance.
 | 
						|
 | 
						|
  The function performs as few config space accesses as possible (without
 | 
						|
  attempting 64-bit wide accesses). PciCapWrite() performs bounds checking on
 | 
						|
  DestinationOffsetInCap and Size, and only invokes PciDevice->WriteConfig() if
 | 
						|
  the requested transfer falls within Cap.
 | 
						|
 | 
						|
  @param[in] PciDevice               Implementation-specific unique
 | 
						|
                                     representation of the PCI device in the
 | 
						|
                                     PCI hierarchy.
 | 
						|
 | 
						|
  @param[in] Cap                     The capability instance to write, located
 | 
						|
                                     with PciCapListFindCap*().
 | 
						|
 | 
						|
  @param[in] DestinationOffsetInCap  Destination offset relative to the
 | 
						|
                                     capability header to start writing at. A
 | 
						|
                                     zero value refers to the first byte of the
 | 
						|
                                     capability header.
 | 
						|
 | 
						|
  @param[in] SourceBuffer            Buffer to read the data to be stored from.
 | 
						|
 | 
						|
  @param[in] Size                    The number of bytes to transfer.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS          Size bytes have been transferred from
 | 
						|
                                  SourceBuffer to Cap.
 | 
						|
 | 
						|
  @retval RETURN_BAD_BUFFER_SIZE  Writing Size bytes starting at
 | 
						|
                                  DestinationOffsetInCap would not (entirely)
 | 
						|
                                  be contained within Cap, as suggested by
 | 
						|
                                  PCI_CAP_INFO.MaxSizeHint. No bytes have been
 | 
						|
                                  written.
 | 
						|
 | 
						|
  @return                         Error codes propagated from
 | 
						|
                                  PciDevice->WriteConfig(). Fewer than Size
 | 
						|
                                  bytes may have been written.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
PciCapWrite (
 | 
						|
  IN PCI_CAP_DEV  *PciDevice,
 | 
						|
  IN PCI_CAP      *Cap,
 | 
						|
  IN UINT16       DestinationOffsetInCap,
 | 
						|
  IN VOID         *SourceBuffer,
 | 
						|
  IN UINT16       Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Note: all UINT16 values are promoted to INT32 below, and addition and
 | 
						|
  // comparison take place between INT32 values.
 | 
						|
  //
 | 
						|
  if (DestinationOffsetInCap + Size > Cap->MaxSizeHint) {
 | 
						|
    return RETURN_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  return PciDevice->WriteConfig (
 | 
						|
                      PciDevice,
 | 
						|
                      Cap->Offset + DestinationOffsetInCap,
 | 
						|
                      SourceBuffer,
 | 
						|
                      Size
 | 
						|
                      );
 | 
						|
}
 |