iPXE
Defines | Functions
efi_pci.c File Reference

iPXE PCI I/O API for EFI More...

#include <stdlib.h>
#include <errno.h>
#include <ipxe/pci.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_pci.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/Protocol/PciIo.h>
#include <ipxe/efi/Protocol/PciRootBridgeIo.h>

Go to the source code of this file.

Defines

#define EINFO_EEFI_PCI
#define EINFO_EEFI_PCI_NOT_PCI
#define EEFI_PCI_NOT_PCI   __einfo_error ( EINFO_EEFI_PCI_NOT_PCI )
#define EINFO_EEFI_PCI_IN_USE
#define EEFI_PCI_IN_USE   __einfo_error ( EINFO_EEFI_PCI_IN_USE )
#define EEFI_PCI(efirc)

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int efipci_root (struct pci_device *pci, EFI_HANDLE *handle, EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root)
 Locate EFI PCI root bridge I/O protocol.
static unsigned long efipci_address (struct pci_device *pci, unsigned long location)
 Calculate EFI PCI configuration space address.
int efipci_read (struct pci_device *pci, unsigned long location, void *value)
 Read from PCI configuration space.
int efipci_write (struct pci_device *pci, unsigned long location, unsigned long value)
 Write to PCI configuration space.
 PROVIDE_PCIAPI_INLINE (efi, pci_num_bus)
 PROVIDE_PCIAPI_INLINE (efi, pci_read_config_byte)
 PROVIDE_PCIAPI_INLINE (efi, pci_read_config_word)
 PROVIDE_PCIAPI_INLINE (efi, pci_read_config_dword)
 PROVIDE_PCIAPI_INLINE (efi, pci_write_config_byte)
 PROVIDE_PCIAPI_INLINE (efi, pci_write_config_word)
 PROVIDE_PCIAPI_INLINE (efi, pci_write_config_dword)
int efipci_open (EFI_HANDLE device, UINT32 attributes, struct pci_device *pci)
 Open EFI PCI device.
void efipci_close (EFI_HANDLE device)
 Close EFI PCI device.
int efipci_info (EFI_HANDLE device, struct pci_device *pci)
 Get EFI PCI device information.
static int efipci_supported (EFI_HANDLE device)
 Check to see if driver supports a device.
static int efipci_start (struct efi_device *efidev)
 Attach driver to device.
static void efipci_stop (struct efi_device *efidev)
 Detach driver from device.
struct efi_driver efipci_driver __efi_driver (EFI_DRIVER_NORMAL)
 EFI PCI driver.

Detailed Description

iPXE PCI I/O API for EFI

Definition in file efi_pci.c.


Define Documentation

#define EINFO_EEFI_PCI
Value:
__einfo_uniqify ( EINFO_EPLATFORM, 0x01,                        \
                          "Could not open PCI I/O protocol" )

Definition at line 42 of file efi_pci.c.

Value:

Definition at line 45 of file efi_pci.c.

Definition at line 48 of file efi_pci.c.

Value:
__einfo_platformify ( EINFO_EEFI_PCI, EFI_ACCESS_DENIED,        \
                              "PCI device already has a driver" )

Definition at line 49 of file efi_pci.c.

Definition at line 52 of file efi_pci.c.

#define EEFI_PCI (   efirc)
Value:

Definition at line 53 of file efi_pci.c.

Referenced by efipci_open().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static int efipci_root ( struct pci_device pci,
EFI_HANDLE handle,
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **  root 
) [static]

Locate EFI PCI root bridge I/O protocol.

Parameters:
pciPCI device
Return values:
handleEFI PCI root bridge handle
rootEFI PCI root bridge I/O protocol, or NULL if not found
rcReturn status code

Definition at line 72 of file efi_pci.c.

References EFI_SYSTEM_TABLE::BootServices, pci_device::busdevfn, ByProtocol, EFI_BOOT_SERVICES::CloseProtocol, DBGC, EEFI, efi_handle_name(), efi_image_handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL, efi_pci_root_bridge_io_protocol_guid, efi_systab, ENOENT, EFI_BOOT_SERVICES::FreePool, EFI_BOOT_SERVICES::LocateHandleBuffer, NULL, EFI_BOOT_SERVICES::OpenProtocol, PCI_ARGS, PCI_FMT, PCI_SEG, rc, root, strerror(), and u.

Referenced by efipci_read(), and efipci_write().

                                                                  {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_HANDLE *handles;
        UINTN num_handles;
        union {
                void *interface;
                EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
        } u;
        EFI_STATUS efirc;
        UINTN i;
        int rc;

        /* Enumerate all handles */
        if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol,
                        &efi_pci_root_bridge_io_protocol_guid,
                        NULL, &num_handles, &handles ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( pci, "EFIPCI " PCI_FMT " cannot locate root bridges: "
                       "%s\n", PCI_ARGS ( pci ), strerror ( rc ) );
                goto err_locate;
        }

        /* Look for matching root bridge I/O protocol */
        for ( i = 0 ; i < num_handles ; i++ ) {
                *handle = handles[i];
                if ( ( efirc = bs->OpenProtocol ( *handle,
                                &efi_pci_root_bridge_io_protocol_guid,
                                &u.interface, efi_image_handle, *handle,
                                EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
                        rc = -EEFI ( efirc );
                        DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n",
                               PCI_ARGS ( pci ), efi_handle_name ( *handle ),
                               strerror ( rc ) );
                        continue;
                }
                if ( u.root->SegmentNumber == PCI_SEG ( pci->busdevfn ) ) {
                        *root = u.root;
                        bs->FreePool ( handles );
                        return 0;
                }
                bs->CloseProtocol ( *handle,
                                    &efi_pci_root_bridge_io_protocol_guid,
                                    efi_image_handle, *handle );
        }
        DBGC ( pci, "EFIPCI " PCI_FMT " found no root bridge\n",
               PCI_ARGS ( pci ) );
        rc = -ENOENT;

        bs->FreePool ( handles );
 err_locate:
        return rc;
}
static unsigned long efipci_address ( struct pci_device pci,
unsigned long  location 
) [static]

Calculate EFI PCI configuration space address.

Parameters:
pciPCI device
locationEncoded offset and width
Return values:
addressEFI PCI address

Definition at line 133 of file efi_pci.c.

References pci_device::busdevfn, EFI_PCI_ADDRESS, EFIPCI_OFFSET, PCI_BUS, PCI_FUNC, and PCI_SLOT.

Referenced by efipci_read(), and efipci_write().

                                                               {

        return EFI_PCI_ADDRESS ( PCI_BUS ( pci->busdevfn ),
                                 PCI_SLOT ( pci->busdevfn ),
                                 PCI_FUNC ( pci->busdevfn ),
                                 EFIPCI_OFFSET ( location ) );
}
int efipci_read ( struct pci_device pci,
unsigned long  location,
void *  value 
)

Read from PCI configuration space.

Parameters:
pciPCI device
locationEncoded offset and width
Return values:
valueValue
rcReturn status code

Definition at line 150 of file efi_pci.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, DBGC, EEFI, efi_image_handle, efi_pci_root_bridge_io_protocol_guid, efi_systab, efipci_address(), EFIPCI_OFFSET, efipci_root(), EFIPCI_WIDTH, handle, _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Pci, PCI_ARGS, PCI_FMT, rc, EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS::Read, root, and strerror().

                                {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
        EFI_HANDLE handle;
        EFI_STATUS efirc;
        int rc;

        /* Identify root bridge */
        if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
                goto err_root;

        /* Read from configuration space */
        if ( ( efirc = root->Pci.Read ( root, EFIPCI_WIDTH ( location ),
                                        efipci_address ( pci, location ), 1,
                                        value ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( pci, "EFIPCI " PCI_FMT " config read from offset %02lx "
                       "failed: %s\n", PCI_ARGS ( pci ),
                       EFIPCI_OFFSET ( location ), strerror ( rc ) );
                goto err_read;
        }

 err_read:
        bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
                            efi_image_handle, handle );
 err_root:
        return rc;
}
int efipci_write ( struct pci_device pci,
unsigned long  location,
unsigned long  value 
)

Write to PCI configuration space.

Parameters:
pciPCI device
locationEncoded offset and width
valueValue
Return values:
rcReturn status code

Definition at line 188 of file efi_pci.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, DBGC, EEFI, efi_image_handle, efi_pci_root_bridge_io_protocol_guid, efi_systab, efipci_address(), EFIPCI_OFFSET, efipci_root(), EFIPCI_WIDTH, handle, _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Pci, PCI_ARGS, PCI_FMT, rc, root, strerror(), and EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS::Write.

                                         {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
        EFI_HANDLE handle;
        EFI_STATUS efirc;
        int rc;

        /* Identify root bridge */
        if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
                goto err_root;

        /* Read from configuration space */
        if ( ( efirc = root->Pci.Write ( root, EFIPCI_WIDTH ( location ),
                                         efipci_address ( pci, location ), 1,
                                         &value ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( pci, "EFIPCI " PCI_FMT " config write to offset %02lx "
                       "failed: %s\n", PCI_ARGS ( pci ),
                       EFIPCI_OFFSET ( location ), strerror ( rc ) );
                goto err_write;
        }

 err_write:
        bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
                            efi_image_handle, handle );
 err_root:
        return rc;
}
int efipci_open ( EFI_HANDLE  device,
UINT32  attributes,
struct pci_device pci 
)

Open EFI PCI device.

Parameters:
deviceEFI device handle
attributesProtocol opening attributes
pciPCI device to fill in
Return values:
rcReturn status code

Definition at line 241 of file efi_pci.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, DBGC, DBGCP, EEFI, EEFI_PCI, efi_handle_name(), efi_image_handle, EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY, efi_pci_io_protocol_guid, efi_systab, EfiPciIoAttributeOperationEnable, NULL, EFI_BOOT_SERVICES::OpenProtocol, PCI_ARGS, PCI_BUSDEVFN, PCI_FMT, pci_init(), pci_read_config(), rc, and strerror().

Referenced by efi_bofm_start(), efipci_info(), and efipci_start().

                                           {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        union {
                EFI_PCI_IO_PROTOCOL *pci_io;
                void *interface;
        } pci_io;
        UINTN pci_segment, pci_bus, pci_dev, pci_fn;
        unsigned int busdevfn;
        EFI_STATUS efirc;
        int rc;

        /* See if device is a PCI device */
        if ( ( efirc = bs->OpenProtocol ( device, &efi_pci_io_protocol_guid,
                                          &pci_io.interface, efi_image_handle,
                                          device, attributes ) ) != 0 ) {
                rc = -EEFI_PCI ( efirc );
                DBGCP ( device, "EFIPCI %s cannot open PCI protocols: %s\n",
                        efi_handle_name ( device ), strerror ( rc ) );
                goto err_open_protocol;
        }

        /* Get PCI bus:dev.fn address */
        if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, &pci_segment,
                                                    &pci_bus, &pci_dev,
                                                    &pci_fn ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( device, "EFIPCI %s could not get PCI location: %s\n",
                       efi_handle_name ( device ), strerror ( rc ) );
                goto err_get_location;
        }
        busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn );
        pci_init ( pci, busdevfn );
        DBGCP ( device, "EFIPCI " PCI_FMT " is %s\n",
                PCI_ARGS ( pci ), efi_handle_name ( device ) );

        /* Try to enable I/O cycles, memory cycles, and bus mastering.
         * Some platforms will 'helpfully' report errors if these bits
         * can't be enabled (for example, if the card doesn't actually
         * support I/O cycles).  Work around any such platforms by
         * enabling bits individually and simply ignoring any errors.
         */
        pci_io.pci_io->Attributes ( pci_io.pci_io,
                                    EfiPciIoAttributeOperationEnable,
                                    EFI_PCI_IO_ATTRIBUTE_IO, NULL );
        pci_io.pci_io->Attributes ( pci_io.pci_io,
                                    EfiPciIoAttributeOperationEnable,
                                    EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL );
        pci_io.pci_io->Attributes ( pci_io.pci_io,
                                    EfiPciIoAttributeOperationEnable,
                                    EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );

        /* Populate PCI device */
        if ( ( rc = pci_read_config ( pci ) ) != 0 ) {
                DBGC ( device, "EFIPCI " PCI_FMT " cannot read PCI "
                       "configuration: %s\n",
                       PCI_ARGS ( pci ), strerror ( rc ) );
                goto err_pci_read_config;
        }

        return 0;

 err_pci_read_config:
 err_get_location:
        bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
                            efi_image_handle, device );
 err_open_protocol:
        return rc;
}
void efipci_close ( EFI_HANDLE  device)

Close EFI PCI device.

Parameters:
deviceEFI device handle

Definition at line 316 of file efi_pci.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, efi_image_handle, efi_pci_io_protocol_guid, and efi_systab.

Referenced by efi_bofm_start(), efipci_info(), efipci_start(), and efipci_stop().

int efipci_info ( EFI_HANDLE  device,
struct pci_device pci 
)

Get EFI PCI device information.

Parameters:
deviceEFI device handle
pciPCI device to fill in
Return values:
rcReturn status code

Definition at line 330 of file efi_pci.c.

References EFI_OPEN_PROTOCOL_GET_PROTOCOL, efipci_close(), efipci_open(), and rc.

Referenced by efi_bofm_supported(), efi_pci_info(), and efipci_supported().

                                                              {
        int rc;

        /* Open PCI device, if possible */
        if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
                                  pci ) ) != 0 )
                return rc;

        /* Close PCI device */
        efipci_close ( device );

        return 0;
}
static int efipci_supported ( EFI_HANDLE  device) [static]

Check to see if driver supports a device.

Parameters:
deviceEFI device handle
Return values:
rcReturn status code

Definition at line 357 of file efi_pci.c.

References pci_device::class, DBGC, pci_device::device, efipci_info(), pci_device::id, pci_device_id::name, PCI_ARGS, pci_find_driver(), PCI_FMT, rc, and pci_device::vendor.

                                                  {
        struct pci_device pci;
        int rc;

        /* Get PCI device information */
        if ( ( rc = efipci_info ( device, &pci ) ) != 0 )
                return rc;

        /* Look for a driver */
        if ( ( rc = pci_find_driver ( &pci ) ) != 0 ) {
                DBGC ( device, "EFIPCI " PCI_FMT " (%04x:%04x class %06x) "
                       "has no driver\n", PCI_ARGS ( &pci ), pci.vendor,
                       pci.device, pci.class );
                return rc;
        }
        DBGC ( device, "EFIPCI " PCI_FMT " (%04x:%04x class %06x) has driver "
               "\"%s\"\n", PCI_ARGS ( &pci ), pci.vendor, pci.device,
               pci.class, pci.id->name );

        return 0;
}
static int efipci_start ( struct efi_device efidev) [static]

Attach driver to device.

Parameters:
efidevEFI device
Return values:
rcReturn status code

Definition at line 385 of file efi_pci.c.

References device::children, DBGC, DBGC_EFI_OPENERS, efi_device::dev, pci_device::dev, efi_device::device, efi_handle_name(), EFI_OPEN_PROTOCOL_BY_DRIVER, EFI_OPEN_PROTOCOL_EXCLUSIVE, efi_pci_io_protocol_guid, efidev_set_drvdata(), efipci_close(), efipci_open(), ENOMEM, free, pci_device::id, list_add, list_del, pci_device_id::name, device::parent, PCI_ARGS, pci_find_driver(), PCI_FMT, pci_probe(), pci_remove(), rc, device::siblings, strerror(), and zalloc().

                                                      {
        EFI_HANDLE device = efidev->device;
        struct pci_device *pci;
        int rc;

        /* Allocate PCI device */
        pci = zalloc ( sizeof ( *pci ) );
        if ( ! pci ) {
                rc = -ENOMEM;
                goto err_alloc;
        }

        /* Open PCI device */
        if ( ( rc = efipci_open ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER |
                                            EFI_OPEN_PROTOCOL_EXCLUSIVE ),
                                  pci ) ) != 0 ) {
                DBGC ( device, "EFIPCI %s could not open PCI device: %s\n",
                       efi_handle_name ( device ), strerror ( rc ) );
                DBGC_EFI_OPENERS ( device, device, &efi_pci_io_protocol_guid );
                goto err_open;
        }

        /* Find driver */
        if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
                DBGC ( device, "EFIPCI " PCI_FMT " has no driver\n",
                       PCI_ARGS ( pci ) );
                goto err_find_driver;
        }

        /* Mark PCI device as a child of the EFI device */
        pci->dev.parent = &efidev->dev;
        list_add ( &pci->dev.siblings, &efidev->dev.children );

        /* Probe driver */
        if ( ( rc = pci_probe ( pci ) ) != 0 ) {
                DBGC ( device, "EFIPCI " PCI_FMT " could not probe driver "
                       "\"%s\": %s\n", PCI_ARGS ( pci ), pci->id->name,
                       strerror ( rc ) );
                goto err_probe;
        }
        DBGC ( device, "EFIPCI " PCI_FMT " using driver \"%s\"\n",
               PCI_ARGS ( pci ), pci->id->name );

        efidev_set_drvdata ( efidev, pci );
        return 0;

        pci_remove ( pci );
 err_probe:
        list_del ( &pci->dev.siblings );
 err_find_driver:
        efipci_close ( device );
 err_open:
        free ( pci );
 err_alloc:
        return rc;
}
static void efipci_stop ( struct efi_device efidev) [static]

Detach driver from device.

Parameters:
efidevEFI device

Definition at line 447 of file efi_pci.c.

References pci_device::dev, efi_device::device, efidev_get_drvdata(), efipci_close(), free, list_del, pci_remove(), and device::siblings.

                                                      {
        struct pci_device *pci = efidev_get_drvdata ( efidev );
        EFI_HANDLE device = efidev->device;

        pci_remove ( pci );
        list_del ( &pci->dev.siblings );
        efipci_close ( device );
        free ( pci );
}
struct efi_driver efipci_driver __efi_driver ( EFI_DRIVER_NORMAL  ) [read]

EFI PCI driver.