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

Annotation of sys/arch/sparc64/dev/pyro.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: pyro.c,v 1.7 2007/04/03 19:59:01 kettenis Exp $       */
                      2:
                      3: /*
                      4:  * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
                      5:  * Copyright (c) 2003 Henric Jungheim
                      6:  * Copyright (c) 2007 Mark Kettenis
                      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:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     20:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     21:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     22:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     23:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     24:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     26:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     27:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     28:  * POSSIBILITY OF SUCH DAMAGE.
                     29:  */
                     30:
                     31: #include <sys/param.h>
                     32: #include <sys/device.h>
                     33: #include <sys/errno.h>
                     34: #include <sys/malloc.h>
                     35: #include <sys/systm.h>
                     36:
                     37: #define _SPARC_BUS_DMA_PRIVATE
                     38: #include <machine/bus.h>
                     39: #include <machine/autoconf.h>
                     40:
                     41: #include <dev/pci/pcivar.h>
                     42: #include <dev/pci/pcireg.h>
                     43:
                     44: #include <sparc64/dev/iommureg.h>
                     45: #include <sparc64/dev/iommuvar.h>
                     46: #include <sparc64/dev/pyrovar.h>
                     47:
                     48: #ifdef DEBUG
                     49: #define PDB_PROM        0x01
                     50: #define PDB_BUSMAP      0x02
                     51: #define PDB_INTR        0x04
                     52: #define PDB_CONF        0x08
                     53: int pyro_debug = ~0;
                     54: #define DPRINTF(l, s)   do { if (pyro_debug & l) printf s; } while (0)
                     55: #else
                     56: #define DPRINTF(l, s)
                     57: #endif
                     58:
                     59: extern struct sparc_pci_chipset _sparc_pci_chipset;
                     60:
                     61: int pyro_match(struct device *, void *, void *);
                     62: void pyro_attach(struct device *, struct device *, void *);
                     63: void pyro_init(struct pyro_softc *, int);
                     64: void pyro_init_iommu(struct pyro_softc *, struct pyro_pbm *);
                     65: int pyro_print(void *, const char *);
                     66:
                     67: pci_chipset_tag_t pyro_alloc_chipset(struct pyro_pbm *, int,
                     68:     pci_chipset_tag_t);
                     69: bus_space_tag_t pyro_alloc_mem_tag(struct pyro_pbm *);
                     70: bus_space_tag_t pyro_alloc_io_tag(struct pyro_pbm *);
                     71: bus_space_tag_t pyro_alloc_config_tag(struct pyro_pbm *);
                     72: bus_space_tag_t _pyro_alloc_bus_tag(struct pyro_pbm *, const char *,
                     73:     int, int, int);
                     74: bus_dma_tag_t pyro_alloc_dma_tag(struct pyro_pbm *);
                     75:
                     76: int pyro_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
                     77: int _pyro_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
                     78:     bus_size_t, int, bus_space_handle_t *);
                     79: paddr_t _pyro_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t, off_t,
                     80:     int, int);
                     81: void *_pyro_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
                     82:     int (*)(void *), void *, const char *);
                     83:
                     84: int pyro_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int,
                     85:     bus_size_t, bus_size_t, int, bus_dmamap_t *);
                     86:
                     87: int
                     88: pyro_match(struct device *parent, void *match, void *aux)
                     89: {
                     90:        struct mainbus_attach_args *ma = aux;
                     91:        char *str;
                     92:
                     93:        if (strcmp(ma->ma_name, "pci") != 0)
                     94:                return (0);
                     95:
                     96:        str = getpropstring(ma->ma_node, "compatible");
                     97:        if (strcmp(str, "pciex108e,80f0") == 0)
                     98:                return (1);
                     99:
                    100:        return (0);
                    101: }
                    102:
                    103: void
                    104: pyro_attach(struct device *parent, struct device *self, void *aux)
                    105: {
                    106:        struct pyro_softc *sc = (struct pyro_softc *)self;
                    107:        struct mainbus_attach_args *ma = aux;
                    108:        int busa;
                    109:
                    110:        sc->sc_node = ma->ma_node;
                    111:        sc->sc_dmat = ma->ma_dmatag;
                    112:        sc->sc_bust = ma->ma_bustag;
                    113:        sc->sc_csr = ma->ma_reg[0].ur_paddr;
                    114:        sc->sc_xbc = ma->ma_reg[1].ur_paddr;
                    115:        sc->sc_ign = INTIGN(ma->ma_upaid << INTMAP_IGN_SHIFT);
                    116:
                    117:        if ((ma->ma_reg[0].ur_paddr & 0x00700000) == 0x00600000)
                    118:                busa = 1;
                    119:        else
                    120:                busa = 0;
                    121:
                    122:        if (bus_space_map(sc->sc_bust, sc->sc_csr,
                    123:            ma->ma_reg[0].ur_len, 0, &sc->sc_csrh)) {
                    124:                printf(": failed to map csr registers\n");
                    125:                return;
                    126:        }
                    127:
                    128:        if (bus_space_map(sc->sc_bust, sc->sc_xbc,
                    129:            ma->ma_reg[1].ur_len, 0, &sc->sc_xbch)) {
                    130:                printf(": failed to map xbc registers\n");
                    131:                return;
                    132:        }
                    133:
                    134:        pyro_init(sc, busa);
                    135: }
                    136:
                    137: void
                    138: pyro_init(struct pyro_softc *sc, int busa)
                    139: {
                    140:        struct pyro_pbm *pbm;
                    141:        struct pcibus_attach_args pba;
                    142:        int *busranges = NULL, nranges;
                    143:
                    144:        pbm = (struct pyro_pbm *)malloc(sizeof(*pbm), M_DEVBUF, M_NOWAIT);
                    145:        if (pbm == NULL)
                    146:                panic("pyro: can't alloc pyro pbm");
                    147:        bzero(pbm, sizeof(*pbm));
                    148:
                    149:        pbm->pp_sc = sc;
                    150:        pbm->pp_bus_a = busa;
                    151:
                    152:        if (getprop(sc->sc_node, "ranges", sizeof(struct pyro_range),
                    153:            &pbm->pp_nrange, (void **)&pbm->pp_range))
                    154:                panic("pyro: can't get ranges");
                    155:
                    156:        if (getprop(sc->sc_node, "bus-range", sizeof(int), &nranges,
                    157:            (void **)&busranges))
                    158:                panic("pyro: can't get bus-range");
                    159:
                    160:        printf(": \"%s\", rev %d, ign %x, bus %c %d to %d\n",
                    161:            sc->sc_oberon ? "Oberon" : "Fire",
                    162:            getpropint(sc->sc_node, "module-revision#", 0), sc->sc_ign,
                    163:            busa ? 'A' : 'B', busranges[0], busranges[1]);
                    164:
                    165:        printf("%s: ", sc->sc_dv.dv_xname);
                    166:        pyro_init_iommu(sc, pbm);
                    167:
                    168:        pbm->pp_memt = pyro_alloc_mem_tag(pbm);
                    169:        pbm->pp_iot = pyro_alloc_io_tag(pbm);
                    170:        pbm->pp_cfgt = pyro_alloc_config_tag(pbm);
                    171:        pbm->pp_dmat = pyro_alloc_dma_tag(pbm);
                    172:
                    173:        if (bus_space_map(pbm->pp_cfgt, 0, 0x10000000, 0, &pbm->pp_cfgh))
                    174:                panic("pyro: could not map config space");
                    175:
                    176:        pbm->pp_pc = pyro_alloc_chipset(pbm, sc->sc_node, &_sparc_pci_chipset);
                    177:
                    178:        pbm->pp_pc->bustag = pbm->pp_cfgt;
                    179:        pbm->pp_pc->bushandle = pbm->pp_cfgh;
                    180:
                    181:        pba.pba_busname = "pci";
                    182:        pba.pba_domain = pci_ndomains++;
                    183:        pba.pba_bus = busranges[0];
                    184:        pba.pba_bridgetag = NULL;
                    185:        pba.pba_pc = pbm->pp_pc;
                    186: #if 0
                    187:        pba.pba_flags = pbm->pp_flags;
                    188: #endif
                    189:        pba.pba_dmat = pbm->pp_dmat;
                    190:        pba.pba_memt = pbm->pp_memt;
                    191:        pba.pba_iot = pbm->pp_iot;
                    192:        pba.pba_pc->intr_map = pyro_intr_map;
                    193:
                    194:        free(busranges, M_DEVBUF);
                    195:
                    196:        config_found(&sc->sc_dv, &pba, pyro_print);
                    197: }
                    198:
                    199: void
                    200: pyro_init_iommu(struct pyro_softc *sc, struct pyro_pbm *pbm)
                    201: {
                    202:        struct iommu_state *is = &pbm->pp_is;
                    203:        int tsbsize = 7;
                    204:        u_int32_t iobase = -1;
                    205:        char *name;
                    206:
                    207:        is->is_bustag = sc->sc_bust;
                    208:
                    209:        if (bus_space_subregion(is->is_bustag, sc->sc_csrh,
                    210:            0x40000, 0x100, &is->is_iommu)) {
                    211:                panic("pyro: unable to create iommu handle");
                    212:        }
                    213:
                    214:        is->is_sb[0] = &pbm->pp_sb;
                    215:        is->is_sb[0]->sb_bustag = is->is_bustag;
                    216:
                    217:        name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
                    218:        if (name == NULL)
                    219:                panic("couldn't malloc iommu name");
                    220:        snprintf(name, 32, "%s dvma", sc->sc_dv.dv_xname);
                    221:
                    222:        iommu_init(name, is, tsbsize, iobase);
                    223: }
                    224:
                    225: int
                    226: pyro_print(void *aux, const char *p)
                    227: {
                    228:        if (p == NULL)
                    229:                return (UNCONF);
                    230:        return (QUIET);
                    231: }
                    232:
                    233: /*
                    234:  * Bus-specific interrupt mapping
                    235:  */
                    236: int
                    237: pyro_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
                    238: {
                    239:        struct pyro_pbm *pp = pa->pa_pc->cookie;
                    240:        struct pyro_softc *sc = pp->pp_sc;
                    241:        u_int dev;
                    242:
                    243:        if (*ihp != (pci_intr_handle_t)-1) {
                    244:                *ihp |= sc->sc_ign;
                    245:                return (0);
                    246:        }
                    247:
                    248:        /*
                    249:         * We didn't find a PROM mapping for this interrupt.  Try to
                    250:         * construct one ourselves based on the swizzled interrupt pin
                    251:         * and the interrupt mapping for PCI slots documented in the
                    252:         * UltraSPARC-IIi User's Manual.
                    253:         */
                    254:
                    255:        if (pa->pa_intrpin == 0)
                    256:                return (-1);
                    257:
                    258:        /*
                    259:         * This deserves some documentation.  Should anyone
                    260:         * have anything official looking, please speak up.
                    261:         */
                    262:        dev = pa->pa_device - 1;
                    263:
                    264:        *ihp = (pa->pa_intrpin - 1) & INTMAP_PCIINT;
                    265:        *ihp |= (dev << 2) & INTMAP_PCISLOT;
                    266:        *ihp |= sc->sc_ign;
                    267:
                    268:        return (0);
                    269: }
                    270:
                    271: bus_space_tag_t
                    272: pyro_alloc_mem_tag(struct pyro_pbm *pp)
                    273: {
                    274:        return (_pyro_alloc_bus_tag(pp, "mem",
                    275:            0x02,       /* 32-bit mem space (where's the #define???) */
                    276:            ASI_PRIMARY, ASI_PRIMARY_LITTLE));
                    277: }
                    278:
                    279: bus_space_tag_t
                    280: pyro_alloc_io_tag(struct pyro_pbm *pp)
                    281: {
                    282:        return (_pyro_alloc_bus_tag(pp, "io",
                    283:            0x01,       /* IO space (where's the #define???) */
                    284:            ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
                    285: }
                    286:
                    287: bus_space_tag_t
                    288: pyro_alloc_config_tag(struct pyro_pbm *pp)
                    289: {
                    290:        return (_pyro_alloc_bus_tag(pp, "cfg",
                    291:            0x00,       /* Config space (where's the #define???) */
                    292:            ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
                    293: }
                    294:
                    295: bus_space_tag_t
                    296: _pyro_alloc_bus_tag(struct pyro_pbm *pbm, const char *name, int ss,
                    297:     int asi, int sasi)
                    298: {
                    299:        struct pyro_softc *sc = pbm->pp_sc;
                    300:        struct sparc_bus_space_tag *bt;
                    301:
                    302:        bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
                    303:        if (bt == NULL)
                    304:                panic("pyro: could not allocate bus tag");
                    305:
                    306:        bzero(bt, sizeof *bt);
                    307:        snprintf(bt->name, sizeof(bt->name), "%s-pbm_%s(%d/%2.2x)",
                    308:            sc->sc_dv.dv_xname, name, ss, asi);
                    309:
                    310:        bt->cookie = pbm;
                    311:        bt->parent = sc->sc_bust;
                    312:        bt->default_type = ss;
                    313:        bt->asi = asi;
                    314:        bt->sasi = sasi;
                    315:        bt->sparc_bus_map = _pyro_bus_map;
                    316:        bt->sparc_bus_mmap = _pyro_bus_mmap;
                    317:        bt->sparc_intr_establish = _pyro_intr_establish;
                    318:        return (bt);
                    319: }
                    320:
                    321: bus_dma_tag_t
                    322: pyro_alloc_dma_tag(struct pyro_pbm *pbm)
                    323: {
                    324:        struct pyro_softc *sc = pbm->pp_sc;
                    325:        bus_dma_tag_t dt, pdt = sc->sc_dmat;
                    326:
                    327:        dt = (bus_dma_tag_t)malloc(sizeof(struct sparc_bus_dma_tag),
                    328:            M_DEVBUF, M_NOWAIT);
                    329:        if (dt == NULL)
                    330:                panic("pyro: could not alloc dma tag");
                    331:
                    332:        bzero(dt, sizeof(*dt));
                    333:        dt->_cookie = pbm;
                    334:        dt->_parent = pdt;
                    335:        dt->_dmamap_create      = pyro_dmamap_create;
                    336:        dt->_dmamap_destroy     = iommu_dvmamap_destroy;
                    337:        dt->_dmamap_load        = iommu_dvmamap_load;
                    338:        dt->_dmamap_load_raw    = iommu_dvmamap_load_raw;
                    339:        dt->_dmamap_unload      = iommu_dvmamap_unload;
                    340:        dt->_dmamap_sync        = iommu_dvmamap_sync;
                    341:        dt->_dmamem_alloc       = iommu_dvmamem_alloc;
                    342:        dt->_dmamem_free        = iommu_dvmamem_free;
                    343:        dt->_dmamem_map         = iommu_dvmamem_map;
                    344:        dt->_dmamem_unmap       = iommu_dvmamem_unmap;
                    345:        return (dt);
                    346: }
                    347:
                    348: pci_chipset_tag_t
                    349: pyro_alloc_chipset(struct pyro_pbm *pbm, int node, pci_chipset_tag_t pc)
                    350: {
                    351:        pci_chipset_tag_t npc;
                    352:
                    353:        npc = malloc(sizeof *npc, M_DEVBUF, M_NOWAIT);
                    354:        if (npc == NULL)
                    355:                panic("pyro: could not allocate pci_chipset_tag_t");
                    356:        memcpy(npc, pc, sizeof *pc);
                    357:        npc->cookie = pbm;
                    358:        npc->rootnode = node;
                    359:        npc->tagshift = 4;      /* PCIe has a larger config space */
                    360:        return (npc);
                    361: }
                    362:
                    363: int
                    364: pyro_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
                    365:     int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
                    366:     bus_dmamap_t *dmamp)
                    367: {
                    368:        struct pyro_pbm *pp = t->_cookie;
                    369:
                    370:        return (iommu_dvmamap_create(t, t0, &pp->pp_sb, size, nsegments,
                    371:            maxsegsz, boundary, flags, dmamp));
                    372: }
                    373:
                    374: int
                    375: _pyro_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
                    376:     bus_size_t size, int flags, bus_space_handle_t *hp)
                    377: {
                    378:        struct pyro_pbm *pbm = t->cookie;
                    379:        int i, ss;
                    380:
                    381:        DPRINTF(PDB_BUSMAP, ("_pyro_bus_map: type %d off %qx sz %qx flags %d",
                    382:            t->default_type,
                    383:            (unsigned long long)offset,
                    384:            (unsigned long long)size,
                    385:            flags));
                    386:
                    387:        ss = t->default_type;
                    388:        DPRINTF(PDB_BUSMAP, (" cspace %d", ss));
                    389:
                    390:        if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
                    391:                printf("\n_pyro_bus_map: invalid parent");
                    392:                return (EINVAL);
                    393:        }
                    394:
                    395:        if (flags & BUS_SPACE_MAP_PROMADDRESS) {
                    396:                return ((*t->parent->sparc_bus_map)
                    397:                    (t, t0, offset, size, flags, hp));
                    398:        }
                    399:
                    400:        for (i = 0; i < pbm->pp_nrange; i++) {
                    401:                bus_addr_t paddr;
                    402:
                    403:                if (((pbm->pp_range[i].cspace >> 24) & 0x03) != ss)
                    404:                        continue;
                    405:
                    406:                paddr = pbm->pp_range[i].phys_lo + offset;
                    407:                paddr |= ((bus_addr_t)pbm->pp_range[i].phys_hi) << 32;
                    408:                return ((*t->parent->sparc_bus_map)
                    409:                    (t, t0, paddr, size, flags, hp));
                    410:        }
                    411:
                    412:        return (EINVAL);
                    413: }
                    414:
                    415: paddr_t
                    416: _pyro_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
                    417:     off_t off, int prot, int flags)
                    418: {
                    419:        bus_addr_t offset = paddr;
                    420:        struct pyro_pbm *pbm = t->cookie;
                    421:        int i, ss;
                    422:
                    423:        ss = t->default_type;
                    424:
                    425:        DPRINTF(PDB_BUSMAP, ("_pyro_bus_mmap: prot %d flags %d pa %qx\n",
                    426:            prot, flags, (unsigned long long)paddr));
                    427:
                    428:        if (t->parent == 0 || t->parent->sparc_bus_mmap == 0) {
                    429:                printf("\n_pyro_bus_mmap: invalid parent");
                    430:                return (-1);
                    431:        }
                    432:
                    433:        for (i = 0; i < pbm->pp_nrange; i++) {
                    434:                bus_addr_t paddr;
                    435:
                    436:                if (((pbm->pp_range[i].cspace >> 24) & 0x03) != ss)
                    437:                        continue;
                    438:
                    439:                paddr = pbm->pp_range[i].phys_lo + offset;
                    440:                paddr |= ((bus_addr_t)pbm->pp_range[i].phys_hi<<32);
                    441:                return ((*t->parent->sparc_bus_mmap)
                    442:                    (t, t0, paddr, off, prot, flags));
                    443:        }
                    444:
                    445:        return (-1);
                    446: }
                    447:
                    448: void *
                    449: _pyro_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
                    450:     int level, int flags, int (*handler)(void *), void *arg, const char *what)
                    451: {
                    452:        struct pyro_pbm *pbm = t->cookie;
                    453:        struct pyro_softc *sc = pbm->pp_sc;
                    454:        struct intrhand *ih = NULL;
                    455:        volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
                    456:        int ino;
                    457:
                    458:        ino = INTINO(ihandle);
                    459:
                    460:        if (level == IPL_NONE)
                    461:                level = INTLEV(ihandle);
                    462:        if (level == IPL_NONE) {
                    463:                printf(": no IPL, setting IPL 2.\n");
                    464:                level = 2;
                    465:        }
                    466:
                    467:        if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
                    468:                u_int64_t *imap, *iclr;
                    469:
                    470:                imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
                    471:                iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
                    472:                intrmapptr = &imap[ino];
                    473:                intrclrptr = &iclr[ino];
                    474:                ino |= INTVEC(ihandle);
                    475:        }
                    476:
                    477:        ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
                    478:            intrclrptr, what);
                    479:        if (ih == NULL)
                    480:                return (NULL);
                    481:
                    482:        intr_establish(ih->ih_pil, ih);
                    483:
                    484:        if (intrmapptr != NULL) {
                    485:                u_int64_t intrmap;
                    486:
                    487:                intrmap = *intrmapptr;
                    488:                intrmap |= (1LL << 6);
                    489:                intrmap |= INTMAP_V;
                    490:                *intrmapptr = intrmap;
                    491:                intrmap = *intrmapptr;
                    492:                ih->ih_number |= intrmap & INTMAP_INR;
                    493:        }
                    494:
                    495:        return (ih);
                    496: }
                    497:
                    498: const struct cfattach pyro_ca = {
                    499:        sizeof(struct pyro_softc), pyro_match, pyro_attach
                    500: };
                    501:
                    502: struct cfdriver pyro_cd = {
                    503:        NULL, "pyro", DV_DULL
                    504: };

CVSweb