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);
 | |
| }
 |