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

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * Based in part on pci.c from Etherboot 5.4, by Ken Yap and David
        !             5:  * Munro, in turn based on the Linux kernel's PCI implementation.
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or
        !             8:  * modify it under the terms of the GNU General Public License as
        !             9:  * published by the Free Software Foundation; either version 2 of the
        !            10:  * License, or any later version.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            15:  * General Public License for more details.
        !            16:  *
        !            17:  * You should have received a copy of the GNU General Public License
        !            18:  * along with this program; if not, write to the Free Software
        !            19:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            20:  */
        !            21: 
        !            22: FILE_LICENCE ( GPL2_OR_LATER );
        !            23: 
        !            24: #include <stdint.h>
        !            25: #include <stdlib.h>
        !            26: #include <stdio.h>
        !            27: #include <string.h>
        !            28: #include <errno.h>
        !            29: #include <ipxe/tables.h>
        !            30: #include <ipxe/device.h>
        !            31: #include <ipxe/pci.h>
        !            32: 
        !            33: /** @file
        !            34:  *
        !            35:  * PCI bus
        !            36:  *
        !            37:  */
        !            38: 
        !            39: static void pcibus_remove ( struct root_device *rootdev );
        !            40: 
        !            41: /**
        !            42:  * Read PCI BAR
        !            43:  *
        !            44:  * @v pci              PCI device
        !            45:  * @v reg              PCI register number
        !            46:  * @ret bar            Base address register
        !            47:  *
        !            48:  * Reads the specified PCI base address register, including the flags
        !            49:  * portion.  64-bit BARs will be handled automatically.  If the value
        !            50:  * of the 64-bit BAR exceeds the size of an unsigned long (i.e. if the
        !            51:  * high dword is non-zero on a 32-bit platform), then the value
        !            52:  * returned will be zero plus the flags for a 64-bit BAR.  Unreachable
        !            53:  * 64-bit BARs are therefore returned as uninitialised 64-bit BARs.
        !            54:  */
        !            55: static unsigned long pci_bar ( struct pci_device *pci, unsigned int reg ) {
        !            56:        uint32_t low;
        !            57:        uint32_t high;
        !            58: 
        !            59:        pci_read_config_dword ( pci, reg, &low );
        !            60:        if ( ( low & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK) )
        !            61:             == (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64) ){
        !            62:                pci_read_config_dword ( pci, reg + 4, &high );
        !            63:                if ( high ) {
        !            64:                        if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
        !            65:                                return ( ( ( uint64_t ) high << 32 ) | low );
        !            66:                        } else {
        !            67:                                DBGC ( pci, PCI_FMT " unhandled 64-bit BAR "
        !            68:                                       "%08x%08x\n",
        !            69:                                       PCI_ARGS ( pci ), high, low );
        !            70:                                return PCI_BASE_ADDRESS_MEM_TYPE_64;
        !            71:                        }
        !            72:                }
        !            73:        }
        !            74:        return low;
        !            75: }
        !            76: 
        !            77: /**
        !            78:  * Find the start of a PCI BAR
        !            79:  *
        !            80:  * @v pci              PCI device
        !            81:  * @v reg              PCI register number
        !            82:  * @ret start          BAR start address
        !            83:  *
        !            84:  * Reads the specified PCI base address register, and returns the
        !            85:  * address portion of the BAR (i.e. without the flags).
        !            86:  *
        !            87:  * If the address exceeds the size of an unsigned long (i.e. if a
        !            88:  * 64-bit BAR has a non-zero high dword on a 32-bit machine), the
        !            89:  * return value will be zero.
        !            90:  */
        !            91: unsigned long pci_bar_start ( struct pci_device *pci, unsigned int reg ) {
        !            92:        unsigned long bar;
        !            93: 
        !            94:        bar = pci_bar ( pci, reg );
        !            95:        if ( (bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY ){
        !            96:                return ( bar & PCI_BASE_ADDRESS_MEM_MASK );
        !            97:        } else {
        !            98:                return ( bar & PCI_BASE_ADDRESS_IO_MASK );
        !            99:        }
        !           100: }
        !           101: 
        !           102: /**
        !           103:  * Read membase and ioaddr for a PCI device
        !           104:  *
        !           105:  * @v pci              PCI device
        !           106:  *
        !           107:  * This scans through all PCI BARs on the specified device.  The first
        !           108:  * valid memory BAR is recorded as pci_device::membase, and the first
        !           109:  * valid IO BAR is recorded as pci_device::ioaddr.
        !           110:  *
        !           111:  * 64-bit BARs are handled automatically.  On a 32-bit platform, if a
        !           112:  * 64-bit BAR has a non-zero high dword, it will be regarded as
        !           113:  * invalid.
        !           114:  */
        !           115: static void pci_read_bases ( struct pci_device *pci ) {
        !           116:        unsigned long bar;
        !           117:        int reg;
        !           118: 
        !           119:        for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) {
        !           120:                bar = pci_bar ( pci, reg );
        !           121:                if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) {
        !           122:                        if ( ! pci->ioaddr )
        !           123:                                pci->ioaddr = 
        !           124:                                        ( bar & PCI_BASE_ADDRESS_IO_MASK );
        !           125:                } else {
        !           126:                        if ( ! pci->membase )
        !           127:                                pci->membase =
        !           128:                                        ( bar & PCI_BASE_ADDRESS_MEM_MASK );
        !           129:                        /* Skip next BAR if 64-bit */
        !           130:                        if ( bar & PCI_BASE_ADDRESS_MEM_TYPE_64 )
        !           131:                                reg += 4;
        !           132:                }
        !           133:        }
        !           134: }
        !           135: 
        !           136: /**
        !           137:  * Enable PCI device
        !           138:  *
        !           139:  * @v pci              PCI device
        !           140:  *
        !           141:  * Set device to be a busmaster in case BIOS neglected to do so.  Also
        !           142:  * adjust PCI latency timer to a reasonable value, 32.
        !           143:  */
        !           144: void adjust_pci_device ( struct pci_device *pci ) {
        !           145:        unsigned short new_command, pci_command;
        !           146:        unsigned char pci_latency;
        !           147: 
        !           148:        pci_read_config_word ( pci, PCI_COMMAND, &pci_command );
        !           149:        new_command = ( pci_command | PCI_COMMAND_MASTER |
        !           150:                        PCI_COMMAND_MEM | PCI_COMMAND_IO );
        !           151:        if ( pci_command != new_command ) {
        !           152:                DBGC ( pci, PCI_FMT " device not enabled by BIOS! Updating "
        !           153:                       "PCI command %04x->%04x\n",
        !           154:                       PCI_ARGS ( pci ), pci_command, new_command );
        !           155:                pci_write_config_word ( pci, PCI_COMMAND, new_command );
        !           156:        }
        !           157: 
        !           158:        pci_read_config_byte ( pci, PCI_LATENCY_TIMER, &pci_latency);
        !           159:        if ( pci_latency < 32 ) {
        !           160:                DBGC ( pci, PCI_FMT " latency timer is unreasonably low at "
        !           161:                       "%d. Setting to 32.\n", PCI_ARGS ( pci ), pci_latency );
        !           162:                pci_write_config_byte ( pci, PCI_LATENCY_TIMER, 32);
        !           163:        }
        !           164: }
        !           165: 
        !           166: /**
        !           167:  * Read PCI device configuration
        !           168:  *
        !           169:  * @v pci              PCI device
        !           170:  * @ret rc             Return status code
        !           171:  */
        !           172: int pci_read_config ( struct pci_device *pci ) {
        !           173:        uint32_t tmp;
        !           174: 
        !           175:        /* Check for physical device presence */
        !           176:        pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
        !           177:        if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
        !           178:                return -ENODEV;
        !           179: 
        !           180:        /* Populate struct pci_device */
        !           181:        pci->vendor = ( tmp & 0xffff );
        !           182:        pci->device = ( tmp >> 16 );
        !           183:        pci_read_config_dword ( pci, PCI_REVISION, &tmp );
        !           184:        pci->class = ( tmp >> 8 );
        !           185:        pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
        !           186:        pci_read_bases ( pci );
        !           187: 
        !           188:        /* Initialise generic device component */
        !           189:        snprintf ( pci->dev.name, sizeof ( pci->dev.name ),
        !           190:                   "PCI%02x:%02x.%x", PCI_BUS ( pci->busdevfn ),
        !           191:                   PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) );
        !           192:        pci->dev.desc.bus_type = BUS_TYPE_PCI;
        !           193:        pci->dev.desc.location = pci->busdevfn;
        !           194:        pci->dev.desc.vendor = pci->vendor;
        !           195:        pci->dev.desc.device = pci->device;
        !           196:        pci->dev.desc.class = pci->class;
        !           197:        pci->dev.desc.ioaddr = pci->ioaddr;
        !           198:        pci->dev.desc.irq = pci->irq;
        !           199:        INIT_LIST_HEAD ( &pci->dev.siblings );
        !           200:        INIT_LIST_HEAD ( &pci->dev.children );
        !           201: 
        !           202:        return 0;
        !           203: }
        !           204: 
        !           205: /**
        !           206:  * Find driver for PCI device
        !           207:  *
        !           208:  * @v pci              PCI device
        !           209:  * @ret rc             Return status code
        !           210:  */
        !           211: int pci_find_driver ( struct pci_device *pci ) {
        !           212:        struct pci_driver *driver;
        !           213:        struct pci_device_id *id;
        !           214:        unsigned int i;
        !           215: 
        !           216:        for_each_table_entry ( driver, PCI_DRIVERS ) {
        !           217:                for ( i = 0 ; i < driver->id_count ; i++ ) {
        !           218:                        id = &driver->ids[i];
        !           219:                        if ( ( id->vendor != PCI_ANY_ID ) &&
        !           220:                             ( id->vendor != pci->vendor ) )
        !           221:                                continue;
        !           222:                        if ( ( id->device != PCI_ANY_ID ) &&
        !           223:                             ( id->device != pci->device ) )
        !           224:                                continue;
        !           225:                        pci_set_driver ( pci, driver, id );
        !           226:                        return 0;
        !           227:                }
        !           228:        }
        !           229:        return -ENOENT;
        !           230: }
        !           231: 
        !           232: /**
        !           233:  * Probe a PCI device
        !           234:  *
        !           235:  * @v pci              PCI device
        !           236:  * @ret rc             Return status code
        !           237:  *
        !           238:  * Searches for a driver for the PCI device.  If a driver is found,
        !           239:  * its probe() routine is called.
        !           240:  */
        !           241: int pci_probe ( struct pci_device *pci ) {
        !           242:        int rc;
        !           243: 
        !           244:        DBGC ( pci, PCI_FMT " (%04x:%04x) has driver \"%s\"\n",
        !           245:               PCI_ARGS ( pci ), pci->vendor, pci->device, pci->id->name );
        !           246:        DBGC ( pci, PCI_FMT " has mem %lx io %lx irq %d\n",
        !           247:               PCI_ARGS ( pci ), pci->membase, pci->ioaddr, pci->irq );
        !           248: 
        !           249:        if ( ( rc = pci->driver->probe ( pci ) ) != 0 ) {
        !           250:                DBGC ( pci, PCI_FMT " probe failed: %s\n",
        !           251:                       PCI_ARGS ( pci ), strerror ( rc ) );
        !           252:                return rc;
        !           253:        }
        !           254: 
        !           255:        return 0;
        !           256: }
        !           257: 
        !           258: /**
        !           259:  * Remove a PCI device
        !           260:  *
        !           261:  * @v pci              PCI device
        !           262:  */
        !           263: void pci_remove ( struct pci_device *pci ) {
        !           264:        pci->driver->remove ( pci );
        !           265:        DBGC ( pci, PCI_FMT " removed\n", PCI_ARGS ( pci ) );
        !           266: }
        !           267: 
        !           268: /**
        !           269:  * Probe PCI root bus
        !           270:  *
        !           271:  * @v rootdev          PCI bus root device
        !           272:  *
        !           273:  * Scans the PCI bus for devices and registers all devices it can
        !           274:  * find.
        !           275:  */
        !           276: static int pcibus_probe ( struct root_device *rootdev ) {
        !           277:        struct pci_device *pci = NULL;
        !           278:        unsigned int num_bus;
        !           279:        unsigned int busdevfn;
        !           280:        uint8_t hdrtype = 0;
        !           281:        int rc;
        !           282: 
        !           283:        num_bus = pci_num_bus();
        !           284:        for ( busdevfn = 0 ; busdevfn < PCI_BUSDEVFN ( num_bus, 0, 0 ) ;
        !           285:              busdevfn++ ) {
        !           286: 
        !           287:                /* Allocate struct pci_device */
        !           288:                if ( ! pci )
        !           289:                        pci = malloc ( sizeof ( *pci ) );
        !           290:                if ( ! pci ) {
        !           291:                        rc = -ENOMEM;
        !           292:                        goto err;
        !           293:                }
        !           294:                memset ( pci, 0, sizeof ( *pci ) );
        !           295:                pci_init ( pci, busdevfn );
        !           296:                        
        !           297:                /* Skip all but the first function on
        !           298:                 * non-multifunction cards
        !           299:                 */
        !           300:                if ( PCI_FUNC ( busdevfn ) == 0 ) {
        !           301:                        pci_read_config_byte ( pci, PCI_HEADER_TYPE,
        !           302:                                               &hdrtype );
        !           303:                } else if ( ! ( hdrtype & 0x80 ) ) {
        !           304:                        continue;
        !           305:                }
        !           306: 
        !           307:                /* Read device configuration */
        !           308:                if ( ( rc = pci_read_config ( pci ) ) != 0 )
        !           309:                        continue;
        !           310: 
        !           311:                /* Look for a driver */
        !           312:                if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
        !           313:                        DBGC ( pci, PCI_FMT " (%04x:%04x) has no driver\n",
        !           314:                               PCI_ARGS ( pci ), pci->vendor, pci->device );
        !           315:                        continue;
        !           316:                }
        !           317: 
        !           318:                /* Add to device hierarchy */
        !           319:                pci->dev.parent = &rootdev->dev;
        !           320:                list_add ( &pci->dev.siblings, &rootdev->dev.children);
        !           321: 
        !           322:                /* Look for a driver */
        !           323:                if ( ( rc = pci_probe ( pci ) ) == 0 ) {
        !           324:                        /* pcidev registered, we can drop our ref */
        !           325:                        pci = NULL;
        !           326:                } else {
        !           327:                        /* Not registered; re-use struct pci_device */
        !           328:                        list_del ( &pci->dev.siblings );
        !           329:                }
        !           330:        }
        !           331: 
        !           332:        free ( pci );
        !           333:        return 0;
        !           334: 
        !           335:  err:
        !           336:        free ( pci );
        !           337:        pcibus_remove ( rootdev );
        !           338:        return rc;
        !           339: }
        !           340: 
        !           341: /**
        !           342:  * Remove PCI root bus
        !           343:  *
        !           344:  * @v rootdev          PCI bus root device
        !           345:  */
        !           346: static void pcibus_remove ( struct root_device *rootdev ) {
        !           347:        struct pci_device *pci;
        !           348:        struct pci_device *tmp;
        !           349: 
        !           350:        list_for_each_entry_safe ( pci, tmp, &rootdev->dev.children,
        !           351:                                   dev.siblings ) {
        !           352:                pci_remove ( pci );
        !           353:                list_del ( &pci->dev.siblings );
        !           354:                free ( pci );
        !           355:        }
        !           356: }
        !           357: 
        !           358: /** PCI bus root device driver */
        !           359: static struct root_driver pci_root_driver = {
        !           360:        .probe = pcibus_probe,
        !           361:        .remove = pcibus_remove,
        !           362: };
        !           363: 
        !           364: /** PCI bus root device */
        !           365: struct root_device pci_root_device __root_device = {
        !           366:        .dev = { .name = "PCI" },
        !           367:        .driver = &pci_root_driver,
        !           368: };

unix.superglobalmegacorp.com

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