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

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

1.1       nbrk        1: /*     $OpenBSD: iommu.c,v 1.47 2007/05/29 09:53:59 sobrado Exp $      */
                      2: /*     $NetBSD: iommu.c,v 1.47 2002/02/08 20:03:45 eeh Exp $   */
                      3:
                      4: /*
                      5:  * Copyright (c) 2003 Henric Jungheim
                      6:  * Copyright (c) 2001, 2002 Eduardo Horvath
                      7:  * Copyright (c) 1999, 2000 Matthew R. Green
                      8:  * All rights reserved.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     26:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     27:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     28:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     29:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  */
                     33:
                     34: /*
                     35:  * UltraSPARC IOMMU support; used by both the sbus and pci code.
                     36:  */
                     37: #include <sys/param.h>
                     38: #include <sys/extent.h>
                     39: #include <sys/malloc.h>
                     40: #include <sys/systm.h>
                     41: #include <sys/device.h>
                     42: #include <sys/mbuf.h>
                     43:
                     44: #include <uvm/uvm_extern.h>
                     45:
                     46: #include <machine/bus.h>
                     47: #include <sparc64/sparc64/cache.h>
                     48: #include <sparc64/dev/iommureg.h>
                     49: #include <sparc64/dev/iommuvar.h>
                     50:
                     51: #include <machine/autoconf.h>
                     52: #include <machine/cpu.h>
                     53:
                     54: #ifdef DDB
                     55: #include <machine/db_machdep.h>
                     56: #include <ddb/db_sym.h>
                     57: #include <ddb/db_extern.h>
                     58: #endif
                     59:
                     60: #ifdef DEBUG
                     61: #define IDB_BUSDMA     0x1
                     62: #define IDB_IOMMU      0x2
                     63: #define IDB_INFO       0x4
                     64: #define IDB_SYNC       0x8
                     65: #define IDB_XXX                0x10
                     66: #define IDB_PRINT_MAP  0x20
                     67: #define IDB_BREAK      0x40
                     68: int iommudebug = IDB_INFO;
                     69: #define DPRINTF(l, s)   do { if (iommudebug & l) printf s; } while (0)
                     70: #else
                     71: #define DPRINTF(l, s)
                     72: #endif
                     73:
                     74: void iommu_enter(struct iommu_state *, struct strbuf_ctl *, vaddr_t, paddr_t,
                     75:     int);
                     76: void iommu_remove(struct iommu_state *, struct strbuf_ctl *, vaddr_t);
                     77: int iommu_dvmamap_sync_range(struct strbuf_ctl*, vaddr_t, bus_size_t);
                     78: int iommu_strbuf_flush_done(struct iommu_map_state *);
                     79: int iommu_dvmamap_load_seg(bus_dma_tag_t, struct iommu_state *,
                     80:     bus_dmamap_t, bus_dma_segment_t *, int, int, bus_size_t, bus_size_t);
                     81: int iommu_dvmamap_load_mlist(bus_dma_tag_t, struct iommu_state *,
                     82:     bus_dmamap_t, struct pglist *, int, bus_size_t, bus_size_t);
                     83: int iommu_dvmamap_validate_map(bus_dma_tag_t, struct iommu_state *,
                     84:     bus_dmamap_t);
                     85: void iommu_dvmamap_print_map(bus_dma_tag_t, struct iommu_state *,
                     86:     bus_dmamap_t);
                     87: int iommu_dvmamap_append_range(bus_dma_tag_t, bus_dmamap_t, paddr_t,
                     88:     bus_size_t, int, bus_size_t);
                     89: int64_t iommu_tsb_entry(struct iommu_state *, vaddr_t);
                     90: void strbuf_reset(struct strbuf_ctl *);
                     91: int iommu_iomap_insert_page(struct iommu_map_state *, paddr_t);
                     92: vaddr_t iommu_iomap_translate(struct iommu_map_state *, paddr_t);
                     93: int iommu_iomap_load_map(struct iommu_state *, struct iommu_map_state *,
                     94:     vaddr_t, int);
                     95: int iommu_iomap_unload_map(struct iommu_state *, struct iommu_map_state *);
                     96: struct iommu_map_state *iommu_iomap_create(int);
                     97: void iommu_iomap_destroy(struct iommu_map_state *);
                     98: void iommu_iomap_clear_pages(struct iommu_map_state *);
                     99: void _iommu_dvmamap_sync(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t,
                    100:     bus_addr_t, bus_size_t, int);
                    101:
                    102: /*
                    103:  * Initiate an STC entry flush.
                    104:  */
                    105: static inline void
                    106: iommu_strbuf_flush(struct strbuf_ctl *sb, vaddr_t va)
                    107: {
                    108: #ifdef DEBUG
                    109:        if (sb->sb_flush == NULL) {
                    110:                printf("iommu_strbuf_flush: attempting to flush w/o STC\n");
                    111:                return;
                    112:        }
                    113: #endif
                    114:
                    115:        bus_space_write_8(sb->sb_bustag, sb->sb_sb,
                    116:            STRBUFREG(strbuf_pgflush), va);
                    117: }
                    118:
                    119: /*
                    120:  * initialise the UltraSPARC IOMMU (SBus or PCI):
                    121:  *     - allocate and setup the iotsb.
                    122:  *     - enable the IOMMU
                    123:  *     - initialise the streaming buffers (if they exist)
                    124:  *     - create a private DVMA map.
                    125:  */
                    126: void
                    127: iommu_init(char *name, struct iommu_state *is, int tsbsize, u_int32_t iovabase)
                    128: {
                    129:        psize_t size;
                    130:        vaddr_t va;
                    131:        paddr_t pa;
                    132:        struct vm_page *m;
                    133:        struct pglist mlist;
                    134:
                    135:        /*
                    136:         * Setup the iommu.
                    137:         *
                    138:         * The sun4u iommu is part of the SBus or PCI controller so we will
                    139:         * deal with it here..
                    140:         *
                    141:         * For sysio and psycho/psycho+ the IOMMU address space always ends at
                    142:         * 0xffffe000, but the starting address depends on the size of the
                    143:         * map.  The map size is 1024 * 2 ^ is->is_tsbsize entries, where each
                    144:         * entry is 8 bytes.  The start of the map can be calculated by
                    145:         * (0xffffe000 << (8 + is->is_tsbsize)).
                    146:         *
                    147:         * But sabre and hummingbird use a different scheme that seems to
                    148:         * be hard-wired, so we read the start and size from the PROM and
                    149:         * just use those values.
                    150:         */
                    151:        is->is_cr = IOMMUCR_EN;
                    152:        is->is_tsbsize = tsbsize;
                    153:        if (iovabase == (u_int32_t)-1) {
                    154:                is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize);
                    155:                is->is_dvmaend = IOTSB_VEND;
                    156:        } else {
                    157:                is->is_dvmabase = iovabase;
                    158:                is->is_dvmaend = iovabase + IOTSB_VSIZE(tsbsize) - 1;
                    159:        }
                    160:
                    161:        /*
                    162:         * Allocate memory for I/O pagetables.  They need to be physically
                    163:         * contiguous.
                    164:         */
                    165:
                    166:        size = PAGE_SIZE << is->is_tsbsize;
                    167:        TAILQ_INIT(&mlist);
                    168:        if (uvm_pglistalloc((psize_t)size, (paddr_t)0, (paddr_t)-1,
                    169:                (paddr_t)PAGE_SIZE, (paddr_t)0, &mlist, 1, 0) != 0)
                    170:                panic("iommu_init: no memory");
                    171:
                    172:        va = uvm_km_valloc(kernel_map, size);
                    173:        if (va == 0)
                    174:                panic("iommu_init: no memory");
                    175:        is->is_tsb = (int64_t *)va;
                    176:
                    177:        m = TAILQ_FIRST(&mlist);
                    178:        is->is_ptsb = VM_PAGE_TO_PHYS(m);
                    179:
                    180:        /* Map the pages */
                    181:        for (; m != NULL; m = TAILQ_NEXT(m,pageq)) {
                    182:                pa = VM_PAGE_TO_PHYS(m);
                    183:                pmap_enter(pmap_kernel(), va, pa | PMAP_NVC,
                    184:                        VM_PROT_READ|VM_PROT_WRITE,
                    185:                        VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
                    186:                va += PAGE_SIZE;
                    187:        }
                    188:        pmap_update(pmap_kernel());
                    189:        memset(is->is_tsb, 0, size);
                    190:
                    191: #ifdef DEBUG
                    192:        if (iommudebug & IDB_INFO) {
                    193:                /* Probe the iommu */
                    194:                /* The address or contents of the regs...? */
                    195:                printf("iommu regs at: cr=%lx tsb=%lx flush=%lx\n",
                    196:                    (u_long)bus_space_vaddr(is->is_bustag, is->is_iommu) +
                    197:                        IOMMUREG(iommu_cr),
                    198:                    (u_long)bus_space_vaddr(is->is_bustag, is->is_iommu) +
                    199:                        IOMMUREG(iommu_tsb),
                    200:                    (u_long)bus_space_vaddr(is->is_bustag, is->is_iommu) +
                    201:                        IOMMUREG(iommu_flush));
                    202:                printf("iommu cr=%llx tsb=%llx\n",
                    203:                    IOMMUREG_READ(is, iommu_cr),
                    204:                    IOMMUREG_READ(is, iommu_tsb));
                    205:                printf("TSB base %p phys %llx\n",
                    206:                    (void *)is->is_tsb, (unsigned long long)is->is_ptsb);
                    207:                delay(1000000); /* 1 s */
                    208:        }
                    209: #endif
                    210:
                    211:        /*
                    212:         * Now all the hardware's working we need to allocate a dvma map.
                    213:         */
                    214:        printf("dvma map %x-%x, ", is->is_dvmabase, is->is_dvmaend);
                    215:        printf("iotdb %llx-%llx",
                    216:            (unsigned long long)is->is_ptsb,
                    217:            (unsigned long long)(is->is_ptsb + size));
                    218:        is->is_dvmamap = extent_create(name,
                    219:            is->is_dvmabase, (u_long)is->is_dvmaend + 1,
                    220:            M_DEVBUF, 0, 0, EX_NOWAIT);
                    221:
                    222:        /*
                    223:         * Set the TSB size.  The relevant bits were moved to the TSB
                    224:         * base register in the PCIe host bridges.
                    225:         */
                    226:        if (strncmp(name, "pyro", 4) == 0)
                    227:                is->is_ptsb |= is->is_tsbsize;
                    228:        else
                    229:                is->is_cr |= (is->is_tsbsize << 16);
                    230:
                    231:        /*
                    232:         * Now actually start up the IOMMU.
                    233:         */
                    234:        iommu_reset(is);
                    235:        printf("\n");
                    236: }
                    237:
                    238: /*
                    239:  * Streaming buffers don't exist on the UltraSPARC IIi/e; we should have
                    240:  * detected that already and disabled them.  If not, we will notice that
                    241:  * they aren't there when the STRBUF_EN bit does not remain.
                    242:  */
                    243: void
                    244: iommu_reset(struct iommu_state *is)
                    245: {
                    246:        int i;
                    247:
                    248:        IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb);
                    249:
                    250:        /* Enable IOMMU */
                    251:        IOMMUREG_WRITE(is, iommu_cr, is->is_cr);
                    252:
                    253:        for (i = 0; i < 2; ++i) {
                    254:                struct strbuf_ctl *sb = is->is_sb[i];
                    255:
                    256:                if (sb == NULL)
                    257:                        continue;
                    258:
                    259:                sb->sb_iommu = is;
                    260:                strbuf_reset(sb);
                    261:
                    262:                if (sb->sb_flush)
                    263:                        printf(", STC%d enabled", i);
                    264:        }
                    265: }
                    266:
                    267: /*
                    268:  * Initialize one STC.
                    269:  */
                    270: void
                    271: strbuf_reset(struct strbuf_ctl *sb)
                    272: {
                    273:        if(sb->sb_flush == NULL)
                    274:                return;
                    275:
                    276:        bus_space_write_8(sb->sb_bustag, sb->sb_sb,
                    277:            STRBUFREG(strbuf_ctl), STRBUF_EN);
                    278:
                    279:        membar(Lookaside);
                    280:
                    281:        /* No streaming buffers? Disable them */
                    282:        if (bus_space_read_8(sb->sb_bustag, sb->sb_sb,
                    283:            STRBUFREG(strbuf_ctl)) == 0) {
                    284:                sb->sb_flush = NULL;
                    285:        } else {
                    286:                /*
                    287:                 * locate the pa of the flush buffer
                    288:                 */
                    289:                if (pmap_extract(pmap_kernel(),
                    290:                    (vaddr_t)sb->sb_flush, &sb->sb_flushpa) == FALSE)
                    291:                        sb->sb_flush = NULL;
                    292:        }
                    293: }
                    294:
                    295: /*
                    296:  * Add an entry to the IOMMU table.
                    297:  *
                    298:  * The entry is marked streaming if an STC was detected and
                    299:  * the BUS_DMA_STREAMING flag is set.
                    300:  */
                    301: void
                    302: iommu_enter(struct iommu_state *is, struct strbuf_ctl *sb, vaddr_t va,
                    303:     paddr_t pa, int flags)
                    304: {
                    305:        int64_t tte;
                    306:        volatile int64_t *tte_ptr = &is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)];
                    307:
                    308: #ifdef DIAGNOSTIC
                    309:        if (va < is->is_dvmabase || (va + PAGE_MASK) > is->is_dvmaend)
                    310:                panic("iommu_enter: va %#lx not in DVMA space", va);
                    311:
                    312:        tte = *tte_ptr;
                    313:
                    314:        if (tte & IOTTE_V) {
                    315:                printf("Overwriting valid tte entry (dva %lx pa %lx "
                    316:                    "&tte %p tte %llx)\n", va, pa, tte_ptr, tte);
                    317:                extent_print(is->is_dvmamap);
                    318:                panic("IOMMU overwrite");
                    319:        }
                    320: #endif
                    321:
                    322:        tte = MAKEIOTTE(pa, !(flags & BUS_DMA_NOWRITE),
                    323:            !(flags & BUS_DMA_NOCACHE), (flags & BUS_DMA_STREAMING));
                    324:
                    325:        DPRINTF(IDB_IOMMU, ("Clearing TSB slot %d for va %p\n",
                    326:            (int)IOTSBSLOT(va,is->is_tsbsize), (void *)(u_long)va));
                    327:
                    328:        *tte_ptr = tte;
                    329:
                    330:        /*
                    331:         * Why bother to flush this va?  It should only be relevant for
                    332:         * V ==> V or V ==> non-V transitions.  The former is illegal and
                    333:         * the latter is never done here.  It is true that this provides
                    334:         * some protection against a misbehaving master using an address
                    335:         * after it should.  The IOMMU documentations specifically warns
                    336:         * that the consequences of a simultaneous IOMMU flush and DVMA
                    337:         * access to the same address are undefined.  (By that argument,
                    338:         * the STC should probably be flushed as well.)   Note that if
                    339:         * a bus master keeps using a memory region after it has been
                    340:         * unmapped, the specific behavior of the IOMMU is likely to
                    341:         * be the least of our worries.
                    342:         */
                    343:        IOMMUREG_WRITE(is, iommu_flush, va);
                    344:
                    345:        DPRINTF(IDB_IOMMU, ("iommu_enter: va %lx pa %lx TSB[%lx]@%p=%lx\n",
                    346:            va, (long)pa, (u_long)IOTSBSLOT(va,is->is_tsbsize),
                    347:            (void *)(u_long)&is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
                    348:            (u_long)tte));
                    349: }
                    350:
                    351: /*
                    352:  * Remove an entry from the IOMMU table.
                    353:  *
                    354:  * The entry is flushed from the STC if an STC is detected and the TSB
                    355:  * entry has the IOTTE_STREAM flags set.  It should be impossible for
                    356:  * the TSB entry to have this flag set without the BUS_DMA_STREAMING
                    357:  * flag, but better to be safe.  (The IOMMU will be ignored as long
                    358:  * as an STC entry exists.)
                    359:  */
                    360: void
                    361: iommu_remove(struct iommu_state *is, struct strbuf_ctl *sb, vaddr_t va)
                    362: {
                    363:        int64_t *tte_ptr = &is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)];
                    364:        int64_t tte;
                    365:
                    366: #ifdef DIAGNOSTIC
                    367:        if (va < is->is_dvmabase || (va + PAGE_MASK) > is->is_dvmaend)
                    368:                panic("iommu_remove: va 0x%lx not in DVMA space", (u_long)va);
                    369:        if (va != trunc_page(va)) {
                    370:                printf("iommu_remove: unaligned va: %lx\n", va);
                    371:                va = trunc_page(va);
                    372:        }
                    373: #endif
                    374:        tte = *tte_ptr;
                    375:
                    376:        DPRINTF(IDB_IOMMU, ("iommu_remove: va %lx TSB[%llx]@%p\n",
                    377:            va, tte, tte_ptr));
                    378:
                    379: #ifdef DIAGNOSTIC
                    380:        if ((tte & IOTTE_V) == 0) {
                    381:                printf("Removing invalid tte entry (dva %lx &tte %p "
                    382:                    "tte %llx)\n", va, tte_ptr, tte);
                    383:                extent_print(is->is_dvmamap);
                    384:                panic("IOMMU remove overwrite");
                    385:        }
                    386: #endif
                    387:
                    388:        *tte_ptr = tte & ~IOTTE_V;
                    389:
                    390:        /*
                    391:         * IO operations are strongly ordered WRT each other.  It is
                    392:         * unclear how they relate to normal memory accesses.
                    393:         */
                    394:        membar(StoreStore);
                    395:
                    396:        IOMMUREG_WRITE(is, iommu_flush, va);
                    397:
                    398:        if (sb && (tte & IOTTE_STREAM))
                    399:                iommu_strbuf_flush(sb, va);
                    400:
                    401:        /* Should we sync the iommu and stc here? */
                    402: }
                    403:
                    404: /*
                    405:  * Find the physical address of a DVMA address (debug routine).
                    406:  */
                    407: paddr_t
                    408: iommu_extract(struct iommu_state *is, vaddr_t dva)
                    409: {
                    410:        int64_t tte = 0;
                    411:
                    412:        if (dva >= is->is_dvmabase && dva <= is->is_dvmaend)
                    413:                tte = is->is_tsb[IOTSBSLOT(dva, is->is_tsbsize)];
                    414:
                    415:        return (tte & IOTTE_PAMASK);
                    416: }
                    417:
                    418: /*
                    419:  * Lookup a TSB entry for a given DVMA (debug routine).
                    420:  */
                    421: int64_t
                    422: iommu_lookup_tte(struct iommu_state *is, vaddr_t dva)
                    423: {
                    424:        int64_t tte = 0;
                    425:
                    426:        if (dva >= is->is_dvmabase && dva <= is->is_dvmaend)
                    427:                tte = is->is_tsb[IOTSBSLOT(dva, is->is_tsbsize)];
                    428:
                    429:        return (tte);
                    430: }
                    431:
                    432: /*
                    433:  * Lookup a TSB entry at a given physical address (debug routine).
                    434:  */
                    435: int64_t
                    436: iommu_fetch_tte(struct iommu_state *is, paddr_t pa)
                    437: {
                    438:        int64_t tte = 0;
                    439:
                    440:        if (pa >= is->is_ptsb && pa < is->is_ptsb +
                    441:            (PAGE_SIZE << is->is_tsbsize))
                    442:                tte = ldxa(pa, ASI_PHYS_CACHED);
                    443:
                    444:        return (tte);
                    445: }
                    446:
                    447: /*
                    448:  * Fetch a TSB entry with some sanity checking.
                    449:  */
                    450: int64_t
                    451: iommu_tsb_entry(struct iommu_state *is, vaddr_t dva)
                    452: {
                    453:        int64_t tte;
                    454:
                    455:        if (dva < is->is_dvmabase || dva > is->is_dvmaend)
                    456:                panic("invalid dva: %llx", (long long)dva);
                    457:
                    458:        tte = is->is_tsb[IOTSBSLOT(dva,is->is_tsbsize)];
                    459:
                    460:        if ((tte & IOTTE_V) == 0)
                    461:                panic("iommu_tsb_entry: invalid entry %lx", dva);
                    462:
                    463:        return (tte);
                    464: }
                    465:
                    466: /*
                    467:  * Initiate and then block until an STC flush synchronization has completed.
                    468:  */
                    469: int
                    470: iommu_strbuf_flush_done(struct iommu_map_state *ims)
                    471: {
                    472:        struct strbuf_ctl *sb = ims->ims_sb;
                    473:        struct strbuf_flush *sf = &ims->ims_flush;
                    474:        struct timeval cur, flushtimeout;
                    475:        struct timeval to = { 0, 500000 };
                    476:        u_int64_t flush;
                    477:        int timeout_started = 0;
                    478:
                    479: #ifdef DIAGNOSTIC
                    480:        if (sb == NULL) {
                    481:                panic("iommu_strbuf_flush_done: invalid flush buffer");
                    482:        }
                    483: #endif
                    484:
                    485:        /*
                    486:         * Streaming buffer flushes:
                    487:         *
                    488:         *   1 Tell strbuf to flush by storing va to strbuf_pgflush.
                    489:         *   2 Store 0 in flag
                    490:         *   3 Store pointer to flag in flushsync
                    491:         *   4 wait till flushsync becomes 0x1
                    492:         *
                    493:         * If it takes more than .5 sec, something went very, very wrong.
                    494:         */
                    495:
                    496:        /*
                    497:         * If we're reading from ASI_PHYS_CACHED, then we'll write to
                    498:         * it too.  No need to tempt fate or learn about Si bugs or such.
                    499:         * FreeBSD just uses normal "volatile" reads/writes...
                    500:         */
                    501:
                    502:        stxa(sf->sbf_flushpa, ASI_PHYS_CACHED, 0);
                    503:
                    504:        /*
                    505:         * Insure any previous strbuf operations are complete and that
                    506:         * memory is initialized before the IOMMU uses it.
                    507:         * Is this Needed?  How are IO and memory operations ordered?
                    508:         */
                    509:        membar(StoreStore);
                    510:
                    511:        bus_space_write_8(sb->sb_bustag, sb->sb_sb,
                    512:                    STRBUFREG(strbuf_flushsync), sf->sbf_flushpa);
                    513:
                    514:        DPRINTF(IDB_IOMMU,
                    515:            ("iommu_strbuf_flush_done: flush = %llx pa = %lx\n",
                    516:                ldxa(sf->sbf_flushpa, ASI_PHYS_CACHED), sf->sbf_flushpa));
                    517:
                    518:        membar(StoreLoad | Lookaside);
                    519:
                    520:        for(;;) {
                    521:                int i;
                    522:
                    523:                /*
                    524:                 * Try to shave a few instruction cycles off the average
                    525:                 * latency by only checking the elapsed time every few
                    526:                 * fetches.
                    527:                 */
                    528:                for (i = 0; i < 1000; ++i) {
                    529:                        membar(LoadLoad);
                    530:                        /* Bypass non-coherent D$ */
                    531:                        /* non-coherent...?   Huh? */
                    532:                        flush = ldxa(sf->sbf_flushpa, ASI_PHYS_CACHED);
                    533:
                    534:                        if (flush) {
                    535:                                DPRINTF(IDB_IOMMU,
                    536:                                    ("iommu_strbuf_flush_done: flushed\n"));
                    537:                                return (0);
                    538:                        }
                    539:                }
                    540:
                    541:                microtime(&cur);
                    542:
                    543:                if (timeout_started) {
                    544:                        if (timercmp(&cur, &flushtimeout, >))
                    545:                                panic("STC timeout at %lx (%lld)",
                    546:                                    sf->sbf_flushpa, flush);
                    547:                } else {
                    548:                        timeradd(&cur, &to, &flushtimeout);
                    549:
                    550:                        timeout_started = 1;
                    551:
                    552:                        DPRINTF(IDB_IOMMU,
                    553:                            ("iommu_strbuf_flush_done: flush = %llx pa = %lx "
                    554:                                "now=%lx:%lx until = %lx:%lx\n",
                    555:                                ldxa(sf->sbf_flushpa, ASI_PHYS_CACHED),
                    556:                                sf->sbf_flushpa, cur.tv_sec, cur.tv_usec,
                    557:                                flushtimeout.tv_sec, flushtimeout.tv_usec));
                    558:                }
                    559:        }
                    560: }
                    561:
                    562: /*
                    563:  * IOMMU DVMA operations, common to SBus and PCI.
                    564:  */
                    565:
                    566: #define BUS_DMA_FIND_PARENT(t, fn)                                      \
                    567:         if (t->_parent == NULL)                                         \
                    568:                 panic("null bus_dma parent (" #fn ")");                 \
                    569:         for (t = t->_parent; t->fn == NULL; t = t->_parent)             \
                    570:                 if (t->_parent == NULL)                                 \
                    571:                         panic("no bus_dma " #fn " located");
                    572:
                    573: int
                    574: iommu_dvmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, struct strbuf_ctl *sb,
                    575:     bus_size_t size, int nsegments, bus_size_t maxsegsz, bus_size_t boundary,
                    576:     int flags, bus_dmamap_t *dmamap)
                    577: {
                    578:        int ret;
                    579:        bus_dmamap_t map;
                    580:        struct iommu_map_state *ims;
                    581:
                    582:        BUS_DMA_FIND_PARENT(t, _dmamap_create);
                    583:        ret = (*t->_dmamap_create)(t, t0, size, nsegments, maxsegsz, boundary,
                    584:            flags, &map);
                    585:
                    586:        if (ret)
                    587:                return (ret);
                    588:
                    589:        ims = iommu_iomap_create(atop(round_page(size)));
                    590:
                    591:        if (ims == NULL) {
                    592:                bus_dmamap_destroy(t0, map);
                    593:                return (ENOMEM);
                    594:        }
                    595:
                    596:        ims->ims_sb = sb;
                    597:        map->_dm_cookie = ims;
                    598:
                    599: #ifdef DIAGNOSTIC
                    600:        if (ims->ims_sb == NULL)
                    601:                panic("iommu_dvmamap_create: null sb");
                    602:        if (ims->ims_sb->sb_iommu == NULL)
                    603:                panic("iommu_dvmamap_create: null iommu");
                    604: #endif
                    605:        *dmamap = map;
                    606:
                    607:        return (0);
                    608: }
                    609:
                    610: void
                    611: iommu_dvmamap_destroy(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map)
                    612: {
                    613:        /*
                    614:         * The specification (man page) requires a loaded
                    615:         * map to be unloaded before it is destroyed.
                    616:         */
                    617:        if (map->dm_nsegs)
                    618:                bus_dmamap_unload(t0, map);
                    619:
                    620:         if (map->_dm_cookie)
                    621:                 iommu_iomap_destroy(map->_dm_cookie);
                    622:        map->_dm_cookie = NULL;
                    623:
                    624:        BUS_DMA_FIND_PARENT(t, _dmamap_destroy);
                    625:        (*t->_dmamap_destroy)(t, t0, map);
                    626: }
                    627:
                    628: /*
                    629:  * Load a contiguous kva buffer into a dmamap.  The physical pages are
                    630:  * not assumed to be contiguous.  Two passes are made through the buffer
                    631:  * and both call pmap_extract() for the same va->pa translations.  It
                    632:  * is possible to run out of pa->dvma mappings; the code should be smart
                    633:  * enough to resize the iomap (when the "flags" permit allocation).  It
                    634:  * is trivial to compute the number of entries required (round the length
                    635:  * up to the page size and then divide by the page size)...
                    636:  */
                    637: int
                    638: iommu_dvmamap_load(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
                    639:     void *buf, bus_size_t buflen, struct proc *p, int flags)
                    640: {
                    641:        int s;
                    642:        int err = 0;
                    643:        bus_size_t sgsize;
                    644:        u_long dvmaddr, sgstart, sgend;
                    645:        bus_size_t align, boundary;
                    646:        struct iommu_state *is;
                    647:        struct iommu_map_state *ims = map->_dm_cookie;
                    648:        pmap_t pmap;
                    649:
                    650: #ifdef DIAGNOSTIC
                    651:        if (ims == NULL)
                    652:                panic("iommu_dvmamap_load: null map state");
                    653: #endif
                    654: #ifdef DEBUG
                    655:        if (ims->ims_sb == NULL)
                    656:                panic("iommu_dvmamap_load: null sb");
                    657:        if (ims->ims_sb->sb_iommu == NULL)
                    658:                panic("iommu_dvmamap_load: null iommu");
                    659: #endif /* DEBUG */
                    660:        is = ims->ims_sb->sb_iommu;
                    661:
                    662:        if (map->dm_nsegs) {
                    663:                /*
                    664:                 * Is it still in use? _bus_dmamap_load should have taken care
                    665:                 * of this.
                    666:                 */
                    667: #ifdef DIAGNOSTIC
                    668:                panic("iommu_dvmamap_load: map still in use");
                    669: #endif
                    670:                bus_dmamap_unload(t0, map);
                    671:        }
                    672:
                    673:        /*
                    674:         * Make sure that on error condition we return "no valid mappings".
                    675:         */
                    676:        map->dm_nsegs = 0;
                    677:
                    678:        if (buflen < 1 || buflen > map->_dm_size) {
                    679:                DPRINTF(IDB_BUSDMA,
                    680:                    ("iommu_dvmamap_load(): error %d > %d -- "
                    681:                     "map size exceeded!\n", (int)buflen, (int)map->_dm_size));
                    682:                return (EINVAL);
                    683:        }
                    684:
                    685:        /*
                    686:         * A boundary presented to bus_dmamem_alloc() takes precedence
                    687:         * over boundary in the map.
                    688:         */
                    689:        if ((boundary = (map->dm_segs[0]._ds_boundary)) == 0)
                    690:                boundary = map->_dm_boundary;
                    691:        align = MAX(map->dm_segs[0]._ds_align, PAGE_SIZE);
                    692:
                    693:        pmap = p ? p->p_vmspace->vm_map.pmap : pmap = pmap_kernel();
                    694:
                    695:        /* Count up the total number of pages we need */
                    696:        iommu_iomap_clear_pages(ims);
                    697:        { /* Scope */
                    698:                bus_addr_t a, aend;
                    699:                bus_addr_t addr = (vaddr_t)buf;
                    700:                int seg_len = buflen;
                    701:
                    702:                aend = round_page(addr + seg_len);
                    703:                for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
                    704:                        paddr_t pa;
                    705:
                    706:                        if (pmap_extract(pmap, a, &pa) == FALSE) {
                    707:                                printf("iomap pmap error addr 0x%llx\n", a);
                    708:                                iommu_iomap_clear_pages(ims);
                    709:                                return (EFBIG);
                    710:                        }
                    711:
                    712:                        err = iommu_iomap_insert_page(ims, pa);
                    713:                        if (err) {
                    714:                                printf("iomap insert error: %d for "
                    715:                                    "va 0x%llx pa 0x%lx "
                    716:                                    "(buf %p len %lld/%llx)\n",
                    717:                                    err, a, pa, buf, buflen, buflen);
                    718:                                iommu_dvmamap_print_map(t, is, map);
                    719:                                iommu_iomap_clear_pages(ims);
                    720:                                return (EFBIG);
                    721:                        }
                    722:                }
                    723:        }
                    724:        sgsize = ims->ims_map.ipm_pagecnt * PAGE_SIZE;
                    725:
                    726:        if (flags & BUS_DMA_24BIT) {
                    727:                sgstart = MAX(is->is_dvmamap->ex_start, 0xff000000);
                    728:                sgend = MIN(is->is_dvmamap->ex_end, 0xffffffff);
                    729:        } else {
                    730:                sgstart = is->is_dvmamap->ex_start;
                    731:                sgend = is->is_dvmamap->ex_end;
                    732:        }
                    733:
                    734:        /*
                    735:         * If our segment size is larger than the boundary we need to
                    736:         * split the transfer up into little pieces ourselves.
                    737:         */
                    738:        s = splhigh();
                    739:        err = extent_alloc_subregion(is->is_dvmamap, sgstart, sgend,
                    740:            sgsize, align, 0, (sgsize > boundary) ? 0 : boundary,
                    741:            EX_NOWAIT | EX_BOUNDZERO, (u_long *)&dvmaddr);
                    742:        splx(s);
                    743:
                    744: #ifdef DEBUG
                    745:        if (err || (dvmaddr == (bus_addr_t)-1)) {
                    746:                printf("iommu_dvmamap_load(): extent_alloc(%d, %x) failed!\n",
                    747:                    (int)sgsize, flags);
                    748: #ifdef DDB
                    749:                if (iommudebug & IDB_BREAK)
                    750:                        Debugger();
                    751: #endif
                    752:        }
                    753: #endif
                    754:        if (err != 0)
                    755:                return (err);
                    756:
                    757:        if (dvmaddr == (bus_addr_t)-1)
                    758:                return (ENOMEM);
                    759:
                    760:        /* Set the active DVMA map */
                    761:        map->_dm_dvmastart = dvmaddr;
                    762:        map->_dm_dvmasize = sgsize;
                    763:
                    764:        map->dm_mapsize = buflen;
                    765:
                    766: #ifdef DEBUG
                    767:        iommu_dvmamap_validate_map(t, is, map);
                    768: #endif
                    769:
                    770:        if (iommu_iomap_load_map(is, ims, dvmaddr, flags))
                    771:                return (EFBIG);
                    772:
                    773:        { /* Scope */
                    774:                bus_addr_t a, aend;
                    775:                bus_addr_t addr = (vaddr_t)buf;
                    776:                int seg_len = buflen;
                    777:
                    778:                aend = round_page(addr + seg_len);
                    779:                for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
                    780:                        bus_addr_t pgstart;
                    781:                        bus_addr_t pgend;
                    782:                        paddr_t pa;
                    783:                        int pglen;
                    784:
                    785:                        /* Yuck... Redoing the same pmap_extract... */
                    786:                        if (pmap_extract(pmap, a, &pa) == FALSE) {
                    787:                                printf("iomap pmap error addr 0x%llx\n", a);
                    788:                                iommu_iomap_clear_pages(ims);
                    789:                                return (EFBIG);
                    790:                        }
                    791:
                    792:                        pgstart = pa | (MAX(a, addr) & PAGE_MASK);
                    793:                        pgend = pa | (MIN(a + PAGE_SIZE - 1,
                    794:                            addr + seg_len - 1) & PAGE_MASK);
                    795:                        pglen = pgend - pgstart + 1;
                    796:
                    797:                        if (pglen < 1)
                    798:                                continue;
                    799:
                    800:                        err = iommu_dvmamap_append_range(t, map, pgstart,
                    801:                            pglen, flags, boundary);
                    802:                        if (err == EFBIG)
                    803:                                return (err);
                    804:                        if (err) {
                    805:                                printf("iomap load seg page: %d for "
                    806:                                    "va 0x%llx pa %lx (%llx - %llx) "
                    807:                                    "for %d/0x%x\n",
                    808:                                    err, a, pa, pgstart, pgend, pglen, pglen);
                    809:                                return (err);
                    810:                        }
                    811:                }
                    812:        }
                    813:
                    814: #ifdef DIAGNOSTIC
                    815:        iommu_dvmamap_validate_map(t, is, map);
                    816: #endif
                    817:
                    818: #ifdef DEBUG
                    819:        if (err)
                    820:                printf("**** iommu_dvmamap_load failed with error %d\n",
                    821:                    err);
                    822:
                    823:        if (err || (iommudebug & IDB_PRINT_MAP)) {
                    824:                iommu_dvmamap_print_map(t, is, map);
                    825: #ifdef DDB
                    826:                if (iommudebug & IDB_BREAK)
                    827:                        Debugger();
                    828: #endif
                    829:        }
                    830: #endif
                    831:
                    832:        return (err);
                    833: }
                    834:
                    835: /*
                    836:  * Load a dvmamap from an array of segs or an mlist (if the first
                    837:  * "segs" entry's mlist is non-null).  It calls iommu_dvmamap_load_segs()
                    838:  * or iommu_dvmamap_load_mlist() for part of the 2nd pass through the
                    839:  * mapping.  This is ugly.  A better solution would probably be to have
                    840:  * function pointers for implementing the traversal.  That way, there
                    841:  * could be one core load routine for each of the three required algorithms
                    842:  * (buffer, seg, and mlist).  That would also mean that the traversal
                    843:  * algorithm would then only need one implementation for each algorithm
                    844:  * instead of two (one for populating the iomap and one for populating
                    845:  * the dvma map).
                    846:  */
                    847: int
                    848: iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
                    849:     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
                    850: {
                    851:        int i, s;
                    852:        int left;
                    853:        int err = 0;
                    854:        bus_size_t sgsize;
                    855:        bus_size_t boundary, align;
                    856:        u_long dvmaddr, sgstart, sgend;
                    857:        struct iommu_state *is;
                    858:        struct iommu_map_state *ims = map->_dm_cookie;
                    859:
                    860: #ifdef DIAGNOSTIC
                    861:        if (ims == NULL)
                    862:                panic("iommu_dvmamap_load_raw: null map state");
                    863: #endif
                    864: #ifdef DEBUG
                    865:        if (ims->ims_sb == NULL)
                    866:                panic("iommu_dvmamap_load_raw: null sb");
                    867:        if (ims->ims_sb->sb_iommu == NULL)
                    868:                panic("iommu_dvmamap_load_raw: null iommu");
                    869: #endif /* DEBUG */
                    870:        is = ims->ims_sb->sb_iommu;
                    871:
                    872:        if (map->dm_nsegs) {
                    873:                /* Already in use?? */
                    874: #ifdef DIAGNOSTIC
                    875:                panic("iommu_dvmamap_load_raw: map still in use");
                    876: #endif
                    877:                bus_dmamap_unload(t0, map);
                    878:        }
                    879:
                    880:        /*
                    881:         * A boundary presented to bus_dmamem_alloc() takes precedence
                    882:         * over boundary in the map.
                    883:         */
                    884:        if ((boundary = segs[0]._ds_boundary) == 0)
                    885:                boundary = map->_dm_boundary;
                    886:
                    887:        align = MAX(segs[0]._ds_align, PAGE_SIZE);
                    888:
                    889:        /*
                    890:         * Make sure that on error condition we return "no valid mappings".
                    891:         */
                    892:        map->dm_nsegs = 0;
                    893:
                    894:        iommu_iomap_clear_pages(ims);
                    895:        if (segs[0]._ds_mlist) {
                    896:                struct pglist *mlist = segs[0]._ds_mlist;
                    897:                struct vm_page *m;
                    898:                for (m = TAILQ_FIRST(mlist); m != NULL;
                    899:                    m = TAILQ_NEXT(m,pageq)) {
                    900:                        err = iommu_iomap_insert_page(ims, VM_PAGE_TO_PHYS(m));
                    901:
                    902:                        if(err) {
                    903:                                printf("iomap insert error: %d for "
                    904:                                    "pa 0x%lx\n", err, VM_PAGE_TO_PHYS(m));
                    905:                                iommu_dvmamap_print_map(t, is, map);
                    906:                                iommu_iomap_clear_pages(ims);
                    907:                                return (EFBIG);
                    908:                        }
                    909:                }
                    910:        } else {
                    911:                /* Count up the total number of pages we need */
                    912:                for (i = 0, left = size; left > 0 && i < nsegs; i++) {
                    913:                        bus_addr_t a, aend;
                    914:                        bus_size_t len = segs[i].ds_len;
                    915:                        bus_addr_t addr = segs[i].ds_addr;
                    916:                        int seg_len = MIN(left, len);
                    917:
                    918:                        if (len < 1)
                    919:                                continue;
                    920:
                    921:                        aend = round_page(addr + seg_len);
                    922:                        for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
                    923:
                    924:                                err = iommu_iomap_insert_page(ims, a);
                    925:                                if (err) {
                    926:                                        printf("iomap insert error: %d for "
                    927:                                            "pa 0x%llx\n", err, a);
                    928:                                        iommu_dvmamap_print_map(t, is, map);
                    929:                                        iommu_iomap_clear_pages(ims);
                    930:                                        return (EFBIG);
                    931:                                }
                    932:                        }
                    933:
                    934:                        left -= seg_len;
                    935:                }
                    936:        }
                    937:        sgsize = ims->ims_map.ipm_pagecnt * PAGE_SIZE;
                    938:
                    939:        if (flags & BUS_DMA_24BIT) {
                    940:                sgstart = MAX(is->is_dvmamap->ex_start, 0xff000000);
                    941:                sgend = MIN(is->is_dvmamap->ex_end, 0xffffffff);
                    942:        } else {
                    943:                sgstart = is->is_dvmamap->ex_start;
                    944:                sgend = is->is_dvmamap->ex_end;
                    945:        }
                    946:
                    947:        /*
                    948:         * If our segment size is larger than the boundary we need to
                    949:         * split the transfer up into little pieces ourselves.
                    950:         */
                    951:        s = splhigh();
                    952:        err = extent_alloc_subregion(is->is_dvmamap, sgstart, sgend,
                    953:            sgsize, align, 0, (sgsize > boundary) ? 0 : boundary,
                    954:            EX_NOWAIT | EX_BOUNDZERO, (u_long *)&dvmaddr);
                    955:        splx(s);
                    956:
                    957:        if (err != 0)
                    958:                return (err);
                    959:
                    960: #ifdef DEBUG
                    961:        if (dvmaddr == (bus_addr_t)-1)  {
                    962:                printf("iommu_dvmamap_load_raw(): extent_alloc(%d, %x) "
                    963:                    "failed!\n", (int)sgsize, flags);
                    964: #ifdef DDB
                    965:                if (iommudebug & IDB_BREAK)
                    966:                        Debugger();
                    967: #else
                    968:                panic("");
                    969: #endif
                    970:        }
                    971: #endif
                    972:        if (dvmaddr == (bus_addr_t)-1)
                    973:                return (ENOMEM);
                    974:
                    975:        /* Set the active DVMA map */
                    976:        map->_dm_dvmastart = dvmaddr;
                    977:        map->_dm_dvmasize = sgsize;
                    978:
                    979:        map->dm_mapsize = size;
                    980:
                    981: #ifdef DEBUG
                    982:        iommu_dvmamap_validate_map(t, is, map);
                    983: #endif
                    984:
                    985:        if (iommu_iomap_load_map(is, ims, dvmaddr, flags))
                    986:                return (EFBIG);
                    987:
                    988:        if (segs[0]._ds_mlist)
                    989:                err = iommu_dvmamap_load_mlist(t, is, map, segs[0]._ds_mlist,
                    990:                    flags, size, boundary);
                    991:        else
                    992:                err = iommu_dvmamap_load_seg(t, is, map, segs, nsegs,
                    993:                    flags, size, boundary);
                    994:
                    995:        if (err)
                    996:                iommu_iomap_unload_map(is, ims);
                    997:
                    998: #ifdef DIAGNOSTIC
                    999:        /* The map should be valid even if the load failed */
                   1000:        if (iommu_dvmamap_validate_map(t, is, map)) {
                   1001:                printf("load size %lld/0x%llx\n", size, size);
                   1002:                if (segs[0]._ds_mlist)
                   1003:                        printf("mlist %p\n", segs[0]._ds_mlist);
                   1004:                else  {
                   1005:                        long tot_len = 0;
                   1006:                        long clip_len = 0;
                   1007:                        printf("segs %p nsegs %d\n", segs, nsegs);
                   1008:
                   1009:                        left = size;
                   1010:                        for(i = 0; i < nsegs; i++) {
                   1011:                                bus_size_t len = segs[i].ds_len;
                   1012:                                bus_addr_t addr = segs[i].ds_addr;
                   1013:                                int seg_len = MIN(left, len);
                   1014:
                   1015:                                printf("addr %llx len %lld/0x%llx seg_len "
                   1016:                                    "%d/0x%x left %d/0x%x\n", addr, len, len,
                   1017:                                    seg_len, seg_len, left, left);
                   1018:
                   1019:                                left -= seg_len;
                   1020:
                   1021:                                clip_len += seg_len;
                   1022:                                tot_len += segs[i].ds_len;
                   1023:                        }
                   1024:                        printf("total length %ld/0x%lx total seg. "
                   1025:                            "length %ld/0x%lx\n", tot_len, tot_len, clip_len,
                   1026:                            clip_len);
                   1027:                }
                   1028:
                   1029:                if (err == 0)
                   1030:                        err = 1;
                   1031:        }
                   1032:
                   1033: #endif
                   1034:
                   1035: #ifdef DEBUG
                   1036:        if (err)
                   1037:                printf("**** iommu_dvmamap_load_raw failed with error %d\n",
                   1038:                    err);
                   1039:
                   1040:        if (err || (iommudebug & IDB_PRINT_MAP)) {
                   1041:                iommu_dvmamap_print_map(t, is, map);
                   1042: #ifdef DDB
                   1043:                if (iommudebug & IDB_BREAK)
                   1044:                        Debugger();
                   1045: #endif
                   1046:        }
                   1047: #endif
                   1048:
                   1049:        return (err);
                   1050: }
                   1051:
                   1052: /*
                   1053:  * Insert a range of addresses into a loaded map respecting the specified
                   1054:  * boundary and alignment restrictions.  The range is specified by its
                   1055:  * physical address and length.  The range cannot cross a page boundary.
                   1056:  * This code (along with most of the rest of the function in this file)
                   1057:  * assumes that the IOMMU page size is equal to PAGE_SIZE.
                   1058:  */
                   1059: int
                   1060: iommu_dvmamap_append_range(bus_dma_tag_t t, bus_dmamap_t map, paddr_t pa,
                   1061:     bus_size_t length, int flags, bus_size_t boundary)
                   1062: {
                   1063:        struct iommu_map_state *ims = map->_dm_cookie;
                   1064:        bus_addr_t sgstart, sgend, bd_mask;
                   1065:        bus_dma_segment_t *seg = NULL;
                   1066:        int i = map->dm_nsegs;
                   1067:
                   1068: #ifdef DEBUG
                   1069:        if (ims == NULL)
                   1070:                panic("iommu_dvmamap_append_range: null map state");
                   1071: #endif
                   1072:
                   1073:        sgstart = iommu_iomap_translate(ims, pa);
                   1074:        sgend = sgstart + length - 1;
                   1075:
                   1076: #ifdef DIAGNOSTIC
                   1077:        if (sgstart == NULL || sgstart > sgend) {
                   1078:                printf("append range invalid mapping for %lx "
                   1079:                    "(0x%llx - 0x%llx)\n", pa, sgstart, sgend);
                   1080:                map->dm_nsegs = 0;
                   1081:                return (EINVAL);
                   1082:        }
                   1083: #endif
                   1084:
                   1085: #ifdef DEBUG
                   1086:        if (trunc_page(sgstart) != trunc_page(sgend)) {
                   1087:                printf("append range crossing page boundary! "
                   1088:                    "pa %lx length %lld/0x%llx sgstart %llx sgend %llx\n",
                   1089:                    pa, length, length, sgstart, sgend);
                   1090:        }
                   1091: #endif
                   1092:
                   1093:        /*
                   1094:         * We will attempt to merge this range with the previous entry
                   1095:         * (if there is one).
                   1096:         */
                   1097:        if (i > 0) {
                   1098:                seg = &map->dm_segs[i - 1];
                   1099:                if (sgstart == seg->ds_addr + seg->ds_len) {
                   1100:                        length += seg->ds_len;
                   1101:                        sgstart = seg->ds_addr;
                   1102:                        sgend = sgstart + length - 1;
                   1103:                } else
                   1104:                        seg = NULL;
                   1105:        }
                   1106:
                   1107:        if (seg == NULL) {
                   1108:                seg = &map->dm_segs[i];
                   1109:                if (++i > map->_dm_segcnt) {
                   1110:                        map->dm_nsegs = 0;
                   1111:                        return (EFBIG);
                   1112:                }
                   1113:        }
                   1114:
                   1115:        /*
                   1116:         * At this point, "i" is the index of the *next* bus_dma_segment_t
                   1117:         * (the segment count, aka map->dm_nsegs) and "seg" points to the
                   1118:         * *current* entry.  "length", "sgstart", and "sgend" reflect what
                   1119:         * we intend to put in "*seg".  No assumptions should be made about
                   1120:         * the contents of "*seg".  Only "boundary" issue can change this
                   1121:         * and "boundary" is often zero, so explicitly test for that case
                   1122:         * (the test is strictly an optimization).
                   1123:         */
                   1124:        if (boundary != 0) {
                   1125:                bd_mask = ~(boundary - 1);
                   1126:
                   1127:                while ((sgstart & bd_mask) != (sgend & bd_mask)) {
                   1128:                        /*
                   1129:                         * We are crossing a boundary so fill in the current
                   1130:                         * segment with as much as possible, then grab a new
                   1131:                         * one.
                   1132:                         */
                   1133:
                   1134:                        seg->ds_addr = sgstart;
                   1135:                        seg->ds_len = boundary - (sgstart & bd_mask);
                   1136:
                   1137:                        sgstart += seg->ds_len; /* sgend stays the same */
                   1138:                        length -= seg->ds_len;
                   1139:
                   1140:                        seg = &map->dm_segs[i];
                   1141:                        if (++i > map->_dm_segcnt) {
                   1142:                                map->dm_nsegs = 0;
                   1143:                                return (EFBIG);
                   1144:                        }
                   1145:                }
                   1146:        }
                   1147:
                   1148:        seg->ds_addr = sgstart;
                   1149:        seg->ds_len = length;
                   1150:        map->dm_nsegs = i;
                   1151:
                   1152:        return (0);
                   1153: }
                   1154:
                   1155: /*
                   1156:  * Populate the iomap from a bus_dma_segment_t array.  See note for
                   1157:  * iommu_dvmamap_load() * regarding page entry exhaustion of the iomap.
                   1158:  * This is less of a problem for load_seg, as the number of pages
                   1159:  * is usually similar to the number of segments (nsegs).
                   1160:  */
                   1161: int
                   1162: iommu_dvmamap_load_seg(bus_dma_tag_t t, struct iommu_state *is,
                   1163:     bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, int flags,
                   1164:     bus_size_t size, bus_size_t boundary)
                   1165: {
                   1166:        int i;
                   1167:        int left;
                   1168:        int seg;
                   1169:
                   1170:        /*
                   1171:         * This segs is made up of individual physical
                   1172:         * segments, probably by _bus_dmamap_load_uio() or
                   1173:         * _bus_dmamap_load_mbuf().  Ignore the mlist and
                   1174:         * load each one individually.
                   1175:         */
                   1176:
                   1177:        /*
                   1178:         * Keep in mind that each segment could span
                   1179:         * multiple pages and that these are not always
                   1180:         * adjacent. The code is no longer adding dvma
                   1181:         * aliases to the IOMMU.  The STC will not cross
                   1182:         * page boundaries anyway and a IOMMU table walk
                   1183:         * vs. what may be a streamed PCI DMA to a ring
                   1184:         * descriptor is probably a wash.  It eases TLB
                   1185:         * pressure and in the worst possible case, it is
                   1186:         * only as bad a non-IOMMUed architecture.  More
                   1187:         * importantly, the code is not quite as hairy.
                   1188:         * (It's bad enough as it is.)
                   1189:         */
                   1190:        left = size;
                   1191:        seg = 0;
                   1192:        for (i = 0; left > 0 && i < nsegs; i++) {
                   1193:                bus_addr_t a, aend;
                   1194:                bus_size_t len = segs[i].ds_len;
                   1195:                bus_addr_t addr = segs[i].ds_addr;
                   1196:                int seg_len = MIN(left, len);
                   1197:
                   1198:                if (len < 1)
                   1199:                        continue;
                   1200:
                   1201:                aend = round_page(addr + seg_len);
                   1202:                for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
                   1203:                        bus_addr_t pgstart;
                   1204:                        bus_addr_t pgend;
                   1205:                        int pglen;
                   1206:                        int err;
                   1207:
                   1208:                        pgstart = MAX(a, addr);
                   1209:                        pgend = MIN(a + PAGE_SIZE - 1, addr + seg_len - 1);
                   1210:                        pglen = pgend - pgstart + 1;
                   1211:
                   1212:                        if (pglen < 1)
                   1213:                                continue;
                   1214:
                   1215:                        err = iommu_dvmamap_append_range(t, map, pgstart,
                   1216:                            pglen, flags, boundary);
                   1217:                        if (err == EFBIG)
                   1218:                                return (err);
                   1219:                        if (err) {
                   1220:                                printf("iomap load seg page: %d for "
                   1221:                                    "pa 0x%llx (%llx - %llx for %d/%x\n",
                   1222:                                    err, a, pgstart, pgend, pglen, pglen);
                   1223:                                return (err);
                   1224:                        }
                   1225:
                   1226:                }
                   1227:
                   1228:                left -= seg_len;
                   1229:        }
                   1230:        return (0);
                   1231: }
                   1232:
                   1233: /*
                   1234:  * Populate the iomap from an mlist.  See note for iommu_dvmamap_load()
                   1235:  * regarding page entry exhaustion of the iomap.
                   1236:  */
                   1237: int
                   1238: iommu_dvmamap_load_mlist(bus_dma_tag_t t, struct iommu_state *is,
                   1239:     bus_dmamap_t map, struct pglist *mlist, int flags,
                   1240:     bus_size_t size, bus_size_t boundary)
                   1241: {
                   1242:        struct vm_page *m;
                   1243:        paddr_t pa;
                   1244:        int err;
                   1245:
                   1246:        /*
                   1247:         * This was allocated with bus_dmamem_alloc.
                   1248:         * The pages are on an `mlist'.
                   1249:         */
                   1250:        for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq)) {
                   1251:                pa = VM_PAGE_TO_PHYS(m);
                   1252:
                   1253:                err = iommu_dvmamap_append_range(t, map, pa, PAGE_SIZE,
                   1254:                    flags, boundary);
                   1255:                if (err == EFBIG)
                   1256:                        return (err);
                   1257:                if (err) {
                   1258:                        printf("iomap load seg page: %d for pa 0x%lx "
                   1259:                            "(%lx - %lx for %d/%x\n", err, pa, pa,
                   1260:                            pa + PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
                   1261:                        return (err);
                   1262:                }
                   1263:        }
                   1264:
                   1265:        return (0);
                   1266: }
                   1267:
                   1268: /*
                   1269:  * Unload a dvmamap.
                   1270:  */
                   1271: void
                   1272: iommu_dvmamap_unload(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map)
                   1273: {
                   1274:        struct iommu_state *is;
                   1275:        struct iommu_map_state *ims = map->_dm_cookie;
                   1276:        bus_addr_t dvmaddr = map->_dm_dvmastart;
                   1277:        bus_size_t sgsize = map->_dm_dvmasize;
                   1278:        int error, s;
                   1279:
                   1280: #ifdef DEBUG
                   1281:        if (ims == NULL)
                   1282:                panic("iommu_dvmamap_unload: null map state");
                   1283:        if (ims->ims_sb == NULL)
                   1284:                panic("iommu_dvmamap_unload: null sb");
                   1285:        if (ims->ims_sb->sb_iommu == NULL)
                   1286:                panic("iommu_dvmamap_unload: null iommu");
                   1287: #endif /* DEBUG */
                   1288:
                   1289:        is = ims->ims_sb->sb_iommu;
                   1290:
                   1291:        /* Flush the iommu */
                   1292: #ifdef DEBUG
                   1293:        if (dvmaddr == 0) {
                   1294:                printf("iommu_dvmamap_unload: No dvmastart\n");
                   1295: #ifdef DDB
                   1296:                if (iommudebug & IDB_BREAK)
                   1297:                        Debugger();
                   1298: #endif
                   1299:                return;
                   1300:        }
                   1301:        iommu_dvmamap_validate_map(t, is, map);
                   1302:
                   1303:        if (iommudebug & IDB_PRINT_MAP)
                   1304:                iommu_dvmamap_print_map(t, is, map);
                   1305: #endif /* DEBUG */
                   1306:
                   1307:        /* Remove the IOMMU entries */
                   1308:        iommu_iomap_unload_map(is, ims);
                   1309:
                   1310:        /* Clear the iomap */
                   1311:        iommu_iomap_clear_pages(ims);
                   1312:
                   1313:        bus_dmamap_unload(t->_parent, map);
                   1314:
                   1315:        /* Mark the mappings as invalid. */
                   1316:        map->dm_mapsize = 0;
                   1317:        map->dm_nsegs = 0;
                   1318:
                   1319:        s = splhigh();
                   1320:        error = extent_free(is->is_dvmamap, dvmaddr,
                   1321:                sgsize, EX_NOWAIT);
                   1322:        map->_dm_dvmastart = 0;
                   1323:        map->_dm_dvmasize = 0;
                   1324:        splx(s);
                   1325:        if (error != 0)
                   1326:                printf("warning: %qd of DVMA space lost\n", sgsize);
                   1327: }
                   1328:
                   1329: /*
                   1330:  * Perform internal consistency checking on a dvmamap.
                   1331:  */
                   1332: int
                   1333: iommu_dvmamap_validate_map(bus_dma_tag_t t, struct iommu_state *is,
                   1334:     bus_dmamap_t map)
                   1335: {
                   1336:        int err = 0;
                   1337:        int seg;
                   1338:
                   1339:        if (trunc_page(map->_dm_dvmastart) != map->_dm_dvmastart) {
                   1340:                printf("**** dvmastart address not page aligned: %llx",
                   1341:                        map->_dm_dvmastart);
                   1342:                err = 1;
                   1343:        }
                   1344:        if (trunc_page(map->_dm_dvmasize) != map->_dm_dvmasize) {
                   1345:                printf("**** dvmasize not a multiple of page size: %llx",
                   1346:                        map->_dm_dvmasize);
                   1347:                err = 1;
                   1348:        }
                   1349:        if (map->_dm_dvmastart < is->is_dvmabase ||
                   1350:            (round_page(map->_dm_dvmastart + map->_dm_dvmasize) - 1) >
                   1351:            is->is_dvmaend) {
                   1352:                printf("dvmaddr %llx len %llx out of range %x - %x\n",
                   1353:                            map->_dm_dvmastart, map->_dm_dvmasize,
                   1354:                            is->is_dvmabase, is->is_dvmaend);
                   1355:                err = 1;
                   1356:        }
                   1357:        for (seg = 0; seg < map->dm_nsegs; seg++) {
                   1358:                if (map->dm_segs[seg].ds_addr == 0 ||
                   1359:                    map->dm_segs[seg].ds_len == 0) {
                   1360:                        printf("seg %d null segment dvmaddr %llx len %llx for "
                   1361:                            "range %llx len %llx\n",
                   1362:                            seg,
                   1363:                            map->dm_segs[seg].ds_addr,
                   1364:                            map->dm_segs[seg].ds_len,
                   1365:                            map->_dm_dvmastart, map->_dm_dvmasize);
                   1366:                        err = 1;
                   1367:                } else if (map->dm_segs[seg].ds_addr < map->_dm_dvmastart ||
                   1368:                    round_page(map->dm_segs[seg].ds_addr +
                   1369:                        map->dm_segs[seg].ds_len) >
                   1370:                    map->_dm_dvmastart + map->_dm_dvmasize) {
                   1371:                        printf("seg %d dvmaddr %llx len %llx out of "
                   1372:                            "range %llx len %llx\n",
                   1373:                            seg,
                   1374:                            map->dm_segs[seg].ds_addr,
                   1375:                            map->dm_segs[seg].ds_len,
                   1376:                            map->_dm_dvmastart, map->_dm_dvmasize);
                   1377:                        err = 1;
                   1378:                }
                   1379:        }
                   1380:
                   1381:        if (err) {
                   1382:                iommu_dvmamap_print_map(t, is, map);
                   1383: #if defined(DDB) && defined(DEBUG)
                   1384:                if (iommudebug & IDB_BREAK)
                   1385:                        Debugger();
                   1386: #endif
                   1387:        }
                   1388:
                   1389:        return (err);
                   1390: }
                   1391:
                   1392: void
                   1393: iommu_dvmamap_print_map(bus_dma_tag_t t, struct iommu_state *is,
                   1394:     bus_dmamap_t map)
                   1395: {
                   1396:        int seg, i;
                   1397:        long full_len, source_len;
                   1398:        struct mbuf *m;
                   1399:
                   1400:        printf("DVMA %x for %x, mapping %p: dvstart %llx dvsize %llx "
                   1401:            "size %lld/%llx maxsegsz %llx boundary %llx segcnt %d "
                   1402:            "flags %x type %d source %p "
                   1403:            "cookie %p mapsize %llx nsegs %d\n",
                   1404:            is ? is->is_dvmabase : 0, is ? is->is_dvmaend : 0, map,
                   1405:            map->_dm_dvmastart, map->_dm_dvmasize,
                   1406:            map->_dm_size, map->_dm_size, map->_dm_maxsegsz, map->_dm_boundary,
                   1407:            map->_dm_segcnt, map->_dm_flags, map->_dm_type,
                   1408:            map->_dm_source, map->_dm_cookie, map->dm_mapsize,
                   1409:            map->dm_nsegs);
                   1410:
                   1411:        full_len = 0;
                   1412:        for (seg = 0; seg < map->dm_nsegs; seg++) {
                   1413:                printf("seg %d dvmaddr %llx pa %lx len %llx (tte %llx)\n",
                   1414:                    seg, map->dm_segs[seg].ds_addr,
                   1415:                    is ? iommu_extract(is, map->dm_segs[seg].ds_addr) : 0,
                   1416:                    map->dm_segs[seg].ds_len,
                   1417:                    is ? iommu_lookup_tte(is, map->dm_segs[seg].ds_addr) : 0);
                   1418:                full_len += map->dm_segs[seg].ds_len;
                   1419:        }
                   1420:        printf("total length = %ld/0x%lx\n", full_len, full_len);
                   1421:
                   1422:        if (map->_dm_source) switch (map->_dm_type) {
                   1423:        case _DM_TYPE_MBUF:
                   1424:                m = map->_dm_source;
                   1425:                if (m->m_flags & M_PKTHDR)
                   1426:                        printf("source PKTHDR mbuf (%p) hdr len = %d/0x%x:\n",
                   1427:                            m, m->m_pkthdr.len, m->m_pkthdr.len);
                   1428:                else
                   1429:                        printf("source mbuf (%p):\n", m);
                   1430:
                   1431:                source_len = 0;
                   1432:                for ( ; m; m = m->m_next) {
                   1433:                        vaddr_t vaddr = mtod(m, vaddr_t);
                   1434:                        long len = m->m_len;
                   1435:                        paddr_t pa;
                   1436:
                   1437:                        if (pmap_extract(pmap_kernel(), vaddr, &pa))
                   1438:                                printf("kva %lx pa %lx len %ld/0x%lx\n",
                   1439:                                    vaddr, pa, len, len);
                   1440:                        else
                   1441:                                printf("kva %lx pa <invalid> len %ld/0x%lx\n",
                   1442:                                    vaddr, len, len);
                   1443:
                   1444:                        source_len += len;
                   1445:                }
                   1446:
                   1447:                if (full_len != source_len)
                   1448:                        printf("mbuf length %ld/0x%lx is %s than mapping "
                   1449:                            "length %ld/0x%lx\n", source_len, source_len,
                   1450:                            (source_len > full_len) ? "greater" : "less",
                   1451:                            full_len, full_len);
                   1452:                else
                   1453:                        printf("mbuf length %ld/0x%lx\n", source_len,
                   1454:                            source_len);
                   1455:                break;
                   1456:        case _DM_TYPE_LOAD:
                   1457:        case _DM_TYPE_SEGS:
                   1458:        case _DM_TYPE_UIO:
                   1459:        default:
                   1460:                break;
                   1461:        }
                   1462:
                   1463:        if (map->_dm_cookie) {
                   1464:                struct iommu_map_state *ims = map->_dm_cookie;
                   1465:                struct iommu_page_map *ipm = &ims->ims_map;
                   1466:
                   1467:                printf("page map (%p) of size %d with %d entries\n",
                   1468:                    ipm, ipm->ipm_maxpage, ipm->ipm_pagecnt);
                   1469:                for (i = 0; i < ipm->ipm_pagecnt; ++i) {
                   1470:                        struct iommu_page_entry *e = &ipm->ipm_map[i];
                   1471:                        printf("%d: vmaddr 0x%lx pa 0x%lx\n", i,
                   1472:                            e->ipe_va, e->ipe_pa);
                   1473:                }
                   1474:        } else
                   1475:                printf("iommu map state (cookie) is NULL\n");
                   1476: }
                   1477:
                   1478: void
                   1479: _iommu_dvmamap_sync(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
                   1480:        bus_addr_t offset, bus_size_t len, int ops)
                   1481: {
                   1482:        struct iommu_state *is;
                   1483:        struct iommu_map_state *ims = map->_dm_cookie;
                   1484:        struct strbuf_ctl *sb;
                   1485:        bus_size_t count;
                   1486:        int i, needsflush = 0;
                   1487:
                   1488:        sb = ims->ims_sb;
                   1489:        is = sb->sb_iommu;
                   1490:
                   1491:        for (i = 0; i < map->dm_nsegs; i++) {
                   1492:                if (offset < map->dm_segs[i].ds_len)
                   1493:                        break;
                   1494:                offset -= map->dm_segs[i].ds_len;
                   1495:        }
                   1496:
                   1497:        if (i == map->dm_nsegs)
                   1498:                panic("iommu_dvmamap_sync: too short %llu", offset);
                   1499:
                   1500:        for (; len > 0 && i < map->dm_nsegs; i++) {
                   1501:                count = MIN(map->dm_segs[i].ds_len - offset, len);
                   1502:                if (count > 0 && iommu_dvmamap_sync_range(sb,
                   1503:                    map->dm_segs[i].ds_addr + offset, count))
                   1504:                        needsflush = 1;
                   1505:                len -= count;
                   1506:        }
                   1507:
                   1508: #ifdef DIAGNOSTIC
                   1509:        if (i == map->dm_nsegs && len > 0)
                   1510:                panic("iommu_dvmamap_sync: leftover %llu", len);
                   1511: #endif
                   1512:
                   1513:        if (needsflush)
                   1514:                iommu_strbuf_flush_done(ims);
                   1515: }
                   1516:
                   1517: void
                   1518: iommu_dvmamap_sync(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
                   1519:     bus_addr_t offset, bus_size_t len, int ops)
                   1520: {
                   1521:        struct iommu_map_state *ims = map->_dm_cookie;
                   1522:
                   1523: #ifdef DIAGNOSTIC
                   1524:        if (ims == NULL)
                   1525:                panic("iommu_dvmamap_sync: null map state");
                   1526:        if (ims->ims_sb == NULL)
                   1527:                panic("iommu_dvmamap_sync: null sb");
                   1528:        if (ims->ims_sb->sb_iommu == NULL)
                   1529:                panic("iommu_dvmamap_sync: null iommu");
                   1530: #endif
                   1531:        if (len == 0)
                   1532:                return;
                   1533:
                   1534:        if (ops & BUS_DMASYNC_PREWRITE)
                   1535:                membar(MemIssue);
                   1536:
                   1537:        if ((ims->ims_flags & IOMMU_MAP_STREAM) &&
                   1538:            (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE)))
                   1539:                _iommu_dvmamap_sync(t, t0, map, offset, len, ops);
                   1540:
                   1541:        if (ops & BUS_DMASYNC_POSTREAD)
                   1542:                membar(MemIssue);
                   1543: }
                   1544:
                   1545: /*
                   1546:  * Flush an individual dma segment, returns non-zero if the streaming buffers
                   1547:  * need flushing afterwards.
                   1548:  */
                   1549: int
                   1550: iommu_dvmamap_sync_range(struct strbuf_ctl *sb, vaddr_t va, bus_size_t len)
                   1551: {
                   1552:        vaddr_t vaend;
                   1553: #ifdef DIAGNOSTIC
                   1554:        struct iommu_state *is = sb->sb_iommu;
                   1555:
                   1556:        if (va < is->is_dvmabase || va > is->is_dvmaend)
                   1557:                panic("invalid va: %llx", (long long)va);
                   1558:
                   1559:        if ((is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)] & IOTTE_STREAM) == 0) {
                   1560:                printf("iommu_dvmamap_sync_range: attempting to flush "
                   1561:                    "non-streaming entry\n");
                   1562:                return (0);
                   1563:        }
                   1564: #endif
                   1565:
                   1566:        vaend = (va + len + PAGE_MASK) & ~PAGE_MASK;
                   1567:        va &= ~PAGE_MASK;
                   1568:
                   1569: #ifdef DIAGNOSTIC
                   1570:        if (va < is->is_dvmabase || (vaend - 1) > is->is_dvmaend)
                   1571:                panic("invalid va range: %llx to %llx (%x to %x)",
                   1572:                    (long long)va, (long long)vaend,
                   1573:                    is->is_dvmabase,
                   1574:                    is->is_dvmaend);
                   1575: #endif
                   1576:
                   1577:        for ( ; va <= vaend; va += PAGE_SIZE) {
                   1578:                DPRINTF(IDB_BUSDMA,
                   1579:                    ("iommu_dvmamap_sync_range: flushing va %p\n",
                   1580:                    (void *)(u_long)va));
                   1581:                iommu_strbuf_flush(sb, va);
                   1582:        }
                   1583:
                   1584:        return (1);
                   1585: }
                   1586:
                   1587: int
                   1588: iommu_dvmamem_alloc(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
                   1589:     bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
                   1590:     int nsegs, int *rsegs, int flags)
                   1591: {
                   1592:
                   1593:        DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_alloc: sz %llx align %llx "
                   1594:            "bound %llx segp %p flags %d\n", (unsigned long long)size,
                   1595:            (unsigned long long)alignment, (unsigned long long)boundary,
                   1596:            segs, flags));
                   1597:        BUS_DMA_FIND_PARENT(t, _dmamem_alloc);
                   1598:        return ((*t->_dmamem_alloc)(t, t0, size, alignment, boundary,
                   1599:            segs, nsegs, rsegs, flags | BUS_DMA_DVMA));
                   1600: }
                   1601:
                   1602: void
                   1603: iommu_dvmamem_free(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dma_segment_t *segs,
                   1604:     int nsegs)
                   1605: {
                   1606:
                   1607:        DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_free: segp %p nsegs %d\n",
                   1608:            segs, nsegs));
                   1609:        BUS_DMA_FIND_PARENT(t, _dmamem_free);
                   1610:        (*t->_dmamem_free)(t, t0, segs, nsegs);
                   1611: }
                   1612:
                   1613: /*
                   1614:  * Map the DVMA mappings into the kernel pmap.
                   1615:  * Check the flags to see whether we're streaming or coherent.
                   1616:  */
                   1617: int
                   1618: iommu_dvmamem_map(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dma_segment_t *segs,
                   1619:     int nsegs, size_t size, caddr_t *kvap, int flags)
                   1620: {
                   1621:        struct vm_page *m;
                   1622:        vaddr_t va;
                   1623:        bus_addr_t addr;
                   1624:        struct pglist *mlist;
                   1625:        bus_addr_t cbit = 0;
                   1626:
                   1627:        DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_map: segp %p nsegs %d size %lx\n",
                   1628:            segs, nsegs, size));
                   1629:
                   1630:        /*
                   1631:         * Allocate some space in the kernel map, and then map these pages
                   1632:         * into this space.
                   1633:         */
                   1634:        size = round_page(size);
                   1635:        va = uvm_km_valloc(kernel_map, size);
                   1636:        if (va == 0)
                   1637:                return (ENOMEM);
                   1638:
                   1639:        *kvap = (caddr_t)va;
                   1640:
                   1641:        /*
                   1642:         * digest flags:
                   1643:         */
                   1644: #if 0
                   1645:        if (flags & BUS_DMA_COHERENT)   /* Disable vcache */
                   1646:                cbit |= PMAP_NVC;
                   1647: #endif
                   1648:        if (flags & BUS_DMA_NOCACHE)    /* sideffects */
                   1649:                cbit |= PMAP_NC;
                   1650:
                   1651:        /*
                   1652:         * Now take this and map it into the CPU.
                   1653:         */
                   1654:        mlist = segs[0]._ds_mlist;
                   1655:        TAILQ_FOREACH(m, mlist, pageq) {
                   1656: #ifdef DIAGNOSTIC
                   1657:                if (size == 0)
                   1658:                        panic("iommu_dvmamem_map: size botch");
                   1659: #endif
                   1660:                addr = VM_PAGE_TO_PHYS(m);
                   1661:                DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_map: "
                   1662:                    "mapping va %lx at %llx\n", va,
                   1663:                    (unsigned long long)addr | cbit));
                   1664:                pmap_enter(pmap_kernel(), va, addr | cbit,
                   1665:                    VM_PROT_READ | VM_PROT_WRITE,
                   1666:                    VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
                   1667:                va += PAGE_SIZE;
                   1668:                size -= PAGE_SIZE;
                   1669:        }
                   1670:        pmap_update(pmap_kernel());
                   1671:
                   1672:        return (0);
                   1673: }
                   1674:
                   1675: /*
                   1676:  * Unmap DVMA mappings from kernel
                   1677:  */
                   1678: void
                   1679: iommu_dvmamem_unmap(bus_dma_tag_t t, bus_dma_tag_t t0, caddr_t kva,
                   1680:     size_t size)
                   1681: {
                   1682:
                   1683:        DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_unmap: kvm %p size %lx\n",
                   1684:            kva, size));
                   1685:
                   1686: #ifdef DIAGNOSTIC
                   1687:        if ((u_long)kva & PAGE_MASK)
                   1688:                panic("iommu_dvmamem_unmap");
                   1689: #endif
                   1690:
                   1691:        size = round_page(size);
                   1692:        pmap_remove(pmap_kernel(), (vaddr_t)kva, size);
                   1693:        pmap_update(pmap_kernel());
                   1694:        uvm_km_free(kernel_map, (vaddr_t)kva, size);
                   1695: }
                   1696:
                   1697: /*
                   1698:  * Create a new iomap.
                   1699:  */
                   1700: struct iommu_map_state *
                   1701: iommu_iomap_create(int n)
                   1702: {
                   1703:        struct iommu_map_state *ims;
                   1704:        struct strbuf_flush *sbf;
                   1705:        vaddr_t va;
                   1706:
                   1707:        /* Safety for heavily fragmented data, such as mbufs */
                   1708:        n += 4;
                   1709:        if (n < 16)
                   1710:                n = 16;
                   1711:
                   1712:        ims = malloc(sizeof(*ims) + (n - 1) * sizeof(ims->ims_map.ipm_map[0]),
                   1713:                M_DEVBUF, M_NOWAIT);
                   1714:        if (ims == NULL)
                   1715:                return (NULL);
                   1716:
                   1717:        memset(ims, 0, sizeof *ims);
                   1718:
                   1719:        /* Initialize the map. */
                   1720:        ims->ims_map.ipm_maxpage = n;
                   1721:        SPLAY_INIT(&ims->ims_map.ipm_tree);
                   1722:
                   1723:        /* Initialize the flush area. */
                   1724:        sbf = &ims->ims_flush;
                   1725:        va = (vaddr_t)&sbf->sbf_area[0x40];
                   1726:        va &= ~0x3f;
                   1727:        pmap_extract(pmap_kernel(), va, &sbf->sbf_flushpa);
                   1728:        sbf->sbf_flush = (void *)va;
                   1729:
                   1730:        return (ims);
                   1731: }
                   1732:
                   1733: /*
                   1734:  * Destroy an iomap.
                   1735:  */
                   1736: void
                   1737: iommu_iomap_destroy(struct iommu_map_state *ims)
                   1738: {
                   1739: #ifdef DIAGNOSTIC
                   1740:        if (ims->ims_map.ipm_pagecnt > 0)
                   1741:                printf("iommu_iomap_destroy: %d page entries in use\n",
                   1742:                    ims->ims_map.ipm_pagecnt);
                   1743: #endif
                   1744:
                   1745:        free(ims, M_DEVBUF);
                   1746: }
                   1747:
                   1748: /*
                   1749:  * Utility function used by splay tree to order page entries by pa.
                   1750:  */
                   1751: static inline int
                   1752: iomap_compare(struct iommu_page_entry *a, struct iommu_page_entry *b)
                   1753: {
                   1754:        return ((a->ipe_pa > b->ipe_pa) ? 1 :
                   1755:                (a->ipe_pa < b->ipe_pa) ? -1 : 0);
                   1756: }
                   1757:
                   1758: SPLAY_PROTOTYPE(iommu_page_tree, iommu_page_entry, ipe_node, iomap_compare);
                   1759:
                   1760: SPLAY_GENERATE(iommu_page_tree, iommu_page_entry, ipe_node, iomap_compare);
                   1761:
                   1762: /*
                   1763:  * Insert a pa entry in the iomap.
                   1764:  */
                   1765: int
                   1766: iommu_iomap_insert_page(struct iommu_map_state *ims, paddr_t pa)
                   1767: {
                   1768:        struct iommu_page_map *ipm = &ims->ims_map;
                   1769:        struct iommu_page_entry *e;
                   1770:
                   1771:        if (ipm->ipm_pagecnt >= ipm->ipm_maxpage) {
                   1772:                struct iommu_page_entry ipe;
                   1773:
                   1774:                ipe.ipe_pa = pa;
                   1775:                if (SPLAY_FIND(iommu_page_tree, &ipm->ipm_tree, &ipe))
                   1776:                        return (0);
                   1777:
                   1778:                return (ENOMEM);
                   1779:        }
                   1780:
                   1781:        e = &ipm->ipm_map[ipm->ipm_pagecnt];
                   1782:
                   1783:        e->ipe_pa = pa;
                   1784:        e->ipe_va = NULL;
                   1785:
                   1786:        e = SPLAY_INSERT(iommu_page_tree, &ipm->ipm_tree, e);
                   1787:
                   1788:        /* Duplicates are okay, but only count them once. */
                   1789:        if (e)
                   1790:                return (0);
                   1791:
                   1792:        ++ipm->ipm_pagecnt;
                   1793:
                   1794:        return (0);
                   1795: }
                   1796:
                   1797: /*
                   1798:  * Locate the iomap by filling in the pa->va mapping and inserting it
                   1799:  * into the IOMMU tables.
                   1800:  */
                   1801: int
                   1802: iommu_iomap_load_map(struct iommu_state *is, struct iommu_map_state *ims,
                   1803:     vaddr_t vmaddr, int flags)
                   1804: {
                   1805:        struct iommu_page_map *ipm = &ims->ims_map;
                   1806:        struct iommu_page_entry *e;
                   1807:        struct strbuf_ctl *sb = ims->ims_sb;
                   1808:        int i;
                   1809:
                   1810:        if (sb->sb_flush == NULL)
                   1811:                flags &= ~BUS_DMA_STREAMING;
                   1812:
                   1813:        if (flags & BUS_DMA_STREAMING)
                   1814:                ims->ims_flags |= IOMMU_MAP_STREAM;
                   1815:        else
                   1816:                ims->ims_flags &= ~IOMMU_MAP_STREAM;
                   1817:
                   1818:        for (i = 0, e = ipm->ipm_map; i < ipm->ipm_pagecnt; ++i, ++e) {
                   1819:                e->ipe_va = vmaddr;
                   1820:                iommu_enter(is, sb, e->ipe_va, e->ipe_pa, flags);
                   1821:                vmaddr += PAGE_SIZE;
                   1822:        }
                   1823:
                   1824:        return (0);
                   1825: }
                   1826:
                   1827: /*
                   1828:  * Remove the iomap from the IOMMU.
                   1829:  */
                   1830: int
                   1831: iommu_iomap_unload_map(struct iommu_state *is, struct iommu_map_state *ims)
                   1832: {
                   1833:        struct iommu_page_map *ipm = &ims->ims_map;
                   1834:        struct iommu_page_entry *e;
                   1835:        struct strbuf_ctl *sb = ims->ims_sb;
                   1836:        int i;
                   1837:
                   1838:        for (i = 0, e = ipm->ipm_map; i < ipm->ipm_pagecnt; ++i, ++e)
                   1839:                iommu_remove(is, sb, e->ipe_va);
                   1840:
                   1841:        return (0);
                   1842: }
                   1843:
                   1844: /*
                   1845:  * Translate a physical address (pa) into a DVMA address.
                   1846:  */
                   1847: vaddr_t
                   1848: iommu_iomap_translate(struct iommu_map_state *ims, paddr_t pa)
                   1849: {
                   1850:        struct iommu_page_map *ipm = &ims->ims_map;
                   1851:        struct iommu_page_entry *e;
                   1852:        struct iommu_page_entry pe;
                   1853:        paddr_t offset = pa & PAGE_MASK;
                   1854:
                   1855:        pe.ipe_pa = trunc_page(pa);
                   1856:
                   1857:        e = SPLAY_FIND(iommu_page_tree, &ipm->ipm_tree, &pe);
                   1858:
                   1859:        if (e == NULL)
                   1860:                return (NULL);
                   1861:
                   1862:        return (e->ipe_va | offset);
                   1863: }
                   1864:
                   1865: /*
                   1866:  * Clear the iomap table and tree.
                   1867:  */
                   1868: void
                   1869: iommu_iomap_clear_pages(struct iommu_map_state *ims)
                   1870: {
                   1871:        ims->ims_map.ipm_pagecnt = 0;
                   1872:        SPLAY_INIT(&ims->ims_map.ipm_tree);
                   1873: }
                   1874:

CVSweb