--- /dev/null
+/** @file\r
+ Library class layered on top of PciCapLib that allows clients to plug an\r
+ EFI_PCI_IO_PROTOCOL backend into PciCapLib, for config space access.\r
+\r
+ Copyright (C) 2018, Red Hat, Inc.\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __PCI_CAP_PCI_IO_LIB_H__\r
+#define __PCI_CAP_PCI_IO_LIB_H__\r
+\r
+#include <Protocol/PciIo.h>\r
+\r
+#include <Library/PciCapLib.h>\r
+\r
+\r
+/**\r
+ Create a PCI_CAP_DEV object from an EFI_PCI_IO_PROTOCOL instance. The config\r
+ space accessors are based upon EFI_PCI_IO_PROTOCOL.Pci.Read() and\r
+ EFI_PCI_IO_PROTOCOL.Pci.Write().\r
+\r
+ @param[in] PciIo EFI_PCI_IO_PROTOCOL representation of the PCI device.\r
+\r
+ @param[out] PciDevice The PCI_CAP_DEV object constructed as described above.\r
+ PciDevice can be passed to the PciCapLib APIs.\r
+\r
+ @retval EFI_SUCCESS PciDevice has been constructed and output.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PciCapPciIoDeviceInit (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ OUT PCI_CAP_DEV **PciDevice\r
+ );\r
+\r
+\r
+/**\r
+ Free the resources used by PciDevice.\r
+\r
+ @param[in] PciDevice The PCI_CAP_DEV object to free, originally produced by\r
+ PciCapPciIoDeviceInit().\r
+**/\r
+VOID\r
+EFIAPI\r
+PciCapPciIoDeviceUninit (\r
+ IN PCI_CAP_DEV *PciDevice\r
+ );\r
+\r
+#endif // __PCI_CAP_PCI_IO_LIB_H__\r
--- /dev/null
+/** @file\r
+ Plug an EFI_PCI_IO_PROTOCOL backend into PciCapLib, for config space access.\r
+\r
+ Copyright (C) 2018, Red Hat, Inc.\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include "UefiPciCapPciIoLib.h"\r
+\r
+\r
+/**\r
+ Transfer bytes between the config space of a given PCI device and a memory\r
+ buffer.\r
+\r
+ ProtoDevTransferConfig() performs as few config space accesses as possible\r
+ (without attempting 64-bit wide accesses).\r
+\r
+ @param[in] PciIo The EFI_PCI_IO_PROTOCOL representation of the\r
+ PCI device.\r
+\r
+ @param[in] TransferFunction The EFI_PCI_IO_PROTOCOL_CONFIG function that\r
+ implements the transfer. The direction of the\r
+ transfer is inherent to TransferFunction.\r
+ TransferFunction() is required to return an\r
+ unspecified error if any sub-transfer within\r
+ Size bytes from ConfigOffset exceeds the config\r
+ space limit of the PCI device.\r
+\r
+ @param[in] ConfigOffset The offset in the config space of the PCI device\r
+ at which the transfer should commence.\r
+\r
+ @param[in,out] Buffer The memory buffer where the transfer should\r
+ occur.\r
+\r
+ @param[in] Size The number of bytes to transfer.\r
+\r
+ @retval EFI_SUCCESS Size bytes have been transferred between config space\r
+ and Buffer.\r
+\r
+ @return Error codes propagated from TransferFunction(). Fewer\r
+ than Size bytes may have been transferred.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ProtoDevTransferConfig (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_PCI_IO_PROTOCOL_CONFIG TransferFunction,\r
+ IN UINT16 ConfigOffset,\r
+ IN OUT UINT8 *Buffer,\r
+ IN UINT16 Size\r
+ )\r
+{\r
+ while (Size > 0) {\r
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+ UINT16 Count;\r
+ EFI_STATUS Status;\r
+ UINT16 Progress;\r
+\r
+ //\r
+ // Pick the largest access size that is allowed by the remaining transfer\r
+ // Size and by the alignment of ConfigOffset.\r
+ //\r
+ // When the largest access size is available, transfer as many bytes as\r
+ // possible in one iteration of the loop. Otherwise, transfer only one\r
+ // unit, to improve the alignment.\r
+ //\r
+ if (Size >= 4 && (ConfigOffset & 3) == 0) {\r
+ Width = EfiPciIoWidthUint32;\r
+ Count = Size >> Width;\r
+ } else if (Size >= 2 && (ConfigOffset & 1) == 0) {\r
+ Width = EfiPciIoWidthUint16;\r
+ Count = 1;\r
+ } else {\r
+ Width = EfiPciIoWidthUint8;\r
+ Count = 1;\r
+ }\r
+ Status = TransferFunction (PciIo, Width, ConfigOffset, Count, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Progress = Count << Width;\r
+ ConfigOffset += Progress;\r
+ Buffer += Progress;\r
+ Size -= Progress;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Read the config space of a given PCI device (both normal and extended).\r
+\r
+ ProtoDevReadConfig() performs as few config space accesses as possible\r
+ (without attempting 64-bit wide accesses).\r
+\r
+ ProtoDevReadConfig() returns an unspecified error if accessing Size bytes\r
+ from SourceOffset exceeds the config space limit of the PCI device. Fewer\r
+ than Size bytes may have been read in this case.\r
+\r
+ @param[in] PciDevice Implementation-specific unique representation\r
+ of the PCI device in the PCI hierarchy.\r
+\r
+ @param[in] SourceOffset Source offset in the config space of the PCI\r
+ device to start reading from.\r
+\r
+ @param[out] DestinationBuffer Buffer to store the read data to.\r
+\r
+ @param[in] Size The number of bytes to transfer.\r
+\r
+ @retval RETURN_SUCCESS Size bytes have been transferred from config space to\r
+ DestinationBuffer.\r
+\r
+ @return Error codes propagated from\r
+ EFI_PCI_IO_PROTOCOL.Pci.Read(). Fewer than Size bytes\r
+ may have been read.\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+EFIAPI\r
+ProtoDevReadConfig (\r
+ IN PCI_CAP_DEV *PciDevice,\r
+ IN UINT16 SourceOffset,\r
+ OUT VOID *DestinationBuffer,\r
+ IN UINT16 Size\r
+ )\r
+{\r
+ PROTO_DEV *ProtoDev;\r
+\r
+ ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);\r
+ return ProtoDevTransferConfig (ProtoDev->PciIo, ProtoDev->PciIo->Pci.Read,\r
+ SourceOffset, DestinationBuffer, Size);\r
+}\r
+\r
+\r
+/**\r
+ Write the config space of a given PCI device (both normal and extended).\r
+\r
+ ProtoDevWriteConfig() performs as few config space accesses as possible\r
+ (without attempting 64-bit wide accesses).\r
+\r
+ ProtoDevWriteConfig() returns an unspecified error if accessing Size bytes at\r
+ DestinationOffset exceeds the config space limit of the PCI device. Fewer\r
+ than Size bytes may have been written in this case.\r
+\r
+ @param[in] PciDevice Implementation-specific unique representation\r
+ of the PCI device in the PCI hierarchy.\r
+\r
+ @param[in] DestinationOffset Destination offset in the config space of the\r
+ PCI device to start writing at.\r
+\r
+ @param[in] SourceBuffer Buffer to read the data to be stored from.\r
+\r
+ @param[in] Size The number of bytes to transfer.\r
+\r
+ @retval RETURN_SUCCESS Size bytes have been transferred from SourceBuffer to\r
+ config space.\r
+\r
+ @return Error codes propagated from\r
+ EFI_PCI_IO_PROTOCOL.Pci.Write(). Fewer than Size\r
+ bytes may have been written.\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+EFIAPI\r
+ProtoDevWriteConfig (\r
+ IN PCI_CAP_DEV *PciDevice,\r
+ IN UINT16 DestinationOffset,\r
+ IN VOID *SourceBuffer,\r
+ IN UINT16 Size\r
+ )\r
+{\r
+ PROTO_DEV *ProtoDev;\r
+\r
+ ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);\r
+ return ProtoDevTransferConfig (ProtoDev->PciIo, ProtoDev->PciIo->Pci.Write,\r
+ DestinationOffset, SourceBuffer, Size);\r
+}\r
+\r
+\r
+/**\r
+ Create a PCI_CAP_DEV object from an EFI_PCI_IO_PROTOCOL instance. The config\r
+ space accessors are based upon EFI_PCI_IO_PROTOCOL.Pci.Read() and\r
+ EFI_PCI_IO_PROTOCOL.Pci.Write().\r
+\r
+ @param[in] PciIo EFI_PCI_IO_PROTOCOL representation of the PCI device.\r
+\r
+ @param[out] PciDevice The PCI_CAP_DEV object constructed as described above.\r
+ PciDevice can be passed to the PciCapLib APIs.\r
+\r
+ @retval EFI_SUCCESS PciDevice has been constructed and output.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PciCapPciIoDeviceInit (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ OUT PCI_CAP_DEV **PciDevice\r
+ )\r
+{\r
+ PROTO_DEV *ProtoDev;\r
+\r
+ ProtoDev = AllocatePool (sizeof *ProtoDev);\r
+ if (ProtoDev == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ProtoDev->Signature = PROTO_DEV_SIG;\r
+ ProtoDev->PciIo = PciIo;\r
+ ProtoDev->BaseDevice.ReadConfig = ProtoDevReadConfig;\r
+ ProtoDev->BaseDevice.WriteConfig = ProtoDevWriteConfig;\r
+\r
+ *PciDevice = &ProtoDev->BaseDevice;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Free the resources used by PciDevice.\r
+\r
+ @param[in] PciDevice The PCI_CAP_DEV object to free, originally produced by\r
+ PciCapPciIoDeviceInit().\r
+**/\r
+VOID\r
+EFIAPI\r
+PciCapPciIoDeviceUninit (\r
+ IN PCI_CAP_DEV *PciDevice\r
+ )\r
+{\r
+ PROTO_DEV *ProtoDev;\r
+\r
+ ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);\r
+ FreePool (ProtoDev);\r
+}\r
--- /dev/null
+/** @file\r
+ Plug an EFI_PCI_IO_PROTOCOL backend into PciCapLib, for config space access\r
+ -- internal macro and type definitions.\r
+\r
+ Copyright (C) 2018, Red Hat, Inc.\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __UEFI_PCI_CAP_PCI_IO_LIB_H__\r
+#define __UEFI_PCI_CAP_PCI_IO_LIB_H__\r
+\r
+#include <Library/DebugLib.h>\r
+\r
+#include <Library/PciCapPciIoLib.h>\r
+\r
+#define PROTO_DEV_SIG SIGNATURE_64 ('P', 'C', 'P', 'I', 'O', 'P', 'R', 'T')\r
+\r
+typedef struct {\r
+ //\r
+ // Signature identifying the derived class.\r
+ //\r
+ UINT64 Signature;\r
+ //\r
+ // Members added by the derived class, specific to the use of\r
+ // EFI_PCI_IO_PROTOCOL.\r
+ //\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ //\r
+ // Base class.\r
+ //\r
+ PCI_CAP_DEV BaseDevice;\r
+} PROTO_DEV;\r
+\r
+#define PROTO_DEV_FROM_PCI_CAP_DEV(PciDevice) \\r
+ CR (PciDevice, PROTO_DEV, BaseDevice, PROTO_DEV_SIG)\r
+\r
+#endif // __UEFI_PCI_CAP_PCI_IO_LIB_H__\r