/** @file | |
Library class to 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 | |
**/ | |
#ifndef __PCI_CAP_LIB_H__ | |
#define __PCI_CAP_LIB_H__ | |
#include <Uefi/UefiBaseType.h> | |
// | |
// Base structure for representing a PCI device -- down to the PCI function | |
// level -- for the purposes of this library class. This is a forward | |
// declaration that is completed below. Concrete implementations are supposed | |
// to inherit and extend this type. | |
// | |
typedef struct PCI_CAP_DEV PCI_CAP_DEV; | |
/** | |
Read the config space of a given PCI device (both normal and extended). | |
PCI_CAP_DEV_READ_CONFIG performs as few config space accesses as possible | |
(without attempting 64-bit wide accesses). | |
PCI_CAP_DEV_READ_CONFIG returns an unspecified error if accessing Size bytes | |
from SourceOffset exceeds the config space limit of the PCI device. Fewer | |
than Size bytes may have been read in this case. | |
@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. | |
@return Unspecified error codes. Fewer than Size bytes may | |
have been read. | |
**/ | |
typedef | |
RETURN_STATUS | |
(EFIAPI *PCI_CAP_DEV_READ_CONFIG)( | |
IN PCI_CAP_DEV *PciDevice, | |
IN UINT16 SourceOffset, | |
OUT VOID *DestinationBuffer, | |
IN UINT16 Size | |
); | |
/** | |
Write the config space of a given PCI device (both normal and extended). | |
PCI_CAP_DEV_WRITE_CONFIG performs as few config space accesses as possible | |
(without attempting 64-bit wide accesses). | |
PCI_CAP_DEV_WRITE_CONFIG returns an unspecified error if accessing Size bytes | |
at DestinationOffset exceeds the config space limit of the PCI device. Fewer | |
than Size bytes may have been written in this case. | |
@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. | |
@return Unspecified error codes. Fewer than Size bytes may | |
have been written. | |
**/ | |
typedef | |
RETURN_STATUS | |
(EFIAPI *PCI_CAP_DEV_WRITE_CONFIG)( | |
IN PCI_CAP_DEV *PciDevice, | |
IN UINT16 DestinationOffset, | |
IN VOID *SourceBuffer, | |
IN UINT16 Size | |
); | |
// | |
// Complete the PCI_CAP_DEV type here. The base abstraction only requires | |
// config space accessors. | |
// | |
struct PCI_CAP_DEV { | |
PCI_CAP_DEV_READ_CONFIG ReadConfig; | |
PCI_CAP_DEV_WRITE_CONFIG WriteConfig; | |
}; | |
// | |
// Opaque data structure representing parsed PCI Capabilities Lists. | |
// | |
typedef struct PCI_CAP_LIST PCI_CAP_LIST; | |
// | |
// Opaque data structure representing a PCI Capability in a parsed Capability | |
// List. | |
// | |
typedef struct PCI_CAP PCI_CAP; | |
// | |
// Distinguishes whether a Capability ID 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. | |
// | |
typedef enum { | |
PciCapNormal, | |
PciCapExtended | |
} PCI_CAP_DOMAIN; | |
// | |
// Public data structure that PciCapGetInfo() fills in about a PCI_CAP object. | |
// | |
typedef struct { | |
PCI_CAP_DOMAIN Domain; | |
UINT16 CapId; | |
// | |
// The capability identified by Domain and CapId may have multiple instances | |
// in config space. NumInstances provides the total count of occurrences of | |
// the capability. It is always positive. | |
// | |
UINT16 NumInstances; | |
// | |
// Instance is the serial number, in capabilities list traversal order (not | |
// necessarily config space offset order), of the one capability instance | |
// that PciCapGetInfo() is reporting about. Instance is always smaller than | |
// NumInstances. | |
// | |
UINT16 Instance; | |
// | |
// The offset in config space at which the capability header of the | |
// capability instance starts. | |
// | |
UINT16 Offset; | |
// | |
// The deduced maximum size of the capability instance, including the | |
// capability header. This hint is an upper bound, calculated -- without | |
// regard to the internal structure of the capability -- from (a) the next | |
// lowest offset in configuration space that is known to be used by another | |
// capability, and (b) from the end of the config space identified by Domain, | |
// whichever is lower. | |
// | |
UINT16 MaxSizeHint; | |
// | |
// The version number of the capability instance. Always zero when Domain is | |
// PciCapNormal. | |
// | |
UINT8 Version; | |
} PCI_CAP_INFO; | |
/** | |
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 | |
); | |
/** | |
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 | |
); | |
/** | |
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 | |
); | |
/** | |
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 | |
); | |
/** | |
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 | |
); | |
/** | |
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 | |
); | |
/** | |
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 | |
); | |
#endif // __PCI_CAP_LIB_H__ |