Annotation of qemu/roms/ipxe/src/drivers/bus/pcivpd.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2010 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 <stdlib.h>
        !            23: #include <unistd.h>
        !            24: #include <errno.h>
        !            25: #include <byteswap.h>
        !            26: #include <ipxe/pci.h>
        !            27: #include <ipxe/isapnp.h>
        !            28: #include <ipxe/pcivpd.h>
        !            29: 
        !            30: /** @file
        !            31:  *
        !            32:  * PCI Vital Product Data
        !            33:  *
        !            34:  */
        !            35: 
        !            36: /**
        !            37:  * Initialise PCI Vital Product Data
        !            38:  *
        !            39:  * @v vpd              PCI VPD
        !            40:  * @v pci              PCI device
        !            41:  * @ret rc             Return status code
        !            42:  */
        !            43: int pci_vpd_init ( struct pci_vpd *vpd, struct pci_device *pci ) {
        !            44: 
        !            45:        /* Initialise structure */
        !            46:        vpd->pci = pci;
        !            47:        pci_vpd_invalidate_cache ( vpd );
        !            48: 
        !            49:        /* Locate VPD capability */
        !            50:        vpd->cap = pci_find_capability ( pci, PCI_CAP_ID_VPD );
        !            51:        if ( ! vpd->cap ) {
        !            52:                DBGC ( vpd, PCI_FMT " does not support VPD\n",
        !            53:                       PCI_ARGS ( pci ) );
        !            54:                return -ENOTTY;
        !            55:        }
        !            56: 
        !            57:        DBGC ( vpd, PCI_FMT " VPD is at offset %02x\n",
        !            58:               PCI_ARGS ( pci ), vpd->cap );
        !            59:        return 0;
        !            60: }
        !            61: 
        !            62: /**
        !            63:  * Read one dword of PCI Vital Product Data
        !            64:  *
        !            65:  * @v vpd              PCI VPD
        !            66:  * @v address          Address to read
        !            67:  * @ret data           Read data
        !            68:  * @ret rc             Return status code
        !            69:  */
        !            70: static int pci_vpd_read_dword ( struct pci_vpd *vpd, int address,
        !            71:                                uint32_t *data ) {
        !            72:        struct pci_device *pci = vpd->pci;
        !            73:        unsigned int cap = vpd->cap;
        !            74:        unsigned int retries;
        !            75:        uint16_t flag;
        !            76: 
        !            77:        /* Fail if no VPD present */
        !            78:        if ( ! cap )
        !            79:                return -ENOTTY;
        !            80: 
        !            81:        /* Return cached value, if present */
        !            82:        if ( pci_vpd_cache_is_valid ( vpd ) &&
        !            83:             ( vpd->cache.address == address ) ) {
        !            84:                *data = vpd->cache.data;
        !            85:                return 0;
        !            86:        }
        !            87: 
        !            88:        /* Initiate read */
        !            89:        pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), address );
        !            90: 
        !            91:        /* Wait for read to complete */
        !            92:        for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
        !            93: 
        !            94:                /* Check if data is ready */
        !            95:                pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
        !            96:                if ( flag & PCI_VPD_FLAG ) {
        !            97: 
        !            98:                        /* Read data */
        !            99:                        pci_read_config_dword ( pci, ( cap + PCI_VPD_DATA ),
        !           100:                                                data );
        !           101:                        DBGC2 ( vpd, PCI_FMT " VPD %04x => %08x\n",
        !           102:                                PCI_ARGS ( pci ), address, htonl ( *data ) );
        !           103: 
        !           104:                        /* Populate cache */
        !           105:                        vpd->cache.address = address;
        !           106:                        vpd->cache.data = *data;
        !           107: 
        !           108:                        return 0;
        !           109:                }
        !           110: 
        !           111:                /* Wait 1ms before retrying */
        !           112:                mdelay ( 1 );
        !           113:        }
        !           114: 
        !           115:        DBGC ( vpd, PCI_FMT " VPD %04x read via %02x timed out\n",
        !           116:               PCI_ARGS ( pci ), address, cap );
        !           117:        return -ETIMEDOUT;
        !           118: }
        !           119: 
        !           120: /**
        !           121:  * Write one dword of PCI Vital Product Data
        !           122:  *
        !           123:  * @v vpd              PCI VPD
        !           124:  * @v address          Address to write
        !           125:  * @v data             Data to write
        !           126:  * @ret rc             Return status code
        !           127:  */
        !           128: static int pci_vpd_write_dword ( struct pci_vpd *vpd, int address,
        !           129:                                 uint32_t data ) {
        !           130:        struct pci_device *pci = vpd->pci;
        !           131:        unsigned int cap = vpd->cap;
        !           132:        unsigned int retries;
        !           133:        uint16_t flag;
        !           134: 
        !           135:        /* Fail if no VPD present */
        !           136:        if ( ! cap )
        !           137:                return -ENOTTY;
        !           138: 
        !           139:        /* Invalidate cache */
        !           140:        pci_vpd_invalidate_cache ( vpd );
        !           141: 
        !           142:        DBGC2 ( vpd, PCI_FMT " VPD %04x <= %08x\n",
        !           143:                PCI_ARGS ( pci ), address, htonl ( data ) );
        !           144: 
        !           145:        /* Write data */
        !           146:        pci_write_config_dword ( pci, ( cap + PCI_VPD_DATA ), data );
        !           147: 
        !           148:        /* Initiate write */
        !           149:        pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ),
        !           150:                                ( address | PCI_VPD_FLAG ) );
        !           151: 
        !           152:        /* Wait for write to complete */
        !           153:        for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
        !           154: 
        !           155:                /* Check if write has completed */
        !           156:                pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
        !           157:                if ( ! ( flag & PCI_VPD_FLAG ) )
        !           158:                        return 0;
        !           159: 
        !           160:                /* Wait 1ms before retrying */
        !           161:                mdelay ( 1 );
        !           162:        }
        !           163: 
        !           164:        DBGC ( vpd, PCI_FMT " VPD %04x write via %02x timed out\n",
        !           165:               PCI_ARGS ( pci ), address, cap );
        !           166:        return -ETIMEDOUT;
        !           167: }
        !           168: 
        !           169: /**
        !           170:  * Read PCI VPD
        !           171:  *
        !           172:  * @v vpd              PCI VPD
        !           173:  * @v address          Starting address
        !           174:  * @v buf              Data buffer
        !           175:  * @v len              Length of data buffer
        !           176:  * @ret rc             Return status code
        !           177:  */
        !           178: int pci_vpd_read ( struct pci_vpd *vpd, unsigned int address, void *buf,
        !           179:                   size_t len ) {
        !           180:        uint8_t *bytes = buf;
        !           181:        uint32_t data;
        !           182:        size_t skip_len;
        !           183:        unsigned int i;
        !           184:        int rc;
        !           185: 
        !           186:        /* Calculate length to skip at start of data */
        !           187:        skip_len = ( address & 0x03 );
        !           188: 
        !           189:        /* Read data, a dword at a time */
        !           190:        for ( address &= ~0x03 ; len ; address += 4 ) {
        !           191: 
        !           192:                /* Read whole dword */
        !           193:                if ( ( rc = pci_vpd_read_dword ( vpd, address, &data ) ) != 0 )
        !           194:                        return rc;
        !           195: 
        !           196:                /* Copy data to buffer */
        !           197:                for ( i = 4 ; i ; i-- ) {
        !           198:                        if ( skip_len ) {
        !           199:                                skip_len--;
        !           200:                        } else if ( len ) {
        !           201:                                *(bytes++) = data;
        !           202:                                len--;
        !           203:                        }
        !           204:                        data = ( ( data << 24 ) | ( data >> 8 ) );
        !           205:                }
        !           206:        }
        !           207: 
        !           208:        return 0;
        !           209: }
        !           210: 
        !           211: /**
        !           212:  * Write PCI VPD
        !           213:  *
        !           214:  * @v vpd              PCI VPD
        !           215:  * @v address          Starting address
        !           216:  * @v buf              Data buffer
        !           217:  * @v len              Length of data buffer
        !           218:  * @ret rc             Return status code
        !           219:  */
        !           220: int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address, const void *buf,
        !           221:                    size_t len ) {
        !           222:        const uint8_t *bytes = buf;
        !           223:        uint32_t data;
        !           224:        size_t skip_len;
        !           225:        unsigned int i;
        !           226:        int rc;
        !           227: 
        !           228:        /* Calculate length to skip at start of data */
        !           229:        skip_len = ( address & 0x03 );
        !           230: 
        !           231:        /* Write data, a dword at a time */
        !           232:        for ( address &= ~0x03 ; len ; address += 4 ) {
        !           233: 
        !           234:                /* Read existing dword, if necessary */
        !           235:                if ( skip_len || ( len <= 0x03 ) ) {
        !           236:                        if ( ( rc = pci_vpd_read_dword ( vpd, address,
        !           237:                                                         &data ) ) != 0 )
        !           238:                                return rc;
        !           239:                }
        !           240: 
        !           241:                /* Copy data from buffer */
        !           242:                for ( i = 4 ; i ; i-- ) {
        !           243:                        if ( skip_len ) {
        !           244:                                skip_len--;
        !           245:                        } else if ( len ) {
        !           246:                                data = ( ( data & ~0xff ) | *(bytes++) );
        !           247:                                len--;
        !           248:                        }
        !           249:                        data = ( ( data << 24 ) | ( data >> 8 ) );
        !           250:                }
        !           251: 
        !           252:                /* Write whole dword */
        !           253:                if ( ( rc = pci_vpd_write_dword ( vpd, address, data ) ) != 0 )
        !           254:                        return rc;
        !           255:        }
        !           256:        return 0;
        !           257: }
        !           258: 
        !           259: /**
        !           260:  * Dump PCI VPD region (for debugging)
        !           261:  *
        !           262:  * @v vpd              PCI VPD
        !           263:  * @v address          Starting address
        !           264:  * @v len              Length of data
        !           265:  */
        !           266: static void pci_vpd_dump ( struct pci_vpd *vpd, unsigned int address,
        !           267:                           size_t len ) {
        !           268:        int rc;
        !           269: 
        !           270:        /* Do nothing in non-debug builds */
        !           271:        if ( ! DBG_LOG )
        !           272:                return;
        !           273: 
        !           274:        /* Read data */
        !           275:        {
        !           276:                char buf[len];
        !           277:                if ( ( rc = pci_vpd_read ( vpd, address, buf,
        !           278:                                           sizeof ( buf ) ) ) != 0 )
        !           279:                        return;
        !           280:                DBGC_HDA ( vpd, address, buf, sizeof ( buf ) );
        !           281:        }
        !           282: }
        !           283: 
        !           284: /**
        !           285:  * Locate PCI VPD tag
        !           286:  *
        !           287:  * @v vpd              PCI VPD
        !           288:  * @v tag              ISAPnP tag
        !           289:  * @ret address                Address of tag body
        !           290:  * @ret len            Length of tag body
        !           291:  * @ret rc             Return status code
        !           292:  */
        !           293: static int pci_vpd_find_tag ( struct pci_vpd *vpd, unsigned int tag,
        !           294:                              unsigned int *address, size_t *len ) {
        !           295:        uint8_t read_tag;
        !           296:        uint16_t read_len;
        !           297:        int rc;
        !           298: 
        !           299:        /* Scan through tags looking for a match */
        !           300:        *address = 0;
        !           301:        do {
        !           302:                /* Read tag byte */
        !           303:                if ( ( rc = pci_vpd_read ( vpd, (*address)++, &read_tag,
        !           304:                                           sizeof ( read_tag ) ) ) != 0 )
        !           305:                        return rc;
        !           306: 
        !           307:                /* Extract tag and length */
        !           308:                if ( ISAPNP_IS_LARGE_TAG ( read_tag ) ) {
        !           309:                        if ( ( rc = pci_vpd_read ( vpd, *address, &read_len,
        !           310:                                                   sizeof ( read_len ) ) ) != 0)
        !           311:                                return rc;
        !           312:                        *address += sizeof ( read_len );
        !           313:                        read_len = le16_to_cpu ( read_len );
        !           314:                        read_tag = ISAPNP_LARGE_TAG_NAME ( read_tag );
        !           315:                } else {
        !           316:                        read_len = ISAPNP_SMALL_TAG_LEN ( read_tag );
        !           317:                        read_tag = ISAPNP_SMALL_TAG_NAME ( read_tag );
        !           318:                }
        !           319: 
        !           320:                /* Check for tag match */
        !           321:                if ( tag == read_tag ) {
        !           322:                        *len = read_len;
        !           323:                        DBGC ( vpd, PCI_FMT " VPD tag %02x is at "
        !           324:                               "[%04x,%04zx)\n", PCI_ARGS ( vpd->pci ), tag,
        !           325:                               *address, ( *address + *len ) );
        !           326:                        return 0;
        !           327:                }
        !           328: 
        !           329:                /* Move to next tag */
        !           330:                *address += read_len;
        !           331: 
        !           332:        } while ( read_tag != ISAPNP_TAG_END );
        !           333: 
        !           334:        DBGC ( vpd, PCI_FMT " VPD tag %02x not found\n",
        !           335:               PCI_ARGS ( vpd->pci ), tag );
        !           336:        return -ENOENT;
        !           337: }
        !           338: 
        !           339: /**
        !           340:  * Locate PCI VPD field
        !           341:  *
        !           342:  * @v vpd              PCI VPD
        !           343:  * @v field            VPD field descriptor
        !           344:  * @ret address                Address of field body
        !           345:  * @ret len            Length of field body
        !           346:  * @ret rc             Return status code
        !           347:  */
        !           348: int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
        !           349:                   unsigned int *address, size_t *len ) {
        !           350:        struct pci_vpd_field read_field;
        !           351:        int rc;
        !           352: 
        !           353:        /* Locate containing tag */
        !           354:        if ( ( rc = pci_vpd_find_tag ( vpd, PCI_VPD_TAG ( field ),
        !           355:                                       address, len ) ) != 0 )
        !           356:                return rc;
        !           357: 
        !           358:        /* Return immediately if we are searching for a whole-tag field */
        !           359:        if ( ! PCI_VPD_KEYWORD ( field ) ) {
        !           360:                pci_vpd_dump ( vpd, *address, *len );
        !           361:                return 0;
        !           362:        }
        !           363: 
        !           364:        /* Scan through fields looking for a match */
        !           365:        while ( *len >= sizeof ( read_field ) ) {
        !           366: 
        !           367:                /* Read field header */
        !           368:                if ( ( rc = pci_vpd_read ( vpd, *address, &read_field,
        !           369:                                           sizeof ( read_field ) ) ) != 0 )
        !           370:                        return rc;
        !           371:                *address += sizeof ( read_field );
        !           372:                *len -= sizeof ( read_field );
        !           373: 
        !           374:                /* Check for keyword match */
        !           375:                if ( read_field.keyword == PCI_VPD_KEYWORD ( field ) ) {
        !           376:                        *len = read_field.len;
        !           377:                        DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
        !           378:                               " is at [%04x,%04zx)\n", PCI_ARGS ( vpd->pci ),
        !           379:                               PCI_VPD_FIELD_ARGS ( field ),
        !           380:                               *address, ( *address + *len ) );
        !           381:                        pci_vpd_dump ( vpd, *address, *len );
        !           382:                        return 0;
        !           383:                }
        !           384: 
        !           385:                /* Move to next field */
        !           386:                if ( read_field.len > *len )
        !           387:                        break;
        !           388:                *address += read_field.len;
        !           389:                *len -= read_field.len;
        !           390:        }
        !           391: 
        !           392:        DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " not found\n",
        !           393:               PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ) );
        !           394:        return -ENOENT;
        !           395: }
        !           396: 
        !           397: /**
        !           398:  * Resize VPD field
        !           399:  *
        !           400:  * @v vpd              PCI VPD
        !           401:  * @v field            VPD field descriptor
        !           402:  * @v len              New length of field body
        !           403:  * @ret address                Address of field body
        !           404:  * @ret rc             Return status code
        !           405:  */
        !           406: int pci_vpd_resize ( struct pci_vpd *vpd, unsigned int field, size_t len,
        !           407:                     unsigned int *address ) {
        !           408:        struct pci_vpd_field rw_field;
        !           409:        struct pci_vpd_field old_field;
        !           410:        struct pci_vpd_field new_field;
        !           411:        unsigned int rw_address;
        !           412:        unsigned int old_address;
        !           413:        unsigned int copy_address;
        !           414:        unsigned int dst_address;
        !           415:        unsigned int dump_address;
        !           416:        size_t rw_len;
        !           417:        size_t old_len;
        !           418:        size_t available_len;
        !           419:        size_t copy_len;
        !           420:        size_t dump_len;
        !           421:        void *copy;
        !           422:        int rc;
        !           423: 
        !           424:        /* Sanity checks */
        !           425:        assert ( PCI_VPD_TAG ( field ) == PCI_VPD_TAG_RW );
        !           426:        assert ( PCI_VPD_KEYWORD ( field ) != 0 );
        !           427:        assert ( field != PCI_VPD_FIELD_RW );
        !           428: 
        !           429:        /* Locate 'RW' field */
        !           430:        if ( ( rc = pci_vpd_find ( vpd, PCI_VPD_FIELD_RW, &rw_address,
        !           431:                                   &rw_len ) ) != 0 )
        !           432:                goto err_no_rw;
        !           433: 
        !           434:        /* Locate old field, if any */
        !           435:        if ( ( rc = pci_vpd_find ( vpd, field, &old_address,
        !           436:                                   &old_len ) ) == 0 ) {
        !           437: 
        !           438:                /* Field already exists */
        !           439:                if ( old_address > rw_address ) {
        !           440:                        DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
        !           441:                               " at [%04x,%04zx) is after field "
        !           442:                               PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
        !           443:                               PCI_ARGS ( vpd->pci ),
        !           444:                               PCI_VPD_FIELD_ARGS ( field ),
        !           445:                               old_address, ( old_address + old_len ),
        !           446:                               PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ),
        !           447:                               rw_address, ( rw_address + rw_len ) );
        !           448:                        rc = -ENXIO;
        !           449:                        goto err_after_rw;
        !           450:                }
        !           451:                dst_address = ( old_address - sizeof ( old_field ) );
        !           452:                copy_address = ( old_address + old_len );
        !           453:                copy_len = ( rw_address - sizeof ( rw_field ) - copy_address );
        !           454: 
        !           455:                /* Calculate available length */
        !           456:                available_len = ( rw_len + old_len );
        !           457: 
        !           458:        } else {
        !           459: 
        !           460:                /* Field does not yet exist */
        !           461:                dst_address = ( rw_address - sizeof ( rw_field ) );
        !           462:                copy_address = dst_address;
        !           463:                copy_len = 0;
        !           464: 
        !           465:                /* Calculate available length */
        !           466:                available_len = ( ( rw_len > sizeof ( new_field ) ) ?
        !           467:                                  ( rw_len - sizeof ( new_field ) ) : 0 );
        !           468:        }
        !           469: 
        !           470:        /* Dump region before changes */
        !           471:        dump_address = dst_address;
        !           472:        dump_len = ( rw_address + rw_len - dump_address );
        !           473:        DBGC ( vpd, PCI_FMT " VPD before resizing field " PCI_VPD_FIELD_FMT
        !           474:               " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
        !           475:               PCI_VPD_FIELD_ARGS ( field ), len );
        !           476:        pci_vpd_dump ( vpd, dump_address, dump_len );
        !           477: 
        !           478:        /* Check available length */
        !           479:        if ( available_len > PCI_VPD_MAX_LEN )
        !           480:                available_len = PCI_VPD_MAX_LEN;
        !           481:        if ( len > available_len ) {
        !           482:                DBGC ( vpd, PCI_FMT " VPD no space for field "
        !           483:                       PCI_VPD_FIELD_FMT " (need %02zx, have %02zx)\n",
        !           484:                       PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ),
        !           485:                       len, available_len );
        !           486:                rc = -ENOSPC;
        !           487:                goto err_no_space;
        !           488:        }
        !           489: 
        !           490:        /* Preserve intermediate fields, if any */
        !           491:        copy = malloc ( copy_len );
        !           492:        if ( ! copy ) {
        !           493:                rc = -ENOMEM;
        !           494:                goto err_copy_alloc;
        !           495:        }
        !           496:        if ( ( rc = pci_vpd_read ( vpd, copy_address, copy, copy_len ) ) != 0 )
        !           497:                goto err_copy_read;
        !           498: 
        !           499:        /* Create new field, if applicable */
        !           500:        if ( len ) {
        !           501:                new_field.keyword = PCI_VPD_KEYWORD ( field );
        !           502:                new_field.len = len;
        !           503:                if ( ( rc = pci_vpd_write ( vpd, dst_address, &new_field,
        !           504:                                            sizeof ( new_field ) ) ) != 0 )
        !           505:                        goto err_new_write;
        !           506:                dst_address += sizeof ( new_field );
        !           507:                *address = dst_address;
        !           508:                DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
        !           509:                       "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
        !           510:                       PCI_VPD_FIELD_ARGS ( field ), dst_address,
        !           511:                       ( dst_address + new_field.len ) );
        !           512:                dst_address += len;
        !           513:        } else {
        !           514:                DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
        !           515:                       " no longer exists\n", PCI_ARGS ( vpd->pci ),
        !           516:                       PCI_VPD_FIELD_ARGS ( field ) );
        !           517:        }
        !           518: 
        !           519:        /* Restore intermediate fields, if any */
        !           520:        if ( ( rc = pci_vpd_write ( vpd, dst_address, copy, copy_len ) ) != 0 )
        !           521:                goto err_copy_write;
        !           522:        dst_address += copy_len;
        !           523: 
        !           524:        /* Create 'RW' field */
        !           525:        rw_field.keyword = PCI_VPD_KEYWORD ( PCI_VPD_FIELD_RW );
        !           526:        rw_field.len = ( rw_len +
        !           527:                         ( rw_address - sizeof ( rw_field ) ) - dst_address );
        !           528:        if ( ( rc = pci_vpd_write ( vpd, dst_address, &rw_field,
        !           529:                                    sizeof ( rw_field ) ) ) != 0 )
        !           530:                goto err_rw_write;
        !           531:        dst_address += sizeof ( rw_field );
        !           532:        DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
        !           533:               "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
        !           534:               PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ), dst_address,
        !           535:               ( dst_address + rw_field.len ) );
        !           536: 
        !           537:        /* Dump region after changes */
        !           538:        DBGC ( vpd, PCI_FMT " VPD after resizing field " PCI_VPD_FIELD_FMT
        !           539:               " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
        !           540:               PCI_VPD_FIELD_ARGS ( field ), len );
        !           541:        pci_vpd_dump ( vpd, dump_address, dump_len );
        !           542: 
        !           543:        rc = 0;
        !           544: 
        !           545:  err_rw_write:
        !           546:  err_new_write:
        !           547:  err_copy_write:
        !           548:  err_copy_read:
        !           549:        free ( copy );
        !           550:  err_copy_alloc:
        !           551:  err_no_space:
        !           552:  err_after_rw:
        !           553:  err_no_rw:
        !           554:        return rc;
        !           555: }

unix.superglobalmegacorp.com

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