[BACK]Return to int_bus_dma.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / evbarm / integrator

Annotation of src/sys/arch/evbarm/integrator/int_bus_dma.c, Revision 1.3

1.3     ! thorpej     1: /*     $NetBSD: int_bus_dma.c,v 1.2 2001/11/23 19:36:50 thorpej Exp $  */
1.1       rearnsha    2:
                      3: /*-
                      4:  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
                      9:  * NASA Ames Research Center.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by the NetBSD
                     22:  *     Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39: /*
                     40:  * The integrator board has memory steering hardware that means that
                     41:  * the normal physical addresses used by the processor cannot be used
                     42:  * for DMA.  Instead we have to use the "core module alias mapping
                     43:  * addresses".  We don't use these for normal processor accesses since
                     44:  * they are much slower than the direct addresses when accessing
                     45:  * memory on the local board.
                     46:  */
                     47:
                     48: #include <sys/param.h>
                     49: #include <sys/systm.h>
                     50: #include <sys/kernel.h>
                     51: #include <sys/map.h>
                     52: #include <sys/proc.h>
                     53: #include <sys/buf.h>
                     54: #include <sys/reboot.h>
                     55: #include <sys/conf.h>
                     56: #include <sys/file.h>
                     57: #include <sys/malloc.h>
                     58: #include <sys/mbuf.h>
                     59: #include <sys/vnode.h>
                     60: #include <sys/device.h>
                     61:
                     62: #include <uvm/uvm_extern.h>
                     63:
                     64: #define _ARM32_BUS_DMA_PRIVATE
                     65: #include <evbarm/integrator/int_bus_dma.h>
                     66:
                     67: #include <machine/cpu.h>
1.2       thorpej    68: #include <arm/cpufunc.h>
1.1       rearnsha   69:
                     70: static int     integrator_bus_dmamap_load_buffer __P((bus_dma_tag_t,
                     71:                    bus_dmamap_t, void *, bus_size_t, struct proc *, int,
                     72:                    vm_offset_t *, int *, int));
                     73: static int     integrator_bus_dma_inrange __P((bus_dma_segment_t *, int,
                     74:                    bus_addr_t));
                     75:
                     76: /*
                     77:  * Common function for loading a DMA map with a linear buffer.  May
                     78:  * be called by bus-specific DMA map load functions.
                     79:  */
                     80: int
                     81: integrator_bus_dmamap_load(t, map, buf, buflen, p, flags)
                     82:        bus_dma_tag_t t;
                     83:        bus_dmamap_t map;
                     84:        void *buf;
                     85:        bus_size_t buflen;
                     86:        struct proc *p;
                     87:        int flags;
                     88: {
                     89:        vm_offset_t lastaddr;
                     90:        int seg, error;
                     91:
                     92: #ifdef DEBUG_DMA
                     93:        printf("dmamap_load: t=%p map=%p buf=%p len=%lx p=%p f=%d\n",
                     94:            t, map, buf, buflen, p, flags);
                     95: #endif /* DEBUG_DMA */
                     96:
                     97:        /*
                     98:         * Make sure that on error condition we return "no valid mappings".
                     99:         */
                    100:        map->dm_mapsize = 0;
                    101:        map->dm_nsegs = 0;
                    102:
                    103:        if (buflen > map->_dm_size)
                    104:                return (EINVAL);
                    105:
                    106:        seg = 0;
                    107:        error = integrator_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
                    108:            &lastaddr, &seg, 1);
                    109:        if (error == 0) {
                    110:                map->dm_mapsize = buflen;
                    111:                map->dm_nsegs = seg + 1;
                    112:        }
                    113: #ifdef DEBUG_DMA
                    114:        printf("dmamap_load: error=%d\n", error);
                    115: #endif /* DEBUG_DMA */
                    116:        return (error);
                    117: }
                    118:
                    119: /*
                    120:  * Like _bus_dmamap_load(), but for mbufs.
                    121:  */
                    122: int
                    123: integrator_bus_dmamap_load_mbuf(t, map, m0, flags)
                    124:        bus_dma_tag_t t;
                    125:        bus_dmamap_t map;
                    126:        struct mbuf *m0;
                    127:        int flags;
                    128: {
                    129:        vm_offset_t lastaddr;
                    130:        int seg, error, first;
                    131:        struct mbuf *m;
                    132:
                    133: #ifdef DEBUG_DMA
                    134:        printf("dmamap_load_mbuf: t=%p map=%p m0=%p f=%d\n",
                    135:            t, map, m0, flags);
                    136: #endif /* DEBUG_DMA */
                    137:
                    138:        /*
                    139:         * Make sure that on error condition we return "no valid mappings."
                    140:         */
                    141:        map->dm_mapsize = 0;
                    142:        map->dm_nsegs = 0;
                    143:
                    144: #ifdef DIAGNOSTIC
                    145:        if ((m0->m_flags & M_PKTHDR) == 0)
                    146:                panic("integrator_bus_dmamap_load_mbuf: no packet header");
                    147: #endif /* DIAGNOSTIC */
                    148:
                    149:        if (m0->m_pkthdr.len > map->_dm_size)
                    150:                return (EINVAL);
                    151:
                    152:        first = 1;
                    153:        seg = 0;
                    154:        error = 0;
                    155:        for (m = m0; m != NULL && error == 0; m = m->m_next) {
                    156:                error = integrator_bus_dmamap_load_buffer(t, map, m->m_data,
                    157:                    m->m_len, NULL, flags, &lastaddr, &seg, first);
                    158:                first = 0;
                    159:        }
                    160:        if (error == 0) {
                    161:                map->dm_mapsize = m0->m_pkthdr.len;
                    162:                map->dm_nsegs = seg + 1;
                    163:        }
                    164: #ifdef DEBUG_DMA
                    165:        printf("dmamap_load_mbuf: error=%d\n", error);
                    166: #endif /* DEBUG_DMA */
                    167:        return (error);
                    168: }
                    169:
                    170: /*
                    171:  * Like _bus_dmamap_load(), but for uios.
                    172:  */
                    173: int
                    174: integrator_bus_dmamap_load_uio(t, map, uio, flags)
                    175:        bus_dma_tag_t t;
                    176:        bus_dmamap_t map;
                    177:        struct uio *uio;
                    178:        int flags;
                    179: {
                    180:        vm_offset_t lastaddr;
                    181:        int seg, i, error, first;
                    182:        bus_size_t minlen, resid;
                    183:        struct proc *p = NULL;
                    184:        struct iovec *iov;
                    185:        caddr_t addr;
                    186:
                    187:        /*
                    188:         * Make sure that on error condition we return "no valid mappings."
                    189:         */
                    190:        map->dm_mapsize = 0;
                    191:        map->dm_nsegs = 0;
                    192:
                    193:        resid = uio->uio_resid;
                    194:        iov = uio->uio_iov;
                    195:
                    196:        if (uio->uio_segflg == UIO_USERSPACE) {
                    197:                p = uio->uio_procp;
                    198: #ifdef DIAGNOSTIC
                    199:                if (p == NULL)
                    200:                        panic("integrator_bus_dmamap_load_uio: USERSPACE but no proc");
                    201: #endif
                    202:        }
                    203:
                    204:        first = 1;
                    205:        seg = 0;
                    206:        error = 0;
                    207:        for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
                    208:                /*
                    209:                 * Now at the first iovec to load.  Load each iovec
                    210:                 * until we have exhausted the residual count.
                    211:                 */
                    212:                minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
                    213:                addr = (caddr_t)iov[i].iov_base;
                    214:
                    215:                error = integrator_bus_dmamap_load_buffer(t, map, addr, minlen,
                    216:                    p, flags, &lastaddr, &seg, first);
                    217:                first = 0;
                    218:
                    219:                resid -= minlen;
                    220:        }
                    221:        if (error == 0) {
                    222:                map->dm_mapsize = uio->uio_resid;
                    223:                map->dm_nsegs = seg + 1;
                    224:        }
                    225:        return (error);
                    226: }
                    227:
                    228: /*
                    229:  * Common function for DMA-safe memory allocation.  May be called
                    230:  * by bus-specific DMA memory allocation functions.
                    231:  */
                    232:
                    233: extern vm_offset_t physical_start;
                    234: extern vm_offset_t physical_freestart;
                    235: extern vm_offset_t physical_freeend;
                    236: extern vm_offset_t physical_end;
                    237:
                    238: int
                    239: integrator_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
                    240:        bus_dma_tag_t t;
                    241:        bus_size_t size, alignment, boundary;
                    242:        bus_dma_segment_t *segs;
                    243:        int nsegs;
                    244:        int *rsegs;
                    245:        int flags;
                    246: {
                    247:        int error;
                    248: #ifdef DEBUG_DMA
                    249:        printf("dmamem_alloc t=%p size=%lx align=%lx boundary=%lx segs=%p nsegs=%x rsegs=%p flags=%x\n",
                    250:            t, size, alignment, boundary, segs, nsegs, rsegs, flags);
                    251: #endif /* DEBUG_DMA */
                    252:        error =  (integrator_bus_dmamem_alloc_range(t, size, alignment, boundary,
                    253:            segs, nsegs, rsegs, flags, trunc_page(physical_start), trunc_page(physical_end)));
                    254: #ifdef DEBUG_DMA
                    255:        printf("dmamem_alloc: =%d\n", error);
                    256: #endif /* DEBUG_DMA */
                    257:        return(error);
                    258: }
                    259:
                    260: /*
                    261:  * Common function for freeing DMA-safe memory.  May be called by
                    262:  * bus-specific DMA memory free functions.
                    263:  */
                    264: void
                    265: integrator_bus_dmamem_free(t, segs, nsegs)
                    266:        bus_dma_tag_t t;
                    267:        bus_dma_segment_t *segs;
                    268:        int nsegs;
                    269: {
                    270:        struct vm_page *m;
                    271:        bus_addr_t addr;
                    272:        struct pglist mlist;
                    273:        int curseg;
                    274:
                    275: #ifdef DEBUG_DMA
                    276:        printf("dmamem_free: t=%p segs=%p nsegs=%x\n", t, segs, nsegs);
                    277: #endif /* DEBUG_DMA */
                    278:
                    279:        /*
                    280:         * Build a list of pages to free back to the VM system.
                    281:         */
                    282:        TAILQ_INIT(&mlist);
                    283:        for (curseg = 0; curseg < nsegs; curseg++) {
                    284:                for (addr = segs[curseg].ds_addr;
                    285:                    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
                    286:                    addr += PAGE_SIZE) {
                    287:                        m = PHYS_TO_VM_PAGE(CM_ALIAS_TO_LOCAL(addr));
                    288:                        TAILQ_INSERT_TAIL(&mlist, m, pageq);
                    289:                }
                    290:        }
                    291:        uvm_pglistfree(&mlist);
                    292: }
                    293:
                    294: /*
                    295:  * Common function for mapping DMA-safe memory.  May be called by
                    296:  * bus-specific DMA memory map functions.
                    297:  */
                    298: int
                    299: integrator_bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
                    300:        bus_dma_tag_t t;
                    301:        bus_dma_segment_t *segs;
                    302:        int nsegs;
                    303:        size_t size;
                    304:        caddr_t *kvap;
                    305:        int flags;
                    306: {
                    307:        vm_offset_t va;
                    308:        bus_addr_t addr;
                    309:        int curseg;
                    310:        pt_entry_t *ptep/*, pte*/;
                    311:
                    312: #ifdef DEBUG_DMA
                    313:        printf("dmamem_map: t=%p segs=%p nsegs=%x size=%lx flags=%x\n", t,
                    314:            segs, nsegs, (unsigned long)size, flags);
                    315: #endif /* DEBUG_DMA */
                    316:
                    317:        size = round_page(size);
                    318:        va = uvm_km_valloc(kernel_map, size);
                    319:
                    320:        if (va == 0)
                    321:                return (ENOMEM);
                    322:
                    323:        *kvap = (caddr_t)va;
                    324:
                    325:        for (curseg = 0; curseg < nsegs; curseg++) {
                    326:                for (addr = segs[curseg].ds_addr;
                    327:                    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
                    328:                    addr += NBPG, va += NBPG, size -= NBPG) {
                    329: #ifdef DEBUG_DMA
                    330:                        printf("wiring p%lx to v%lx", CM_ALIAS_TO_LOCAL(addr),
                    331:                            va);
                    332: #endif /* DEBUG_DMA */
                    333:                        if (size == 0)
                    334:                                panic("integrator_bus_dmamem_map: size botch");
                    335:                        pmap_enter(pmap_kernel(), va, CM_ALIAS_TO_LOCAL(addr),
                    336:                            VM_PROT_READ | VM_PROT_WRITE,
                    337:                            VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
                    338:                        /*
                    339:                         * If the memory must remain coherent with the
                    340:                         * cache then we must make the memory uncacheable
                    341:                         * in order to maintain virtual cache coherency.
                    342:                         * We must also guarentee the cache does not already
                    343:                         * contain the virtal addresses we are making
                    344:                         * uncacheable.
                    345:                         */
                    346:                        if (flags & BUS_DMA_COHERENT) {
                    347:                                cpu_cache_purgeD_rng(va, NBPG);
                    348:                                cpu_drain_writebuf();
                    349:                                ptep = vtopte(va);
                    350:                                *ptep = ((*ptep) & (~PT_C | PT_B));
                    351:                                tlb_flush();
                    352:                        }
                    353: #ifdef DEBUG_DMA
                    354:                        ptep = vtopte(va);
                    355:                        printf(" pte=v%p *pte=%x\n", ptep, *ptep);
                    356: #endif /* DEBUG_DMA */
                    357:                }
                    358:        }
                    359:        pmap_update(pmap_kernel());
                    360: #ifdef DEBUG_DMA
                    361:        printf("dmamem_map: =%p\n", *kvap);
                    362: #endif /* DEBUG_DMA */
                    363:        return (0);
                    364: }
                    365:
                    366: /*
                    367:  * Common functin for mmap(2)'ing DMA-safe memory.  May be called by
                    368:  * bus-specific DMA mmap(2)'ing functions.
                    369:  */
                    370: paddr_t
                    371: integrator_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
                    372:        bus_dma_tag_t t;
                    373:        bus_dma_segment_t *segs;
                    374:        int nsegs;
                    375:        off_t off;
                    376:        int prot, flags;
                    377: {
                    378:        int i;
                    379:
                    380:        for (i = 0; i < nsegs; i++) {
                    381: #ifdef DIAGNOSTIC
                    382:                if (off & PGOFSET)
                    383:                        panic("integrator_bus_dmamem_mmap: offset unaligned");
                    384:                if (segs[i].ds_addr & PGOFSET)
                    385:                        panic("integrator_bus_dmamem_mmap: segment unaligned");
                    386:                if (segs[i].ds_len & PGOFSET)
                    387:                        panic("integrator_bus_dmamem_mmap: segment size not multiple"
                    388:                            " of page size");
                    389: #endif /* DIAGNOSTIC */
                    390:                if (off >= segs[i].ds_len) {
                    391:                        off -= segs[i].ds_len;
                    392:                        continue;
                    393:                }
                    394:
                    395:                return arm_byte_to_page((u_long)CM_ALIAS_TO_LOCAL(segs[i].ds_addr) + off);
                    396:        }
                    397:
                    398:        /* Page not found. */
                    399:        return -1;
                    400: }
                    401:
                    402: /**********************************************************************
                    403:  * DMA utility functions
                    404:  **********************************************************************/
                    405:
                    406: /*
                    407:  * Utility function to load a linear buffer.  lastaddrp holds state
                    408:  * between invocations (for multiple-buffer loads).  segp contains
                    409:  * the starting segment on entrace, and the ending segment on exit.
                    410:  * first indicates if this is the first invocation of this function.
                    411:  */
                    412: static int
                    413: integrator_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp,
                    414:     segp, first)
                    415:        bus_dma_tag_t t;
                    416:        bus_dmamap_t map;
                    417:        void *buf;
                    418:        bus_size_t buflen;
                    419:        struct proc *p;
                    420:        int flags;
                    421:        vm_offset_t *lastaddrp;
                    422:        int *segp;
                    423:        int first;
                    424: {
                    425:        bus_size_t sgsize;
                    426:        bus_addr_t curaddr, lastaddr, baddr, bmask;
                    427:        vm_offset_t vaddr = (vm_offset_t)buf;
                    428:        int seg;
                    429:        pmap_t pmap;
                    430:
                    431: #ifdef DEBUG_DMA
                    432:        printf("integrator_bus_dmamem_load_buffer(buf=%p, len=%lx, flags=%d, 1st=%d)\n",
                    433:            buf, buflen, flags, first);
                    434: #endif /* DEBUG_DMA */
                    435:
                    436:        if (p != NULL)
                    437:                pmap = p->p_vmspace->vm_map.pmap;
                    438:        else
                    439:                pmap = pmap_kernel();
                    440:
                    441:        lastaddr = *lastaddrp;
                    442:        bmask  = ~(map->_dm_boundary - 1);
                    443:
                    444:        for (seg = *segp; buflen > 0; ) {
                    445:                /*
                    446:                 * Get the physical address for this segment.
                    447:                 */
                    448:                (void) pmap_extract(pmap, (vaddr_t)vaddr, &curaddr);
                    449:
                    450:                /*
                    451:                 * Make sure we're in an allowed DMA range.
                    452:                 */
                    453:                if (t->_ranges != NULL &&
                    454:                    integrator_bus_dma_inrange(t->_ranges, t->_nranges, curaddr) == 0)
                    455:                        return (EINVAL);
                    456:
                    457:                /*
                    458:                 * Compute the segment size, and adjust counts.
                    459:                 */
                    460:                sgsize = NBPG - ((u_long)vaddr & PGOFSET);
                    461:                if (buflen < sgsize)
                    462:                        sgsize = buflen;
                    463:
                    464:                /*
                    465:                 * Make sure we don't cross any boundaries.
                    466:                 */
                    467:                if (map->_dm_boundary > 0) {
                    468:                        baddr = (curaddr + map->_dm_boundary) & bmask;
                    469:                        if (sgsize > (baddr - curaddr))
                    470:                                sgsize = (baddr - curaddr);
                    471:                }
                    472:
                    473:                /*
                    474:                 * Insert chunk into a segment, coalescing with
                    475:                 * previous segment if possible.
                    476:                 */
                    477:                if (first) {
                    478:                        map->dm_segs[seg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
                    479:                        map->dm_segs[seg].ds_len = sgsize;
                    480:                        map->dm_segs[seg]._ds_vaddr = vaddr;
                    481:                        first = 0;
                    482:                } else {
                    483:                        if (curaddr == lastaddr &&
                    484:                            (map->dm_segs[seg].ds_len + sgsize) <=
                    485:                             map->_dm_maxsegsz &&
                    486:                            (map->_dm_boundary == 0 ||
                    487:                             (map->dm_segs[seg].ds_addr & bmask) ==
                    488:                             (LOCAL_TO_CM_ALIAS(curaddr) & bmask)))
                    489:                                map->dm_segs[seg].ds_len += sgsize;
                    490:                        else {
                    491:                                if (++seg >= map->_dm_segcnt)
                    492:                                        break;
                    493:                                map->dm_segs[seg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
                    494:                                map->dm_segs[seg].ds_len = sgsize;
                    495:                                map->dm_segs[seg]._ds_vaddr = vaddr;
                    496:                        }
                    497:                }
                    498:
                    499:                lastaddr = curaddr + sgsize;
                    500:                vaddr += sgsize;
                    501:                buflen -= sgsize;
                    502:        }
                    503:
                    504:        *segp = seg;
                    505:        *lastaddrp = lastaddr;
                    506:
                    507:        /*
                    508:         * Did we fit?
                    509:         */
                    510:        if (buflen != 0)
                    511:                return (EFBIG);         /* XXX better return value here? */
                    512:        return (0);
                    513: }
                    514:
                    515: /*
                    516:  * Check to see if the specified page is in an allowed DMA range.
                    517:  */
                    518: static int
                    519: integrator_bus_dma_inrange(ranges, nranges, curaddr)
                    520:        bus_dma_segment_t *ranges;
                    521:        int nranges;
                    522:        bus_addr_t curaddr;
                    523: {
                    524:        bus_dma_segment_t *ds;
                    525:        int i;
                    526:
                    527:        for (i = 0, ds = ranges; i < nranges; i++, ds++) {
                    528:                if (curaddr >= CM_ALIAS_TO_LOCAL(ds->ds_addr) &&
                    529:                    round_page(curaddr) <= (CM_ALIAS_TO_LOCAL(ds->ds_addr) + ds->ds_len))
                    530:                        return (1);
                    531:        }
                    532:
                    533:        return (0);
                    534: }
                    535:
                    536: /*
                    537:  * Allocate physical memory from the given physical address range.
                    538:  * Called by DMA-safe memory allocation methods.
                    539:  */
                    540: int
                    541: integrator_bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs,
                    542:     flags, low, high)
                    543:        bus_dma_tag_t t;
                    544:        bus_size_t size, alignment, boundary;
                    545:        bus_dma_segment_t *segs;
                    546:        int nsegs;
                    547:        int *rsegs;
                    548:        int flags;
                    549:        vm_offset_t low;
                    550:        vm_offset_t high;
                    551: {
                    552:        vm_offset_t curaddr, lastaddr;
                    553:        struct vm_page *m;
                    554:        struct pglist mlist;
                    555:        int curseg, error;
                    556:
                    557: #ifdef DEBUG_DMA
                    558:        printf("alloc_range: t=%p size=%lx align=%lx boundary=%lx segs=%p nsegs=%x rsegs=%p flags=%x lo=%lx hi=%lx\n",
                    559:            t, size, alignment, boundary, segs, nsegs, rsegs, flags, low, high);
                    560: #endif /* DEBUG_DMA */
                    561:
                    562:        /* Always round the size. */
                    563:        size = round_page(size);
                    564:
                    565:        /*
                    566:         * Allocate pages from the VM system.
                    567:         */
                    568:        TAILQ_INIT(&mlist);
                    569:        error = uvm_pglistalloc(size, low, high, alignment, boundary,
                    570:            &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
                    571:        if (error)
                    572:                return (error);
                    573:
                    574:        /*
                    575:         * Compute the location, size, and number of segments actually
                    576:         * returned by the VM code.
                    577:         */
                    578:        m = mlist.tqh_first;
                    579:        curseg = 0;
                    580:        lastaddr = VM_PAGE_TO_PHYS(m);
                    581:        segs[curseg].ds_addr = LOCAL_TO_CM_ALIAS(lastaddr);
                    582:        segs[curseg].ds_len = PAGE_SIZE;
                    583: #ifdef DEBUG_DMA
                    584:                printf("alloc: page %lx\n", lastaddr);
                    585: #endif /* DEBUG_DMA */
                    586:        m = m->pageq.tqe_next;
                    587:
                    588:        for (; m != NULL; m = m->pageq.tqe_next) {
                    589:                curaddr = VM_PAGE_TO_PHYS(m);
                    590: #ifdef DIAGNOSTIC
                    591:                if (curaddr < low || curaddr >= high) {
                    592:                        printf("uvm_pglistalloc returned non-sensical"
                    593:                            " address 0x%lx\n", curaddr);
                    594:                        panic("integrator_bus_dmamem_alloc_range");
                    595:                }
                    596: #endif /* DIAGNOSTIC */
                    597: #ifdef DEBUG_DMA
                    598:                printf("alloc: page %lx\n", curaddr);
                    599: #endif /* DEBUG_DMA */
                    600:                if (curaddr == (lastaddr + PAGE_SIZE))
                    601:                        segs[curseg].ds_len += PAGE_SIZE;
                    602:                else {
                    603:                        curseg++;
                    604:                        segs[curseg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
                    605:                        segs[curseg].ds_len = PAGE_SIZE;
                    606:                }
                    607:                lastaddr = curaddr;
                    608:        }
                    609:
                    610:        *rsegs = curseg + 1;
                    611:
                    612:        return (0);
                    613: }

CVSweb <webmaster@jp.NetBSD.org>