iPXE
Functions | Variables
pci.c File Reference

PCI bus. More...

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ipxe/tables.h>
#include <ipxe/device.h>
#include <ipxe/pci.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void pcibus_remove (struct root_device *rootdev)
 Remove PCI root bus.
static unsigned long pci_bar (struct pci_device *pci, unsigned int reg)
 Read PCI BAR.
unsigned long pci_bar_start (struct pci_device *pci, unsigned int reg)
 Find the start of a PCI BAR.
static void pci_read_bases (struct pci_device *pci)
 Read membase and ioaddr for a PCI device.
void adjust_pci_device (struct pci_device *pci)
 Enable PCI device.
int pci_read_config (struct pci_device *pci)
 Read PCI device configuration.
int pci_find_next (struct pci_device *pci, unsigned int busdevfn)
 Find next device on PCI bus.
int pci_find_driver (struct pci_device *pci)
 Find driver for PCI device.
int pci_probe (struct pci_device *pci)
 Probe a PCI device.
void pci_remove (struct pci_device *pci)
 Remove a PCI device.
static int pcibus_probe (struct root_device *rootdev)
 Probe PCI root bus.

Variables

static struct root_driver pci_root_driver
 PCI bus root device driver.
struct root_device pci_root_device __root_device
 PCI bus root device.

Detailed Description

PCI bus.

Definition in file pci.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void pcibus_remove ( struct root_device rootdev) [static]

Remove PCI root bus.

Parameters:
rootdevPCI bus root device

Definition at line 377 of file pci.c.

References device::children, root_device::dev, pci_device::dev, free, list_del, list_for_each_entry_safe, pci_remove(), and device::siblings.

Referenced by pcibus_probe().

                                                          {
        struct pci_device *pci;
        struct pci_device *tmp;

        list_for_each_entry_safe ( pci, tmp, &rootdev->dev.children,
                                   dev.siblings ) {
                pci_remove ( pci );
                list_del ( &pci->dev.siblings );
                free ( pci );
        }
}
static unsigned long pci_bar ( struct pci_device pci,
unsigned int  reg 
) [static]

Read PCI BAR.

Parameters:
pciPCI device
regPCI register number
Return values:
barBase address register

Reads the specified PCI base address register, including the flags portion. 64-bit BARs will be handled automatically. If the value of the 64-bit BAR exceeds the size of an unsigned long (i.e. if the high dword is non-zero on a 32-bit platform), then the value returned will be zero plus the flags for a 64-bit BAR. Unreachable 64-bit BARs are therefore returned as uninitialised 64-bit BARs.

Definition at line 60 of file pci.c.

References DBGC, high, low, PCI_ARGS, PCI_BASE_ADDRESS_MEM_TYPE_64, PCI_BASE_ADDRESS_MEM_TYPE_MASK, PCI_BASE_ADDRESS_SPACE_IO, PCI_FMT, and pci_read_config_dword().

Referenced by pci_bar_start(), and pci_read_bases().

                                                                          {
        uint32_t low;
        uint32_t high;

        pci_read_config_dword ( pci, reg, &low );
        if ( ( low & (PCI_BASE_ADDRESS_SPACE_IO|PCI_BASE_ADDRESS_MEM_TYPE_MASK))
             == PCI_BASE_ADDRESS_MEM_TYPE_64 ) {
                pci_read_config_dword ( pci, reg + 4, &high );
                if ( high ) {
                        if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
                                return ( ( ( uint64_t ) high << 32 ) | low );
                        } else {
                                DBGC ( pci, PCI_FMT " unhandled 64-bit BAR "
                                       "%08x%08x\n",
                                       PCI_ARGS ( pci ), high, low );
                                return PCI_BASE_ADDRESS_MEM_TYPE_64;
                        }
                }
        }
        return low;
}
unsigned long pci_bar_start ( struct pci_device pci,
unsigned int  reg 
)

Find the start of a PCI BAR.

Parameters:
pciPCI device
regPCI register number
Return values:
startBAR start address

Reads the specified PCI base address register, and returns the address portion of the BAR (i.e. without the flags).

If the address exceeds the size of an unsigned long (i.e. if a 64-bit BAR has a non-zero high dword on a 32-bit machine), the return value will be zero.

Definition at line 96 of file pci.c.

References pci_bar(), PCI_BASE_ADDRESS_IO_MASK, PCI_BASE_ADDRESS_MEM_MASK, and PCI_BASE_ADDRESS_SPACE_IO.

Referenced by amd8111e_probe(), arbel_probe(), bnx2_init_board(), dmfe_probe(), efab_probe(), efx_probe(), ehci_probe(), exanic_probe(), flexboot_nodnic_alloc_uar(), forcedeth_map_regs(), golan_alloc_uar(), golan_pci_init(), hermon_bofm_probe(), hermon_probe(), hvm_probe(), igbvf_probe(), mlx_pci_init_priv(), phantom_map_crb(), skge_probe(), sky2_probe(), tg3_init_one(), undipci_find_rom(), virtio_pci_map_capability(), vmxnet3_probe(), vxge_probe(), and xhci_probe().

                                                                         {
        unsigned long bar;

        bar = pci_bar ( pci, reg );
        if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) {
                return ( bar & ~PCI_BASE_ADDRESS_IO_MASK );
        } else {
                return ( bar & ~PCI_BASE_ADDRESS_MEM_MASK );
        }
}
static void pci_read_bases ( struct pci_device pci) [static]

Read membase and ioaddr for a PCI device.

Parameters:
pciPCI device

This scans through all PCI BARs on the specified device. The first valid memory BAR is recorded as pci_device::membase, and the first valid IO BAR is recorded as pci_device::ioaddr.

64-bit BARs are handled automatically. On a 32-bit platform, if a 64-bit BAR has a non-zero high dword, it will be regarded as invalid.

Definition at line 120 of file pci.c.

References pci_device::ioaddr, pci_device::membase, pci_bar(), PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_5, PCI_BASE_ADDRESS_IO_MASK, PCI_BASE_ADDRESS_MEM_MASK, PCI_BASE_ADDRESS_MEM_TYPE_64, PCI_BASE_ADDRESS_SPACE_IO, and reg.

Referenced by pci_read_config().

                                                      {
        unsigned long bar;
        int reg;

        for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) {
                bar = pci_bar ( pci, reg );
                if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) {
                        if ( ! pci->ioaddr )
                                pci->ioaddr = 
                                        ( bar & ~PCI_BASE_ADDRESS_IO_MASK );
                } else {
                        if ( ! pci->membase )
                                pci->membase =
                                        ( bar & ~PCI_BASE_ADDRESS_MEM_MASK );
                        /* Skip next BAR if 64-bit */
                        if ( bar & PCI_BASE_ADDRESS_MEM_TYPE_64 )
                                reg += 4;
                }
        }
}
void adjust_pci_device ( struct pci_device pci)

Enable PCI device.

Parameters:
pciPCI device

Set device to be a busmaster in case BIOS neglected to do so. Also adjust PCI latency timer to a reasonable value, 32.

Definition at line 149 of file pci.c.

References DBGC, PCI_ARGS, PCI_COMMAND, PCI_COMMAND_IO, PCI_COMMAND_MASTER, PCI_COMMAND_MEM, PCI_FMT, PCI_LATENCY_TIMER, pci_read_config_byte(), pci_read_config_word(), pci_write_config_byte(), and pci_write_config_word().

Referenced by a3c90x_probe(), amd8111e_probe(), arbel_probe(), ath5k_probe(), ath_pci_probe(), atl1e_probe(), b44_probe(), bnx2_init_board(), dmfe_probe(), efab_probe(), efx_probe(), ehci_probe(), ena_probe(), exanic_probe(), forcedeth_probe(), golan_pci_init(), hermon_bofm_probe(), hermon_probe(), hvm_probe(), icplus_probe(), ifec_pci_probe(), igbvf_probe(), intel_probe(), intelx_probe(), intelxl_probe(), intelxvf_probe(), jme_probe(), linda_probe(), mlx_pci_init_priv(), myri10ge_pci_probe(), myson_probe(), natsemi_probe(), pcnet32_probe(), phantom_probe(), pnic_probe(), qib7322_probe(), realtek_probe(), rhine_probe(), rtl818x_probe(), sis190_init_board(), sis900_probe(), skeleton_probe(), skge_probe(), sky2_probe(), sundance_probe(), tg3_init_one(), tlan_probe(), tulip_probe(), txnic_bgx_probe(), txnic_pf_probe(), uhci_probe(), velocity_probe(), virtnet_probe_legacy(), virtnet_probe_modern(), vmxnet3_probe(), vxge_probe(), w89c840_probe(), and xhci_probe().

                                                  {
        unsigned short new_command, pci_command;
        unsigned char pci_latency;

        pci_read_config_word ( pci, PCI_COMMAND, &pci_command );
        new_command = ( pci_command | PCI_COMMAND_MASTER |
                        PCI_COMMAND_MEM | PCI_COMMAND_IO );
        if ( pci_command != new_command ) {
                DBGC ( pci, PCI_FMT " device not enabled by BIOS! Updating "
                       "PCI command %04x->%04x\n",
                       PCI_ARGS ( pci ), pci_command, new_command );
                pci_write_config_word ( pci, PCI_COMMAND, new_command );
        }

        pci_read_config_byte ( pci, PCI_LATENCY_TIMER, &pci_latency);
        if ( pci_latency < 32 ) {
                DBGC ( pci, PCI_FMT " latency timer is unreasonably low at "
                       "%d. Setting to 32.\n", PCI_ARGS ( pci ), pci_latency );
                pci_write_config_byte ( pci, PCI_LATENCY_TIMER, 32);
        }
}
int pci_read_config ( struct pci_device pci)

Read PCI device configuration.

Parameters:
pciPCI device
Return values:
rcReturn status code

Definition at line 177 of file pci.c.

References device_description::bus_type, BUS_TYPE_PCI, pci_device::busdevfn, device::children, device_description::class, pci_device::class, device::desc, pci_device::dev, device_description::device, pci_device::device, ENODEV, INIT_LIST_HEAD, device_description::ioaddr, pci_device::ioaddr, device_description::irq, pci_device::irq, device_description::location, device::name, PCI_BUS, PCI_FIRST_FUNC, PCI_FUNC, PCI_HEADER_TYPE, PCI_HEADER_TYPE_MULTI, PCI_INTERRUPT_LINE, pci_read_bases(), pci_read_config_byte(), pci_read_config_dword(), PCI_REVISION, PCI_SEG, PCI_SLOT, PCI_VENDOR_ID, device::siblings, snprintf(), device_description::vendor, and pci_device::vendor.

Referenced by bofm_test_init(), efipci_open(), ehci_companion(), and pci_find_next().

                                               {
        uint32_t busdevfn;
        uint8_t hdrtype;
        uint32_t tmp;

        /* Ignore all but the first function on non-multifunction devices */
        if ( PCI_FUNC ( pci->busdevfn ) != 0 ) {
                busdevfn = pci->busdevfn;
                pci->busdevfn = PCI_FIRST_FUNC ( pci->busdevfn );
                pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
                pci->busdevfn = busdevfn;
                if ( ! ( hdrtype & PCI_HEADER_TYPE_MULTI ) )
                        return -ENODEV;
        }

        /* Check for physical device presence */
        pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
        if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
                return -ENODEV;

        /* Populate struct pci_device */
        pci->vendor = ( tmp & 0xffff );
        pci->device = ( tmp >> 16 );
        pci_read_config_dword ( pci, PCI_REVISION, &tmp );
        pci->class = ( tmp >> 8 );
        pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
        pci_read_bases ( pci );

        /* Initialise generic device component */
        snprintf ( pci->dev.name, sizeof ( pci->dev.name ), "%04x:%02x:%02x.%x",
                   PCI_SEG ( pci->busdevfn ), PCI_BUS ( pci->busdevfn ),
                   PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) );
        pci->dev.desc.bus_type = BUS_TYPE_PCI;
        pci->dev.desc.location = pci->busdevfn;
        pci->dev.desc.vendor = pci->vendor;
        pci->dev.desc.device = pci->device;
        pci->dev.desc.class = pci->class;
        pci->dev.desc.ioaddr = pci->ioaddr;
        pci->dev.desc.irq = pci->irq;
        INIT_LIST_HEAD ( &pci->dev.siblings );
        INIT_LIST_HEAD ( &pci->dev.children );

        return 0;
}
int pci_find_next ( struct pci_device pci,
unsigned int  busdevfn 
)

Find next device on PCI bus.

Parameters:
pciPCI device to fill in
busdevfnStarting bus:dev.fn address
Return values:
busdevfnBus:dev.fn address of next PCI device, or negative error

Definition at line 229 of file pci.c.

References end, ENODEV, memset(), PCI_BUSDEVFN, pci_init(), pci_num_bus(), pci_read_config(), and rc.

Referenced by pcibus_probe(), and pciscan_exec().

                                                                    {
        static unsigned int end;
        int rc;

        /* Determine number of PCI buses */
        if ( ! end )
                end = PCI_BUSDEVFN ( 0, pci_num_bus(), 0, 0 );

        /* Find next PCI device, if any */
        for ( ; busdevfn < end ; busdevfn++ ) {
                memset ( pci, 0, sizeof ( *pci ) );
                pci_init ( pci, busdevfn );
                if ( ( rc = pci_read_config ( pci ) ) == 0 )
                        return busdevfn;
        }

        return -ENODEV;
}
int pci_find_driver ( struct pci_device pci)

Find driver for PCI device.

Parameters:
pciPCI device
Return values:
rcReturn status code

Definition at line 254 of file pci.c.

References pci_class_id::class, pci_device::class, pci_driver::class, pci_device_id::device, pci_device::device, driver, ENOENT, for_each_table_entry, id, pci_driver::id_count, pci_driver::ids, pci_class_id::mask, PCI_ANY_ID, PCI_DRIVERS, pci_set_driver(), pci_device_id::vendor, and pci_device::vendor.

Referenced by efipci_start(), efipci_supported(), and pcibus_probe().

                                               {
        struct pci_driver *driver;
        struct pci_device_id *id;
        unsigned int i;

        for_each_table_entry ( driver, PCI_DRIVERS ) {
                if ( ( driver->class.class ^ pci->class ) & driver->class.mask )
                        continue;
                for ( i = 0 ; i < driver->id_count ; i++ ) {
                        id = &driver->ids[i];
                        if ( ( id->vendor != PCI_ANY_ID ) &&
                             ( id->vendor != pci->vendor ) )
                                continue;
                        if ( ( id->device != PCI_ANY_ID ) &&
                             ( id->device != pci->device ) )
                                continue;
                        pci_set_driver ( pci, driver, id );
                        return 0;
                }
        }
        return -ENOENT;
}
int pci_probe ( struct pci_device pci)

Probe a PCI device.

Parameters:
pciPCI device
Return values:
rcReturn status code

Searches for a driver for the PCI device. If a driver is found, its probe() routine is called.

Definition at line 286 of file pci.c.

References DBGC, pci_device::device, pci_device::driver, pci_device::id, pci_device::ioaddr, pci_device::irq, pci_device::membase, pci_device_id::name, PCI_ARGS, PCI_FMT, pci_driver::probe, rc, strerror(), and pci_device::vendor.

Referenced by bofm_probe(), efipci_start(), and pcibus_probe().

                                         {
        int rc;

        DBGC ( pci, PCI_FMT " (%04x:%04x) has driver \"%s\"\n",
               PCI_ARGS ( pci ), pci->vendor, pci->device, pci->id->name );
        DBGC ( pci, PCI_FMT " has mem %lx io %lx irq %d\n",
               PCI_ARGS ( pci ), pci->membase, pci->ioaddr, pci->irq );

        if ( ( rc = pci->driver->probe ( pci ) ) != 0 ) {
                DBGC ( pci, PCI_FMT " probe failed: %s\n",
                       PCI_ARGS ( pci ), strerror ( rc ) );
                return rc;
        }

        return 0;
}
void pci_remove ( struct pci_device pci)

Remove a PCI device.

Parameters:
pciPCI device

Definition at line 308 of file pci.c.

References DBGC, pci_device::driver, PCI_ARGS, PCI_FMT, and pci_driver::remove.

Referenced by bofm_remove(), efipci_start(), efipci_stop(), and pcibus_remove().

                                           {
        pci->driver->remove ( pci );
        DBGC ( pci, PCI_FMT " removed\n", PCI_ARGS ( pci ) );
}
static int pcibus_probe ( struct root_device rootdev) [static]

Probe PCI root bus.

Parameters:
rootdevPCI bus root device

Scans the PCI bus for devices and registers all devices it can find.

Definition at line 321 of file pci.c.

References pci_device::busdevfn, device::children, pci_device::class, DBGC, root_device::dev, pci_device::dev, pci_device::device, ENOMEM, free, list_add, list_del, malloc(), NULL, device::parent, PCI_ARGS, pci_find_driver(), pci_find_next(), PCI_FMT, pci_probe(), pcibus_remove(), rc, device::siblings, and pci_device::vendor.

                                                        {
        struct pci_device *pci = NULL;
        int busdevfn = 0;
        int rc;

        for ( busdevfn = 0 ; 1 ; busdevfn++ ) {

                /* Allocate struct pci_device */
                if ( ! pci )
                        pci = malloc ( sizeof ( *pci ) );
                if ( ! pci ) {
                        rc = -ENOMEM;
                        goto err;
                }

                /* Find next PCI device, if any */
                busdevfn = pci_find_next ( pci, busdevfn );
                if ( busdevfn < 0 )
                        break;

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

                /* Add to device hierarchy */
                pci->dev.parent = &rootdev->dev;
                list_add ( &pci->dev.siblings, &rootdev->dev.children );

                /* Look for a driver */
                if ( ( rc = pci_probe ( pci ) ) == 0 ) {
                        /* pcidev registered, we can drop our ref */
                        pci = NULL;
                } else {
                        /* Not registered; re-use struct pci_device */
                        list_del ( &pci->dev.siblings );
                }
        }

        free ( pci );
        return 0;

 err:
        free ( pci );
        pcibus_remove ( rootdev );
        return rc;
}

Variable Documentation

struct root_driver pci_root_driver [static]
Initial value:
 {
        .probe = pcibus_probe,
        .remove = pcibus_remove,
}

PCI bus root device driver.

Definition at line 390 of file pci.c.

struct root_device pci_root_device __root_device
Initial value:
 {
        .dev = { .name = "PCI" },
        .driver = &pci_root_driver,
}

PCI bus root device.

Definition at line 396 of file pci.c.