iPXE
Functions
bofm.c File Reference

IBM BladeCenter Open Fabric Manager (BOFM) More...

#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <ipxe/uaccess.h>
#include <ipxe/list.h>
#include <ipxe/ethernet.h>
#include <ipxe/bofm.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static LIST_HEAD (bofmdevs)
 List of BOFM devices.
int bofm_register (struct bofm_device *bofm)
 Register BOFM device.
void bofm_unregister (struct bofm_device *bofm)
 Unregister BOFM device.
static struct bofm_devicebofm_find_busdevfn (unsigned int busdevfn)
 Find BOFM device matching PCI bus:dev.fn address.
int bofm_find_driver (struct pci_device *pci)
 Find BOFM driver for PCI device.
static int bofm_probe (struct pci_device *pci)
 Probe PCI device for BOFM driver.
static void bofm_remove (struct pci_device *pci)
 Remove PCI device.
static size_t bofm_locate_section (userptr_t bofmtab, size_t len, uint32_t magic, struct bofm_section_header *bofmsec)
 Locate BOFM table section.
static int bofm_en (struct bofm_device *bofm, struct bofm_en *en)
 Process BOFM Ethernet parameter entry.
int bofm (userptr_t bofmtab, struct pci_device *pci)
 Process BOFM table.

Detailed Description

IBM BladeCenter Open Fabric Manager (BOFM)

Definition in file bofm.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static LIST_HEAD ( bofmdevs  ) [static]

List of BOFM devices.

int bofm_register ( struct bofm_device bofm)

Register BOFM device.

Parameters:
bofmBOFM device
Return values:
rcReturn status code

Definition at line 49 of file bofm.c.

References DBG, pci_device::id, bofm_device::list, list_add, pci_device_id::name, bofm_device::pci, PCI_ARGS, and PCI_FMT.

Referenced by hermon_bofm_probe().

                                               {

        list_add ( &bofm->list, &bofmdevs );
        DBG ( "BOFM: " PCI_FMT " registered using driver \"%s\"\n",
              PCI_ARGS ( bofm->pci ), bofm->pci->id->name );
        return 0;
}
void bofm_unregister ( struct bofm_device bofm)

Unregister BOFM device.

Parameters:
bofmBOFM device

Definition at line 62 of file bofm.c.

References DBG, bofm_device::list, list_del, bofm_device::pci, PCI_ARGS, and PCI_FMT.

Referenced by hermon_bofm_remove().

                                                  {

        list_del ( &bofm->list );
        DBG ( "BOFM: " PCI_FMT " unregistered\n", PCI_ARGS ( bofm->pci ) );
}
static struct bofm_device* bofm_find_busdevfn ( unsigned int  busdevfn) [static, read]

Find BOFM device matching PCI bus:dev.fn address.

Parameters:
busdevfnPCI bus:dev.fn address
Return values:
bofmBOFM device, or NULL

Definition at line 74 of file bofm.c.

References bofm(), pci_device::busdevfn, bofm_device::list, list_for_each_entry, NULL, and bofm_device::pci.

Referenced by bofm().

                                                                         {
        struct bofm_device *bofm;

        list_for_each_entry ( bofm, &bofmdevs, list ) {
                if ( bofm->pci->busdevfn == busdevfn )
                        return bofm;
        }
        return NULL;
}
int bofm_find_driver ( struct pci_device pci)

Find BOFM driver for PCI device.

Parameters:
pciPCI device
Return values:
rcReturn status code

Definition at line 90 of file bofm.c.

References BOFM_DRIVERS, pci_device_id::device, pci_device::device, driver, ENOENT, for_each_table_entry, id, pci_driver::id_count, pci_driver::ids, pci_set_driver(), pci_device_id::vendor, and pci_device::vendor.

Referenced by bofm(), and efi_bofm_supported().

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

        for_each_table_entry ( driver, BOFM_DRIVERS ) {
                for ( i = 0 ; i < driver->id_count ; i++ ) {
                        id = &driver->ids[i];
                        if ( ( id->vendor == pci->vendor ) &&
                             ( id->device == pci->device ) ) {
                                pci_set_driver ( pci, driver, id );
                                return 0;
                        }
                }
        }
        return -ENOENT;
}
static int bofm_probe ( struct pci_device pci) [static]

Probe PCI device for BOFM driver.

Parameters:
pciPCI device
Return values:
rcReturn status code

Definition at line 114 of file bofm.c.

References DBG, PCI_ARGS, PCI_FMT, pci_probe(), rc, and strerror().

Referenced by bofm().

                                                 {
        int rc;

        /* Probe device */
        if ( ( rc = pci_probe ( pci ) ) != 0 ) {
                DBG ( "BOFM: " PCI_FMT " could not load driver: %s\n",
                      PCI_ARGS ( pci ), strerror ( rc ) );
                return rc;
        }

        return 0;
}
static void bofm_remove ( struct pci_device pci) [static]

Remove PCI device.

Parameters:
pciPCI device

Definition at line 132 of file bofm.c.

References DBG, PCI_ARGS, PCI_FMT, and pci_remove().

Referenced by bofm().

                                                   {

        /* Note that the IBM BIOS may re-read the expansion ROM after
         * the BOFM initialisation call.  The BOFM driver must ensure
         * that the card is left in a state in which expansion ROM
         * reads will succeed.  (For example, if a card contains an
         * embedded CPU that may issue reads to the same underlying
         * flash device, and these reads are not locked against reads
         * via the expansion ROM BAR, then the CPU must be stopped.)
         *
         * If this is not done, then occasional corrupted reads from
         * the expansion ROM will be seen, and the BIOS may complain
         * about a ROM checksum error.
         */
        pci_remove ( pci );
        DBG ( "BOFM: " PCI_FMT " removed\n", PCI_ARGS ( pci ) );
}
static size_t bofm_locate_section ( userptr_t  bofmtab,
size_t  len,
uint32_t  magic,
struct bofm_section_header bofmsec 
) [static]

Locate BOFM table section.

Parameters:
bofmtabBOFM table
lenLength of BOFM table
magicSection magic
bofmsecBOFM section header to fill in
Return values:
offsetOffset to section, or 0 if not found

Definition at line 159 of file bofm.c.

References BOFM_DONE_MAGIC, copy_from_user(), bofm_section_header::length, bofm_section_header::magic, and offset.

Referenced by bofm().

                                                                          {
        size_t offset = sizeof ( struct bofm_global_header );

        while ( offset < len ) {
                copy_from_user ( bofmsec, bofmtab, offset,
                                 sizeof ( *bofmsec ) );
                if ( bofmsec->magic == magic )
                        return offset;
                if ( bofmsec->magic == BOFM_DONE_MAGIC )
                        break;
                offset += ( sizeof ( *bofmsec ) + bofmsec->length );
        }
        return 0;
}
static int bofm_en ( struct bofm_device bofm,
struct bofm_en en 
) [static]

Process BOFM Ethernet parameter entry.

Parameters:
bofmBOFM device
enEN parameter entry
Return values:
rcReturn status code

Definition at line 183 of file bofm.c.

References BOFM_EN_CHG_CHANGED, BOFM_EN_EN_A, BOFM_EN_HVST, BOFM_EN_RQ_HVST_MASK, BOFM_EN_USAGE_ENTRY, BOFM_EN_USAGE_HARVEST, DBG, eth_ntoa(), bofm_operations::harvest, mac, bofm_en::mac_a, memcmp(), memcpy(), bofm_en::mport, bofm_device::op, bofm_en::options, bofm_device::pci, PCI_ARGS, PCI_FMT, rc, strerror(), and bofm_operations::update.

                                                                    {
        uint8_t mac[6];
        int rc;

        /* Retrieve current MAC address */
        if ( ( rc = bofm->op->harvest ( bofm, en->mport, mac ) ) != 0 ) {
                DBG ( "BOFM: " PCI_FMT " mport %d could not harvest: %s\n",
                      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
                return rc;
        }

        /* Harvest MAC address if necessary */
        if ( en->options & BOFM_EN_RQ_HVST_MASK ) {
                DBG ( "BOFM: " PCI_FMT " mport %d harvested MAC %s\n",
                      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
                memcpy ( en->mac_a, mac, sizeof ( en->mac_a ) );
                en->options |= ( BOFM_EN_EN_A | BOFM_EN_HVST );
        }

        /* Mark as changed if necessary */
        if ( ( en->options & BOFM_EN_EN_A ) &&
             ( memcmp ( en->mac_a, mac, sizeof ( en->mac_a ) ) != 0 ) ) {
                DBG ( "BOFM: " PCI_FMT " mport %d MAC %s",
                      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
                DBG ( " changed to %s\n", eth_ntoa ( en->mac_a ) );
                en->options |= BOFM_EN_CHG_CHANGED;
        }

        /* Apply MAC address if necessary */
        if ( ( en->options & BOFM_EN_EN_A ) &&
             ( en->options & BOFM_EN_USAGE_ENTRY ) &&
             ( ! ( en->options & BOFM_EN_USAGE_HARVEST ) ) ) {
                DBG ( "BOFM: " PCI_FMT " mport %d applied MAC %s\n",
                      PCI_ARGS ( bofm->pci ), en->mport,
                      eth_ntoa ( en->mac_a ) );
                memcpy ( mac, en->mac_a, sizeof ( mac ) );
        }

        /* Store MAC address */
        if ( ( rc = bofm->op->update ( bofm, en->mport, mac ) ) != 0 ) {
                DBG ( "BOFM: " PCI_FMT " mport %d could not update: %s\n",
                      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
                return rc;
        }

        return 0;
}
int bofm ( userptr_t  bofmtab,
struct pci_device pci 
)

Process BOFM table.

Parameters:
bofmtabBOFM table
pciPCI device
Return values:
bofmrcBOFM return status

Definition at line 238 of file bofm.c.

References bofm_global_header::action, bofm(), BOFM_ACTION_DFLT, BOFM_ACTION_HVST, BOFM_ACTION_NONE, BOFM_ACTION_PARM, BOFM_ACTION_UPDT, BOFM_EN_CSM_FAILED, BOFM_EN_CSM_SUCCESS, BOFM_EN_MAGIC, BOFM_EN_MAP_MASK, BOFM_EN_MAP_PFA, BOFM_ERR_DEVICE_ERROR, BOFM_ERR_INVALID_ACTION, bofm_find_busdevfn(), bofm_find_driver(), BOFM_IOAA_MAGIC, bofm_locate_section(), BOFM_MAGIC_ARGS, BOFM_MAGIC_FMT, bofm_probe(), bofm_remove(), BOFM_SKIP_INIT, BOFM_SUCCESS, bofm_en::busdevfn, copy_from_user(), copy_to_user(), DBG, DBG2, DBG2_HDA, en, bofm_global_header::length, bofm_section_header::length, bofm_global_header::magic, bofm_en::mport, bofm_en::options, PCI_ARGS, PCI_BUS, PCI_FMT, PCI_FUNC, PCI_SLOT, bofm_en::port, bofm_global_header::profile, rc, and bofm_en::slot.

Referenced by bofm(), bofm_find_busdevfn(), bofm_test(), and efi_bofm_start().

                                                       {
        struct bofm_global_header bofmhdr;
        struct bofm_section_header bofmsec;
        struct bofm_en en;
        struct bofm_device *bofm;
        size_t en_region_offset;
        size_t en_offset;
        int skip;
        int rc;
        int bofmrc;

        /* Read BOFM structure */
        copy_from_user ( &bofmhdr, bofmtab, 0, sizeof ( bofmhdr ) );
        if ( bofmhdr.magic != BOFM_IOAA_MAGIC ) {
                DBG ( "BOFM: invalid table signature " BOFM_MAGIC_FMT "\n",
                      BOFM_MAGIC_ARGS ( bofmhdr.magic ) );
                bofmrc = BOFM_ERR_INVALID_ACTION;
                goto err_bad_signature;
        }
        DBG ( "BOFM: " BOFM_MAGIC_FMT " (profile \"%s\")\n",
              BOFM_MAGIC_ARGS ( bofmhdr.action ), bofmhdr.profile );

        /* Determine whether or not we should skip normal POST
         * initialisation.
         */
        switch ( bofmhdr.action ) {
        case BOFM_ACTION_UPDT:
        case BOFM_ACTION_DFLT:
        case BOFM_ACTION_HVST:
                skip = BOFM_SKIP_INIT;
                break;
        case BOFM_ACTION_PARM:
        case BOFM_ACTION_NONE:
                skip = 0;
                break;
        default:
                DBG ( "BOFM: invalid action " BOFM_MAGIC_FMT "\n",
                      BOFM_MAGIC_ARGS ( bofmhdr.action ) );
                bofmrc = BOFM_ERR_INVALID_ACTION;
                goto err_bad_action;
        }

        /* Find BOFM driver */
        if ( ( rc = bofm_find_driver ( pci ) ) != 0 ) {
                DBG ( "BOFM: " PCI_FMT " has no driver\n", PCI_ARGS ( pci ) );
                bofmrc = BOFM_ERR_DEVICE_ERROR;
                goto err_find_driver;
        }

        /* Probe driver for PCI device */
        if ( ( rc = bofm_probe ( pci ) ) != 0 ) {
                bofmrc = BOFM_ERR_DEVICE_ERROR;
                goto err_probe;
        }

        /* Locate EN section, if present */
        en_region_offset = bofm_locate_section ( bofmtab, bofmhdr.length,
                                                 BOFM_EN_MAGIC, &bofmsec );
        if ( ! en_region_offset ) {
                DBG ( "BOFM: No EN section found\n" );
                bofmrc = ( BOFM_SUCCESS | skip );
                goto err_no_en_section;
        }

        /* Iterate through EN entries */
        for ( en_offset = ( en_region_offset + sizeof ( bofmsec ) ) ;
              en_offset < ( en_region_offset + sizeof ( bofmsec ) +
                            bofmsec.length ) ; en_offset += sizeof ( en ) ) {
                copy_from_user ( &en, bofmtab, en_offset, sizeof ( en ) );
                DBG2 ( "BOFM: EN entry found:\n" );
                DBG2_HDA ( en_offset, &en, sizeof ( en ) );
                if ( ( en.options & BOFM_EN_MAP_MASK ) != BOFM_EN_MAP_PFA ) {
                        DBG ( "BOFM: slot %d port %d has no PCI mapping\n",
                              en.slot, ( en.port + 1 ) );
                        continue;
                }
                DBG ( "BOFM: slot %d port %d%s is " PCI_FMT " mport %d\n",
                      en.slot, ( en.port + 1 ),
                      ( ( en.slot || en.port ) ? "" : "(?)" ), 0,
                      PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
                      PCI_FUNC ( en.busdevfn ), en.mport );
                bofm = bofm_find_busdevfn ( en.busdevfn );
                if ( ! bofm ) {
                        DBG ( "BOFM: " PCI_FMT " mport %d ignored\n", 0,
                              PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
                              PCI_FUNC ( en.busdevfn ), en.mport );
                        continue;
                }
                if ( ( rc = bofm_en ( bofm, &en ) ) == 0 ) {
                        en.options |= BOFM_EN_CSM_SUCCESS;
                } else {
                        en.options |= BOFM_EN_CSM_FAILED;
                }
                DBG2 ( "BOFM: EN entry after processing:\n" );
                DBG2_HDA ( en_offset, &en, sizeof ( en ) );
                copy_to_user ( bofmtab, en_offset, &en, sizeof ( en ) );
        }

        bofmrc = ( BOFM_SUCCESS | skip );

 err_no_en_section:
        bofm_remove ( pci );
 err_probe:
 err_find_driver:
 err_bad_action:
 err_bad_signature:
        return bofmrc;
}