Annotation of qemu/roms/openbios/drivers/pci.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *   OpenBIOS pci driver
        !             3:  *
        !             4:  *   This driver is compliant to the
        !             5:  *   PCI bus binding to IEEE 1275-1994 Rev 2.1
        !             6:  *
        !             7:  *   (C) 2004 Stefan Reinauer <[email protected]>
        !             8:  *   (C) 2005 Ed Schouten <[email protected]>
        !             9:  *
        !            10:  *   Some parts from OpenHackWare-0.4, Copyright (c) 2004-2005 Jocelyn Mayer
        !            11:  *
        !            12:  *   This program is free software; you can redistribute it and/or
        !            13:  *   modify it under the terms of the GNU General Public License
        !            14:  *   version 2
        !            15:  *
        !            16:  */
        !            17: 
        !            18: #include "config.h"
        !            19: #include "libopenbios/bindings.h"
        !            20: #include "kernel/kernel.h"
        !            21: #include "drivers/pci.h"
        !            22: #include "libc/byteorder.h"
        !            23: #include "libc/vsprintf.h"
        !            24: 
        !            25: #include "drivers/drivers.h"
        !            26: #include "drivers/vga.h"
        !            27: #include "timer.h"
        !            28: #include "pci.h"
        !            29: #include "pci_database.h"
        !            30: #ifdef CONFIG_DRIVER_MACIO
        !            31: #include "cuda.h"
        !            32: #include "macio.h"
        !            33: #endif
        !            34: 
        !            35: #if defined (CONFIG_DEBUG_PCI)
        !            36: # define PCI_DPRINTF(format, ...) printk(format, ## __VA_ARGS__)
        !            37: #else
        !            38: # define PCI_DPRINTF(format, ...) do { } while (0)
        !            39: #endif
        !            40: 
        !            41: #define set_bool_property(ph, name) set_property(ph, name, NULL, 0);
        !            42: 
        !            43: /* DECLARE data structures for the nodes.  */
        !            44: 
        !            45: DECLARE_UNNAMED_NODE( ob_pci_bus_node, INSTALL_OPEN, 2*sizeof(int) );
        !            46: DECLARE_UNNAMED_NODE( ob_pci_simple_node, INSTALL_OPEN, 2*sizeof(int) );
        !            47: 
        !            48: const pci_arch_t *arch;
        !            49: 
        !            50: #define IS_NOT_RELOCATABLE     0x80000000
        !            51: #define IS_PREFETCHABLE                0x40000000
        !            52: #define IS_ALIASED             0x20000000
        !            53: 
        !            54: enum {
        !            55:        CONFIGURATION_SPACE = 0,
        !            56:        IO_SPACE = 1,
        !            57:        MEMORY_SPACE_32 = 2,
        !            58:        MEMORY_SPACE_64 = 3,
        !            59: };
        !            60: 
        !            61: static int encode_int32_cells(int num_cells, u32 *prop, ucell val)
        !            62: {
        !            63:     int i = 0;
        !            64: 
        !            65:     /* hi ... lo */
        !            66:     for (i=0; i < num_cells; ++i) {
        !            67:         prop[num_cells - i - 1] = val;
        !            68:         val >>= 16;
        !            69:         val >>= 16;
        !            70:     }
        !            71: 
        !            72:     return num_cells;
        !            73: }
        !            74: 
        !            75: static inline int pci_encode_phys_addr(u32 *phys, int flags, int space_code,
        !            76:                                 pci_addr dev, uint8_t reg, uint64_t addr)
        !            77: {
        !            78: 
        !            79:        /* phys.hi */
        !            80: 
        !            81:        phys[0] = flags | (space_code << 24) | dev | reg;
        !            82: 
        !            83:        /* phys.mid */
        !            84: 
        !            85:        phys[1] = addr >> 32;
        !            86: 
        !            87:        /* phys.lo */
        !            88: 
        !            89:        phys[2] = addr;
        !            90: 
        !            91:        return 3;
        !            92: }
        !            93: 
        !            94: static inline int pci_encode_size(u32 *prop, uint64_t size)
        !            95: {
        !            96:     return encode_int32_cells(2, prop, size);
        !            97: }
        !            98: 
        !            99: static int host_address_cells(void)
        !           100: {
        !           101:     return get_int_property(find_dev("/"), "#address-cells", NULL);
        !           102: }
        !           103: 
        !           104: static int host_encode_phys_addr(u32 *prop, ucell addr)
        !           105: {
        !           106:     return encode_int32_cells(host_address_cells(), prop, addr);
        !           107: }
        !           108: 
        !           109: static int host_size_cells(void)
        !           110: {
        !           111:     return get_int_property(find_dev("/"), "#size-cells", NULL);
        !           112: }
        !           113: 
        !           114: /*
        !           115: static int parent_address_cells(void)
        !           116: {
        !           117:     phandle_t parent_ph = ih_to_phandle(my_parent());
        !           118:     return get_int_property(parent_ph, "#address-cells", NULL);
        !           119: }
        !           120: 
        !           121: static int parent_size_cells(void)
        !           122: {
        !           123:     phandle_t parent_ph = ih_to_phandle(my_parent());
        !           124:     return get_int_property(parent_ph, "#size-cells", NULL);
        !           125: }
        !           126: */
        !           127: 
        !           128: #if defined(CONFIG_DEBUG_PCI)
        !           129: static void dump_reg_property(const char* description, int nreg, u32 *reg)
        !           130: {
        !           131:     int i;
        !           132:     printk("%s reg", description);
        !           133:     for (i=0; i < nreg; ++i) {
        !           134:         printk(" %08X", reg[i]);
        !           135:     }
        !           136:     printk("\n");
        !           137: }
        !           138: #endif
        !           139: 
        !           140: static void
        !           141: ob_pci_open(int *idx)
        !           142: {
        !           143:        int ret=1;
        !           144:        RET ( -ret );
        !           145: }
        !           146: 
        !           147: static void
        !           148: ob_pci_close(int *idx)
        !           149: {
        !           150: }
        !           151: 
        !           152: static void
        !           153: ob_pci_initialize(int *idx)
        !           154: {
        !           155: }
        !           156: 
        !           157: /* ( str len -- phys.lo phys.mid phys.hi ) */
        !           158: 
        !           159: static void
        !           160: ob_pci_decode_unit(int *idx)
        !           161: {
        !           162:        ucell hi, mid, lo;
        !           163:        const char *arg = pop_fstr_copy();
        !           164:        int dev, fn, reg, ss, n, p, t;
        !           165:        int bus = 0;            /* no information */
        !           166:        char *ptr;
        !           167: 
        !           168:        PCI_DPRINTF("ob_pci_decode_unit idx=%p\n", idx);
        !           169: 
        !           170:        fn = 0;
        !           171:        reg = 0;
        !           172:        n = 0;
        !           173:        p = 0;
        !           174:        t = 0;
        !           175: 
        !           176:        ptr = (char*)arg;
        !           177:        if (*ptr == 'n') {
        !           178:                n = IS_NOT_RELOCATABLE;
        !           179:                ptr++;
        !           180:        }
        !           181:        if (*ptr == 'i') {
        !           182:                ss = IO_SPACE;
        !           183:                ptr++;
        !           184:                if (*ptr == 't') {
        !           185:                        t = IS_ALIASED;
        !           186:                        ptr++;
        !           187:                }
        !           188: 
        !           189:                /* DD,F,RR,NNNNNNNN */
        !           190: 
        !           191:                dev = strtol(ptr, &ptr, 16);
        !           192:                ptr++;
        !           193:                fn = strtol(ptr, &ptr, 16);
        !           194:                ptr++;
        !           195:                reg = strtol(ptr, &ptr, 16);
        !           196:                ptr++;
        !           197:                lo = strtol(ptr, &ptr, 16);
        !           198:                mid = 0;
        !           199: 
        !           200:        } else if (*ptr == 'm') {
        !           201:                ss = MEMORY_SPACE_32;
        !           202:                ptr++;
        !           203:                if (*ptr == 't') {
        !           204:                        t = IS_ALIASED;
        !           205:                        ptr++;
        !           206:                }
        !           207:                if (*ptr == 'p') {
        !           208:                        p = IS_PREFETCHABLE;
        !           209:                        ptr++;
        !           210:                }
        !           211: 
        !           212:                /* DD,F,RR,NNNNNNNN */
        !           213: 
        !           214:                dev = strtol(ptr, &ptr, 16);
        !           215:                ptr++;
        !           216:                fn = strtol(ptr, &ptr, 16);
        !           217:                ptr++;
        !           218:                reg = strtol(ptr, &ptr, 16);
        !           219:                ptr++;
        !           220:                lo = strtol(ptr, &ptr, 16);
        !           221:                mid = 0;
        !           222: 
        !           223:        } else if (*ptr == 'x') {
        !           224:                unsigned long long addr64;
        !           225:                ss = MEMORY_SPACE_64;
        !           226:                ptr++;
        !           227:                if (*ptr == 'p') {
        !           228:                        p = IS_PREFETCHABLE;
        !           229:                        ptr++;
        !           230:                }
        !           231: 
        !           232:                /* DD,F,RR,NNNNNNNNNNNNNNNN */
        !           233: 
        !           234:                dev = strtol(ptr, &ptr, 16);
        !           235:                ptr++;
        !           236:                fn = strtol(ptr, &ptr, 16);
        !           237:                ptr++;
        !           238:                reg = strtol(ptr, &ptr, 16);
        !           239:                ptr++;
        !           240:                addr64 = strtoll(ptr, &ptr, 16);
        !           241:                lo = (ucell)addr64;
        !           242:                mid = addr64 >> 32;
        !           243: 
        !           244:        } else {
        !           245:                ss = CONFIGURATION_SPACE;
        !           246:                /* "DD" or "DD,FF" */
        !           247:                dev = strtol(ptr, &ptr, 16);
        !           248:                if (*ptr == ',') {
        !           249:                        ptr++;
        !           250:                        fn = strtol(ptr, NULL, 16);
        !           251:                }
        !           252:                lo = 0;
        !           253:                mid = 0;
        !           254:        }
        !           255:        free((char*)arg);
        !           256: 
        !           257:        hi = n | p | t | (ss << 24) | (bus << 16) | (dev << 11) | (fn << 8) | reg;
        !           258: 
        !           259:        PUSH(lo);
        !           260:        PUSH(mid);
        !           261:        PUSH(hi);
        !           262: 
        !           263:        PCI_DPRINTF("ob_pci_decode_unit idx=%p addr="
        !           264:                FMT_ucellx " " FMT_ucellx " " FMT_ucellx "\n",
        !           265:                idx, lo, mid, hi);
        !           266: }
        !           267: 
        !           268: /*  ( phys.lo phy.mid phys.hi -- str len ) */
        !           269: 
        !           270: static void
        !           271: ob_pci_encode_unit(int *idx)
        !           272: {
        !           273:        char buf[28];
        !           274:        cell hi = POP();
        !           275:        cell mid = POP();
        !           276:        cell lo = POP();
        !           277:         int n, p, t, ss, dev, fn, reg;
        !           278: 
        !           279:        n = hi & IS_NOT_RELOCATABLE;
        !           280:        p = hi & IS_PREFETCHABLE;
        !           281:        t = hi & IS_ALIASED;
        !           282:        ss = (hi >> 24) & 0x03;
        !           283: 
        !           284:        dev = (hi >> 11) & 0x1F;
        !           285:        fn = (hi >> 8) & 0x07;
        !           286:        reg = hi & 0xFF;
        !           287: 
        !           288:        switch(ss) {
        !           289:        case CONFIGURATION_SPACE:
        !           290: 
        !           291:                if (fn == 0)    /* DD */
        !           292:                        snprintf(buf, sizeof(buf), "%x", dev);
        !           293:                else            /* DD,F */
        !           294:                        snprintf(buf, sizeof(buf), "%x,%x", dev, fn);
        !           295:                break;
        !           296: 
        !           297:        case IO_SPACE:
        !           298: 
        !           299:                /* [n]i[t]DD,F,RR,NNNNNNNN */
        !           300:                 snprintf(buf, sizeof(buf), "%si%s%x,%x,%x," FMT_ucellx,
        !           301:                         n ? "n" : "",  /* relocatable */
        !           302:                         t ? "t" : "",  /* aliased */
        !           303:                         dev, fn, reg, t ? lo & 0x03FF : lo);
        !           304:                break;
        !           305: 
        !           306:        case MEMORY_SPACE_32:
        !           307: 
        !           308:                /* [n]m[t][p]DD,F,RR,NNNNNNNN */
        !           309:                 snprintf(buf, sizeof(buf), "%sm%s%s%x,%x,%x," FMT_ucellx,
        !           310:                         n ? "n" : "",  /* relocatable */
        !           311:                         t ? "t" : "",  /* aliased */
        !           312:                         p ? "p" : "",  /* prefetchable */
        !           313:                         dev, fn, reg, lo );
        !           314:                break;
        !           315: 
        !           316:        case MEMORY_SPACE_64:
        !           317: 
        !           318:                /* [n]x[p]DD,F,RR,NNNNNNNNNNNNNNNN */
        !           319:                snprintf(buf, sizeof(buf), "%sx%s%x,%x,%x,%llx",
        !           320:                         n ? "n" : "",  /* relocatable */
        !           321:                         p ? "p" : "",  /* prefetchable */
        !           322:                          dev, fn, reg, ((long long)mid << 32) | (long long)lo);
        !           323:                break;
        !           324:        }
        !           325:        push_str(buf);
        !           326: 
        !           327:        PCI_DPRINTF("ob_pci_encode_unit space=%d dev=%d fn=%d buf=%s\n",
        !           328:                ss, dev, fn, buf);
        !           329: }
        !           330: 
        !           331: NODE_METHODS(ob_pci_bus_node) = {
        !           332:        { NULL,                 ob_pci_initialize       },
        !           333:        { "open",               ob_pci_open             },
        !           334:        { "close",              ob_pci_close            },
        !           335:        { "decode-unit",        ob_pci_decode_unit      },
        !           336:        { "encode-unit",        ob_pci_encode_unit      },
        !           337: };
        !           338: 
        !           339: NODE_METHODS(ob_pci_simple_node) = {
        !           340:        { NULL,                 ob_pci_initialize       },
        !           341:        { "open",               ob_pci_open             },
        !           342:        { "close",              ob_pci_close            },
        !           343: };
        !           344: 
        !           345: static void pci_set_bus_range(const pci_config_t *config)
        !           346: {
        !           347:        phandle_t dev = find_dev(config->path);
        !           348:        u32 props[2];
        !           349: 
        !           350:        props[0] = config->secondary_bus;
        !           351:        props[1] = config->subordinate_bus;
        !           352: 
        !           353:        PCI_DPRINTF("setting bus range for %s PCI device, "
        !           354:                "package handle " FMT_ucellx " "
        !           355:             "bus primary=%d secondary=%d subordinate=%d\n",
        !           356:             config->path,
        !           357:             dev,
        !           358:             config->primary_bus,
        !           359:             config->secondary_bus,
        !           360:             config->subordinate_bus);
        !           361: 
        !           362: 
        !           363:        set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0]));
        !           364: }
        !           365: 
        !           366: static void pci_host_set_interrupt_map(const pci_config_t *config)
        !           367: {
        !           368: /* XXX We currently have a hook in the MPIC init code to fill in its handle.
        !           369:  *     If you want to have interrupt maps for your PCI host bus, add your
        !           370:  *     architecture to the #if and make your bridge detect code fill in its
        !           371:  *     handle too.
        !           372:  *
        !           373:  *     It would be great if someone clever could come up with a more universal
        !           374:  *     mechanism here.
        !           375:  */
        !           376: #if defined(CONFIG_PPC)
        !           377:        phandle_t dev = get_cur_dev();
        !           378:        u32 props[7 * 4];
        !           379:        int i;
        !           380: 
        !           381: #if defined(CONFIG_PPC)
        !           382:        /* Oldworld macs do interrupt maps differently */
        !           383:        if(!is_newworld())
        !           384:                return;
        !           385: #endif
        !           386: 
        !           387:        for (i = 0; i < (7*4); i+=7) {
        !           388:                props[i+PCI_INT_MAP_PCI0] = 0;
        !           389:                props[i+PCI_INT_MAP_PCI1] = 0;
        !           390:                props[i+PCI_INT_MAP_PCI2] = 0;
        !           391:                props[i+PCI_INT_MAP_PCI_INT] = (i / 7) + 1; // starts at PINA=1
        !           392:                props[i+PCI_INT_MAP_PIC_HANDLE] = 0; // gets patched in later
        !           393:                props[i+PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7];
        !           394:                props[i+PCI_INT_MAP_PIC_POL] = 3;
        !           395:        }
        !           396:        set_property(dev, "interrupt-map", (char *)props, 7 * 4 * sizeof(props[0]));
        !           397: 
        !           398:        props[PCI_INT_MAP_PCI0] = 0;
        !           399:        props[PCI_INT_MAP_PCI1] = 0;
        !           400:        props[PCI_INT_MAP_PCI2] = 0;
        !           401:        props[PCI_INT_MAP_PCI_INT] = 0x7;
        !           402: 
        !           403:        set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
        !           404: #endif
        !           405: }
        !           406: 
        !           407: static void pci_host_set_reg(phandle_t phandle)
        !           408: {
        !           409:     phandle_t dev = phandle;
        !           410: 
        !           411:     /* at most 2 integers for address and size */
        !           412:     u32 props[4];
        !           413:     int ncells = 0;
        !           414: 
        !           415:     ncells += encode_int32_cells(host_address_cells(), props + ncells,
        !           416:             arch->cfg_base);
        !           417: 
        !           418:     ncells += encode_int32_cells(host_size_cells(), props + ncells,
        !           419:             arch->cfg_len);
        !           420: 
        !           421:     set_property(dev, "reg", (char *)props, ncells * sizeof(props[0]));
        !           422: 
        !           423: #if defined(CONFIG_DEBUG_PCI)
        !           424:     dump_reg_property("pci_host_set_reg", 4, props);
        !           425: #endif
        !           426: }
        !           427: 
        !           428: /* child-phys : parent-phys : size */
        !           429: /* 3 cells for PCI : 2 cells for 64bit parent : 2 cells for PCI */
        !           430: 
        !           431: static void pci_host_set_ranges(const pci_config_t *config)
        !           432: {
        !           433:        phandle_t dev = get_cur_dev();
        !           434:        u32 props[32];
        !           435:        int ncells;
        !           436: 
        !           437:        ncells = 0;
        !           438:        /* first encode PCI configuration space */
        !           439:        {
        !           440:            ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE,
        !           441:                      config->dev, 0, 0);
        !           442:         ncells += host_encode_phys_addr(props + ncells, arch->cfg_addr);
        !           443:         ncells += pci_encode_size(props + ncells, arch->cfg_len);
        !           444:        }
        !           445: 
        !           446:        if (arch->io_base) {
        !           447:            ncells += pci_encode_phys_addr(props + ncells, 0, IO_SPACE,
        !           448:                                     config->dev, 0, 0);
        !           449:         ncells += host_encode_phys_addr(props + ncells, arch->io_base);
        !           450:         ncells += pci_encode_size(props + ncells, arch->io_len);
        !           451:        }
        !           452:        if (arch->rbase) {
        !           453:            ncells += pci_encode_phys_addr(props + ncells, 0, MEMORY_SPACE_32,
        !           454:                                     config->dev, 0, 0);
        !           455:         ncells += host_encode_phys_addr(props + ncells, arch->rbase);
        !           456:         ncells += pci_encode_size(props + ncells, arch->rlen);
        !           457:        }
        !           458:        if (arch->host_mem_base) {
        !           459:            ncells += pci_encode_phys_addr(props + ncells, 0, MEMORY_SPACE_32,
        !           460:                                     config->dev, 0, arch->pci_mem_base);
        !           461:         ncells += host_encode_phys_addr(props + ncells, arch->host_mem_base);
        !           462:         ncells += pci_encode_size(props + ncells, arch->mem_len);
        !           463:        }
        !           464:        set_property(dev, "ranges", (char *)props, ncells * sizeof(props[0]));
        !           465: }
        !           466: 
        !           467: static unsigned long pci_bus_addr_to_host_addr(uint32_t ba)
        !           468: {
        !           469: #ifdef CONFIG_SPARC64
        !           470:     return arch->cfg_data + (unsigned long)ba;
        !           471: #else
        !           472:     return (unsigned long)ba;
        !           473: #endif
        !           474: }
        !           475: 
        !           476: int host_config_cb(const pci_config_t *config)
        !           477: {
        !           478:        //XXX this overrides "reg" property
        !           479:        pci_host_set_reg(get_cur_dev());
        !           480:        pci_host_set_ranges(config);
        !           481:        pci_host_set_interrupt_map(config);
        !           482: 
        !           483:        return 0;
        !           484: }
        !           485: 
        !           486: static int sabre_configure(phandle_t dev)
        !           487: {
        !           488:         uint32_t props[28];
        !           489: 
        !           490:         props[0] = 0xc0000000;
        !           491:         props[1] = 0x20000000;
        !           492:         set_property(dev, "virtual-dma", (char *)props, 2 * sizeof(props[0]));
        !           493:         props[0] = 1;
        !           494:         set_property(dev, "#virtual-dma-size-cells", (char *)props,
        !           495:                      sizeof(props[0]));
        !           496:         set_property(dev, "#virtual-dma-addr-cells", (char *)props,
        !           497:                      sizeof(props[0]));
        !           498:         props[0] = 0x000007f0;
        !           499:         props[1] = 0x000007ee;
        !           500:         props[2] = 0x000007ef;
        !           501:         props[3] = 0x000007e5;
        !           502:         set_property(dev, "interrupts", (char *)props, 4 * sizeof(props[0]));
        !           503:         props[0] = 0x0000001f;
        !           504:         set_property(dev, "upa-portid", (char *)props, 1 * sizeof(props[0]));
        !           505:         return 0;
        !           506: }
        !           507: 
        !           508: int sabre_config_cb(const pci_config_t *config)
        !           509: {
        !           510:     host_config_cb(config);
        !           511: 
        !           512:     return sabre_configure(get_cur_dev());
        !           513: }
        !           514: 
        !           515: int bridge_config_cb(const pci_config_t *config)
        !           516: {
        !           517:        phandle_t aliases;
        !           518: 
        !           519:        aliases = find_dev("/aliases");
        !           520:        set_property(aliases, "bridge", config->path, strlen(config->path) + 1);
        !           521: 
        !           522:        return 0;
        !           523: }
        !           524: 
        !           525: int ide_config_cb2 (const pci_config_t *config)
        !           526: {
        !           527:        ob_ide_init(config->path,
        !           528:                    config->assigned[0] & ~0x0000000F,
        !           529:                    config->assigned[1] & ~0x0000000F,
        !           530:                    config->assigned[2] & ~0x0000000F,
        !           531:                    config->assigned[3] & ~0x0000000F);
        !           532:        return 0;
        !           533: }
        !           534: 
        !           535: int eth_config_cb (const pci_config_t *config)
        !           536: {
        !           537:        phandle_t ph = get_cur_dev();
        !           538: 
        !           539:        set_property(ph, "network-type", "ethernet", 9);
        !           540:        set_property(ph, "removable", "network", 8);
        !           541:        set_property(ph, "category", "net", 4);
        !           542: 
        !           543:         return 0;
        !           544: }
        !           545: 
        !           546: static inline void pci_decode_pci_addr(pci_addr addr, int *flags,
        !           547:                                       int *space_code, uint32_t *mask)
        !           548: {
        !           549:     *flags = 0;
        !           550: 
        !           551:        if (addr & 0x01) {
        !           552:                *space_code = IO_SPACE;
        !           553:                *mask = 0x00000001;
        !           554:        } else {
        !           555:            if (addr & 0x04) {
        !           556:             *space_code = MEMORY_SPACE_64;
        !           557:             *flags |= IS_NOT_RELOCATABLE; /* XXX: why not relocatable? */
        !           558:         } else {
        !           559:             *space_code = MEMORY_SPACE_32;
        !           560:         }
        !           561: 
        !           562:         if (addr & 0x08) {
        !           563:             *flags |= IS_PREFETCHABLE;
        !           564:         }
        !           565: 
        !           566:         *mask = 0x0000000F;
        !           567:        }
        !           568: }
        !           569: 
        !           570: /*
        !           571:  * "Designing PCI Cards and Drivers for Power Macintosh Computers", p. 454
        !           572:  *
        !           573:  *  "AAPL,address" provides an array of 32-bit logical addresses
        !           574:  *  Nth entry corresponding to Nth "assigned-address" base address entry.
        !           575:  */
        !           576: 
        !           577: static void pci_set_AAPL_address(const pci_config_t *config)
        !           578: {
        !           579:        phandle_t dev = get_cur_dev();
        !           580:        cell props[7];
        !           581:        int ncells, i;
        !           582: 
        !           583:        ncells = 0;
        !           584:        for (i = 0; i < 6; i++) {
        !           585:                if (!config->assigned[i] || !config->sizes[i])
        !           586:                        continue;
        !           587:                props[ncells++] = config->assigned[i] & ~0x0000000F;
        !           588:        }
        !           589:        if (ncells)
        !           590:                set_property(dev, "AAPL,address", (char *)props,
        !           591:                             ncells * sizeof(cell));
        !           592: }
        !           593: 
        !           594: static void pci_set_assigned_addresses(phandle_t phandle,
        !           595:                                        const pci_config_t *config, int num_bars)
        !           596: {
        !           597:        phandle_t dev = phandle;
        !           598:        u32 props[32];
        !           599:        int ncells;
        !           600:        int i;
        !           601:        uint32_t mask;
        !           602:        int flags, space_code;
        !           603: 
        !           604:        ncells = 0;
        !           605:        for (i = 0; i < num_bars; i++) {
        !           606:                /* consider only bars with non-zero region size */
        !           607:                if (!config->sizes[i])
        !           608:                        continue;
        !           609:                pci_decode_pci_addr(config->assigned[i],
        !           610:                                    &flags, &space_code, &mask);
        !           611: 
        !           612:                ncells += pci_encode_phys_addr(props + ncells,
        !           613:                                     flags, space_code, config->dev,
        !           614:                                     PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)),
        !           615:                                     config->assigned[i] & ~mask);
        !           616: 
        !           617:                props[ncells++] = 0x00000000;
        !           618:                props[ncells++] = config->sizes[i];
        !           619:        }
        !           620:        if (ncells)
        !           621:                set_property(dev, "assigned-addresses", (char *)props,
        !           622:                             ncells * sizeof(props[0]));
        !           623: }
        !           624: 
        !           625: /* call after writing "reg" property to update config->path */
        !           626: static void ob_pci_reload_device_path(phandle_t phandle, pci_config_t *config)
        !           627: {
        !           628:     /* since "name" and "reg" are now assigned
        !           629:        we need to reload current node name */
        !           630: 
        !           631:     PUSH(phandle);
        !           632:     fword("get-package-path");
        !           633:     char *new_path = pop_fstr_copy();
        !           634:     if (new_path) {
        !           635:         if (0 != strcmp(config->path, new_path)) {
        !           636:             PCI_DPRINTF("\n=== CHANGED === package path old=%s new=%s\n",
        !           637:                     config->path, new_path);
        !           638:             strncpy(config->path, new_path, sizeof(config->path));
        !           639:             config->path[sizeof(config->path)-1] = '\0';
        !           640:         }
        !           641:         free(new_path);
        !           642:     } else {
        !           643:         PCI_DPRINTF("\n=== package path old=%s new=NULL\n", config->path);
        !           644:     }
        !           645: }
        !           646: 
        !           647: static void pci_set_reg(phandle_t phandle,
        !           648:                         pci_config_t *config, int num_bars)
        !           649: {
        !           650:        phandle_t dev = phandle;
        !           651:        u32 props[38];
        !           652:        int ncells;
        !           653:        int i;
        !           654:        uint32_t mask;
        !           655:        int space_code, flags;
        !           656: 
        !           657:     ncells = 0;
        !           658: 
        !           659:     /* first (addr, size) pair is the beginning of configuration address space */
        !           660:        ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE,
        !           661:                             config->dev, 0, 0);
        !           662: 
        !           663:        ncells += pci_encode_size(props + ncells, 0);
        !           664: 
        !           665:        for (i = 0; i < num_bars; i++) {
        !           666:                /* consider only bars with non-zero region size */
        !           667:                if (!config->sizes[i])
        !           668:                        continue;
        !           669: 
        !           670:                pci_decode_pci_addr(config->regions[i],
        !           671:                                    &flags, &space_code, &mask);
        !           672: 
        !           673:                ncells += pci_encode_phys_addr(props + ncells,
        !           674:                                     flags, space_code, config->dev,
        !           675:                                     PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)),
        !           676:                                     config->regions[i] & ~mask);
        !           677: 
        !           678:                /* set size */
        !           679:                ncells += pci_encode_size(props + ncells, config->sizes[i]);
        !           680:        }
        !           681: 
        !           682:        set_property(dev, "reg", (char *)props, ncells * sizeof(props[0]));
        !           683:     ob_pci_reload_device_path(dev, config);
        !           684: 
        !           685: #if defined(CONFIG_DEBUG_PCI)
        !           686:     dump_reg_property("pci_set_reg", ncells, props);
        !           687: #endif
        !           688: }
        !           689: 
        !           690: 
        !           691: static void pci_set_ranges(const pci_config_t *config)
        !           692: {
        !           693:        phandle_t dev = get_cur_dev();
        !           694:        u32 props[32];
        !           695:        int ncells;
        !           696:        int i;
        !           697:        uint32_t mask;
        !           698:        int flags;
        !           699:        int space_code;
        !           700: 
        !           701:        ncells = 0;
        !           702:        for (i = 0; i < 6; i++) {
        !           703:                if (!config->assigned[i] || !config->sizes[i])
        !           704:                        continue;
        !           705: 
        !           706:                /* child address */
        !           707: 
        !           708:                props[ncells++] = 0x00000000;
        !           709: 
        !           710:                /* parent address */
        !           711: 
        !           712:                pci_decode_pci_addr(config->assigned[i],
        !           713:                                    &flags, &space_code, &mask);
        !           714:                ncells += pci_encode_phys_addr(props + ncells, flags, space_code,
        !           715:                                     config->dev, 0x10 + i * 4,
        !           716:                                     config->assigned[i] & ~mask);
        !           717: 
        !           718:                /* size */
        !           719: 
        !           720:                props[ncells++] = config->sizes[i];
        !           721:        }
        !           722:        set_property(dev, "ranges", (char *)props, ncells * sizeof(props[0]));
        !           723: }
        !           724: 
        !           725: int macio_heathrow_config_cb (const pci_config_t *config)
        !           726: {
        !           727:        pci_set_ranges(config);
        !           728: 
        !           729: #ifdef CONFIG_DRIVER_MACIO
        !           730:         ob_macio_heathrow_init(config->path, config->assigned[0] & ~0x0000000F);
        !           731: #endif
        !           732:        return 0;
        !           733: }
        !           734: 
        !           735: int macio_keylargo_config_cb (const pci_config_t *config)
        !           736: {
        !           737:         pci_set_ranges(config);
        !           738: 
        !           739: #ifdef CONFIG_DRIVER_MACIO
        !           740:         ob_macio_keylargo_init(config->path, config->assigned[0] & ~0x0000000F);
        !           741: #endif
        !           742:         return 0;
        !           743: }
        !           744: 
        !           745: int vga_config_cb (const pci_config_t *config)
        !           746: {
        !           747:        if (config->assigned[0] != 0x00000000)
        !           748:             vga_vbe_init(config->path,
        !           749:                          pci_bus_addr_to_host_addr(config->assigned[0] & ~0x0000000F),
        !           750:                          config->sizes[0],
        !           751:                          pci_bus_addr_to_host_addr(config->assigned[1] & ~0x0000000F),
        !           752:                          config->sizes[1]);
        !           753:        return 0;
        !           754: }
        !           755: 
        !           756: int ebus_config_cb(const pci_config_t *config)
        !           757: {
        !           758: #ifdef CONFIG_DRIVER_EBUS
        !           759: #ifdef CONFIG_DRIVER_FLOPPY
        !           760:     ob_floppy_init(config->path, "fdthree", 0x3f0ULL, 0);
        !           761: #endif
        !           762: #ifdef CONFIG_DRIVER_PC_SERIAL
        !           763:     ob_pc_serial_init(config->path, "su", arch->io_base, 0x3f8ULL, 0);
        !           764: #endif
        !           765: #ifdef CONFIG_DRIVER_PC_KBD
        !           766:     ob_pc_kbd_init(config->path, "kb_ps2", arch->io_base, 0x60ULL, 0);
        !           767: #endif
        !           768: #endif
        !           769:     return 0;
        !           770: }
        !           771: 
        !           772: static void ob_pci_add_properties(phandle_t phandle,
        !           773:                                   pci_addr addr, const pci_dev_t *pci_dev,
        !           774:                                   const pci_config_t *config, int num_bars)
        !           775: {
        !           776:        /* cannot use get_cur_dev() path resolution since "name" and "reg"
        !           777:           properties are being changed */
        !           778:        phandle_t dev=phandle;
        !           779:        int status,id;
        !           780:        uint16_t vendor_id, device_id;
        !           781:        uint8_t rev;
        !           782:        uint32_t class_code;
        !           783: 
        !           784:        vendor_id = pci_config_read16(addr, PCI_VENDOR_ID);
        !           785:        device_id = pci_config_read16(addr, PCI_DEVICE_ID);
        !           786:        rev = pci_config_read8(addr, PCI_REVISION_ID);
        !           787:        class_code = pci_config_read16(addr, PCI_CLASS_DEVICE);
        !           788: 
        !           789:     if (pci_dev) {
        !           790:         /**/
        !           791:         if (pci_dev->name) {
        !           792:             push_str(pci_dev->name);
        !           793:             fword("encode-string");
        !           794:             push_str("name");
        !           795:             fword("property");
        !           796:         } else {
        !           797:             char path[256];
        !           798:             snprintf(path, sizeof(path),
        !           799:                     "pci%x,%x", vendor_id, device_id);
        !           800:             push_str(path);
        !           801:             fword("encode-string");
        !           802:             push_str("name");
        !           803:             fword("property");
        !           804:         }
        !           805:     } else {
        !           806:         PCI_DPRINTF("*** missing pci_dev\n");
        !           807:     }
        !           808: 
        !           809:        /* create properties as described in 2.5 */
        !           810: 
        !           811:        set_int_property(dev, "vendor-id", vendor_id);
        !           812:        set_int_property(dev, "device-id", device_id);
        !           813:        set_int_property(dev, "revision-id", rev);
        !           814:        set_int_property(dev, "class-code", class_code << 8);
        !           815: 
        !           816:        if (config->irq_pin) {
        !           817:                OLDWORLD(set_int_property(dev, "AAPL,interrupts",
        !           818:                                          config->irq_line));
        !           819:                set_int_property(dev, "interrupts", config->irq_pin);
        !           820:        }
        !           821: 
        !           822:        set_int_property(dev, "min-grant", pci_config_read8(addr, PCI_MIN_GNT));
        !           823:        set_int_property(dev, "max-latency", pci_config_read8(addr, PCI_MAX_LAT));
        !           824: 
        !           825:        status=pci_config_read16(addr, PCI_STATUS);
        !           826: 
        !           827:        set_int_property(dev, "devsel-speed",
        !           828:                        (status&PCI_STATUS_DEVSEL_MASK)>>10);
        !           829: 
        !           830:        if(status&PCI_STATUS_FAST_BACK)
        !           831:                set_bool_property(dev, "fast-back-to-back");
        !           832:        if(status&PCI_STATUS_66MHZ)
        !           833:                set_bool_property(dev, "66mhz-capable");
        !           834:        if(status&PCI_STATUS_UDF)
        !           835:                set_bool_property(dev, "udf-supported");
        !           836: 
        !           837:        id=pci_config_read16(addr, PCI_SUBSYSTEM_VENDOR_ID);
        !           838:        if(id)
        !           839:                set_int_property(dev, "subsystem-vendor-id", id);
        !           840:        id=pci_config_read16(addr, PCI_SUBSYSTEM_ID);
        !           841:        if(id)
        !           842:                set_int_property(dev, "subsystem-id", id);
        !           843: 
        !           844:        set_int_property(dev, "cache-line-size",
        !           845:                        pci_config_read16(addr, PCI_CACHE_LINE_SIZE));
        !           846: 
        !           847:        if (pci_dev) {
        !           848:                if (pci_dev->type) {
        !           849:                        push_str(pci_dev->type);
        !           850:                        fword("encode-string");
        !           851:                        push_str("device_type");
        !           852:                        fword("property");
        !           853:                }
        !           854:                if (pci_dev->model) {
        !           855:                        push_str(pci_dev->model);
        !           856:                        fword("encode-string");
        !           857:                        push_str("model");
        !           858:                        fword("property");
        !           859:                }
        !           860:                if (pci_dev->compat)
        !           861:                        set_property(dev, "compatible",
        !           862:                                     pci_dev->compat, pci_compat_len(pci_dev));
        !           863: 
        !           864:                if (pci_dev->acells)
        !           865:                        set_int_property(dev, "#address-cells",
        !           866:                                              pci_dev->acells);
        !           867:                if (pci_dev->scells)
        !           868:                        set_int_property(dev, "#size-cells",
        !           869:                                               pci_dev->scells);
        !           870:                if (pci_dev->icells)
        !           871:                        set_int_property(dev, "#interrupt-cells",
        !           872:                                              pci_dev->icells);
        !           873:        }
        !           874: 
        !           875:        pci_set_assigned_addresses(phandle, config, num_bars);
        !           876:        OLDWORLD(pci_set_AAPL_address(config));
        !           877: 
        !           878:        PCI_DPRINTF("\n");
        !           879: }
        !           880: 
        !           881: #ifdef CONFIG_XBOX
        !           882: static char pci_xbox_blacklisted (int bus, int devnum, int fn)
        !           883: {
        !           884:        /*
        !           885:         * The Xbox MCPX chipset is a derivative of the nForce 1
        !           886:         * chipset. It almost has the same bus layout; some devices
        !           887:         * cannot be used, because they have been removed.
        !           888:         */
        !           889: 
        !           890:        /*
        !           891:         * Devices 00:00.1 and 00:00.2 used to be memory controllers on
        !           892:         * the nForce chipset, but on the Xbox, using them will lockup
        !           893:         * the chipset.
        !           894:         */
        !           895:        if ((bus == 0) && (devnum == 0) && ((fn == 1) || (fn == 2)))
        !           896:                return 1;
        !           897: 
        !           898:        /*
        !           899:         * Bus 1 only contains a VGA controller at 01:00.0. When you try
        !           900:         * to probe beyond that device, you only get garbage, which
        !           901:         * could cause lockups.
        !           902:         */
        !           903:        if ((bus == 1) && ((devnum != 0) || (fn != 0)))
        !           904:                return 1;
        !           905: 
        !           906:        /*
        !           907:         * Bus 2 used to contain the AGP controller, but the Xbox MCPX
        !           908:         * doesn't have one. Probing it can cause lockups.
        !           909:         */
        !           910:        if (bus >= 2)
        !           911:                return 1;
        !           912: 
        !           913:        /*
        !           914:         * The device is not blacklisted.
        !           915:         */
        !           916:        return 0;
        !           917: }
        !           918: #endif
        !           919: 
        !           920: static void ob_pci_configure_bar(pci_addr addr, pci_config_t *config,
        !           921:                                  int reg, int config_addr,
        !           922:                                  uint32_t *p_omask,
        !           923:                                  unsigned long *mem_base,
        !           924:                                  unsigned long *io_base)
        !           925: {
        !           926:         uint32_t smask, amask, size, reloc, min_align;
        !           927:         unsigned long base;
        !           928: 
        !           929:         config->assigned[reg] = 0x00000000;
        !           930:         config->sizes[reg] = 0x00000000;
        !           931: 
        !           932:         if ((*p_omask & 0x0000000f) == 0x4) {
        !           933:                 /* 64 bits memory mapping */
        !           934:                 return;
        !           935:         }
        !           936: 
        !           937:         config->regions[reg] = pci_config_read32(addr, config_addr);
        !           938: 
        !           939:         /* get region size */
        !           940: 
        !           941:         pci_config_write32(addr, config_addr, 0xffffffff);
        !           942:         smask = pci_config_read32(addr, config_addr);
        !           943:         if (smask == 0x00000000 || smask == 0xffffffff)
        !           944:                 return;
        !           945: 
        !           946:         if (smask & 0x00000001 && reg != 6) {
        !           947:                 /* I/O space */
        !           948:                 base = *io_base;
        !           949:                 min_align = 1 << 7;
        !           950:                 amask = 0x00000001;
        !           951:         } else {
        !           952:                 /* Memory Space */
        !           953:                 base = *mem_base;
        !           954:                 min_align = 1 << 16;
        !           955:                 amask = 0x0000000F;
        !           956:                 if (reg == 6) {
        !           957:                         smask |= 1; /* ROM */
        !           958:                 }
        !           959:         }
        !           960:         *p_omask = smask & amask;
        !           961:         smask &= ~amask;
        !           962:         size = (~smask) + 1;
        !           963:         config->sizes[reg] = size;
        !           964:         reloc = base;
        !           965:         if (size < min_align)
        !           966:                 size = min_align;
        !           967:         reloc = (reloc + size -1) & ~(size - 1);
        !           968:         if (*io_base == base) {
        !           969:                 *io_base = reloc + size;
        !           970:                 reloc -= arch->io_base;
        !           971:         } else {
        !           972:                 *mem_base = reloc + size;
        !           973:         }
        !           974:         pci_config_write32(addr, config_addr, reloc | *p_omask);
        !           975:         config->assigned[reg] = reloc | *p_omask;
        !           976: }
        !           977: 
        !           978: static void ob_pci_configure_irq(pci_addr addr, pci_config_t *config)
        !           979: {
        !           980:         uint8_t irq_pin, irq_line;
        !           981: 
        !           982:         irq_pin =  pci_config_read8(addr, PCI_INTERRUPT_PIN);
        !           983:         if (irq_pin) {
        !           984:                 config->irq_pin = irq_pin;
        !           985:                 irq_pin = (((config->dev >> 11) & 0x1F) + irq_pin - 1) & 3;
        !           986:                 irq_line = arch->irqs[irq_pin];
        !           987:                 pci_config_write8(addr, PCI_INTERRUPT_LINE, irq_line);
        !           988:                 config->irq_line = irq_line;
        !           989:         } else
        !           990:                 config->irq_line = -1;
        !           991: }
        !           992: 
        !           993: static void
        !           994: ob_pci_configure(pci_addr addr, pci_config_t *config, int num_regs, int rom_bar,
        !           995:                  unsigned long *mem_base, unsigned long *io_base)
        !           996: 
        !           997: {
        !           998:         uint32_t omask;
        !           999:         uint16_t cmd;
        !          1000:         int reg;
        !          1001:         pci_addr config_addr;
        !          1002: 
        !          1003:         ob_pci_configure_irq(addr, config);
        !          1004: 
        !          1005:         omask = 0x00000000;
        !          1006:         for (reg = 0; reg < num_regs; ++reg) {
        !          1007:                 config_addr = PCI_BASE_ADDR_0 + reg * 4;
        !          1008: 
        !          1009:                 ob_pci_configure_bar(addr, config, reg, config_addr,
        !          1010:                                      &omask, mem_base,
        !          1011:                                      io_base);
        !          1012:         }
        !          1013: 
        !          1014:         if (rom_bar) {
        !          1015:                 config_addr = rom_bar;
        !          1016:                 ob_pci_configure_bar(addr, config, reg, config_addr,
        !          1017:                                      &omask, mem_base, io_base);
        !          1018:         }
        !          1019:         cmd = pci_config_read16(addr, PCI_COMMAND);
        !          1020:         cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
        !          1021:         pci_config_write16(addr, PCI_COMMAND, cmd);
        !          1022: }
        !          1023: 
        !          1024: static void ob_configure_pci_device(const char* parent_path,
        !          1025:         int *bus_num, unsigned long *mem_base, unsigned long *io_base,
        !          1026:         int bus, int devnum, int fn, int *p_is_multi);
        !          1027: 
        !          1028: static void ob_scan_pci_bus(int *bus_num, unsigned long *mem_base,
        !          1029:                             unsigned long *io_base, const char *path,
        !          1030:                             int bus)
        !          1031: {
        !          1032:        int devnum, fn, is_multi;
        !          1033: 
        !          1034:        PCI_DPRINTF("\nScanning bus %d at %s...\n", bus, path);
        !          1035: 
        !          1036:        for (devnum = 0; devnum < 32; devnum++) {
        !          1037:                is_multi = 0;
        !          1038:                for (fn = 0; fn==0 || (is_multi && fn<8); fn++) {
        !          1039:                    ob_configure_pci_device(path, bus_num, mem_base, io_base,
        !          1040:                            bus, devnum, fn, &is_multi);
        !          1041: 
        !          1042:                }
        !          1043:        }
        !          1044: }
        !          1045: 
        !          1046: static void ob_configure_pci_bridge(pci_addr addr,
        !          1047:                                     int *bus_num, unsigned long *mem_base,
        !          1048:                                     unsigned long *io_base,
        !          1049:                                     int primary_bus, pci_config_t *config)
        !          1050: {
        !          1051:     config->primary_bus = primary_bus;
        !          1052:     pci_config_write8(addr, PCI_PRIMARY_BUS, config->primary_bus);
        !          1053: 
        !          1054:     config->secondary_bus = *bus_num;
        !          1055:     pci_config_write8(addr, PCI_SECONDARY_BUS, config->secondary_bus);
        !          1056: 
        !          1057:     config->subordinate_bus = 0xff;
        !          1058:     pci_config_write8(addr, PCI_SUBORDINATE_BUS, config->subordinate_bus);
        !          1059: 
        !          1060:     PCI_DPRINTF("scanning new pci bus %u under bridge %s\n",
        !          1061:             config->secondary_bus, config->path);
        !          1062: 
        !          1063:     /* make pci bridge parent device, prepare for recursion */
        !          1064: 
        !          1065:     ob_scan_pci_bus(bus_num, mem_base, io_base,
        !          1066:                     config->path, config->secondary_bus);
        !          1067: 
        !          1068:     /* bus scan updates *bus_num to last revealed pci bus number */
        !          1069:     config->subordinate_bus = *bus_num;
        !          1070:     pci_config_write8(addr, PCI_SUBORDINATE_BUS, config->subordinate_bus);
        !          1071: 
        !          1072:     PCI_DPRINTF("bridge %s PCI bus primary=%d secondary=%d subordinate=%d\n",
        !          1073:             config->path, config->primary_bus, config->secondary_bus,
        !          1074:             config->subordinate_bus);
        !          1075: 
        !          1076:     pci_set_bus_range(config);
        !          1077: }
        !          1078: 
        !          1079: static int ob_pci_read_identification(int bus, int devnum, int fn,
        !          1080:                                  int *p_vid, int *p_did,
        !          1081:                                  uint8_t *p_class, uint8_t *p_subclass)
        !          1082: {
        !          1083:     int vid, did;
        !          1084:     uint32_t ccode;
        !          1085:     pci_addr addr;
        !          1086: 
        !          1087: #ifdef CONFIG_XBOX
        !          1088:     if (pci_xbox_blacklisted (bus, devnum, fn))
        !          1089:         return;
        !          1090: #endif
        !          1091:     addr = PCI_ADDR(bus, devnum, fn);
        !          1092:     vid = pci_config_read16(addr, PCI_VENDOR_ID);
        !          1093:     did = pci_config_read16(addr, PCI_DEVICE_ID);
        !          1094: 
        !          1095:     if (vid==0xffff || vid==0) {
        !          1096:         return 0;
        !          1097:     }
        !          1098: 
        !          1099:     if (p_vid) {
        !          1100:         *p_vid = vid;
        !          1101:     }
        !          1102: 
        !          1103:     if (p_did) {
        !          1104:         *p_did = did;
        !          1105:     }
        !          1106: 
        !          1107:     ccode = pci_config_read16(addr, PCI_CLASS_DEVICE);
        !          1108: 
        !          1109:     if (p_class) {
        !          1110:         *p_class = ccode >> 8;
        !          1111:     }
        !          1112: 
        !          1113:     if (p_subclass) {
        !          1114:         *p_subclass = ccode;
        !          1115:     }
        !          1116: 
        !          1117:     return 1;
        !          1118: }
        !          1119: 
        !          1120: static void ob_configure_pci_device(const char* parent_path,
        !          1121:         int *bus_num, unsigned long *mem_base, unsigned long *io_base,
        !          1122:         int bus, int devnum, int fn, int *p_is_multi)
        !          1123: {
        !          1124:     int vid, did;
        !          1125:     unsigned int htype;
        !          1126:     pci_addr addr;
        !          1127:     pci_config_t config = {};
        !          1128:         const pci_dev_t *pci_dev;
        !          1129:     uint8_t class, subclass, iface;
        !          1130:     int num_bars, rom_bar;
        !          1131: 
        !          1132:     phandle_t phandle = 0;
        !          1133:     int is_host_bridge = 0;
        !          1134: 
        !          1135:     if (!ob_pci_read_identification(bus, devnum, fn, &vid, &did, &class, &subclass)) {
        !          1136:         return;
        !          1137:     }
        !          1138: 
        !          1139:     addr = PCI_ADDR(bus, devnum, fn);
        !          1140:     iface = pci_config_read8(addr, PCI_CLASS_PROG);
        !          1141: 
        !          1142:     pci_dev = pci_find_device(class, subclass, iface,
        !          1143:                   vid, did);
        !          1144: 
        !          1145:     PCI_DPRINTF("%x:%x.%x - %x:%x - ", bus, devnum, fn,
        !          1146:             vid, did);
        !          1147: 
        !          1148:     htype = pci_config_read8(addr, PCI_HEADER_TYPE);
        !          1149: 
        !          1150:     if (fn == 0) {
        !          1151:         if (p_is_multi) {
        !          1152:             *p_is_multi = htype & 0x80;
        !          1153:         }
        !          1154:     }
        !          1155: 
        !          1156:     /* stop adding host bridge accessible from it's primary bus
        !          1157:        PCI host bridge is to be added by host code
        !          1158:     */
        !          1159:     if (class == PCI_BASE_CLASS_BRIDGE &&
        !          1160:             subclass == PCI_SUBCLASS_BRIDGE_HOST) {
        !          1161:         is_host_bridge = 1;
        !          1162:     }
        !          1163: 
        !          1164:     if (is_host_bridge) {
        !          1165:         /* reuse device tree node */
        !          1166:         PCI_DPRINTF("host bridge found - ");
        !          1167:         snprintf(config.path, sizeof(config.path),
        !          1168:                 "%s", parent_path);
        !          1169:     } else if (pci_dev == NULL || pci_dev->name == NULL) {
        !          1170:         snprintf(config.path, sizeof(config.path),
        !          1171:                 "%s/pci%x,%x", parent_path, vid, did);
        !          1172:     }
        !          1173:     else {
        !          1174:         snprintf(config.path, sizeof(config.path),
        !          1175:                 "%s/%s", parent_path, pci_dev->name);
        !          1176:     }
        !          1177: 
        !          1178:     PCI_DPRINTF("%s - ", config.path);
        !          1179: 
        !          1180:     config.dev = addr & 0x00FFFFFF;
        !          1181: 
        !          1182:     switch (class) {
        !          1183:     case PCI_BASE_CLASS_BRIDGE:
        !          1184:         if (subclass != PCI_SUBCLASS_BRIDGE_HOST) {
        !          1185:             REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle);
        !          1186:         }
        !          1187:         break;
        !          1188:     default:
        !          1189:         REGISTER_NAMED_NODE_PHANDLE(ob_pci_simple_node, config.path, phandle);
        !          1190:         break;
        !          1191:     }
        !          1192: 
        !          1193:     if (is_host_bridge) {
        !          1194:         phandle = find_dev(config.path);
        !          1195: 
        !          1196:         if (get_property(phandle, "vendor-id", NULL)) {
        !          1197:             PCI_DPRINTF("host bridge already configured\n");
        !          1198:             return;
        !          1199:         }
        !          1200:     }
        !          1201: 
        !          1202:     activate_dev(phandle);
        !          1203: 
        !          1204:     if (htype & PCI_HEADER_TYPE_BRIDGE) {
        !          1205:         num_bars = 2;
        !          1206:         rom_bar  = PCI_ROM_ADDRESS1;
        !          1207:     } else {
        !          1208:         num_bars = 6;
        !          1209:         rom_bar  = PCI_ROM_ADDRESS;
        !          1210:     }
        !          1211: 
        !          1212:     ob_pci_configure(addr, &config, num_bars, rom_bar,
        !          1213:                      mem_base, io_base);
        !          1214: 
        !          1215:     ob_pci_add_properties(phandle, addr, pci_dev, &config, num_bars);
        !          1216: 
        !          1217:     if (!is_host_bridge) {
        !          1218:         pci_set_reg(phandle, &config, num_bars);
        !          1219:     }
        !          1220: 
        !          1221:     /* call device-specific configuration callback */
        !          1222:     if (pci_dev && pci_dev->config_cb) {
        !          1223:         //activate_device(config.path);
        !          1224:         pci_dev->config_cb(&config);
        !          1225:     }
        !          1226: 
        !          1227:     /* device is configured so we may move it out of scope */
        !          1228:     device_end();
        !          1229: 
        !          1230:     /* scan bus behind bridge device */
        !          1231:     //if (htype & PCI_HEADER_TYPE_BRIDGE && class == PCI_BASE_CLASS_BRIDGE) {
        !          1232:     if ( class == PCI_BASE_CLASS_BRIDGE &&
        !          1233:             ( subclass == PCI_SUBCLASS_BRIDGE_PCI ||
        !          1234:               subclass == PCI_SUBCLASS_BRIDGE_HOST ) ) {
        !          1235: 
        !          1236:         if (subclass == PCI_SUBCLASS_BRIDGE_PCI) {
        !          1237:             /* reserve next pci bus number for this PCI bridge */
        !          1238:             ++(*bus_num);
        !          1239:         }
        !          1240: 
        !          1241:         ob_configure_pci_bridge(addr, bus_num, mem_base, io_base, bus, &config);
        !          1242:     }
        !          1243: }
        !          1244: 
        !          1245: int ob_pci_init(void)
        !          1246: {
        !          1247:     int bus, devnum, fn;
        !          1248:     uint8_t class, subclass;
        !          1249:     unsigned long mem_base, io_base;
        !          1250: 
        !          1251:     pci_config_t config = {}; /* host bridge */
        !          1252:     phandle_t phandle_host;
        !          1253: 
        !          1254:     PCI_DPRINTF("Initializing PCI host bridge...\n");
        !          1255: 
        !          1256:     activate_device("/");
        !          1257: 
        !          1258:     /* Find all PCI bridges */
        !          1259: 
        !          1260:     mem_base = arch->pci_mem_base;
        !          1261:     /* I/O ports under 0x400 are used by devices mapped at fixed
        !          1262:        location. */
        !          1263:     io_base = arch->io_base + 0x400;
        !          1264: 
        !          1265:     bus = 0;
        !          1266: 
        !          1267:     for (devnum = 0; devnum < 32; devnum++) {
        !          1268:         /* scan only fn 0 */
        !          1269:         fn = 0;
        !          1270: 
        !          1271:         if (!ob_pci_read_identification(bus, devnum, fn,
        !          1272:                                         0, 0, &class, &subclass)) {
        !          1273:             continue;
        !          1274:         }
        !          1275: 
        !          1276:         if (class != PCI_BASE_CLASS_BRIDGE || subclass != PCI_SUBCLASS_BRIDGE_HOST) {
        !          1277:             continue;
        !          1278:         }
        !          1279: 
        !          1280:         /* create root node for host PCI bridge */
        !          1281: 
        !          1282:         /* configure  */
        !          1283:         snprintf(config.path, sizeof(config.path), "/pci");
        !          1284: 
        !          1285:         REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle_host);
        !          1286: 
        !          1287:         pci_host_set_reg(phandle_host);
        !          1288: 
        !          1289:         /* update device path after changing "reg" property */
        !          1290:         ob_pci_reload_device_path(phandle_host, &config);
        !          1291: 
        !          1292:         ob_configure_pci_device(config.path, &bus, &mem_base, &io_base,
        !          1293:                 bus, devnum, fn, 0);
        !          1294: 
        !          1295:         /* we expect single host PCI bridge
        !          1296:            but this may be machine-specific */
        !          1297:         break;
        !          1298:     }
        !          1299: 
        !          1300: 
        !          1301:     device_end();
        !          1302: 
        !          1303:     return 0;
        !          1304: }

unix.superglobalmegacorp.com

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