Annotation of qemu/roms/ipxe/src/interface/bofm/bofm.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (C) 2011 Michael Brown <[email protected]>.
                      3:  *
                      4:  * This program is free software; you can redistribute it and/or
                      5:  * modify it under the terms of the GNU General Public License as
                      6:  * published by the Free Software Foundation; either version 2 of the
                      7:  * License, or any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful, but
                     10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     12:  * General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program; if not, write to the Free Software
                     16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17:  */
                     18: 
                     19: FILE_LICENCE ( GPL2_OR_LATER );
                     20: 
                     21: #include <stdint.h>
                     22: #include <string.h>
                     23: #include <errno.h>
                     24: #include <ipxe/uaccess.h>
                     25: #include <ipxe/list.h>
                     26: #include <ipxe/ethernet.h>
                     27: #include <ipxe/bofm.h>
                     28: 
                     29: /** @file
                     30:  *
                     31:  * IBM BladeCenter Open Fabric Manager (BOFM)
                     32:  *
                     33:  */
                     34: 
                     35: /** List of BOFM devices */
                     36: static LIST_HEAD ( bofmdevs );
                     37: 
                     38: /**
                     39:  * Register BOFM device
                     40:  *
                     41:  * @v bofm             BOFM device
                     42:  * @ret rc             Return status code
                     43:  */
                     44: int bofm_register ( struct bofm_device *bofm ) {
                     45: 
                     46:        list_add ( &bofm->list, &bofmdevs );
                     47:        DBG ( "BOFM: " PCI_FMT " registered using driver \"%s\"\n",
                     48:              PCI_ARGS ( bofm->pci ), bofm->pci->id->name );
                     49:        return 0;
                     50: }
                     51: 
                     52: /**
                     53:  * Unregister BOFM device
                     54:  *
                     55:  * @v bofm             BOFM device
                     56:  */
                     57: void bofm_unregister ( struct bofm_device *bofm ) {
                     58: 
                     59:        list_del ( &bofm->list );
                     60:        DBG ( "BOFM: " PCI_FMT " unregistered\n", PCI_ARGS ( bofm->pci ) );
                     61: }
                     62: 
                     63: /**
                     64:  * Find BOFM device matching PCI bus:dev.fn address
                     65:  *
                     66:  * @v busdevfn         PCI bus:dev.fn address
                     67:  * @ret bofm           BOFM device, or NULL
                     68:  */
                     69: static struct bofm_device * bofm_find_busdevfn ( unsigned int busdevfn ) {
                     70:        struct bofm_device *bofm;
                     71: 
                     72:        list_for_each_entry ( bofm, &bofmdevs, list ) {
                     73:                if ( bofm->pci->busdevfn == busdevfn )
                     74:                        return bofm;
                     75:        }
                     76:        return NULL;
                     77: }
                     78: 
                     79: /**
                     80:  * Find BOFM driver for PCI device
                     81:  *
                     82:  * @v pci              PCI device
                     83:  * @ret rc             Return status code
                     84:  */
                     85: int bofm_find_driver ( struct pci_device *pci ) {
                     86:        struct pci_driver *driver;
                     87:        struct pci_device_id *id;
                     88:        unsigned int i;
                     89: 
                     90:        for_each_table_entry ( driver, BOFM_DRIVERS ) {
                     91:                for ( i = 0 ; i < driver->id_count ; i++ ) {
                     92:                        id = &driver->ids[i];
                     93:                        if ( ( id->vendor == pci->vendor ) &&
                     94:                             ( id->device == pci->device ) ) {
                     95:                                pci_set_driver ( pci, driver, id );
                     96:                                return 0;
                     97:                        }
                     98:                }
                     99:        }
                    100:        return -ENOENT;
                    101: }
                    102: 
                    103: /**
                    104:  * Probe PCI device for BOFM driver
                    105:  *
                    106:  * @v pci              PCI device
                    107:  * @ret rc             Return status code
                    108:  */
                    109: static int bofm_probe ( struct pci_device *pci ) {
                    110:        int rc;
                    111: 
                    112:        /* Probe device */
                    113:        if ( ( rc = pci_probe ( pci ) ) != 0 ) {
                    114:                DBG ( "BOFM: " PCI_FMT " could not load driver: %s\n",
                    115:                      PCI_ARGS ( pci ), strerror ( rc ) );
                    116:                return rc;
                    117:        }
                    118: 
                    119:        return 0;
                    120: }
                    121: 
                    122: /**
                    123:  * Remove PCI device
                    124:  *
                    125:  * @v pci              PCI device
                    126:  */
                    127: static void bofm_remove ( struct pci_device *pci ) {
                    128: 
                    129:        /* Note that the IBM BIOS may re-read the expansion ROM after
                    130:         * the BOFM initialisation call.  The BOFM driver must ensure
                    131:         * that the card is left in a state in which expansion ROM
                    132:         * reads will succeed.  (For example, if a card contains an
                    133:         * embedded CPU that may issue reads to the same underlying
                    134:         * flash device, and these reads are not locked against reads
                    135:         * via the expansion ROM BAR, then the CPU must be stopped.)
                    136:         *
                    137:         * If this is not done, then occasional corrupted reads from
                    138:         * the expansion ROM will be seen, and the BIOS may complain
                    139:         * about a ROM checksum error.
                    140:         */
                    141:        pci_remove ( pci );
                    142:        DBG ( "BOFM: " PCI_FMT " removed\n", PCI_ARGS ( pci ) );
                    143: }
                    144: 
                    145: /**
                    146:  * Locate BOFM table section
                    147:  *
                    148:  * @v bofmtab          BOFM table
                    149:  * @v len              Length of BOFM table
                    150:  * @v magic            Section magic
                    151:  * @v bofmsec          BOFM section header to fill in
                    152:  * @ret offset         Offset to section, or 0 if not found
                    153:  */
                    154: static size_t bofm_locate_section ( userptr_t bofmtab, size_t len,
                    155:                                    uint32_t magic,
                    156:                                    struct bofm_section_header *bofmsec ) {
                    157:        size_t offset = sizeof ( struct bofm_global_header );
                    158: 
                    159:        while ( offset < len ) {
                    160:                copy_from_user ( bofmsec, bofmtab, offset,
                    161:                                 sizeof ( *bofmsec ) );
                    162:                if ( bofmsec->magic == magic )
                    163:                        return offset;
                    164:                if ( bofmsec->magic == BOFM_DONE_MAGIC )
                    165:                        break;
                    166:                offset += ( sizeof ( *bofmsec ) + bofmsec->length );
                    167:        }
                    168:        return 0;
                    169: }
                    170: 
                    171: /**
                    172:  * Process BOFM Ethernet parameter entry
                    173:  *
                    174:  * @v bofm             BOFM device
                    175:  * @v en               EN parameter entry
                    176:  * @ret rc             Return status code
                    177:  */
                    178: static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
                    179:        uint8_t mac[6];
                    180:        int rc;
                    181: 
                    182:        /* Retrieve current MAC address */
                    183:        if ( ( rc = bofm->op->harvest ( bofm, en->mport, mac ) ) != 0 ) {
                    184:                DBG ( "BOFM: " PCI_FMT " port %d could not harvest: %s\n",
                    185:                      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
                    186:                return rc;
                    187:        }
                    188: 
                    189:        /* Harvest MAC address if necessary */
                    190:        if ( en->options & BOFM_EN_RQ_HVST_MASK ) {
                    191:                DBG ( "BOFM: " PCI_FMT " port %d harvested MAC %s\n",
                    192:                      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
                    193:                memcpy ( en->mac_a, mac, sizeof ( en->mac_a ) );
                    194:                en->options |= ( BOFM_EN_EN_A | BOFM_EN_HVST );
                    195:        }
                    196: 
                    197:        /* Mark as changed if necessary */
                    198:        if ( ( en->options & BOFM_EN_EN_A ) &&
                    199:             ( memcmp ( en->mac_a, mac, sizeof ( en->mac_a ) ) != 0 ) ) {
                    200:                DBG ( "BOFM: " PCI_FMT " port %d MAC %s",
                    201:                      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
                    202:                DBG ( " changed to %s\n", eth_ntoa ( en->mac_a ) );
                    203:                en->options |= BOFM_EN_CHG_CHANGED;
                    204:        }
                    205: 
                    206:        /* Apply MAC address if necessary */
                    207:        if ( ( en->options & BOFM_EN_EN_A ) &&
                    208:             ( en->options & BOFM_EN_USAGE_ENTRY ) &&
                    209:             ( ! ( en->options & BOFM_EN_USAGE_HARVEST ) ) ) {
                    210:                DBG ( "BOFM: " PCI_FMT " port %d applied MAC %s\n",
                    211:                      PCI_ARGS ( bofm->pci ), en->mport,
                    212:                      eth_ntoa ( en->mac_a ) );
                    213:                memcpy ( mac, en->mac_a, sizeof ( mac ) );
                    214:        }
                    215: 
                    216:        /* Store MAC address */
                    217:        if ( ( rc = bofm->op->update ( bofm, en->mport, mac ) ) != 0 ) {
                    218:                DBG ( "BOFM: " PCI_FMT " port %d could not update: %s\n",
                    219:                      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
                    220:                return rc;
                    221:        }
                    222: 
                    223:        return 0;
                    224: }
                    225: 
                    226: /**
                    227:  * Process BOFM table
                    228:  *
                    229:  * @v bofmtab          BOFM table
                    230:  * @v pci              PCI device
                    231:  * @ret bofmrc         BOFM return status
                    232:  */
                    233: int bofm ( userptr_t bofmtab, struct pci_device *pci ) {
                    234:        struct bofm_global_header bofmhdr;
                    235:        struct bofm_section_header bofmsec;
                    236:        struct bofm_en en;
                    237:        struct bofm_device *bofm;
                    238:        size_t en_region_offset;
                    239:        size_t en_offset;
                    240:        int skip;
                    241:        int rc;
                    242:        int bofmrc;
                    243: 
                    244:        /* Read BOFM structure */
                    245:        copy_from_user ( &bofmhdr, bofmtab, 0, sizeof ( bofmhdr ) );
                    246:        if ( bofmhdr.magic != BOFM_IOAA_MAGIC ) {
                    247:                DBG ( "BOFM: invalid table signature " BOFM_MAGIC_FMT "\n",
                    248:                      BOFM_MAGIC_ARGS ( bofmhdr.magic ) );
                    249:                bofmrc = BOFM_ERR_INVALID_ACTION;
                    250:                goto err_bad_signature;
                    251:        }
                    252:        DBG ( "BOFM: " BOFM_MAGIC_FMT " (profile \"%s\")\n",
                    253:              BOFM_MAGIC_ARGS ( bofmhdr.action ), bofmhdr.profile );
                    254: 
                    255:        /* Determine whether or not we should skip normal POST
                    256:         * initialisation.
                    257:         */
                    258:        switch ( bofmhdr.action ) {
                    259:        case BOFM_ACTION_UPDT:
                    260:        case BOFM_ACTION_DFLT:
                    261:        case BOFM_ACTION_HVST:
                    262:                skip = BOFM_SKIP_INIT;
                    263:                break;
                    264:        case BOFM_ACTION_PARM:
                    265:        case BOFM_ACTION_NONE:
                    266:                skip = 0;
                    267:                break;
                    268:        default:
                    269:                DBG ( "BOFM: invalid action " BOFM_MAGIC_FMT "\n",
                    270:                      BOFM_MAGIC_ARGS ( bofmhdr.action ) );
                    271:                bofmrc = BOFM_ERR_INVALID_ACTION;
                    272:                goto err_bad_action;
                    273:        }
                    274: 
                    275:        /* Find BOFM driver */
                    276:        if ( ( rc = bofm_find_driver ( pci ) ) != 0 ) {
                    277:                DBG ( "BOFM: " PCI_FMT " has no driver\n", PCI_ARGS ( pci ) );
                    278:                bofmrc = BOFM_ERR_DEVICE_ERROR;
                    279:                goto err_find_driver;
                    280:        }
                    281: 
                    282:        /* Probe driver for PCI device */
                    283:        if ( ( rc = bofm_probe ( pci ) ) != 0 ) {
                    284:                bofmrc = BOFM_ERR_DEVICE_ERROR;
                    285:                goto err_probe;
                    286:        }
                    287: 
                    288:        /* Locate EN section, if present */
                    289:        en_region_offset = bofm_locate_section ( bofmtab, bofmhdr.length,
                    290:                                                 BOFM_EN_MAGIC, &bofmsec );
                    291:        if ( ! en_region_offset ) {
                    292:                DBG ( "BOFM: No EN section found\n" );
                    293:                bofmrc = ( BOFM_SUCCESS | skip );
                    294:                goto err_no_en_section;
                    295:        }
                    296: 
                    297:        /* Iterate through EN entries */
                    298:        for ( en_offset = ( en_region_offset + sizeof ( bofmsec ) ) ;
                    299:              en_offset < ( en_region_offset + sizeof ( bofmsec ) +
                    300:                            bofmsec.length ) ; en_offset += sizeof ( en ) ) {
                    301:                copy_from_user ( &en, bofmtab, en_offset, sizeof ( en ) );
                    302:                DBG2 ( "BOFM: EN entry found:\n" );
                    303:                DBG2_HDA ( en_offset, &en, sizeof ( en ) );
                    304:                if ( ( en.options & BOFM_EN_MAP_MASK ) != BOFM_EN_MAP_PFA ) {
                    305:                        DBG ( "BOFM: slot %d port %d has no PCI mapping\n",
                    306:                              en.slot, en.port );
                    307:                        continue;
                    308:                }
                    309:                bofm = bofm_find_busdevfn ( en.busdevfn );
                    310:                if ( ! bofm ) {
                    311:                        DBG ( "BOFM: " PCI_FMT " ignored\n",
                    312:                              PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
                    313:                              PCI_FUNC ( en.busdevfn ) );
                    314:                        continue;
                    315:                }
                    316:                if ( ( rc = bofm_en ( bofm, &en ) ) == 0 ) {
                    317:                        en.options |= BOFM_EN_CSM_SUCCESS;
                    318:                } else {
                    319:                        en.options |= BOFM_EN_CSM_FAILED;
                    320:                }
                    321:                DBG2 ( "BOFM: EN entry after processing:\n" );
                    322:                DBG2_HDA ( en_offset, &en, sizeof ( en ) );
                    323:                copy_to_user ( bofmtab, en_offset, &en, sizeof ( en ) );
                    324:        }
                    325: 
                    326:        bofmrc = ( BOFM_SUCCESS | skip );
                    327: 
                    328:  err_no_en_section:
                    329:        bofm_remove ( pci );
                    330:  err_probe:
                    331:  err_find_driver:
                    332:  err_bad_action:
                    333:  err_bad_signature:
                    334:        return bofmrc;
                    335: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.