[BACK]Return to mpcpcibus.c CVS log [TXT][DIR] Up to [local] / sys / arch / macppc / pci

Annotation of sys/arch/macppc/pci/mpcpcibus.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: mpcpcibus.c,v 1.36 2006/12/14 17:36:12 kettenis Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1997 Per Fogelstrom
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  *
        !            15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
        !            16:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            18:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
        !            19:  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            20:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            21:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            22:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            23:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            24:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            25:  * SUCH DAMAGE.
        !            26:  *
        !            27:  */
        !            28:
        !            29: /*
        !            30:  * Generic PCI BUS Bridge driver.
        !            31:  * specialized hooks for different config methods.
        !            32:  */
        !            33:
        !            34: #include <sys/param.h>
        !            35: #include <sys/systm.h>
        !            36: #include <sys/kernel.h>
        !            37: #include <sys/malloc.h>
        !            38: #include <sys/device.h>
        !            39: #include <sys/proc.h>
        !            40: #include <uvm/uvm_extern.h>
        !            41:
        !            42: #include <machine/autoconf.h>
        !            43: #include <machine/pcb.h>
        !            44: #include <machine/bat.h>
        !            45: #include <machine/powerpc.h>
        !            46:
        !            47: #include <dev/pci/pcireg.h>
        !            48: #include <dev/pci/pcivar.h>
        !            49: #include <dev/pci/pcidevs.h>
        !            50:
        !            51: #include <macppc/pci/pcibrvar.h>
        !            52: #include <macppc/pci/mpc106reg.h>
        !            53:
        !            54: #include <dev/ofw/openfirm.h>
        !            55:
        !            56: int    mpcpcibrmatch(struct device *, void *, void *);
        !            57: void   mpcpcibrattach(struct device *, struct device *, void *);
        !            58:
        !            59: void   mpc_attach_hook(struct device *, struct device *,
        !            60:                                struct pcibus_attach_args *);
        !            61: int    mpc_bus_maxdevs(void *, int);
        !            62: pcitag_t mpc_make_tag(void *, int, int, int);
        !            63: void   mpc_decompose_tag(void *, pcitag_t, int *, int *, int *);
        !            64: pcireg_t mpc_conf_read(void *, pcitag_t, int);
        !            65: void   mpc_conf_write(void *, pcitag_t, int, pcireg_t);
        !            66:
        !            67: int      mpc_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *);
        !            68: const char *mpc_intr_string(void *, pci_intr_handle_t);
        !            69: int    mpc_intr_line(void *, pci_intr_handle_t);
        !            70: void     *mpc_intr_establish(void *, pci_intr_handle_t,
        !            71:             int, int (*func)(void *), void *, char *);
        !            72: void     mpc_intr_disestablish(void *, void *);
        !            73: int      mpc_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *);
        !            74: u_int32_t mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset);
        !            75: int    of_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *);
        !            76: int    find_node_intr (int parent, u_int32_t *addr, u_int32_t *intr);
        !            77: u_int32_t pci_iack(void);
        !            78:
        !            79: void fix_node_irq(int node, struct pcibus_attach_args *pba);
        !            80:
        !            81: struct cfattach mpcpcibr_ca = {
        !            82:         sizeof(struct pcibr_softc), mpcpcibrmatch, mpcpcibrattach,
        !            83: };
        !            84:
        !            85: struct cfdriver mpcpcibr_cd = {
        !            86:        NULL, "mpcpcibr", DV_DULL,
        !            87: };
        !            88:
        !            89: static int      mpcpcibrprint(void *, const char *pnp);
        !            90:
        !            91: struct pcibr_config mpc_config;
        !            92:
        !            93: /*
        !            94:  * config types
        !            95:  * bit meanings
        !            96:  * 0 - standard cf8/cfc type configurations,
        !            97:  *     sometimes the base addresses for these are different
        !            98:  * 1 - Config Method #2 configuration - uni-north
        !            99:  *
        !           100:  * 2 - 64 bit config bus, data for accesses &4 is at daddr+4;
        !           101:  */
        !           102: struct config_type{
        !           103:        char * compat;
        !           104:        u_int32_t addr; /* offset */
        !           105:        u_int32_t data; /* offset */
        !           106:        int config_type;
        !           107: };
        !           108: struct config_type config_offsets[] = {
        !           109:        {"grackle",             0x00c00cf8, 0x00e00cfc, 0 },
        !           110:        {"bandit",              0x00800000, 0x00c00000, 1 },
        !           111:        {"uni-north",           0x00800000, 0x00c00000, 3 },
        !           112:        {"u3-agp",              0x00800000, 0x00c00000, 3 },
        !           113:        {"u3-ht",               0x00000cf8, 0x00000cfc, 3 },
        !           114:        {"legacy",              0x00000cf8, 0x00000cfc, 0 },
        !           115:        {"IBM,27-82660",        0x00000cf8, 0x00000cfc, 0 },
        !           116:        {NULL,                  0x00000000, 0x00000000, 0 },
        !           117: };
        !           118:
        !           119: struct powerpc_bus_dma_tag pci_bus_dma_tag = {
        !           120:        NULL,
        !           121:        _dmamap_create,
        !           122:        _dmamap_destroy,
        !           123:        _dmamap_load,
        !           124:        _dmamap_load_mbuf,
        !           125:        _dmamap_load_uio,
        !           126:        _dmamap_load_raw,
        !           127:        _dmamap_unload,
        !           128:        _dmamap_sync,
        !           129:        _dmamem_alloc,
        !           130:        _dmamem_free,
        !           131:        _dmamem_map,
        !           132:        _dmamem_unmap,
        !           133:        _dmamem_mmap
        !           134: };
        !           135:
        !           136: int
        !           137: mpcpcibrmatch(struct device *parent, void *match, void *aux)
        !           138: {
        !           139:        struct confargs *ca = aux;
        !           140:        int found = 0;
        !           141:
        !           142:        if (strcmp(ca->ca_name, mpcpcibr_cd.cd_name) != 0)
        !           143:                return (found);
        !           144:
        !           145:        found = 1;
        !           146:
        !           147:        return found;
        !           148: }
        !           149:
        !           150: int pci_map_a = 0;
        !           151:
        !           152: struct ranges_32 {
        !           153:        u_int32_t flags;
        !           154:        u_int32_t pad1;
        !           155:        u_int32_t pad2;
        !           156:        u_int32_t base;
        !           157:        u_int32_t pad3;
        !           158:        u_int32_t size;
        !           159: };
        !           160: void
        !           161: mpcpcibus_find_ranges_32 (struct pcibr_softc *sc, u_int32_t *range_store,
        !           162:     int rangesize);
        !           163: void
        !           164: mpcpcibus_find_ranges_64 (struct pcibr_softc *sc, u_int32_t *range_store,
        !           165:     int rangesize);
        !           166: void
        !           167: mpcpcibus_find_ranges_32 (struct pcibr_softc *sc, u_int32_t *range_store,
        !           168:     int rangesize)
        !           169: {
        !           170:        int found;
        !           171:        unsigned int base = 0;
        !           172:        unsigned int size = 0;
        !           173:        struct ranges_32 *prange = (void *)range_store;
        !           174:        int rangelen;
        !           175:        int i;
        !           176:
        !           177:        rangelen = rangesize / sizeof (struct ranges_32);
        !           178:
        !           179:        /* mac configs */
        !           180:        sc->sc_membus_space.bus_base = 0;
        !           181:        sc->sc_membus_space.bus_io = 0;
        !           182:        sc->sc_iobus_space.bus_base = 0;
        !           183:        sc->sc_iobus_space.bus_io = 1;
        !           184:
        !           185:        /* find io(config) base, flag == 0x01000000 */
        !           186:        found = 0;
        !           187:        for (i = 0; i < rangelen ; i++) {
        !           188:                if (prange[i].flags == 0x01000000) {
        !           189:                        /* find last? */
        !           190:                        found = i;
        !           191:                }
        !           192:        }
        !           193:        /* found the io space ranges */
        !           194:        if (prange[found].flags == 0x01000000) {
        !           195:                sc->sc_iobus_space.bus_base =
        !           196:                    prange[found].base;
        !           197:                sc->sc_iobus_space.bus_size =
        !           198:                    prange[found].size;
        !           199:        }
        !           200:
        !           201:        /* the mem space ranges
        !           202:         * apple openfirmware always puts full
        !           203:         * addresses in config information,
        !           204:         * it is not necessary to have correct bus
        !           205:         * base address, but since 0 is reserved
        !           206:         * and all IO and device memory will be in
        !           207:         * upper 2G of address space, set to
        !           208:         * 0x80000000
        !           209:         * start with segment 1 not 0, 0 is config.
        !           210:         */
        !           211:        for (i = 0; i < rangelen ; i++) {
        !           212:                if (prange[i].flags == 0x02000000) {
        !           213: #ifdef DEBUG_PCI
        !           214:                        printf("\nfound mem %x %x",
        !           215:                                prange[i].base,
        !           216:                                prange[i].size);
        !           217: #endif
        !           218:                        if (base != 0) {
        !           219:                                if ((base + size) == prange[i].base)
        !           220:                                        size += prange[i].size;
        !           221:                                else {
        !           222:                                        size = prange[i].size;
        !           223:                                        base = prange[i].base;
        !           224:                                }
        !           225:                        } else {
        !           226:                                base = prange[i].base;
        !           227:                                size = prange[i].size;
        !           228:                        }
        !           229:                }
        !           230:        }
        !           231:        sc->sc_membus_space.bus_base = base;
        !           232:        sc->sc_membus_space.bus_size = size;
        !           233: }
        !           234:
        !           235: struct ranges_64 {
        !           236:        u_int32_t flags;
        !           237:        u_int32_t pad1;
        !           238:        u_int32_t pad2;
        !           239:        u_int32_t pad3;
        !           240:        u_int32_t base;
        !           241:        u_int32_t pad4;
        !           242:        u_int32_t size;
        !           243: };
        !           244: void
        !           245: mpcpcibus_find_ranges_64 (struct pcibr_softc *sc, u_int32_t *range_store,
        !           246:     int rangesize)
        !           247: {
        !           248:        int i, found;
        !           249:        unsigned int base = 0;
        !           250:        unsigned int size = 0;
        !           251:        int rangelen;
        !           252:        struct ranges_64 *prange = (void *)range_store;
        !           253:
        !           254:        rangelen = rangesize / sizeof (struct ranges_64);
        !           255:
        !           256:        /* mac configs */
        !           257:
        !           258:        sc->sc_membus_space.bus_base = 0;
        !           259:        sc->sc_membus_space.bus_io = 0;
        !           260:        sc->sc_iobus_space.bus_base = 0;
        !           261:        sc->sc_iobus_space.bus_io = 1;
        !           262:
        !           263:        if (prange[0].flags == 0xabb10113) { /* appl U3; */
        !           264:                prange[0].flags = 0x01000000;
        !           265:                prange[0].base = 0xf8070000;
        !           266:                prange[0].size = 0x00001000;
        !           267:                prange[1].flags = 0x02000000;
        !           268:                prange[1].base = 0xf2000000;
        !           269:                prange[1].size = 0x02800000;
        !           270:                rangelen = 2;
        !           271:        }
        !           272:
        !           273:        /* find io(config) base, flag == 0x01000000 */
        !           274:        found = 0;
        !           275:        for (i = 0; i < rangelen ; i++) {
        !           276:                if (prange[i].flags == 0x01000000) {
        !           277:                        /* find last? */
        !           278:                        found = i;
        !           279:                }
        !           280:        }
        !           281:        /* found the io space ranges */
        !           282:        if (prange[found].flags == 0x01000000) {
        !           283:                sc->sc_iobus_space.bus_base = prange[found].base;
        !           284:                sc->sc_iobus_space.bus_size = prange[found].size;
        !           285:        }
        !           286:
        !           287:        /* the mem space ranges
        !           288:         * apple openfirmware always puts full
        !           289:         * addresses in config information,
        !           290:         * it is not necessary to have correct bus
        !           291:         * base address, but since 0 is reserved
        !           292:         * and all IO and device memory will be in
        !           293:         * upper 2G of address space, set to
        !           294:         * 0x80000000
        !           295:         * start with segment 1 not 0, 0 is config.
        !           296:         */
        !           297:        for (i = 0; i < rangelen ; i++) {
        !           298:                if (prange[i].flags == 0x02000000) {
        !           299: #ifdef DEBUG_PCI
        !           300:                        printf("\nfound mem %x %x",
        !           301:                                prange[i].base,
        !           302:                                prange[i].size);
        !           303: #endif
        !           304:
        !           305:                        if (base != 0) {
        !           306:                                if ((base + size) == prange[i].base) {
        !           307:                                        size += prange[i].size;
        !           308:                                } else {
        !           309:                                        base = prange[i].base;
        !           310:                                        size = prange[i].size;
        !           311:                                }
        !           312:                        } else {
        !           313:                                base = prange[i].base;
        !           314:                                size = prange[i].size;
        !           315:                        }
        !           316:                }
        !           317:        }
        !           318:        sc->sc_membus_space.bus_base = base;
        !           319:        sc->sc_membus_space.bus_size = size;
        !           320: }
        !           321:
        !           322: void
        !           323: mpcpcibrattach(struct device *parent, struct device *self, void *aux)
        !           324: {
        !           325:        struct pcibr_softc *sc = (struct pcibr_softc *)self;
        !           326:        struct confargs *ca = aux;
        !           327:        struct pcibr_config *lcp;
        !           328:        struct pcibus_attach_args pba;
        !           329:        int node;
        !           330:        int of_node = 0;
        !           331:        char compat[32];
        !           332:        u_int32_t addr_offset;
        !           333:        u_int32_t data_offset;
        !           334:        int i;
        !           335:        int len;
        !           336:        int rangesize;
        !           337:        u_int32_t range_store[32];
        !           338:
        !           339:        if (ca->ca_node == 0) {
        !           340:                printf("invalid node on mpcpcibr config\n");
        !           341:                return;
        !           342:        }
        !           343:        len=OF_getprop(ca->ca_node, "name", compat, sizeof (compat));
        !           344:        compat[len] = '\0';
        !           345:        if (len > 0)
        !           346:                printf(" %s", compat);
        !           347:
        !           348:        len=OF_getprop(ca->ca_node, "compatible", compat,
        !           349:            sizeof (compat));
        !           350:        if (len <= 0 ) {
        !           351:                len=OF_getprop(ca->ca_node, "name", compat,
        !           352:                        sizeof (compat));
        !           353:                if (len <= 0) {
        !           354:                        printf(" compatible and name not found\n");
        !           355:                        return;
        !           356:                }
        !           357:                compat[len] = 0;
        !           358:                if (strcmp (compat, "bandit") != 0) {
        !           359:                        printf(" compatible not found and name %s found\n",
        !           360:                            compat);
        !           361:                        return;
        !           362:                }
        !           363:        }
        !           364:        compat[len] = 0;
        !           365:        if ((rangesize = OF_getprop(ca->ca_node, "ranges",
        !           366:            range_store, sizeof (range_store))) <= 0) {
        !           367:                if (strcmp(compat, "u3-ht") == 0) {
        !           368:                        range_store[0] = 0xabb10113; /* appl U3; */
        !           369:                } else
        !           370:                        printf("range lookup failed, node %x\n", ca->ca_node);
        !           371:        }
        !           372:        /* translate byte(s) into item count*/
        !           373:
        !           374:        lcp = sc->sc_pcibr = &sc->pcibr_config;
        !           375:
        !           376:        if (ppc_proc_is_64b)
        !           377:                mpcpcibus_find_ranges_64 (sc, range_store, rangesize);
        !           378:        else
        !           379:                mpcpcibus_find_ranges_32 (sc, range_store, rangesize);
        !           380:
        !           381:        addr_offset = 0;
        !           382:        for (i = 0; config_offsets[i].compat != NULL; i++) {
        !           383:                struct config_type *co = &config_offsets[i];
        !           384:                if (strcmp(co->compat, compat) == 0) {
        !           385:                        addr_offset = co->addr;
        !           386:                        data_offset = co->data;
        !           387:                        lcp->config_type = co->config_type;
        !           388:                        break;
        !           389:                }
        !           390:        }
        !           391:        if (addr_offset == 0) {
        !           392:                printf("unable to find match for"
        !           393:                    " compatible %s\n", compat);
        !           394:                return;
        !           395:        }
        !           396: #ifdef DEBUG_FIXUP
        !           397:        printf(" mem base %x sz %x io base %x sz %x\n"
        !           398:            " config addr %x config data %x\n",
        !           399:            sc->sc_membus_space.bus_base,
        !           400:            sc->sc_membus_space.bus_size,
        !           401:            sc->sc_iobus_space.bus_base,
        !           402:            sc->sc_iobus_space.bus_size,
        !           403:            addr_offset, data_offset);
        !           404: #endif
        !           405:
        !           406:        if ( bus_space_map(&(sc->sc_iobus_space), addr_offset,
        !           407:                NBPG, 0, &lcp->ioh_cf8) != 0 )
        !           408:                panic("mpcpcibus: unable to map self");
        !           409:
        !           410:        if ( bus_space_map(&(sc->sc_iobus_space), data_offset,
        !           411:                NBPG, 0, &lcp->ioh_cfc) != 0 )
        !           412:                panic("mpcpcibus: unable to map self");
        !           413:
        !           414:        of_node = ca->ca_node;
        !           415:
        !           416:        lcp->node = ca->ca_node;
        !           417:        lcp->lc_pc.pc_conf_v = lcp;
        !           418:        lcp->lc_pc.pc_attach_hook = mpc_attach_hook;
        !           419:        lcp->lc_pc.pc_bus_maxdevs = mpc_bus_maxdevs;
        !           420:        lcp->lc_pc.pc_make_tag = mpc_make_tag;
        !           421:        lcp->lc_pc.pc_decompose_tag = mpc_decompose_tag;
        !           422:        lcp->lc_pc.pc_conf_read = mpc_conf_read;
        !           423:        lcp->lc_pc.pc_conf_write = mpc_conf_write;
        !           424:        lcp->lc_pc.pc_ether_hw_addr = of_ether_hw_addr;
        !           425:        lcp->lc_iot = &sc->sc_iobus_space;
        !           426:        lcp->lc_memt = &sc->sc_membus_space;
        !           427:
        !           428:        lcp->lc_pc.pc_intr_v = lcp;
        !           429:        lcp->lc_pc.pc_intr_map = mpc_intr_map;
        !           430:        lcp->lc_pc.pc_intr_string = mpc_intr_string;
        !           431:        lcp->lc_pc.pc_intr_line = mpc_intr_line;
        !           432:        lcp->lc_pc.pc_intr_establish = mpc_intr_establish;
        !           433:        lcp->lc_pc.pc_intr_disestablish = mpc_intr_disestablish;
        !           434:
        !           435:        printf(": %s, Revision 0x%x\n", compat,
        !           436:            mpc_cfg_read_1(lcp, MPC106_PCI_REVID));
        !           437:
        !           438:        if ((strcmp(compat, "bandit")) != 0)
        !           439:                pci_addr_fixup(sc, &lcp->lc_pc, 32);
        !           440:
        !           441:        pba.pba_dmat = &pci_bus_dma_tag;
        !           442:
        !           443:        pba.pba_busname = "pci";
        !           444:        pba.pba_iot = &sc->sc_iobus_space;
        !           445:        pba.pba_memt = &sc->sc_membus_space;
        !           446:        pba.pba_pc = &lcp->lc_pc;
        !           447:        pba.pba_domain = pci_ndomains++;
        !           448:        pba.pba_bus = 0;
        !           449:        pba.pba_bridgetag = NULL;
        !           450:
        !           451:        /* we want to check pci irq settings */
        !           452:        if (of_node != 0) {
        !           453:                int nn;
        !           454:
        !           455:                for (node = OF_child(of_node); node; node = nn) {
        !           456:                        char name[32];
        !           457:                        int len;
        !           458:                        len = OF_getprop(node, "name", name,
        !           459:                            sizeof(name));
        !           460:                        name[len] = 0;
        !           461:                        fix_node_irq(node, &pba);
        !           462:
        !           463:                        /* iterate section */
        !           464:                        if ((nn = OF_child(node)) != 0)
        !           465:                                continue;
        !           466:
        !           467:                        while ((nn = OF_peer(node)) == 0) {
        !           468:                                node = OF_parent(node);
        !           469:                                if (node == of_node) {
        !           470:                                        nn = 0; /* done */
        !           471:                                        break;
        !           472:                                }
        !           473:                        }
        !           474:                }
        !           475:        }
        !           476:
        !           477:        config_found(self, &pba, mpcpcibrprint);
        !           478:
        !           479: }
        !           480:
        !           481: #define       OFW_PCI_PHYS_HI_BUSMASK         0x00ff0000
        !           482: #define       OFW_PCI_PHYS_HI_BUSSHIFT        16
        !           483: #define       OFW_PCI_PHYS_HI_DEVICEMASK      0x0000f800
        !           484: #define       OFW_PCI_PHYS_HI_DEVICESHIFT     11
        !           485: #define       OFW_PCI_PHYS_HI_FUNCTIONMASK    0x00000700
        !           486: #define       OFW_PCI_PHYS_HI_FUNCTIONSHIFT   8
        !           487:
        !           488: #define pcibus(x) \
        !           489:        (((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT)
        !           490: #define pcidev(x) \
        !           491:        (((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT)
        !           492: #define pcifunc(x) \
        !           493:        (((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT)
        !           494:
        !           495: /*
        !           496:  * Find PCI IRQ from OF.
        !           497:  */
        !           498: int
        !           499: find_node_intr(int parent, u_int32_t *addr, u_int32_t *intr)
        !           500: {
        !           501:        int iparent, len, mlen, alen, ilen;
        !           502:        int match, i, step;
        !           503:        u_int32_t map[144], *mp, *mp1;
        !           504:        u_int32_t imask[8], maskedaddr[8];
        !           505:        u_int32_t address_cells, interrupt_cells, mask_cells;
        !           506:
        !           507:        len = OF_getprop(parent, "interrupt-map", map, sizeof(map));
        !           508:        mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask));
        !           509:        alen = OF_getprop(parent, "#address-cells",
        !           510:            &address_cells, sizeof(address_cells));
        !           511:        ilen = OF_getprop(parent, "#interrupt-cells",
        !           512:            &interrupt_cells, sizeof(interrupt_cells));
        !           513:
        !           514:        if (len == -1 || mlen == -1 || alen == -1 || ilen == -1)
        !           515:                goto nomap;
        !           516:
        !           517:        mask_cells = address_cells + interrupt_cells;
        !           518:        if (mask_cells != (mlen / sizeof(u_int32_t)))
        !           519:                goto nomap;
        !           520:        for (i = 0; i < mask_cells; i++)
        !           521:                maskedaddr[i] = addr[i] & imask[i];
        !           522:
        !           523:        /* interrupt-map is formatted as follows
        !           524:         * int * #address-cells, int * #interrupt-cells, int, int, int
        !           525:         * eg
        !           526:         * address-cells = 3
        !           527:         * interrupt-cells = 1
        !           528:         * 00001000 00000000 00000000 00000000 ff911258 00000034 00000001
        !           529:         * 00001800 00000000 00000000 00000000 ff911258 00000035 00000001
        !           530:         * 00002000 00000000 00000000 00000000 ff911258 00000036 00000001
        !           531:         * | address cells          | | intr | |parent| | irq  | |edge/level|
        !           532:         *                            | cells|          | interrupt cells   |
        !           533:         *                                              | of parent         |
        !           534:         * or at least something close to that.
        !           535:         */
        !           536:
        !           537:        mp = map;
        !           538:        while (len > mlen) {
        !           539:                mp1 = mp + mask_cells;
        !           540:
        !           541:                iparent = *mp1;
        !           542:                alen = OF_getprop(iparent, "#address-cells",
        !           543:                    &address_cells, sizeof(address_cells));
        !           544:                if (alen == -1)
        !           545:                        address_cells = 0;
        !           546:                ilen = OF_getprop(iparent, "#interrupt-cells",
        !           547:                    &interrupt_cells, sizeof(interrupt_cells));
        !           548:                if (ilen == -1)
        !           549:                        goto nomap;
        !           550:
        !           551:                step = mask_cells + 1 + address_cells + interrupt_cells;
        !           552:
        !           553:                match = bcmp(maskedaddr, mp, mlen);
        !           554:                if (match == 0) {
        !           555:                        if (OF_getprop(iparent, "interrupt-controller",
        !           556:                                       NULL, 0) == 0) {
        !           557:                                *intr = mp1[1];
        !           558:                                return 1;
        !           559:                        }
        !           560:                        /* Recurse with new 'addr'. */
        !           561:                        return find_node_intr(iparent, &mp1[1], intr);
        !           562:                }
        !           563:                len -= step * sizeof(u_int32_t);
        !           564:                mp += step;
        !           565:        }
        !           566: nomap:
        !           567:        return -1;
        !           568: }
        !           569:
        !           570: void
        !           571: fix_node_irq(int node, struct pcibus_attach_args *pba)
        !           572: {
        !           573:        struct {
        !           574:                u_int32_t phys_hi, phys_mid, phys_lo;
        !           575:                u_int32_t size_hi, size_lo;
        !           576:        } addr [8];
        !           577:        u_int32_t map[144];
        !           578:        int len;
        !           579:        pcitag_t tag;
        !           580:        u_int32_t irq;
        !           581:        u_int32_t intr;
        !           582:        int parent;
        !           583:
        !           584:        pci_chipset_tag_t pc = pba->pba_pc;
        !           585:
        !           586:        len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr));
        !           587:        if (len == -1 || len < sizeof(addr[0]))
        !           588:                return;
        !           589:
        !           590:        /* if this node has a AAPL,interrupts property, firmware
        !           591:         * has initialized the register correctly.
        !           592:         */
        !           593:        len = OF_getprop(node, "AAPL,interrupts", &intr, 4);
        !           594:        if (len != 4) {
        !           595:
        !           596:                parent = OF_parent(node);
        !           597:
        !           598:                irq = -1;
        !           599:
        !           600:                /* we want the first interrupt, set size_hi to 1 */
        !           601:                addr[0].size_hi = 1;
        !           602:                if (find_node_intr(parent, &addr[0].phys_hi, &irq) == -1) {
        !           603:                        len = OF_getprop(node, "interrupts", map,
        !           604:                            sizeof(map));
        !           605:                        if (len != -1 && len != 4) {
        !           606:                                irq = map[0];
        !           607:                        } else
        !           608:                                return;
        !           609:                }
        !           610:        } else
        !           611:                irq = intr;
        !           612:        /* program the interrupt line register with the value
        !           613:         * found in openfirmware
        !           614:         */
        !           615:
        !           616:        tag = pci_make_tag(pc, pcibus(addr[0].phys_hi),
        !           617:            pcidev(addr[0].phys_hi), pcifunc(addr[0].phys_hi));
        !           618:
        !           619:        intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
        !           620:        intr &= ~PCI_INTERRUPT_LINE_MASK;
        !           621:        intr |= irq & PCI_INTERRUPT_LINE_MASK;
        !           622:        pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
        !           623: }
        !           624:
        !           625: static int
        !           626: mpcpcibrprint(void *aux, const char *pnp)
        !           627: {
        !           628:        struct pcibus_attach_args *pba = aux;
        !           629:
        !           630:        if (pnp)
        !           631:                printf("%s at %s", pba->pba_busname, pnp);
        !           632:        printf(" bus %d", pba->pba_bus);
        !           633:        return(UNCONF);
        !           634: }
        !           635:
        !           636: void
        !           637: mpc_attach_hook(struct device *parent, struct device *self,
        !           638:     struct pcibus_attach_args *pba)
        !           639: {
        !           640: }
        !           641:
        !           642: int
        !           643: of_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr)
        !           644: {
        !           645:        u_int8_t laddr[6];
        !           646:        struct pcibr_config *lcp = lcpc->pc_conf_v;
        !           647:        int of_node = lcp->node;
        !           648:        int node, nn;
        !           649:        for (node = OF_child(of_node); node; node = nn) {
        !           650:                char name[32];
        !           651:                int len;
        !           652:                len = OF_getprop(node, "name", name,
        !           653:                        sizeof(name));
        !           654:                name[len] = 0;
        !           655:
        !           656:                len = OF_getprop(node, "local-mac-address", laddr,
        !           657:                    sizeof laddr);
        !           658:                if (sizeof (laddr) == len) {
        !           659:                        bcopy (laddr, oaddr, sizeof laddr);
        !           660:                        return 1;
        !           661:                }
        !           662:
        !           663:                /* iterate section */
        !           664:                if ((nn = OF_child(node)) != 0) {
        !           665:                        continue;
        !           666:                }
        !           667:                while ((nn = OF_peer(node)) == 0) {
        !           668:                        node = OF_parent(node);
        !           669:                        if (node == of_node) {
        !           670:                                nn = 0; /* done */
        !           671:                                break;
        !           672:                        }
        !           673:                }
        !           674:        }
        !           675:        oaddr[0] = oaddr[1] = oaddr[2] = 0xff;
        !           676:        oaddr[3] = oaddr[4] = oaddr[5] = 0xff;
        !           677:        return 0;
        !           678: }
        !           679:
        !           680: int
        !           681: mpc_ether_hw_addr(struct ppc_pci_chipset *p, u_int8_t *s)
        !           682: {
        !           683:        printf("mpc_ether_hw_addr not supported\n");
        !           684:        return(0);
        !           685: }
        !           686:
        !           687: int
        !           688: mpc_bus_maxdevs(void *cpv, int busno)
        !           689: {
        !           690:        return(32);
        !           691: }
        !           692:
        !           693: #define BUS_SHIFT 16
        !           694: #define DEVICE_SHIFT 11
        !           695: #define FNC_SHIFT 8
        !           696:
        !           697: pcitag_t
        !           698: mpc_make_tag(void *cpv, int bus, int dev, int fnc)
        !           699: {
        !           700:        return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT);
        !           701: }
        !           702:
        !           703: void
        !           704: mpc_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp)
        !           705: {
        !           706:        if (busp != NULL)
        !           707:                *busp = (tag >> BUS_SHIFT) & 0xff;
        !           708:        if (devp != NULL)
        !           709:                *devp = (tag >> DEVICE_SHIFT) & 0x1f;
        !           710:        if (fncp != NULL)
        !           711:                *fncp = (tag >> FNC_SHIFT) & 0x7;
        !           712: }
        !           713:
        !           714: u_int32_t
        !           715: mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset)
        !           716: {
        !           717:        struct pcibr_config *cp = cpv;
        !           718:        unsigned int bus, dev, fcn;
        !           719:        u_int32_t reg;
        !           720:
        !           721:        mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn);
        !           722:
        !           723:        if (cp->config_type & 1) {
        !           724:                /* Config Mechanism #2 */
        !           725:                if (bus == 0) {
        !           726:                        if (dev < 11)
        !           727:                                return 0xffffffff;
        !           728:                        /*
        !           729:                         * Need to do config type 0 operation
        !           730:                         *  1 << (11?+dev) | fcn << 8 | reg
        !           731:                         * 11? is because pci spec states
        !           732:                         * that 11-15 is reserved.
        !           733:                         */
        !           734:                        reg = 1 << (dev) | fcn << 8 | offset;
        !           735:
        !           736:                } else {
        !           737:                        if (dev > 15)
        !           738:                                return 0xffffffff;
        !           739:                        /*
        !           740:                         * config type 1
        !           741:                         */
        !           742:                        reg =  tag | offset | 1;
        !           743:                }
        !           744:        } else {
        !           745:                /* config mechanism #2, type 0
        !           746:                 * standard cf8/cfc config
        !           747:                 */
        !           748:                reg =  0x80000000 | tag  | offset;
        !           749:        }
        !           750:
        !           751:        return reg;
        !           752: }
        !           753:
        !           754: /* #define DEBUG_CONFIG  */
        !           755: pcireg_t
        !           756: mpc_conf_read(void *cpv, pcitag_t tag, int offset)
        !           757: {
        !           758:        struct pcibr_config *cp = cpv;
        !           759:        pcireg_t data;
        !           760:        u_int32_t reg;
        !           761:        int s;
        !           762:        int daddr = 0;
        !           763:        faultbuf env;
        !           764:        void *oldh;
        !           765:
        !           766:        if (offset & 3 || offset < 0 || offset >= 0x100) {
        !           767: #ifdef DEBUG_CONFIG
        !           768:                printf ("pci_conf_read: bad reg %x\n", offset);
        !           769: #endif /* DEBUG_CONFIG */
        !           770:                return(~0);
        !           771:        }
        !           772:
        !           773:        reg = mpc_gen_config_reg(cpv, tag, offset);
        !           774:        /* if invalid tag, return -1 */
        !           775:        if (reg == 0xffffffff)
        !           776:                return(~0);
        !           777:
        !           778:        if ((cp->config_type & 2) && (offset & 0x04))
        !           779:                daddr += 4;
        !           780:
        !           781:        s = splhigh();
        !           782:
        !           783:        oldh = curpcb->pcb_onfault;
        !           784:        if (setfault(&env)) {
        !           785:                /* we faulted during the read? */
        !           786:                curpcb->pcb_onfault = oldh;
        !           787:                splx(s);
        !           788:                return 0xffffffff;
        !           789:        }
        !           790:
        !           791:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
        !           792:        bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
        !           793:        data = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, daddr);
        !           794:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
        !           795:        bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
        !           796:
        !           797:        curpcb->pcb_onfault = oldh;
        !           798:
        !           799:        splx(s);
        !           800: #ifdef DEBUG_CONFIG
        !           801:        if (!((offset == 0) && (data == 0xffffffff))) {
        !           802:                unsigned int bus, dev, fcn;
        !           803:                mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn);
        !           804:                printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn,
        !           805:                        offset);
        !           806:                printf(" daddr %x reg %x",daddr, reg);
        !           807:                printf(" data %x\n", data);
        !           808:        }
        !           809: #endif
        !           810:
        !           811:        return(data);
        !           812: }
        !           813:
        !           814: void
        !           815: mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
        !           816: {
        !           817:        struct pcibr_config *cp = cpv;
        !           818:        u_int32_t reg;
        !           819:        int s;
        !           820:        int daddr = 0;
        !           821:
        !           822:        reg = mpc_gen_config_reg(cpv, tag, offset);
        !           823:
        !           824:        /* if invalid tag, return ??? */
        !           825:        if (reg == 0xffffffff)
        !           826:                return;
        !           827:
        !           828:        if ((cp->config_type & 2) && (offset & 0x04))
        !           829:                daddr += 4;
        !           830:
        !           831: #ifdef DEBUG_CONFIG
        !           832:        {
        !           833:                unsigned int bus, dev, fcn;
        !           834:                mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn);
        !           835:                printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus,
        !           836:                        dev, fcn, offset);
        !           837:                printf(" daddr %x reg %x",daddr, reg);
        !           838:                printf(" data %x\n", data);
        !           839:        }
        !           840: #endif
        !           841:
        !           842:        s = splhigh();
        !           843:
        !           844:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
        !           845:        bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
        !           846:        bus_space_write_4(cp->lc_iot, cp->ioh_cfc, daddr, data);
        !           847:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
        !           848:        bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
        !           849:
        !           850:        splx(s);
        !           851: }
        !           852:
        !           853:
        !           854: /*ARGSUSED*/
        !           855: int
        !           856: mpc_intr_map(void *lcv, pcitag_t bustag, int buspin, int  line,
        !           857:     pci_intr_handle_t *ihp)
        !           858: {
        !           859:        int error = 0;
        !           860:
        !           861:        *ihp = -1;
        !           862:         if (buspin == 0)
        !           863:                 error = 1; /* No IRQ used. */
        !           864:         else if (buspin > 4) {
        !           865:                 printf("mpc_intr_map: bad interrupt pin %d\n", buspin);
        !           866:                 error = 1;
        !           867:         }
        !           868:
        !           869:        if (!error)
        !           870:                *ihp = line;
        !           871:        return error;
        !           872: }
        !           873:
        !           874: const char *
        !           875: mpc_intr_string(void *lcv, pci_intr_handle_t ih)
        !           876: {
        !           877:        static char str[16];
        !           878:
        !           879:        snprintf(str, sizeof str, "irq %ld", ih);
        !           880:        return(str);
        !           881: }
        !           882:
        !           883: int
        !           884: mpc_intr_line(void *lcv, pci_intr_handle_t ih)
        !           885: {
        !           886:        return (ih);
        !           887: }
        !           888:
        !           889: void *
        !           890: mpc_intr_establish(void *lcv, pci_intr_handle_t ih, int level,
        !           891:     int (*func)(void *), void *arg, char *name)
        !           892: {
        !           893:        return (*intr_establish_func)(lcv, ih, IST_LEVEL, level, func, arg,
        !           894:                name);
        !           895: }
        !           896:
        !           897: void
        !           898: mpc_intr_disestablish(void *lcv, void *cookie)
        !           899: {
        !           900:        /* XXX We should probably do something clever here.... later */
        !           901: }
        !           902:
        !           903: u_int32_t
        !           904: pci_iack()
        !           905: {
        !           906:        /* do pci IACK cycle */
        !           907:        /* this should be bus allocated. */
        !           908:        volatile u_int8_t *iack = (u_int8_t *)0xbffffff0;
        !           909:        u_int8_t val;
        !           910:
        !           911:        val = *iack;
        !           912:        return val;
        !           913: }
        !           914:
        !           915: void
        !           916: mpc_cfg_write_1(struct pcibr_config *cp, u_int32_t reg, u_int8_t val)
        !           917: {
        !           918:        int s;
        !           919:        s = splhigh();
        !           920:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
        !           921:        bus_space_write_1(cp->lc_iot, cp->ioh_cfc, 0, val);
        !           922:        splx(s);
        !           923: }
        !           924:
        !           925: void
        !           926: mpc_cfg_write_2(struct pcibr_config *cp, u_int32_t reg, u_int16_t val)
        !           927: {
        !           928:        int s;
        !           929:        s = splhigh();
        !           930:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
        !           931:        bus_space_write_2(cp->lc_iot, cp->ioh_cfc, 0, val);
        !           932:        splx(s);
        !           933: }
        !           934:
        !           935: void
        !           936: mpc_cfg_write_4(struct pcibr_config *cp, u_int32_t reg, u_int32_t val)
        !           937: {
        !           938:
        !           939:        int s;
        !           940:        s = splhigh();
        !           941:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
        !           942:        bus_space_write_4(cp->lc_iot, cp->ioh_cfc, 0, val);
        !           943:        splx(s);
        !           944: }
        !           945:
        !           946: u_int8_t
        !           947: mpc_cfg_read_1(struct pcibr_config *cp, u_int32_t reg)
        !           948: {
        !           949:        u_int8_t _v_;
        !           950:
        !           951:        int s;
        !           952:        s = splhigh();
        !           953:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
        !           954:        _v_ = bus_space_read_1(cp->lc_iot, cp->ioh_cfc, 0);
        !           955:        splx(s);
        !           956:        return(_v_);
        !           957: }
        !           958:
        !           959: u_int16_t
        !           960: mpc_cfg_read_2(struct pcibr_config *cp, u_int32_t reg)
        !           961: {
        !           962:        u_int16_t _v_;
        !           963:
        !           964:        int s;
        !           965:        s = splhigh();
        !           966:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
        !           967:        _v_ = bus_space_read_2(cp->lc_iot, cp->ioh_cfc, 0);
        !           968:        splx(s);
        !           969:        return(_v_);
        !           970: }
        !           971:
        !           972: u_int32_t
        !           973: mpc_cfg_read_4(struct pcibr_config *cp, u_int32_t reg)
        !           974: {
        !           975:        u_int32_t _v_;
        !           976:
        !           977:        int s;
        !           978:        s = splhigh();
        !           979:        bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
        !           980:        _v_ = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, 0);
        !           981:        splx(s);
        !           982:        return(_v_);
        !           983: }

CVSweb