pci_device_read_cap()

Updated: May 06, 2022

Load a capability module

Synopsis:

#include <pci/pci.h>

pci_err_t pci_device_read_cap( pci_bdf_t bdf,
                               pci_cap_t *cap,
                               uint_t idx );

Arguments:

bdf
The Bus/Device/Function associated with a device.
cap
A pointer to a location where the function can store a pointer to a PCI capabilities structure (note that pci_cap_t itself is defined as a pointer to the structure).
idx
The index of the capability that you want to load.

Library:

libpci

Use the -l pci option to qcc to link against this library.

Description:

Once you've found a desired capability index (by using pci_device_read_capid() or pci_device_find_capid()), you can call pci_device_read_cap() using the idx parameter in order to initialize the cap argument and trigger the loading of the capabilities module.

Note: The first time you call pci_device_read_cap() for a given capability idx, initialize the pointer referred to by cap to NULL (see the example below). The function will return PCI_ERR_EINVAL in this case, by design. Failure to set cap to NULL will likely result in a program exception.

Although there's no need to call pci_device_read_cap() more than once for each capability, you can call it again using the pci_cap_t returned on the first successful call.

If the function fails on a subsequent call using the cap returned from an initial call (i.e., with cap = NULL), the pci_cap_t initially received is destroyed, and you must make a new call with cap = NULL.

After a successful call to pci_device_read_cap(), you can use the APIs for the capability module using the returned pci_cap_t argument in order to configure the capability as desired.

Finally, once the capability has been configured (as applicable), you can enable the capability by calling pci_device_cfg_cap_enable(). If a device supports a capability for which there's no capability module, pci_device_read_cap() returns an error indicating that the capability can't be used.

When you no longer need the pci_cap_t returned from a successful pci_device_read_cap() call, you can release it with free().

Returns:

PCI_ERR_OK
Success; cap refers to a valid pci_cap_t, which you can use with the capability APIs.
PCI_ERR_ENOENT
The capability at idx doesn't exist.
PCI_ERR_EIO
A malformed capability “next” pointer was encountered.
PCI_ERR_EINVAL
The cap argument was NULL.
PCI_ERR_NO_MODULE
A capability module doesn't exist (in the capability module search path) for the capability at idx for the device identified by bdf.
PCI_ERR_MODULE_BLACKLISTED
The identified capability module is contained in the PCI_MODULE_BLACKLIST environment variable.
PCI_ERR_MODULE_SYM
The identified capability module doesn't have a proper initialization function.
PCI_ERR_MOD_COMPAT
The identified capability module is incompatible with the version of either the pci-server binary or libpci.

The following internal errors are specifically related to internal resource availability and use, and are atypical:

PCI_ERR_ENOMEM
Memory for internal resources couldn't be obtained. This may be a temporary condition.
PCI_ERR_LOCK_FAILURE
An error occurred that's related to the creation, acquisition or use of a synchronization object.

If any error occurs, you should consider the contents of the cap argument to be invalid data.

Example:

#include <pci/pci.h>
#include <pci/cap_pcie.h>

int_t cap_pcie_idx = pci_device_find_capid(bdf, CAPID_PCIe);

if (cap_pcie_idx >= 0)
{
        pci_cap_t pcie_cap = NULL;
        pci_err_t r = pci_device_read_cap(bdf, &pcie_cap, cap_pcie_idx);
        if (r == PCI_ERR_OK)
        {
                /* enable and use the capability */

                /* done with the capability */
                free(pcie_cap);
        }
}

Classification:

QNX Neutrino

Safety:  
Cancellation point No
Interrupt handler No
Signal handler No
Thread Yes

See also:

pci_device_find_capid(), pci_device_read_capid()