--- /dev/null
+/** @file\r
+ Library class to work with PCI capabilities in PCI config space.\r
+\r
+ Provides functions to parse capabilities lists, and to locate, describe, read\r
+ and write capabilities. PCI config space access is abstracted away.\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_LIB_H__\r
+#define __PCI_CAP_LIB_H__\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+\r
+//\r
+// Base structure for representing a PCI device -- down to the PCI function\r
+// level -- for the purposes of this library class. This is a forward\r
+// declaration that is completed below. Concrete implementations are supposed\r
+// to inherit and extend this type.\r
+//\r
+typedef struct PCI_CAP_DEV PCI_CAP_DEV;\r
+\r
+/**\r
+ Read the config space of a given PCI device (both normal and extended).\r
+\r
+ PCI_CAP_DEV_READ_CONFIG performs as few config space accesses as possible\r
+ (without attempting 64-bit wide accesses).\r
+\r
+ PCI_CAP_DEV_READ_CONFIG 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 Unspecified error codes. Fewer than Size bytes may\r
+ have been read.\r
+**/\r
+typedef\r
+RETURN_STATUS\r
+(EFIAPI *PCI_CAP_DEV_READ_CONFIG) (\r
+ IN PCI_CAP_DEV *PciDevice,\r
+ IN UINT16 SourceOffset,\r
+ OUT VOID *DestinationBuffer,\r
+ IN UINT16 Size\r
+ );\r
+\r
+/**\r
+ Write the config space of a given PCI device (both normal and extended).\r
+\r
+ PCI_CAP_DEV_WRITE_CONFIG performs as few config space accesses as possible\r
+ (without attempting 64-bit wide accesses).\r
+\r
+ PCI_CAP_DEV_WRITE_CONFIG returns an unspecified error if accessing Size bytes\r
+ at 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 Unspecified error codes. Fewer than Size bytes may\r
+ have been written.\r
+**/\r
+typedef\r
+RETURN_STATUS\r
+(EFIAPI *PCI_CAP_DEV_WRITE_CONFIG) (\r
+ IN PCI_CAP_DEV *PciDevice,\r
+ IN UINT16 DestinationOffset,\r
+ IN VOID *SourceBuffer,\r
+ IN UINT16 Size\r
+ );\r
+\r
+//\r
+// Complete the PCI_CAP_DEV type here. The base abstraction only requires\r
+// config space accessors.\r
+//\r
+struct PCI_CAP_DEV {\r
+ PCI_CAP_DEV_READ_CONFIG ReadConfig;\r
+ PCI_CAP_DEV_WRITE_CONFIG WriteConfig;\r
+};\r
+\r
+//\r
+// Opaque data structure representing parsed PCI Capabilities Lists.\r
+//\r
+typedef struct PCI_CAP_LIST PCI_CAP_LIST;\r
+\r
+//\r
+// Opaque data structure representing a PCI Capability in a parsed Capability\r
+// List.\r
+//\r
+typedef struct PCI_CAP PCI_CAP;\r
+\r
+//\r
+// Distinguishes whether a Capability ID is 8-bit wide and interpreted in\r
+// normal config space, or 16-bit wide and interpreted in extended config\r
+// space. Capability ID definitions are relative to domain.\r
+//\r
+typedef enum {\r
+ PciCapNormal,\r
+ PciCapExtended\r
+} PCI_CAP_DOMAIN;\r
+\r
+//\r
+// Public data structure that PciCapGetInfo() fills in about a PCI_CAP object.\r
+//\r
+typedef struct {\r
+ PCI_CAP_DOMAIN Domain;\r
+ UINT16 CapId;\r
+ //\r
+ // The capability identified by Domain and CapId may have multiple instances\r
+ // in config space. NumInstances provides the total count of occurrences of\r
+ // the capability. It is always positive.\r
+ //\r
+ UINT16 NumInstances;\r
+ //\r
+ // Instance is the serial number, in capabilities list traversal order (not\r
+ // necessarily config space offset order), of the one capability instance\r
+ // that PciCapGetInfo() is reporting about. Instance is always smaller than\r
+ // NumInstances.\r
+ //\r
+ UINT16 Instance;\r
+ //\r
+ // The offset in config space at which the capability header of the\r
+ // capability instance starts.\r
+ //\r
+ UINT16 Offset;\r
+ //\r
+ // The deduced maximum size of the capability instance, including the\r
+ // capability header. This hint is an upper bound, calculated -- without\r
+ // regard to the internal structure of the capability -- from (a) the next\r
+ // lowest offset in configuration space that is known to be used by another\r
+ // capability, and (b) from the end of the config space identified by Domain,\r
+ // whichever is lower.\r
+ //\r
+ UINT16 MaxSizeHint;\r
+ //\r
+ // The version number of the capability instance. Always zero when Domain is\r
+ // PciCapNormal.\r
+ //\r
+ UINT8 Version;\r
+} PCI_CAP_INFO;\r
+\r
+\r
+/**\r
+ Parse the capabilities lists (both normal and extended, as applicable) of a\r
+ PCI device.\r
+\r
+ If the PCI device has no capabilities, that per se will not fail\r
+ PciCapListInit(); an empty capabilities list will be represented.\r
+\r
+ If the PCI device is found to be PCI Express, then an attempt will be made to\r
+ parse the extended capabilities list as well. If the first extended config\r
+ space access -- via PciDevice->ReadConfig() with SourceOffset=0x100 and\r
+ Size=4 -- fails, that per se will not fail PciCapListInit(); the device will\r
+ be assumed to have no extended capabilities.\r
+\r
+ @param[in] PciDevice Implementation-specific unique representation of the\r
+ PCI device in the PCI hierarchy.\r
+\r
+ @param[out] CapList Opaque data structure that holds an in-memory\r
+ representation of the parsed capabilities lists of\r
+ PciDevice.\r
+\r
+ @retval RETURN_SUCCESS The capabilities lists have been parsed from\r
+ config space.\r
+\r
+ @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.\r
+\r
+ @retval RETURN_DEVICE_ERROR A loop or some other kind of invalid pointer\r
+ was detected in the capabilities lists of\r
+ PciDevice.\r
+\r
+ @return Error codes propagated from\r
+ PciDevice->ReadConfig().\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PciCapListInit (\r
+ IN PCI_CAP_DEV *PciDevice,\r
+ OUT PCI_CAP_LIST **CapList\r
+ );\r
+\r
+\r
+/**\r
+ Free the resources used by CapList.\r
+\r
+ @param[in] CapList The PCI_CAP_LIST object to free, originally produced by\r
+ PciCapListInit().\r
+**/\r
+VOID\r
+EFIAPI\r
+PciCapListUninit (\r
+ IN PCI_CAP_LIST *CapList\r
+ );\r
+\r
+\r
+/**\r
+ Locate a capability instance in the parsed capabilities lists.\r
+\r
+ @param[in] CapList The PCI_CAP_LIST object produced by PciCapListInit().\r
+\r
+ @param[in] Domain Distinguishes whether CapId is 8-bit wide and\r
+ interpreted in normal config space, or 16-bit wide and\r
+ interpreted in extended config space. Capability ID\r
+ definitions are relative to domain.\r
+\r
+ @param[in] CapId Capability identifier to look up.\r
+\r
+ @param[in] Instance Domain and CapId may identify a multi-instance\r
+ capability. When Instance is zero, the first instance of\r
+ the capability is located (in list traversal order --\r
+ which may not mean increasing config space offset\r
+ order). Higher Instance values locate subsequent\r
+ instances of the same capability (in list traversal\r
+ order).\r
+\r
+ @param[out] Cap The capability instance that matches the search\r
+ criteria. Cap is owned by CapList and becomes invalid\r
+ when CapList is freed with PciCapListUninit().\r
+ PciCapListFindCap() may be called with Cap set to NULL,\r
+ in order to test the existence of a specific capability\r
+ instance.\r
+\r
+ @retval RETURN_SUCCESS The capability instance identified by (Domain,\r
+ CapId, Instance) has been found.\r
+\r
+ @retval RETURN_NOT_FOUND The requested (Domain, CapId, Instance) capability\r
+ instance does not exist.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PciCapListFindCap (\r
+ IN PCI_CAP_LIST *CapList,\r
+ IN PCI_CAP_DOMAIN Domain,\r
+ IN UINT16 CapId,\r
+ IN UINT16 Instance,\r
+ OUT PCI_CAP **Cap OPTIONAL\r
+ );\r
+\r
+\r
+/**\r
+ Locate the first instance of the capability given by (Domain, CapId) such\r
+ that the instance's Version is greater than or equal to MinVersion.\r
+\r
+ This is a convenience function that may save client code calls to\r
+ PciCapListFindCap() and PciCapGetInfo().\r
+\r
+ @param[in] CapList The PCI_CAP_LIST object produced by PciCapListInit().\r
+\r
+ @param[in] Domain Distinguishes whether CapId is 8-bit wide and\r
+ interpreted in normal config space, or 16-bit wide and\r
+ interpreted in extended config space. Capability ID\r
+ definitions are relative to domain.\r
+\r
+ @param[in] CapId Capability identifier to look up.\r
+\r
+ @param[in] MinVersion The minimum version that the capability instance is\r
+ required to have. Note that all capability instances\r
+ in Domain=PciCapNormal have Version=0.\r
+\r
+ @param[out] Cap The first capability instance that matches the search\r
+ criteria. Cap is owned by CapList and becomes invalid\r
+ when CapList is freed with PciCapListUninit().\r
+ PciCapListFindCapVersion() may be called with Cap set\r
+ to NULL, in order just to test whether the search\r
+ criteria are satisfiable.\r
+\r
+ @retval RETURN_SUCCESS The first capability instance matching (Domain,\r
+ CapId, MinVersion) has been located.\r
+\r
+ @retval RETURN_NOT_FOUND No capability instance matches (Domain, CapId,\r
+ MinVersion).\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PciCapListFindCapVersion (\r
+ IN PCI_CAP_LIST *CapList,\r
+ IN PCI_CAP_DOMAIN Domain,\r
+ IN UINT16 CapId,\r
+ IN UINT8 MinVersion,\r
+ OUT PCI_CAP **Cap OPTIONAL\r
+ );\r
+\r
+\r
+/**\r
+ Get information about a PCI Capability instance.\r
+\r
+ @param[in] Cap The capability instance to get info about, located with\r
+ PciCapListFindCap*().\r
+\r
+ @param[out] Info A PCI_CAP_INFO structure that describes the properties of\r
+ Cap.\r
+\r
+ @retval RETURN_SUCCESS Fields of Info have been set.\r
+\r
+ @return Unspecified error codes, if filling in Info failed\r
+ for some reason.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PciCapGetInfo (\r
+ IN PCI_CAP *Cap,\r
+ OUT PCI_CAP_INFO *Info\r
+ );\r
+\r
+\r
+/**\r
+ Read a slice of a capability instance.\r
+\r
+ The function performs as few config space accesses as possible (without\r
+ attempting 64-bit wide accesses). PciCapRead() performs bounds checking on\r
+ SourceOffsetInCap and Size, and only invokes PciDevice->ReadConfig() if the\r
+ requested transfer falls within Cap.\r
+\r
+ @param[in] PciDevice Implementation-specific unique representation\r
+ of the PCI device in the PCI hierarchy.\r
+\r
+ @param[in] Cap The capability instance to read, located with\r
+ PciCapListFindCap*().\r
+\r
+ @param[in] SourceOffsetInCap Source offset relative to the capability\r
+ header to start reading from. A zero value\r
+ refers to the first byte of the capability\r
+ header.\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 Cap to\r
+ DestinationBuffer.\r
+\r
+ @retval RETURN_BAD_BUFFER_SIZE Reading Size bytes starting from\r
+ SourceOffsetInCap would not (entirely) be\r
+ contained within Cap, as suggested by\r
+ PCI_CAP_INFO.MaxSizeHint. No bytes have been\r
+ read.\r
+\r
+ @return Error codes propagated from\r
+ PciDevice->ReadConfig(). Fewer than Size\r
+ bytes may have been read.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PciCapRead (\r
+ IN PCI_CAP_DEV *PciDevice,\r
+ IN PCI_CAP *Cap,\r
+ IN UINT16 SourceOffsetInCap,\r
+ OUT VOID *DestinationBuffer,\r
+ IN UINT16 Size\r
+ );\r
+\r
+\r
+/**\r
+ Write a slice of a capability instance.\r
+\r
+ The function performs as few config space accesses as possible (without\r
+ attempting 64-bit wide accesses). PciCapWrite() performs bounds checking on\r
+ DestinationOffsetInCap and Size, and only invokes PciDevice->WriteConfig() if\r
+ the requested transfer falls within Cap.\r
+\r
+ @param[in] PciDevice Implementation-specific unique\r
+ representation of the PCI device in the\r
+ PCI hierarchy.\r
+\r
+ @param[in] Cap The capability instance to write, located\r
+ with PciCapListFindCap*().\r
+\r
+ @param[in] DestinationOffsetInCap Destination offset relative to the\r
+ capability header to start writing at. A\r
+ zero value refers to the first byte of the\r
+ capability header.\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\r
+ SourceBuffer to Cap.\r
+\r
+ @retval RETURN_BAD_BUFFER_SIZE Writing Size bytes starting at\r
+ DestinationOffsetInCap would not (entirely)\r
+ be contained within Cap, as suggested by\r
+ PCI_CAP_INFO.MaxSizeHint. No bytes have been\r
+ written.\r
+\r
+ @return Error codes propagated from\r
+ PciDevice->WriteConfig(). Fewer than Size\r
+ bytes may have been written.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PciCapWrite (\r
+ IN PCI_CAP_DEV *PciDevice,\r
+ IN PCI_CAP *Cap,\r
+ IN UINT16 DestinationOffsetInCap,\r
+ IN VOID *SourceBuffer,\r
+ IN UINT16 Size\r
+ );\r
+\r
+#endif // __PCI_CAP_LIB_H__\r