mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 05:25:45 +01:00 
			
		
		
		
	https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
		
			
				
	
	
		
			221 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Plug a PciSegmentLib backend into PciCapLib, for config space access.
 | 
						|
 | 
						|
  Copyright (C) 2018, Red Hat, Inc.
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
**/
 | 
						|
 | 
						|
#include <IndustryStandard/Pci23.h>
 | 
						|
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/PciSegmentLib.h>
 | 
						|
 | 
						|
#include "BasePciCapPciSegmentLib.h"
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Read the config space of a given PCI device (both normal and extended).
 | 
						|
 | 
						|
  SegmentDevReadConfig() performs as few config space accesses as possible
 | 
						|
  (without attempting 64-bit wide accesses).
 | 
						|
 | 
						|
  @param[in] PciDevice           Implementation-specific unique representation
 | 
						|
                                 of the PCI device in the PCI hierarchy.
 | 
						|
 | 
						|
  @param[in] SourceOffset        Source offset in the config space of the PCI
 | 
						|
                                 device to start reading from.
 | 
						|
 | 
						|
  @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 config
 | 
						|
                              space to DestinationBuffer.
 | 
						|
 | 
						|
  @retval RETURN_UNSUPPORTED  Accessing Size bytes from SourceOffset exceeds
 | 
						|
                              the config space limit of the PCI device.
 | 
						|
                              Although PCI_CAP_DEV_READ_CONFIG allows reading
 | 
						|
                              fewer than Size bytes in this case,
 | 
						|
                              SegmentDevReadConfig() will read none.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SegmentDevReadConfig (
 | 
						|
  IN  PCI_CAP_DEV *PciDevice,
 | 
						|
  IN  UINT16      SourceOffset,
 | 
						|
  OUT VOID        *DestinationBuffer,
 | 
						|
  IN  UINT16      Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEGMENT_DEV *SegmentDev;
 | 
						|
  UINT16      ConfigSpaceSize;
 | 
						|
  UINT64      SourceAddress;
 | 
						|
 | 
						|
  SegmentDev = SEGMENT_DEV_FROM_PCI_CAP_DEV (PciDevice);
 | 
						|
  ConfigSpaceSize = (SegmentDev->MaxDomain == PciCapNormal ?
 | 
						|
                     PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET);
 | 
						|
  //
 | 
						|
  // Note that all UINT16 variables below are promoted to INT32, and the
 | 
						|
  // addition and the comparison is carried out in INT32.
 | 
						|
  //
 | 
						|
  if (SourceOffset + Size > ConfigSpaceSize) {
 | 
						|
    return RETURN_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  SourceAddress = PCI_SEGMENT_LIB_ADDRESS (SegmentDev->SegmentNr,
 | 
						|
                    SegmentDev->BusNr, SegmentDev->DeviceNr,
 | 
						|
                    SegmentDev->FunctionNr, SourceOffset);
 | 
						|
  PciSegmentReadBuffer (SourceAddress, Size, DestinationBuffer);
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Write the config space of a given PCI device (both normal and extended).
 | 
						|
 | 
						|
  SegmentDevWriteConfig() performs as few config space accesses as possible
 | 
						|
  (without attempting 64-bit wide accesses).
 | 
						|
 | 
						|
  @param[in] PciDevice          Implementation-specific unique representation
 | 
						|
                                of the PCI device in the PCI hierarchy.
 | 
						|
 | 
						|
  @param[in] DestinationOffset  Destination offset in the config space of the
 | 
						|
                                PCI device to start writing at.
 | 
						|
 | 
						|
  @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 config space.
 | 
						|
 | 
						|
  @retval RETURN_UNSUPPORTED  Accessing Size bytes at DestinationOffset exceeds
 | 
						|
                              the config space limit of the PCI device.
 | 
						|
                              Although PCI_CAP_DEV_WRITE_CONFIG allows writing
 | 
						|
                              fewer than Size bytes in this case,
 | 
						|
                              SegmentDevWriteConfig() will write none.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SegmentDevWriteConfig (
 | 
						|
  IN PCI_CAP_DEV *PciDevice,
 | 
						|
  IN UINT16      DestinationOffset,
 | 
						|
  IN VOID        *SourceBuffer,
 | 
						|
  IN UINT16      Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEGMENT_DEV *SegmentDev;
 | 
						|
  UINT16      ConfigSpaceSize;
 | 
						|
  UINT64      DestinationAddress;
 | 
						|
 | 
						|
  SegmentDev = SEGMENT_DEV_FROM_PCI_CAP_DEV (PciDevice);
 | 
						|
  ConfigSpaceSize = (SegmentDev->MaxDomain == PciCapNormal ?
 | 
						|
                     PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET);
 | 
						|
  //
 | 
						|
  // Note that all UINT16 variables below are promoted to INT32, and the
 | 
						|
  // addition and the comparison is carried out in INT32.
 | 
						|
  //
 | 
						|
  if (DestinationOffset + Size > ConfigSpaceSize) {
 | 
						|
    return RETURN_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  DestinationAddress = PCI_SEGMENT_LIB_ADDRESS (SegmentDev->SegmentNr,
 | 
						|
                         SegmentDev->BusNr, SegmentDev->DeviceNr,
 | 
						|
                         SegmentDev->FunctionNr, DestinationOffset);
 | 
						|
  PciSegmentWriteBuffer (DestinationAddress, Size, SourceBuffer);
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Create a PCI_CAP_DEV object from the PCI Segment:Bus:Device.Function
 | 
						|
  quadruplet. The config space accessors are based upon PciSegmentLib.
 | 
						|
 | 
						|
  @param[in] MaxDomain   If MaxDomain is PciCapExtended, then
 | 
						|
                         PciDevice->ReadConfig() and PciDevice->WriteConfig()
 | 
						|
                         will delegate extended config space accesses too to
 | 
						|
                         PciSegmentReadBuffer() and PciSegmentWriteBuffer(),
 | 
						|
                         respectively. Otherwise, PciDevice->ReadConfig() and
 | 
						|
                         PciDevice->WriteConfig() will reject accesses to
 | 
						|
                         extended config space with RETURN_UNSUPPORTED, without
 | 
						|
                         calling PciSegmentReadBuffer() or
 | 
						|
                         PciSegmentWriteBuffer(). By setting MaxDomain to
 | 
						|
                         PciCapNormal, the platform can prevent undefined
 | 
						|
                         PciSegmentLib behavior when the PCI root bridge under
 | 
						|
                         the PCI device at Segment:Bus:Device.Function doesn't
 | 
						|
                         support extended config space.
 | 
						|
 | 
						|
  @param[in] Segment     16-bit wide segment number.
 | 
						|
 | 
						|
  @param[in] Bus         8-bit wide bus number.
 | 
						|
 | 
						|
  @param[in] Device      5-bit wide device number.
 | 
						|
 | 
						|
  @param[in] Function    3-bit wide function number.
 | 
						|
 | 
						|
  @param[out] PciDevice  The PCI_CAP_DEV object constructed as described above.
 | 
						|
                         PciDevice can be passed to the PciCapLib APIs.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS            PciDevice has been constructed and output.
 | 
						|
 | 
						|
  @retval RETURN_INVALID_PARAMETER  Device or Function does not fit in the
 | 
						|
                                    permitted number of bits.
 | 
						|
 | 
						|
  @retval RETURN_OUT_OF_RESOURCES   Memory allocation failed.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
PciCapPciSegmentDeviceInit (
 | 
						|
  IN  PCI_CAP_DOMAIN MaxDomain,
 | 
						|
  IN  UINT16         Segment,
 | 
						|
  IN  UINT8          Bus,
 | 
						|
  IN  UINT8          Device,
 | 
						|
  IN  UINT8          Function,
 | 
						|
  OUT PCI_CAP_DEV    **PciDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEGMENT_DEV *SegmentDev;
 | 
						|
 | 
						|
  if (Device > PCI_MAX_DEVICE || Function > PCI_MAX_FUNC) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  SegmentDev = AllocatePool (sizeof *SegmentDev);
 | 
						|
  if (SegmentDev == NULL) {
 | 
						|
    return RETURN_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  SegmentDev->Signature              = SEGMENT_DEV_SIG;
 | 
						|
  SegmentDev->MaxDomain              = MaxDomain;
 | 
						|
  SegmentDev->SegmentNr              = Segment;
 | 
						|
  SegmentDev->BusNr                  = Bus;
 | 
						|
  SegmentDev->DeviceNr               = Device;
 | 
						|
  SegmentDev->FunctionNr             = Function;
 | 
						|
  SegmentDev->BaseDevice.ReadConfig  = SegmentDevReadConfig;
 | 
						|
  SegmentDev->BaseDevice.WriteConfig = SegmentDevWriteConfig;
 | 
						|
 | 
						|
  *PciDevice = &SegmentDev->BaseDevice;
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Free the resources used by PciDevice.
 | 
						|
 | 
						|
  @param[in] PciDevice  The PCI_CAP_DEV object to free, originally produced by
 | 
						|
                        PciCapPciSegmentDeviceInit().
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PciCapPciSegmentDeviceUninit (
 | 
						|
  IN PCI_CAP_DEV *PciDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEGMENT_DEV *SegmentDev;
 | 
						|
 | 
						|
  SegmentDev = SEGMENT_DEV_FROM_PCI_CAP_DEV (PciDevice);
 | 
						|
  FreePool (SegmentDev);
 | 
						|
}
 |