[BACK]Return to psycho.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc64 / dev

Annotation of sys/arch/sparc64/dev/psycho.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: psycho.c,v 1.52 2007/08/04 16:44:15 kettenis Exp $    */
        !             2: /*     $NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1999, 2000 Matthew R. Green
        !             6:  * Copyright (c) 2003 Henric Jungheim
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. The name of the author may not be used to endorse or promote products
        !            18:  *    derived from this software without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            21:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            22:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            23:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            24:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
        !            25:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            26:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
        !            27:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        !            28:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  */
        !            32:
        !            33: /*
        !            34:  * Support for `psycho' and `psycho+' UPA to PCI bridge and
        !            35:  * UltraSPARC IIi and IIe `sabre' PCI controllers.
        !            36:  */
        !            37:
        !            38: #include <sys/param.h>
        !            39: #include <sys/device.h>
        !            40: #include <sys/errno.h>
        !            41: #include <sys/extent.h>
        !            42: #include <sys/malloc.h>
        !            43: #include <sys/systm.h>
        !            44: #include <sys/time.h>
        !            45: #include <sys/reboot.h>
        !            46:
        !            47: #include <uvm/uvm_extern.h>
        !            48:
        !            49: #define _SPARC_BUS_DMA_PRIVATE
        !            50: #include <machine/bus.h>
        !            51: #include <machine/autoconf.h>
        !            52: #include <machine/psl.h>
        !            53:
        !            54: #include <dev/pci/pcivar.h>
        !            55: #include <dev/pci/pcireg.h>
        !            56:
        !            57: #include <sparc64/dev/iommureg.h>
        !            58: #include <sparc64/dev/iommuvar.h>
        !            59: #include <sparc64/dev/psychoreg.h>
        !            60: #include <sparc64/dev/psychovar.h>
        !            61: #include <sparc64/sparc64/cache.h>
        !            62:
        !            63: #ifdef DEBUG
        !            64: #define PDB_PROM       0x01
        !            65: #define PDB_BUSMAP     0x02
        !            66: #define PDB_INTR       0x04
        !            67: #define PDB_CONF       0x08
        !            68: int psycho_debug = ~0;
        !            69: #define DPRINTF(l, s)   do { if (psycho_debug & l) printf s; } while (0)
        !            70: #else
        !            71: #define DPRINTF(l, s)
        !            72: #endif
        !            73:
        !            74: pci_chipset_tag_t psycho_alloc_chipset(struct psycho_pbm *, int,
        !            75:     pci_chipset_tag_t);
        !            76: void psycho_get_bus_range(int, int *);
        !            77: void psycho_get_ranges(int, struct psycho_ranges **, int *);
        !            78: void psycho_set_intr(struct psycho_softc *, int, void *,
        !            79:     u_int64_t *, u_int64_t *, const char *);
        !            80: bus_space_tag_t psycho_alloc_bus_tag(struct psycho_pbm *,
        !            81:     const char *, int, int, int);
        !            82:
        !            83: /* Interrupt handlers */
        !            84: int psycho_ue(void *);
        !            85: int psycho_ce(void *);
        !            86: int psycho_bus_a(void *);
        !            87: int psycho_bus_b(void *);
        !            88: int psycho_bus_error(struct psycho_softc *, int);
        !            89: int psycho_powerfail(void *);
        !            90: int psycho_wakeup(void *);
        !            91:
        !            92: /* IOMMU support */
        !            93: void psycho_iommu_init(struct psycho_softc *, int);
        !            94:
        !            95: /*
        !            96:  * bus space and bus dma support for UltraSPARC `psycho'.  note that most
        !            97:  * of the bus dma support is provided by the iommu dvma controller.
        !            98:  */
        !            99: int psycho_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
        !           100:     bus_size_t, int, bus_space_handle_t *);
        !           101: paddr_t psycho_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t, off_t,
        !           102:     int, int);
        !           103: bus_addr_t psycho_bus_addr(bus_space_tag_t, bus_space_tag_t,
        !           104:     bus_space_handle_t);
        !           105: void *psycho_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
        !           106:     int (*)(void *), void *, const char *);
        !           107:
        !           108: int psycho_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int,
        !           109:     bus_size_t, bus_size_t, int, bus_dmamap_t *);
        !           110: void psycho_sabre_dvmamap_sync(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t,
        !           111:     bus_size_t, bus_size_t, int);
        !           112: void psycho_map_psycho(struct psycho_softc *, int, bus_addr_t, bus_size_t,
        !           113:     bus_addr_t, bus_size_t);
        !           114: int psycho_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
        !           115: void psycho_identify_pbm(struct psycho_softc *sc, struct psycho_pbm *pp,
        !           116:     struct pcibus_attach_args *pa);
        !           117:
        !           118: /* base pci_chipset */
        !           119: extern struct sparc_pci_chipset _sparc_pci_chipset;
        !           120:
        !           121: /*
        !           122:  * autoconfiguration
        !           123:  */
        !           124: int    psycho_match(struct device *, void *, void *);
        !           125: void   psycho_attach(struct device *, struct device *, void *);
        !           126: int    psycho_print(void *aux, const char *p);
        !           127:
        !           128:
        !           129: struct cfattach psycho_ca = {
        !           130:         sizeof(struct psycho_softc), psycho_match, psycho_attach
        !           131: };
        !           132:
        !           133: struct cfdriver psycho_cd = {
        !           134:        NULL, "psycho", DV_DULL
        !           135: };
        !           136:
        !           137: /*
        !           138:  * "sabre" is the UltraSPARC IIi onboard UPA to PCI bridge.  It manages a
        !           139:  * single PCI bus and does not have a streaming buffer.  It often has an APB
        !           140:  * (advanced PCI bridge) connected to it, which was designed specifically for
        !           141:  * the IIi.  The APB let's the IIi handle two independednt PCI buses, and
        !           142:  * appears as two "simba"'s underneath the sabre.
        !           143:  *
        !           144:  * "psycho" and "psycho+" is a dual UPA to PCI bridge.  It sits on the UPA bus
        !           145:  * and manages two PCI buses.  "psycho" has two 64-bit 33MHz buses, while
        !           146:  * "psycho+" controls both a 64-bit 33MHz and a 64-bit 66MHz PCI bus.  You
        !           147:  * will usually find a "psycho+" since I don't think the original "psycho"
        !           148:  * ever shipped, and if it did it would be in the U30.
        !           149:  *
        !           150:  * Each "psycho" PCI bus appears as a separate OFW node, but since they are
        !           151:  * both part of the same IC, they only have a single register space.  As such,
        !           152:  * they need to be configured together, even though the autoconfiguration will
        !           153:  * attach them separately.
        !           154:  *
        !           155:  * On UltraIIi machines, "sabre" itself usually takes pci0, with "simba" often
        !           156:  * as pci1 and pci2, although they have been implemented with other PCI bus
        !           157:  * numbers on some machines.
        !           158:  *
        !           159:  * On UltraII machines, there can be any number of "psycho+" ICs, each
        !           160:  * providing two PCI buses.
        !           161:  *
        !           162:  *
        !           163:  * XXXX The psycho/sabre node has an `interrupts' attribute.  They contain
        !           164:  * the values of the following interrupts in this order:
        !           165:  *
        !           166:  * PCI Bus Error       (30)
        !           167:  * DMA UE              (2e)
        !           168:  * DMA CE              (2f)
        !           169:  * Power Fail          (25)
        !           170:  *
        !           171:  * We really should attach handlers for each.
        !           172:  *
        !           173:  */
        !           174: #define        ROM_PCI_NAME            "pci"
        !           175:
        !           176: struct psycho_type {
        !           177:        char *p_name;
        !           178:        int p_type;
        !           179: } psycho_types[] = {
        !           180:        { "SUNW,psycho",        PSYCHO_MODE_PSYCHO      },
        !           181:        { "pci108e,8000",       PSYCHO_MODE_PSYCHO      },
        !           182:        { "SUNW,sabre",         PSYCHO_MODE_SABRE       },
        !           183:        { "pci108e,a000",       PSYCHO_MODE_SABRE       },
        !           184:        { "pci108e,a001",       PSYCHO_MODE_SABRE       },
        !           185:        { NULL, 0 }
        !           186: };
        !           187:
        !           188: int
        !           189: psycho_match(struct device *parent, void *match, void *aux)
        !           190: {
        !           191:        struct mainbus_attach_args *ma = aux;
        !           192:        struct psycho_type *ptype;
        !           193:        char *str;
        !           194:
        !           195:        /* match on a name of "pci" and a sabre or a psycho */
        !           196:        if (strcmp(ma->ma_name, ROM_PCI_NAME) != 0)
        !           197:                return (0);
        !           198:
        !           199:        for (ptype = psycho_types; ptype->p_name != NULL; ptype++) {
        !           200:                str = getpropstring(ma->ma_node, "model");
        !           201:                if (strcmp(str, ptype->p_name) == 0)
        !           202:                        return (1);
        !           203:                str = getpropstring(ma->ma_node, "compatible");
        !           204:                if (strcmp(str, ptype->p_name) == 0)
        !           205:                        return (1);
        !           206:        }
        !           207:        return (0);
        !           208: }
        !           209:
        !           210: /*
        !           211:  * SUNW,psycho initialization ...
        !           212:  *     - find the per-psycho registers
        !           213:  *     - figure out the IGN.
        !           214:  *     - find our partner psycho
        !           215:  *     - configure ourselves
        !           216:  *     - bus range, bus,
        !           217:  *     - get interrupt-map and interrupt-map-mask
        !           218:  *     - setup the chipsets.
        !           219:  *     - if we're the first of the pair, initialise the IOMMU, otherwise
        !           220:  *       just copy its tags and addresses.
        !           221:  */
        !           222: void
        !           223: psycho_attach(struct device *parent, struct device *self, void *aux)
        !           224: {
        !           225:        struct psycho_softc *sc = (struct psycho_softc *)self;
        !           226:        struct psycho_softc *osc = NULL;
        !           227:        struct psycho_pbm *pp;
        !           228:        struct pcibus_attach_args pba;
        !           229:        struct mainbus_attach_args *ma = aux;
        !           230:        u_int64_t csr;
        !           231:        int psycho_br[2], n;
        !           232:        struct psycho_type *ptype;
        !           233:
        !           234:        sc->sc_node = ma->ma_node;
        !           235:        sc->sc_bustag = ma->ma_bustag;
        !           236:        sc->sc_dmatag = ma->ma_dmatag;
        !           237:
        !           238:        /*
        !           239:         * call the model-specific initialization routine.
        !           240:         */
        !           241:
        !           242:        for (ptype = psycho_types; ptype->p_name != NULL; ptype++) {
        !           243:                char *str;
        !           244:
        !           245:                str = getpropstring(ma->ma_node, "model");
        !           246:                if (strcmp(str, ptype->p_name) == 0)
        !           247:                        break;
        !           248:                str = getpropstring(ma->ma_node, "compatible");
        !           249:                if (strcmp(str, ptype->p_name) == 0)
        !           250:                        break;
        !           251:        }
        !           252:        if (ptype->p_name == NULL)
        !           253:                panic("psycho_attach: unknown model?");
        !           254:        sc->sc_mode = ptype->p_type;
        !           255:
        !           256:        /*
        !           257:         * The psycho gets three register banks:
        !           258:         * (0) per-PBM configuration and status registers
        !           259:         * (1) per-PBM PCI configuration space, containing only the
        !           260:         *     PBM 256-byte PCI header
        !           261:         * (2) the shared psycho configuration registers (struct psychoreg)
        !           262:         *
        !           263:         * XXX use the prom address for the psycho registers?  we do so far.
        !           264:         */
        !           265:
        !           266:        /* Register layouts are different.  stuupid. */
        !           267:        if (sc->sc_mode == PSYCHO_MODE_PSYCHO) {
        !           268:                sc->sc_basepaddr = (paddr_t)ma->ma_reg[2].ur_paddr;
        !           269:
        !           270:                if (ma->ma_naddress > 2) {
        !           271:                        psycho_map_psycho(sc, 0,
        !           272:                            ma->ma_address[2], sizeof(struct psychoreg),
        !           273:                            ma->ma_address[0], sizeof(struct pci_ctl));
        !           274:                } else if (ma->ma_nreg > 2) {
        !           275:                        psycho_map_psycho(sc, 1,
        !           276:                            ma->ma_reg[2].ur_paddr, ma->ma_reg[2].ur_len,
        !           277:                            ma->ma_reg[0].ur_paddr, ma->ma_reg[0].ur_len);
        !           278:                } else
        !           279:                        panic("psycho_attach: %d not enough registers",
        !           280:                            ma->ma_nreg);
        !           281:        } else {
        !           282:                sc->sc_basepaddr = (paddr_t)ma->ma_reg[0].ur_paddr;
        !           283:
        !           284:                if (ma->ma_naddress) {
        !           285:                        psycho_map_psycho(sc, 0,
        !           286:                            ma->ma_address[0], sizeof(struct psychoreg),
        !           287:                            ma->ma_address[0] +
        !           288:                                offsetof(struct psychoreg, psy_pcictl[0]),
        !           289:                            sizeof(struct pci_ctl));
        !           290:                } else if (ma->ma_nreg) {
        !           291:                        psycho_map_psycho(sc, 1,
        !           292:                            ma->ma_reg[0].ur_paddr, ma->ma_reg[0].ur_len,
        !           293:                            ma->ma_reg[0].ur_paddr +
        !           294:                                offsetof(struct psychoreg, psy_pcictl[0]),
        !           295:                            sizeof(struct pci_ctl));
        !           296:                } else
        !           297:                        panic("psycho_attach: %d not enough registers",
        !           298:                            ma->ma_nreg);
        !           299:        }
        !           300:
        !           301:        csr = psycho_psychoreg_read(sc, psy_csr);
        !           302:        sc->sc_ign = INTMAP_IGN; /* APB IGN is always 0x1f << 6 = 0x7c */
        !           303:        if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
        !           304:                sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6;
        !           305:
        !           306:        printf(": %s, impl %d, version %d, ign %x\n", ptype->p_name,
        !           307:            PSYCHO_GCSR_IMPL(csr), PSYCHO_GCSR_VERS(csr), sc->sc_ign);
        !           308:
        !           309:        /*
        !           310:         * Match other psycho's that are already configured against
        !           311:         * the base physical address. This will be the same for a
        !           312:         * pair of devices that share register space.
        !           313:         */
        !           314:        for (n = 0; n < psycho_cd.cd_ndevs; n++) {
        !           315:                struct psycho_softc *asc =
        !           316:                    (struct psycho_softc *)psycho_cd.cd_devs[n];
        !           317:
        !           318:                if (asc == NULL || asc == sc)
        !           319:                        /* This entry is not there or it is me */
        !           320:                        continue;
        !           321:
        !           322:                if (asc->sc_basepaddr != sc->sc_basepaddr)
        !           323:                        /* This is an unrelated psycho */
        !           324:                        continue;
        !           325:
        !           326:                /* Found partner */
        !           327:                osc = asc;
        !           328:                break;
        !           329:        }
        !           330:
        !           331:        /* Oh, dear.  OK, lets get started */
        !           332:
        !           333:        /*
        !           334:         * Setup the PCI control register
        !           335:         */
        !           336:        csr = psycho_pcictl_read(sc, pci_csr);
        !           337:        csr |= PCICTL_MRLM | PCICTL_ARB_PARK | PCICTL_ERRINTEN |
        !           338:            PCICTL_4ENABLE;
        !           339:        csr &= ~(PCICTL_SERR | PCICTL_CPU_PRIO | PCICTL_ARB_PRIO |
        !           340:            PCICTL_RTRYWAIT);
        !           341:        psycho_pcictl_write(sc, pci_csr, csr);
        !           342:
        !           343:        /*
        !           344:         * Allocate our psycho_pbm
        !           345:         */
        !           346:        pp = sc->sc_psycho_this = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
        !           347:        if (pp == NULL)
        !           348:                panic("could not allocate psycho pbm");
        !           349:
        !           350:        memset(pp, 0, sizeof *pp);
        !           351:
        !           352:        pp->pp_sc = sc;
        !           353:
        !           354:        /* grab the psycho ranges */
        !           355:        psycho_get_ranges(sc->sc_node, &pp->pp_range, &pp->pp_nrange);
        !           356:
        !           357:        /* get the bus-range for the psycho */
        !           358:        psycho_get_bus_range(sc->sc_node, psycho_br);
        !           359:
        !           360:        pba.pba_domain = pci_ndomains++;
        !           361:        pba.pba_bus = psycho_br[0];
        !           362:        pba.pba_bridgetag = NULL;
        !           363:
        !           364:        printf("%s: bus range %u-%u, PCI bus %d\n", sc->sc_dev.dv_xname,
        !           365:            psycho_br[0], psycho_br[1], psycho_br[0]);
        !           366:
        !           367:        pp->pp_pcictl = sc->sc_pcictl;
        !           368:
        !           369:        /* allocate our tags */
        !           370:        pp->pp_memt = psycho_alloc_mem_tag(pp);
        !           371:        pp->pp_iot = psycho_alloc_io_tag(pp);
        !           372:        pp->pp_dmat = psycho_alloc_dma_tag(pp);
        !           373:        pp->pp_flags = (pp->pp_memt ? PCI_FLAGS_MEM_ENABLED : 0) |
        !           374:                        (pp->pp_iot ? PCI_FLAGS_IO_ENABLED  : 0);
        !           375:
        !           376:        /* allocate a chipset for this */
        !           377:        pp->pp_pc = psycho_alloc_chipset(pp, sc->sc_node, &_sparc_pci_chipset);
        !           378:
        !           379:        /* setup the rest of the psycho pbm */
        !           380:        pba.pba_pc = pp->pp_pc;
        !           381:
        !           382:        /*
        !           383:         * And finally, if we're a sabre or the first of a pair of psycho's to
        !           384:         * arrive here, start up the IOMMU and get a config space tag.
        !           385:         */
        !           386:
        !           387:        if (osc == NULL) {
        !           388:                uint64_t timeo;
        !           389:
        !           390:                /*
        !           391:                 * Establish handlers for interesting interrupts....
        !           392:                 *
        !           393:                 * XXX We need to remember these and remove this to support
        !           394:                 * hotplug on the UPA/FHC bus.
        !           395:                 *
        !           396:                 * XXX Not all controllers have these, but installing them
        !           397:                 * is better than trying to sort through this mess.
        !           398:                 */
        !           399:                psycho_set_intr(sc, 15, psycho_ue,
        !           400:                    psycho_psychoreg_vaddr(sc, ue_int_map),
        !           401:                    psycho_psychoreg_vaddr(sc, ue_clr_int), "ue");
        !           402:                psycho_set_intr(sc, 1, psycho_ce,
        !           403:                    psycho_psychoreg_vaddr(sc, ce_int_map),
        !           404:                    psycho_psychoreg_vaddr(sc, ce_clr_int), "ce");
        !           405:                psycho_set_intr(sc, 15, psycho_bus_a,
        !           406:                    psycho_psychoreg_vaddr(sc, pciaerr_int_map),
        !           407:                    psycho_psychoreg_vaddr(sc, pciaerr_clr_int), "bus_a");
        !           408: #if 0
        !           409:                psycho_set_intr(sc, 15, psycho_powerfail,
        !           410:                    psycho_psychoreg_vaddr(sc, power_int_map),
        !           411:                    psycho_psychoreg_vaddr(sc, power_clr_int), "powerfail");
        !           412: #endif
        !           413:                if (sc->sc_mode == PSYCHO_MODE_PSYCHO) {
        !           414:                        psycho_set_intr(sc, 15, psycho_bus_b,
        !           415:                            psycho_psychoreg_vaddr(sc, pciberr_int_map),
        !           416:                            psycho_psychoreg_vaddr(sc, pciberr_clr_int),
        !           417:                            "bus_b");
        !           418:                        psycho_set_intr(sc, 1, psycho_wakeup,
        !           419:                            psycho_psychoreg_vaddr(sc, pwrmgt_int_map),
        !           420:                            psycho_psychoreg_vaddr(sc, pwrmgt_clr_int),
        !           421:                            "wakeup");
        !           422:                }
        !           423:
        !           424:                /*
        !           425:                 * Apparently a number of machines with psycho and psycho+
        !           426:                 * controllers have interrupt latency issues.  We'll try
        !           427:                 * setting the interrupt retry timeout to 0xff which gives us
        !           428:                 * a retry of 3-6 usec (which is what sysio is set to) for the
        !           429:                 * moment, which seems to help alleviate this problem.
        !           430:                 */
        !           431:                timeo = psycho_psychoreg_read(sc, intr_retry_timer);
        !           432:                if (timeo > 0xfff) {
        !           433: #ifdef DEBUG
        !           434:                        printf("decreasing interrupt retry timeout "
        !           435:                            "from %lx to 0xff\n", (long)timeo);
        !           436: #endif
        !           437:                        psycho_psychoreg_write(sc, intr_retry_timer, 0xff);
        !           438:                }
        !           439:
        !           440:                /*
        !           441:                 * Setup IOMMU and PCI configuration if we're the first
        !           442:                 * of a pair of psycho's to arrive here.
        !           443:                 *
        !           444:                 * We should calculate a TSB size based on the amount of RAM,
        !           445:                 * number of bus controllers, and number and type of child
        !           446:                 * devices.
        !           447:                 *
        !           448:                 * For the moment, 32KB should be more than enough.
        !           449:                 */
        !           450:                sc->sc_is = malloc(sizeof(struct iommu_state),
        !           451:                        M_DEVBUF, M_NOWAIT);
        !           452:                if (sc->sc_is == NULL)
        !           453:                        panic("psycho_attach: malloc iommu_state");
        !           454:
        !           455:                memset(sc->sc_is, 0, sizeof *sc->sc_is);
        !           456:
        !           457:                if (getproplen(sc->sc_node, "no-streaming-cache") < 0) {
        !           458:                        struct strbuf_ctl *sb = &pp->pp_sb;
        !           459:                        vaddr_t va = (vaddr_t)&pp->pp_flush[0x40];
        !           460:
        !           461:                        /*
        !           462:                         * Initialize the strbuf_ctl.
        !           463:                         *
        !           464:                         * The flush sync buffer must be 64-byte aligned.
        !           465:                         */
        !           466:
        !           467:                        sb->sb_flush = (void *)(va & ~0x3f);
        !           468:
        !           469:                        sb->sb_bustag = sc->sc_bustag;
        !           470:                        if (bus_space_subregion(sc->sc_bustag, sc->sc_pcictl,
        !           471:                            offsetof(struct pci_ctl, pci_strbuf),
        !           472:                            sizeof(struct iommu_strbuf),
        !           473:                            &sb->sb_sb)) {
        !           474:                                printf("STC0 subregion failed\n");
        !           475:                                sb->sb_flush = 0;
        !           476:                        }
        !           477:                }
        !           478:
        !           479:                /* Point out iommu at the strbuf_ctl. */
        !           480:                sc->sc_is->is_sb[0] = &pp->pp_sb;
        !           481:
        !           482:                printf("%s: ", sc->sc_dev.dv_xname);
        !           483:                psycho_iommu_init(sc, 2);
        !           484:
        !           485:                sc->sc_configtag = psycho_alloc_config_tag(sc->sc_psycho_this);
        !           486:                if (bus_space_map(sc->sc_configtag,
        !           487:                    sc->sc_basepaddr, 0x01000000, 0, &sc->sc_configaddr))
        !           488:                        panic("could not map psycho PCI configuration space");
        !           489:        } else {
        !           490:                /* Just copy IOMMU state, config tag and address */
        !           491:                sc->sc_is = osc->sc_is;
        !           492:                sc->sc_configtag = osc->sc_configtag;
        !           493:                sc->sc_configaddr = osc->sc_configaddr;
        !           494:
        !           495:                if (getproplen(sc->sc_node, "no-streaming-cache") < 0) {
        !           496:                        struct strbuf_ctl *sb = &pp->pp_sb;
        !           497:                        vaddr_t va = (vaddr_t)&pp->pp_flush[0x40];
        !           498:
        !           499:                        /*
        !           500:                         * Initialize the strbuf_ctl.
        !           501:                         *
        !           502:                         * The flush sync buffer must be 64-byte aligned.
        !           503:                         */
        !           504:
        !           505:                        sb->sb_flush = (void *)(va & ~0x3f);
        !           506:
        !           507:                        sb->sb_bustag = sc->sc_bustag;
        !           508:                        if (bus_space_subregion(sc->sc_bustag, sc->sc_pcictl,
        !           509:                            offsetof(struct pci_ctl, pci_strbuf),
        !           510:                            sizeof(struct iommu_strbuf),
        !           511:                            &sb->sb_sb)) {
        !           512:                                printf("STC1 subregion failed\n");
        !           513:                                sb->sb_flush = 0;
        !           514:                        }
        !           515:
        !           516:                        /* Point out iommu at the strbuf_ctl. */
        !           517:                        sc->sc_is->is_sb[1] = sb;
        !           518:                }
        !           519:
        !           520:                /* Point out iommu at the strbuf_ctl. */
        !           521:                sc->sc_is->is_sb[1] = &pp->pp_sb;
        !           522:
        !           523:                printf("%s: ", sc->sc_dev.dv_xname);
        !           524:                printf("dvma map %x-%x, ", sc->sc_is->is_dvmabase,
        !           525:                    sc->sc_is->is_dvmaend);
        !           526:                printf("iotdb %llx-%llx",
        !           527:                    (unsigned long long)sc->sc_is->is_ptsb,
        !           528:                    (unsigned long long)(sc->sc_is->is_ptsb +
        !           529:                    (PAGE_SIZE << sc->sc_is->is_tsbsize)));
        !           530:                iommu_reset(sc->sc_is);
        !           531:                printf("\n");
        !           532:        }
        !           533:
        !           534:        /*
        !           535:         * attach the pci.. note we pass PCI A tags, etc., for the sabre here.
        !           536:         */
        !           537:        pba.pba_busname = "pci";
        !           538: #if 0
        !           539:        pba.pba_flags = sc->sc_psycho_this->pp_flags;
        !           540: #endif
        !           541:        pba.pba_dmat = sc->sc_psycho_this->pp_dmat;
        !           542:        pba.pba_iot = sc->sc_psycho_this->pp_iot;
        !           543:        pba.pba_memt = sc->sc_psycho_this->pp_memt;
        !           544:        pba.pba_pc->bustag = sc->sc_configtag;
        !           545:        pba.pba_pc->bushandle = sc->sc_configaddr;
        !           546:        pba.pba_pc->intr_map = psycho_intr_map;
        !           547:
        !           548:        if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
        !           549:                psycho_identify_pbm(sc, pp, &pba);
        !           550:        else
        !           551:                pp->pp_id = PSYCHO_PBM_UNKNOWN;
        !           552:
        !           553:        config_found(self, &pba, psycho_print);
        !           554: }
        !           555:
        !           556: void
        !           557: psycho_identify_pbm(struct psycho_softc *sc, struct psycho_pbm *pp,
        !           558:     struct pcibus_attach_args *pa)
        !           559: {
        !           560:        vaddr_t pci_va = (vaddr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_pcictl);
        !           561:        paddr_t pci_pa;
        !           562:
        !           563:        if (pmap_extract(pmap_kernel(), pci_va, &pci_pa) == 0)
        !           564:            pp->pp_id = PSYCHO_PBM_UNKNOWN;
        !           565:        else switch(pci_pa & 0xffff) {
        !           566:                case 0x2000:
        !           567:                        pp->pp_id = PSYCHO_PBM_A;
        !           568:                        break;
        !           569:                case 0x4000:
        !           570:                        pp->pp_id = PSYCHO_PBM_B;
        !           571:                        break;
        !           572:                default:
        !           573:                        pp->pp_id = PSYCHO_PBM_UNKNOWN;
        !           574:                        break;
        !           575:        }
        !           576: }
        !           577:
        !           578: void
        !           579: psycho_map_psycho(struct psycho_softc* sc, int do_map, bus_addr_t reg_addr,
        !           580:     bus_size_t reg_size, bus_addr_t pci_addr, bus_size_t pci_size)
        !           581: {
        !           582:        if (do_map) {
        !           583:                if (bus_space_map(sc->sc_bustag,
        !           584:                    reg_addr, reg_size, 0, &sc->sc_regsh))
        !           585:                        panic("psycho_attach: cannot map regs");
        !           586:
        !           587:                if (pci_addr >= reg_addr &&
        !           588:                    pci_addr + pci_size <= reg_addr + reg_size) {
        !           589:                        if (bus_space_subregion(sc->sc_bustag, sc->sc_regsh,
        !           590:                            pci_addr - reg_addr, pci_size, &sc->sc_pcictl))
        !           591:                                panic("psycho_map_psycho: map ctl");
        !           592:                }
        !           593:                else if (bus_space_map(sc->sc_bustag, pci_addr, pci_size,
        !           594:                    0, &sc->sc_pcictl))
        !           595:                        panic("psycho_map_psycho: cannot map pci");
        !           596:        } else {
        !           597:                if (bus_space_map(sc->sc_bustag, reg_addr, reg_size,
        !           598:                    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_regsh))
        !           599:                        panic("psycho_map_psycho: cannot map ctl");
        !           600:                if (bus_space_map(sc->sc_bustag, pci_addr, pci_size,
        !           601:                    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_pcictl))
        !           602:                        panic("psycho_map_psycho: cannot map pci");
        !           603:        }
        !           604: }
        !           605:
        !           606: int
        !           607: psycho_print(void *aux, const char *p)
        !           608: {
        !           609:        if (p == NULL)
        !           610:                return (UNCONF);
        !           611:        return (QUIET);
        !           612: }
        !           613:
        !           614: void
        !           615: psycho_set_intr(struct psycho_softc *sc, int ipl, void *handler,
        !           616:     u_int64_t *mapper, u_int64_t *clearer, const char *suffix)
        !           617: {
        !           618:        struct intrhand *ih;
        !           619:
        !           620:        ih = (struct intrhand *)malloc(sizeof(struct intrhand),
        !           621:            M_DEVBUF, M_NOWAIT);
        !           622:        if (ih == NULL)
        !           623:                panic("couldn't malloc intrhand");
        !           624:        memset(ih, 0, sizeof(struct intrhand));
        !           625:        ih->ih_arg = sc;
        !           626:        ih->ih_map = mapper;
        !           627:        ih->ih_clr = clearer;
        !           628:        ih->ih_fun = handler;
        !           629:        ih->ih_pil = (1 << ipl);
        !           630:        ih->ih_number = INTVEC(*(ih->ih_map));
        !           631:        snprintf(ih->ih_name, sizeof(ih->ih_name),
        !           632:            "%s:%s", sc->sc_dev.dv_xname, suffix);
        !           633:
        !           634:        DPRINTF(PDB_INTR, (
        !           635:            "\ninstalling handler %p arg %p for %s with number %x pil %u",
        !           636:            ih->ih_fun, ih->ih_arg, sc->sc_dev.dv_xname, ih->ih_number,
        !           637:            ih->ih_pil));
        !           638:
        !           639:        intr_establish(ipl, ih);
        !           640:        *(ih->ih_map) |= INTMAP_V;
        !           641: }
        !           642:
        !           643: /*
        !           644:  * PCI bus support
        !           645:  */
        !           646:
        !           647: /*
        !           648:  * allocate a PCI chipset tag and set its cookie.
        !           649:  */
        !           650: pci_chipset_tag_t
        !           651: psycho_alloc_chipset(struct psycho_pbm *pp, int node, pci_chipset_tag_t pc)
        !           652: {
        !           653:        pci_chipset_tag_t npc;
        !           654:
        !           655:        npc = malloc(sizeof *npc, M_DEVBUF, M_NOWAIT);
        !           656:        if (npc == NULL)
        !           657:                panic("could not allocate pci_chipset_tag_t");
        !           658:        memcpy(npc, pc, sizeof *pc);
        !           659:        npc->cookie = pp;
        !           660:        npc->rootnode = node;
        !           661:
        !           662:        return (npc);
        !           663: }
        !           664:
        !           665: /*
        !           666:  * grovel the OBP for various psycho properties
        !           667:  */
        !           668: void
        !           669: psycho_get_bus_range(node, brp)
        !           670:        int node;
        !           671:        int *brp;
        !           672: {
        !           673:        int n, error;
        !           674:
        !           675:        error = getprop(node, "bus-range", sizeof(*brp), &n, (void **)&brp);
        !           676:        if (error)
        !           677:                panic("could not get psycho bus-range, error %d", error);
        !           678:        if (n != 2)
        !           679:                panic("broken psycho bus-range");
        !           680:        DPRINTF(PDB_PROM,
        !           681:            ("psycho debug: got `bus-range' for node %08x: %u - %u\n",
        !           682:            node, brp[0], brp[1]));
        !           683: }
        !           684:
        !           685: void
        !           686: psycho_get_ranges(int node, struct psycho_ranges **rp, int *np)
        !           687: {
        !           688:
        !           689:        if (getprop(node, "ranges", sizeof(**rp), np, (void **)rp))
        !           690:                panic("could not get psycho ranges");
        !           691:        DPRINTF(PDB_PROM,
        !           692:            ("psycho debug: got `ranges' for node %08x: %d entries\n",
        !           693:            node, *np));
        !           694: }
        !           695:
        !           696: /*
        !           697:  * Interrupt handlers.
        !           698:  */
        !           699:
        !           700: int
        !           701: psycho_ue(void *arg)
        !           702: {
        !           703:        struct psycho_softc *sc = arg;
        !           704:        unsigned long long afsr = psycho_psychoreg_read(sc, psy_ue_afsr);
        !           705:        unsigned long long afar = psycho_psychoreg_read(sc, psy_ue_afar);
        !           706:
        !           707:        /*
        !           708:         * It's uncorrectable.  Dump the regs and panic.
        !           709:         */
        !           710:        panic("%s: uncorrectable DMA error AFAR %llx (pa=%lx tte=%llx/%llx) "
        !           711:            "AFSR %llx", sc->sc_dev.dv_xname, afar,
        !           712:            iommu_extract(sc->sc_is, (vaddr_t)afar),
        !           713:            iommu_lookup_tte(sc->sc_is, (vaddr_t)afar),
        !           714:            iommu_fetch_tte(sc->sc_is, (paddr_t)afar),
        !           715:            afsr);
        !           716:        return (1);
        !           717: }
        !           718:
        !           719: int
        !           720: psycho_ce(void *arg)
        !           721: {
        !           722:        struct psycho_softc *sc = arg;
        !           723:
        !           724:        /*
        !           725:         * It's correctable.  Dump the regs and continue.
        !           726:         */
        !           727:
        !           728:        printf("%s: correctable DMA error AFAR %llx AFSR %llx\n",
        !           729:            sc->sc_dev.dv_xname,
        !           730:            (long long)psycho_psychoreg_read(sc, psy_ce_afar),
        !           731:            (long long)psycho_psychoreg_read(sc, psy_ce_afsr));
        !           732:        return (1);
        !           733: }
        !           734:
        !           735: int
        !           736: psycho_bus_error(struct psycho_softc *sc, int bus)
        !           737: {
        !           738:        u_int64_t afsr, afar, bits;
        !           739:
        !           740:        afar = psycho_psychoreg_read(sc, psy_pcictl[bus].pci_afar);
        !           741:        afsr = psycho_psychoreg_read(sc, psy_pcictl[bus].pci_afsr);
        !           742:
        !           743:        bits = afsr & (PSY_PCIAFSR_PMA | PSY_PCIAFSR_PTA | PSY_PCIAFSR_PTRY |
        !           744:            PSY_PCIAFSR_PPERR | PSY_PCIAFSR_SMA | PSY_PCIAFSR_STA |
        !           745:            PSY_PCIAFSR_STRY | PSY_PCIAFSR_SPERR);
        !           746:
        !           747:        if (bits == 0)
        !           748:                return (0);
        !           749:
        !           750:        /*
        !           751:         * It's uncorrectable.  Dump the regs and panic.
        !           752:         */
        !           753:        printf("%s: PCI bus %c error AFAR %llx (pa=%llx) AFSR %llx\n",
        !           754:            sc->sc_dev.dv_xname, 'A' + bus, (long long)afar,
        !           755:            (long long)iommu_extract(sc->sc_is, (vaddr_t)afar),
        !           756:            (long long)afsr);
        !           757:
        !           758:        psycho_psychoreg_write(sc, psy_pcictl[bus].pci_afsr, bits);
        !           759:        return (1);
        !           760: }
        !           761:
        !           762: int
        !           763: psycho_bus_a(void *arg)
        !           764: {
        !           765:        struct psycho_softc *sc = arg;
        !           766:
        !           767:        return (psycho_bus_error(sc, 0));
        !           768: }
        !           769:
        !           770: int
        !           771: psycho_bus_b(void *arg)
        !           772: {
        !           773:        struct psycho_softc *sc = arg;
        !           774:
        !           775:        return (psycho_bus_error(sc, 1));
        !           776: }
        !           777:
        !           778: int
        !           779: psycho_powerfail(void *arg)
        !           780: {
        !           781:        /*
        !           782:         * We lost power.  Try to shut down NOW.
        !           783:         */
        !           784:        printf("Power Failure Detected: Shutting down NOW.\n");
        !           785:        boot(RB_POWERDOWN|RB_HALT);
        !           786:        return (1);
        !           787: }
        !           788:
        !           789: int
        !           790: psycho_wakeup(void *arg)
        !           791: {
        !           792:        struct psycho_softc *sc = arg;
        !           793:
        !           794:        /*
        !           795:         * Gee, we don't really have a framework to deal with this
        !           796:         * properly.
        !           797:         */
        !           798:        printf("%s: power management wakeup\n", sc->sc_dev.dv_xname);
        !           799:        return (1);
        !           800: }
        !           801:
        !           802: /*
        !           803:  * initialise the IOMMU..
        !           804:  */
        !           805: void
        !           806: psycho_iommu_init(struct psycho_softc *sc, int tsbsize)
        !           807: {
        !           808:        struct iommu_state *is = sc->sc_is;
        !           809:        int *vdma = NULL, nitem;
        !           810:        u_int32_t iobase = -1;
        !           811:        char *name;
        !           812:
        !           813:        /* punch in our copies */
        !           814:        is->is_bustag = sc->sc_bustag;
        !           815:        bus_space_subregion(sc->sc_bustag, sc->sc_regsh,
        !           816:            offsetof(struct psychoreg, psy_iommu), sizeof(struct iommureg),
        !           817:            &is->is_iommu);
        !           818:
        !           819:        /*
        !           820:         * Separate the men from the boys.  If it has a `virtual-dma'
        !           821:         * property, use it.
        !           822:         */
        !           823:        if (!getprop(sc->sc_node, "virtual-dma", sizeof(vdma), &nitem,
        !           824:            (void **)&vdma)) {
        !           825:                /* Damn.  Gotta use these values. */
        !           826:                iobase = vdma[0];
        !           827: #define        TSBCASE(x)      case 1 << ((x) + 23): tsbsize = (x); break
        !           828:                switch (vdma[1]) {
        !           829:                        TSBCASE(1); TSBCASE(2); TSBCASE(3);
        !           830:                        TSBCASE(4); TSBCASE(5); TSBCASE(6);
        !           831:                default:
        !           832:                        printf("bogus tsb size %x, using 7\n", vdma[1]);
        !           833:                        TSBCASE(7);
        !           834:                }
        !           835: #undef TSBCASE
        !           836:                DPRINTF(PDB_CONF, ("psycho_iommu_init: iobase=0x%x\n", iobase));
        !           837:                free(vdma, M_DEVBUF);
        !           838:        } else {
        !           839:                DPRINTF(PDB_CONF, ("psycho_iommu_init: getprop failed, "
        !           840:                    "iobase=0x%x, tsbsize=%d\n", iobase, tsbsize));
        !           841:        }
        !           842:
        !           843:        /* give us a nice name.. */
        !           844:        name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
        !           845:        if (name == NULL)
        !           846:                panic("couldn't malloc iommu name");
        !           847:        snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname);
        !           848:
        !           849:        iommu_init(name, is, tsbsize, iobase);
        !           850: }
        !           851:
        !           852: /*
        !           853:  * below here is bus space and bus dma support
        !           854:  */
        !           855:
        !           856: bus_space_tag_t
        !           857: psycho_alloc_mem_tag(struct psycho_pbm *pp)
        !           858: {
        !           859:        return (psycho_alloc_bus_tag(pp, "mem",
        !           860:            0x02,       /* 32-bit mem space (where's the #define???) */
        !           861:            ASI_PRIMARY, ASI_PRIMARY_LITTLE));
        !           862: }
        !           863:
        !           864: bus_space_tag_t
        !           865: psycho_alloc_io_tag(struct psycho_pbm *pp)
        !           866: {
        !           867:        return (psycho_alloc_bus_tag(pp, "io",
        !           868:            0x01,       /* IO space (where's the #define???) */
        !           869:            ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
        !           870: }
        !           871:
        !           872: bus_space_tag_t
        !           873: psycho_alloc_config_tag(struct psycho_pbm *pp)
        !           874: {
        !           875:        return (psycho_alloc_bus_tag(pp, "cfg",
        !           876:            0x00,       /* Config space (where's the #define???) */
        !           877:            ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
        !           878: }
        !           879:
        !           880: bus_space_tag_t
        !           881: psycho_alloc_bus_tag(struct psycho_pbm *pp,
        !           882:     const char *name, int ss, int asi, int sasi)
        !           883: {
        !           884:        struct psycho_softc *sc = pp->pp_sc;
        !           885:        struct sparc_bus_space_tag *bt;
        !           886:
        !           887:        bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
        !           888:        if (bt == NULL)
        !           889:                panic("could not allocate psycho bus tag");
        !           890:
        !           891:        bzero(bt, sizeof *bt);
        !           892:
        !           893:        snprintf(bt->name, sizeof(bt->name), "%s-pbm_%s(%d-%2.2x)",
        !           894:            sc->sc_dev.dv_xname, name, ss, asi);
        !           895:
        !           896:        bt->cookie = pp;
        !           897:        bt->parent = sc->sc_bustag;
        !           898:        bt->default_type = ss;
        !           899:        bt->asi = asi;
        !           900:        bt->sasi = sasi;
        !           901:        bt->sparc_bus_map = psycho_bus_map;
        !           902:        bt->sparc_bus_mmap = psycho_bus_mmap;
        !           903:        bt->sparc_bus_addr = psycho_bus_addr;
        !           904:        bt->sparc_intr_establish = psycho_intr_establish;
        !           905:
        !           906:        return (bt);
        !           907: }
        !           908:
        !           909: bus_dma_tag_t
        !           910: psycho_alloc_dma_tag(struct psycho_pbm *pp)
        !           911: {
        !           912:        struct psycho_softc *sc = pp->pp_sc;
        !           913:        bus_dma_tag_t dt, pdt = sc->sc_dmatag;
        !           914:
        !           915:        dt = (bus_dma_tag_t)malloc(sizeof(struct sparc_bus_dma_tag),
        !           916:            M_DEVBUF, M_NOWAIT);
        !           917:        if (dt == NULL)
        !           918:                panic("could not allocate psycho dma tag");
        !           919:
        !           920:        bzero(dt, sizeof *dt);
        !           921:        dt->_cookie = pp;
        !           922:        dt->_parent = pdt;
        !           923:        dt->_dmamap_create      = psycho_dmamap_create;
        !           924:        dt->_dmamap_destroy     = iommu_dvmamap_destroy;
        !           925:        dt->_dmamap_load        = iommu_dvmamap_load;
        !           926:        dt->_dmamap_load_raw    = iommu_dvmamap_load_raw;
        !           927:        dt->_dmamap_unload      = iommu_dvmamap_unload;
        !           928:        if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
        !           929:                dt->_dmamap_sync = iommu_dvmamap_sync;
        !           930:        else
        !           931:                dt->_dmamap_sync = psycho_sabre_dvmamap_sync;
        !           932:        dt->_dmamem_alloc       = iommu_dvmamem_alloc;
        !           933:        dt->_dmamem_free        = iommu_dvmamem_free;
        !           934:        dt->_dmamem_map         = iommu_dvmamem_map;
        !           935:        dt->_dmamem_unmap       = iommu_dvmamem_unmap;
        !           936:
        !           937:        return (dt);
        !           938: }
        !           939:
        !           940: /*
        !           941:  * bus space support.  <sparc64/dev/psychoreg.h> has a discussion about
        !           942:  * PCI physical addresses.
        !           943:  */
        !           944:
        !           945: int
        !           946: psycho_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
        !           947:     bus_size_t size, int flags, bus_space_handle_t *hp)
        !           948: {
        !           949:        struct psycho_pbm *pp = t->cookie;
        !           950:        int i, ss;
        !           951:
        !           952:        DPRINTF(PDB_BUSMAP, ("\npsycho_bus_map: type %d off %qx sz %qx "
        !           953:            "flags %d", t->default_type, (unsigned long long)offset,
        !           954:            (unsigned long long)size, flags));
        !           955:
        !           956:        ss = t->default_type;
        !           957:        DPRINTF(PDB_BUSMAP, (" cspace %d", ss));
        !           958:
        !           959:        if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
        !           960:                printf("\npsycho_bus_map: invalid parent");
        !           961:                return (EINVAL);
        !           962:        }
        !           963:
        !           964:        t = t->parent;
        !           965:
        !           966:        if (flags & BUS_SPACE_MAP_PROMADDRESS) {
        !           967:                return ((*t->sparc_bus_map)
        !           968:                    (t, t0, offset, size, flags, hp));
        !           969:        }
        !           970:
        !           971:        for (i = 0; i < pp->pp_nrange; i++) {
        !           972:                bus_addr_t paddr;
        !           973:
        !           974:                if (((pp->pp_range[i].cspace >> 24) & 0x03) != ss)
        !           975:                        continue;
        !           976:
        !           977:                paddr = pp->pp_range[i].phys_lo + offset;
        !           978:                paddr |= ((bus_addr_t)pp->pp_range[i].phys_hi << 32);
        !           979:                DPRINTF(PDB_BUSMAP,
        !           980:                    ("\n_psycho_bus_map: mapping paddr space %lx offset %lx "
        !           981:                        "paddr %qx",
        !           982:                    (long)ss, (long)offset,
        !           983:                    (unsigned long long)paddr));
        !           984:                return ((*t->sparc_bus_map)(t, t0, paddr, size, flags, hp));
        !           985:        }
        !           986:        DPRINTF(PDB_BUSMAP, (" FAILED\n"));
        !           987:        return (EINVAL);
        !           988: }
        !           989:
        !           990: paddr_t
        !           991: psycho_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
        !           992:     off_t off, int prot, int flags)
        !           993: {
        !           994:        bus_addr_t offset = paddr;
        !           995:        struct psycho_pbm *pp = t->cookie;
        !           996:        int i, ss;
        !           997:
        !           998:        ss = t->default_type;
        !           999:
        !          1000:        DPRINTF(PDB_BUSMAP, ("\n_psycho_bus_mmap: prot %d flags %d pa %qx",
        !          1001:            prot, flags, (unsigned long long)paddr));
        !          1002:
        !          1003:        if (t->parent == 0 || t->parent->sparc_bus_mmap == 0) {
        !          1004:                printf("\npsycho_bus_mmap: invalid parent");
        !          1005:                return (-1);
        !          1006:        }
        !          1007:
        !          1008:        t = t->parent;
        !          1009:
        !          1010:        for (i = 0; i < pp->pp_nrange; i++) {
        !          1011:                bus_addr_t paddr;
        !          1012:
        !          1013:                if (((pp->pp_range[i].cspace >> 24) & 0x03) != ss)
        !          1014:                        continue;
        !          1015:
        !          1016:                paddr = pp->pp_range[i].phys_lo + offset;
        !          1017:                paddr |= ((bus_addr_t)pp->pp_range[i].phys_hi << 32);
        !          1018:                DPRINTF(PDB_BUSMAP, ("\npsycho_bus_mmap: mapping paddr "
        !          1019:                    "space %lx offset %lx paddr %qx",
        !          1020:                    (long)ss, (long)offset,
        !          1021:                    (unsigned long long)paddr));
        !          1022:                return ((*t->sparc_bus_mmap)(t, t0, paddr, off, prot, flags));
        !          1023:        }
        !          1024:
        !          1025:        return (-1);
        !          1026: }
        !          1027:
        !          1028: bus_addr_t
        !          1029: psycho_bus_addr(bus_space_tag_t t, bus_space_tag_t t0, bus_space_handle_t h)
        !          1030: {
        !          1031:        struct psycho_pbm *pp = t->cookie;
        !          1032:        bus_addr_t addr;
        !          1033:        int i, ss;
        !          1034:
        !          1035:        ss = t->default_type;
        !          1036:
        !          1037:        if (t->parent == 0 || t->parent->sparc_bus_addr == 0) {
        !          1038:                printf("\npsycho_bus_addr: invalid parent");
        !          1039:                return (-1);
        !          1040:        }
        !          1041:
        !          1042:        t = t->parent;
        !          1043:
        !          1044:        addr = ((*t->sparc_bus_addr)(t, t0, h));
        !          1045:        if (addr == -1)
        !          1046:                return (-1);
        !          1047:
        !          1048:        for (i = 0; i < pp->pp_nrange; i++) {
        !          1049:                if (((pp->pp_range[i].cspace >> 24) & 0x03) != ss)
        !          1050:                        continue;
        !          1051:
        !          1052:                return (BUS_ADDR_PADDR(addr) - pp->pp_range[i].phys_lo);
        !          1053:        }
        !          1054:
        !          1055:        return (-1);
        !          1056: }
        !          1057:
        !          1058: /*
        !          1059:  * Bus-specific interrupt mapping
        !          1060:  */
        !          1061: int
        !          1062: psycho_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
        !          1063: {
        !          1064:        struct psycho_pbm *pp = pa->pa_pc->cookie;
        !          1065:        struct psycho_softc *sc = pp->pp_sc;
        !          1066:        u_int dev;
        !          1067:
        !          1068:        if (*ihp != (pci_intr_handle_t)-1) {
        !          1069:                *ihp |= sc->sc_ign;
        !          1070:                return (0);
        !          1071:        }
        !          1072:
        !          1073:        /*
        !          1074:         * We didn't find a PROM mapping for this interrupt.  Try to
        !          1075:         * construct one ourselves based on the swizzled interrupt pin
        !          1076:         * and the interrupt mapping for PCI slots documented in the
        !          1077:         * UltraSPARC-IIi User's Manual.
        !          1078:         */
        !          1079:
        !          1080:        if (pa->pa_intrpin == 0)
        !          1081:                return (-1);
        !          1082:
        !          1083:        /*
        !          1084:         * This deserves some documentation.  Should anyone
        !          1085:         * have anything official looking, please speak up.
        !          1086:         */
        !          1087:        if (sc->sc_mode == PSYCHO_MODE_PSYCHO &&
        !          1088:            pp->pp_id == PSYCHO_PBM_B)
        !          1089:                dev = PCITAG_DEV(pa->pa_intrtag) - 2;
        !          1090:        else
        !          1091:                dev = PCITAG_DEV(pa->pa_intrtag) - 1;
        !          1092:
        !          1093:        *ihp = (pa->pa_intrpin - 1) & INTMAP_PCIINT;
        !          1094:        *ihp |= ((pp->pp_id == PSYCHO_PBM_B) ? INTMAP_PCIBUS : 0);
        !          1095:        *ihp |= (dev << 2) & INTMAP_PCISLOT;
        !          1096:        *ihp |= sc->sc_ign;
        !          1097:
        !          1098:        return (0);
        !          1099: }
        !          1100:
        !          1101: /*
        !          1102:  * install an interrupt handler for a PCI device
        !          1103:  */
        !          1104: void *
        !          1105: psycho_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
        !          1106:     int level, int flags, int (*handler)(void *), void *arg, const char *what)
        !          1107: {
        !          1108:        struct psycho_pbm *pp = t->cookie;
        !          1109:        struct psycho_softc *sc = pp->pp_sc;
        !          1110:        struct intrhand *ih;
        !          1111:        volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
        !          1112:        int64_t intrmap = 0;
        !          1113:        int ino;
        !          1114:        long vec = INTVEC(ihandle);
        !          1115:
        !          1116:        /*
        !          1117:         * Hunt through all the interrupt mapping regs to look for our
        !          1118:         * interrupt vector.
        !          1119:         *
        !          1120:         * XXX We only compare INOs rather than IGNs since the firmware may
        !          1121:         * not provide the IGN and the IGN is constant for all device on that
        !          1122:         * PCI controller.  This could cause problems for the FFB/external
        !          1123:         * interrupt which has a full vector that can be set arbitrarily.
        !          1124:         */
        !          1125:
        !          1126:        DPRINTF(PDB_INTR,
        !          1127:            ("\npsycho_intr_establish: ihandle %x vec %lx", ihandle, vec));
        !          1128:        ino = INTINO(vec);
        !          1129:        DPRINTF(PDB_INTR, (" ino %x", ino));
        !          1130:
        !          1131:        /* If the device didn't ask for an IPL, use the one encoded. */
        !          1132:        if (level == IPL_NONE)
        !          1133:                level = INTLEV(vec);
        !          1134:        /* If it still has no level, print a warning and assign IPL 2 */
        !          1135:        if (level == IPL_NONE) {
        !          1136:                printf("ERROR: no IPL, setting IPL 2.\n");
        !          1137:                level = 2;
        !          1138:        }
        !          1139:
        !          1140:        if (flags & BUS_INTR_ESTABLISH_SOFTINTR)
        !          1141:                goto found;
        !          1142:
        !          1143:        DPRINTF(PDB_INTR,
        !          1144:            ("\npsycho: intr %lx: %p\nHunting for IRQ...\n",
        !          1145:            (long)ino, intrlev[ino]));
        !          1146:
        !          1147:        /*
        !          1148:         * First look for PCI interrupts, otherwise the PCI A slot 0
        !          1149:         * INTA# interrupt might match an unused non-PCI (obio)
        !          1150:         * interrupt.
        !          1151:         */
        !          1152:
        !          1153:        for (intrmapptr = psycho_psychoreg_vaddr(sc, pcia_slot0_int),
        !          1154:            intrclrptr = psycho_psychoreg_vaddr(sc, pcia0_clr_int[0]);
        !          1155:            intrmapptr <= (volatile u_int64_t *)
        !          1156:                psycho_psychoreg_vaddr(sc, pcib_slot3_int);
        !          1157:            intrmapptr++, intrclrptr += 4) {
        !          1158:                /* Skip PCI-A Slot 2 and PCI-A Slot 3 on psycho's */
        !          1159:                if (sc->sc_mode == PSYCHO_MODE_PSYCHO &&
        !          1160:                    (intrmapptr ==
        !          1161:                        psycho_psychoreg_vaddr(sc, pcia_slot2_int) ||
        !          1162:                    intrmapptr ==
        !          1163:                        psycho_psychoreg_vaddr(sc, pcia_slot3_int)))
        !          1164:                        continue;
        !          1165:
        !          1166:                if (((*intrmapptr ^ vec) & 0x3c) == 0) {
        !          1167:                        intrclrptr += vec & 0x3;
        !          1168:                        goto found;
        !          1169:                }
        !          1170:        }
        !          1171:
        !          1172:        /* Now hunt through obio.  */
        !          1173:        for (intrmapptr = psycho_psychoreg_vaddr(sc, scsi_int_map),
        !          1174:            intrclrptr = psycho_psychoreg_vaddr(sc, scsi_clr_int);
        !          1175:            intrmapptr < (volatile u_int64_t *)
        !          1176:                psycho_psychoreg_vaddr(sc, ffb0_int_map);
        !          1177:            intrmapptr++, intrclrptr++) {
        !          1178:                if (INTINO(*intrmapptr) == ino)
        !          1179:                        goto found;
        !          1180:        }
        !          1181:
        !          1182:        printf("Cannot find interrupt vector %lx\n", vec);
        !          1183:        return (NULL);
        !          1184:
        !          1185: found:
        !          1186:        ih = bus_intr_allocate(t0, handler, arg, ino | sc->sc_ign, level,
        !          1187:            intrmapptr, intrclrptr, what);
        !          1188:        if (ih == NULL) {
        !          1189:                printf("Cannot allocate interrupt vector %lx\n", vec);
        !          1190:                return (NULL);
        !          1191:        }
        !          1192:
        !          1193:        DPRINTF(PDB_INTR, (
        !          1194:            "\ninstalling handler %p arg %p with number %x pil %u",
        !          1195:            ih->ih_fun, ih->ih_arg, ih->ih_number, ih->ih_pil));
        !          1196:
        !          1197:        intr_establish(ih->ih_pil, ih);
        !          1198:
        !          1199:        /*
        !          1200:         * Enable the interrupt now we have the handler installed.
        !          1201:         * Read the current value as we can't change it besides the
        !          1202:         * valid bit so so make sure only this bit is changed.
        !          1203:         *
        !          1204:         * XXXX --- we really should use bus_space for this.
        !          1205:         */
        !          1206:        if (intrmapptr) {
        !          1207:                intrmap = *intrmapptr;
        !          1208:                DPRINTF(PDB_INTR, ("; read intrmap = %016qx",
        !          1209:                        (unsigned long long)intrmap));
        !          1210:
        !          1211:                /* Enable the interrupt */
        !          1212:                intrmap |= INTMAP_V;
        !          1213:                DPRINTF(PDB_INTR, ("; addr of intrmapptr = %p", intrmapptr));
        !          1214:                DPRINTF(PDB_INTR, ("; writing intrmap = %016qx",
        !          1215:                        (unsigned long long)intrmap));
        !          1216:                *intrmapptr = intrmap;
        !          1217:                DPRINTF(PDB_INTR, ("; reread intrmap = %016qx",
        !          1218:                        (unsigned long long)(intrmap = *intrmapptr)));
        !          1219:        }
        !          1220:        return (ih);
        !          1221: }
        !          1222:
        !          1223: /*
        !          1224:  * hooks into the iommu dvma calls.
        !          1225:  */
        !          1226: int
        !          1227: psycho_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
        !          1228:     int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
        !          1229:     bus_dmamap_t *dmamp)
        !          1230: {
        !          1231:        struct psycho_pbm *pp = t->_cookie;
        !          1232:
        !          1233:        return (iommu_dvmamap_create(t, t0, &pp->pp_sb, size, nsegments,
        !          1234:            maxsegsz, boundary, flags, dmamp));
        !          1235: }
        !          1236:
        !          1237: void
        !          1238: psycho_sabre_dvmamap_sync(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
        !          1239:     bus_size_t offset, bus_size_t len, int ops)
        !          1240: {
        !          1241:        struct psycho_pbm *pp = t->_cookie;
        !          1242:        struct psycho_softc *sc = pp->pp_sc;
        !          1243:
        !          1244:        if (ops & BUS_DMASYNC_POSTREAD)
        !          1245:                psycho_psychoreg_read(sc, pci_dma_write_sync);
        !          1246:
        !          1247:        if (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE))
        !          1248:                membar(MemIssue);
        !          1249: }
        !          1250:

CVSweb