Annotation of qemu/roms/ipxe/src/interface/bofm/bofm.c, revision 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.