[BACK]Return to bus_dma.c CVS log [TXT][DIR] Up to [local] / sys / arch / mvme88k / mvme88k

Annotation of sys/arch/mvme88k/mvme88k/bus_dma.c, Revision 1.1

1.1     ! nbrk        1: /*      $OpenBSD: bus_dma.c,v 1.5 2007/02/11 12:49:38 miod Exp $       */
        !             2: /*      $NetBSD: bus_dma.c,v 1.2 2001/06/10 02:31:25 briggs Exp $        */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
        !            10:  * NASA Ames Research Center.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *      This product includes software developed by the NetBSD
        !            23:  *      Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: #include <sys/param.h>
        !            42: #include <sys/proc.h>
        !            43: #include <sys/user.h>
        !            44: #include <sys/extent.h>
        !            45: #include <sys/buf.h>
        !            46: #include <sys/device.h>
        !            47: #include <sys/systm.h>
        !            48: #include <sys/conf.h>
        !            49: #include <sys/file.h>
        !            50: #include <sys/malloc.h>
        !            51: #include <sys/mbuf.h>
        !            52: #include <sys/mount.h>
        !            53:
        !            54: #include <uvm/uvm_extern.h>
        !            55:
        !            56: #include <machine/bus.h>
        !            57: #include <machine/cmmu.h>
        !            58: #include <machine/intr.h>
        !            59:
        !            60: int     _bus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
        !            61:            bus_size_t, struct proc *, int, paddr_t *, int *, int);
        !            62:
        !            63: int    _bus_dmamem_alloc_range(bus_dma_tag_t, bus_size_t, bus_size_t,
        !            64:            bus_size_t, bus_dma_segment_t *, int, int *, int, paddr_t, paddr_t);
        !            65:
        !            66: /*
        !            67:  * Common function for DMA map creation.  May be called by bus-specific
        !            68:  * DMA map creation functions.
        !            69:  */
        !            70: int
        !            71: bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
        !            72:         bus_dma_tag_t t;
        !            73:         bus_size_t size;
        !            74:         int nsegments;
        !            75:         bus_size_t maxsegsz;
        !            76:         bus_size_t boundary;
        !            77:         int flags;
        !            78:         bus_dmamap_t *dmamp;
        !            79: {
        !            80:         struct m88k_bus_dmamap *map;
        !            81:         void *mapstore;
        !            82:         size_t mapsize;
        !            83:
        !            84:         /*
        !            85:          * Allocate and initialize the DMA map.  The end of the map
        !            86:          * is a variable-sized array of segments, so we allocate enough
        !            87:          * room for them in one shot.
        !            88:          *
        !            89:          * Note we don't preserve the WAITOK or NOWAIT flags.  Preservation
        !            90:          * of ALLOCNOW notifies others that we've reserved these resources,
        !            91:          * and they are not to be freed.
        !            92:          *
        !            93:          * The bus_dmamap_t includes one bus_dma_segment_t, hence
        !            94:          * the (nsegments - 1).
        !            95:          */
        !            96:         mapsize = sizeof(struct m88k_bus_dmamap) +
        !            97:             (sizeof(bus_dma_segment_t) * (nsegments - 1));
        !            98:         if ((mapstore = malloc(mapsize, M_DEVBUF,
        !            99:             (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL)
        !           100:                 return (ENOMEM);
        !           101:
        !           102:         memset(mapstore, 0, mapsize);
        !           103:         map = (struct m88k_bus_dmamap *)mapstore;
        !           104:         map->_dm_size = size;
        !           105:         map->_dm_segcnt = nsegments;
        !           106:         map->_dm_maxsegsz = maxsegsz;
        !           107:         map->_dm_boundary = boundary;
        !           108:         map->dm_mapsize = 0;                /* no valid mappings */
        !           109:         map->dm_nsegs = 0;
        !           110:
        !           111:         *dmamp = map;
        !           112:         return (0);
        !           113: }
        !           114:
        !           115: /*
        !           116:  * Common function for DMA map destruction.  May be called by bus-specific
        !           117:  * DMA map destruction functions.
        !           118:  */
        !           119: void
        !           120: bus_dmamap_destroy(t, map)
        !           121:         bus_dma_tag_t t;
        !           122:         bus_dmamap_t map;
        !           123: {
        !           124:
        !           125:         free(map, M_DEVBUF);
        !           126: }
        !           127:
        !           128: /*
        !           129:  * Utility function to load a linear buffer.  lastaddrp holds state
        !           130:  * between invocations (for multiple-buffer loads).  segp contains
        !           131:  * the starting segment on entrance, and the ending segment on exit.
        !           132:  * first indicates if this is the first invocation of this function.
        !           133:  */
        !           134: int
        !           135: _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp, segp, first)
        !           136:         bus_dma_tag_t t;
        !           137:         bus_dmamap_t map;
        !           138:         void *buf;
        !           139:         bus_size_t buflen;
        !           140:         struct proc *p;
        !           141:         int flags;
        !           142:         paddr_t *lastaddrp;
        !           143:         int *segp;
        !           144:         int first;
        !           145: {
        !           146:         bus_size_t sgsize;
        !           147:         bus_addr_t curaddr, lastaddr, baddr, bmask;
        !           148:         vaddr_t vaddr = (vaddr_t)buf;
        !           149:         int seg;
        !           150:        pmap_t pmap;
        !           151:
        !           152:        if (p != NULL)
        !           153:                pmap = vm_map_pmap(&p->p_vmspace->vm_map);
        !           154:        else
        !           155:                pmap = pmap_kernel();
        !           156:
        !           157:         lastaddr = *lastaddrp;
        !           158:         bmask = ~(map->_dm_boundary - 1);
        !           159:
        !           160:         for (seg = *segp; buflen > 0 ; ) {
        !           161:                 /*
        !           162:                  * Get the physical address for this segment.
        !           163:                  */
        !           164:                if (pmap_extract(pmap, vaddr, (paddr_t *)&curaddr) == FALSE)
        !           165:                        return (EINVAL);
        !           166:
        !           167:                 /*
        !           168:                  * Compute the segment size, and adjust counts.
        !           169:                  */
        !           170:                 sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET);
        !           171:                 if (buflen < sgsize)
        !           172:                         sgsize = buflen;
        !           173:
        !           174:                 /*
        !           175:                  * Make sure we don't cross any boundaries.
        !           176:                  */
        !           177:                 if (map->_dm_boundary > 0) {
        !           178:                         baddr = (curaddr + map->_dm_boundary) & bmask;
        !           179:                         if (sgsize > (baddr - curaddr))
        !           180:                                 sgsize = (baddr - curaddr);
        !           181:                 }
        !           182:
        !           183:                 /*
        !           184:                  * Insert chunk into a segment, coalescing with
        !           185:                  * the previous segment if possible.
        !           186:                  */
        !           187:                 if (first) {
        !           188:                         map->dm_segs[seg].ds_addr = curaddr;
        !           189:                         map->dm_segs[seg].ds_len = sgsize;
        !           190:                         first = 0;
        !           191:                 } else {
        !           192:                         if (curaddr == lastaddr &&
        !           193:                             (map->dm_segs[seg].ds_len + sgsize) <=
        !           194:                              map->_dm_maxsegsz &&
        !           195:                             (map->_dm_boundary == 0 ||
        !           196:                              (map->dm_segs[seg].ds_addr & bmask) ==
        !           197:                              (curaddr & bmask)))
        !           198:                                 map->dm_segs[seg].ds_len += sgsize;
        !           199:                         else {
        !           200:                                 if (++seg >= map->_dm_segcnt)
        !           201:                                         break;
        !           202:                                 map->dm_segs[seg].ds_addr = curaddr;
        !           203:                                 map->dm_segs[seg].ds_len = sgsize;
        !           204:                         }
        !           205:                 }
        !           206:
        !           207:                 lastaddr = curaddr + sgsize;
        !           208:                 vaddr += sgsize;
        !           209:                 buflen -= sgsize;
        !           210:         }
        !           211:
        !           212:         *segp = seg;
        !           213:         *lastaddrp = lastaddr;
        !           214:
        !           215:         /*
        !           216:          * Did we fit?
        !           217:          */
        !           218:         if (buflen != 0)
        !           219:                 return (EFBIG);                /* XXX better return value here? */
        !           220:
        !           221:         return (0);
        !           222: }
        !           223:
        !           224: /*
        !           225:  * Common function for loading a DMA map with a linear buffer.  May
        !           226:  * be called by bus-specific DMA map load functions.
        !           227:  */
        !           228: int
        !           229: bus_dmamap_load(t, map, buf, buflen, p, flags)
        !           230:         bus_dma_tag_t t;
        !           231:         bus_dmamap_t map;
        !           232:         void *buf;
        !           233:         bus_size_t buflen;
        !           234:         struct proc *p;
        !           235:         int flags;
        !           236: {
        !           237:         paddr_t lastaddr;
        !           238:         int seg, error;
        !           239:
        !           240:         /*
        !           241:          * Make sure that on error condition we return "no valid mappings".
        !           242:          */
        !           243:         map->dm_mapsize = 0;
        !           244:         map->dm_nsegs = 0;
        !           245:
        !           246:         if (buflen > map->_dm_size)
        !           247:                 return (EINVAL);
        !           248:
        !           249:         seg = 0;
        !           250:         error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
        !           251:                 &lastaddr, &seg, 1);
        !           252:         if (error == 0) {
        !           253:                 map->dm_mapsize = buflen;
        !           254:                 map->dm_nsegs = seg + 1;
        !           255:         }
        !           256:         return (error);
        !           257: }
        !           258:
        !           259: /*
        !           260:  * Like _bus_dmamap_load(), but for mbufs.
        !           261:  */
        !           262: int
        !           263: bus_dmamap_load_mbuf(t, map, m0, flags)
        !           264:         bus_dma_tag_t t;
        !           265:         bus_dmamap_t map;
        !           266:         struct mbuf *m0;
        !           267:         int flags;
        !           268: {
        !           269:         paddr_t lastaddr;
        !           270:         int seg, error, first;
        !           271:         struct mbuf *m;
        !           272:
        !           273:         /*
        !           274:          * Make sure that on error condition we return "no valid mappings."
        !           275:          */
        !           276:         map->dm_mapsize = 0;
        !           277:         map->dm_nsegs = 0;
        !           278:
        !           279: #ifdef DIAGNOSTIC
        !           280:         if ((m0->m_flags & M_PKTHDR) == 0)
        !           281:                 panic("bus_dmamap_load_mbuf: no packet header");
        !           282: #endif
        !           283:
        !           284:         if (m0->m_pkthdr.len > map->_dm_size)
        !           285:                 return (EINVAL);
        !           286:
        !           287:         first = 1;
        !           288:         seg = 0;
        !           289:         error = 0;
        !           290:         for (m = m0; m != NULL && error == 0; m = m->m_next) {
        !           291:                if (m->m_len == 0)
        !           292:                        continue;
        !           293:                 error = _bus_dmamap_load_buffer(t, map, m->m_data, m->m_len,
        !           294:                     NULL, flags, &lastaddr, &seg, first);
        !           295:                 first = 0;
        !           296:         }
        !           297:         if (error == 0) {
        !           298:                 map->dm_mapsize = m0->m_pkthdr.len;
        !           299:                 map->dm_nsegs = seg + 1;
        !           300:         }
        !           301:         return (error);
        !           302: }
        !           303:
        !           304: /*
        !           305:  * Like _bus_dmamap_load(), but for uios.
        !           306:  */
        !           307: int
        !           308: bus_dmamap_load_uio(t, map, uio, flags)
        !           309:         bus_dma_tag_t t;
        !           310:         bus_dmamap_t map;
        !           311:         struct uio *uio;
        !           312:         int flags;
        !           313: {
        !           314:         paddr_t lastaddr;
        !           315:         int seg, i, error, first;
        !           316:         bus_size_t minlen, resid;
        !           317:         struct proc *p = NULL;
        !           318:         struct iovec *iov;
        !           319:         caddr_t addr;
        !           320:
        !           321:         /*
        !           322:          * Make sure that on error condition we return "no valid mappings."
        !           323:          */
        !           324:         map->dm_mapsize = 0;
        !           325:         map->dm_nsegs = 0;
        !           326:
        !           327:         resid = uio->uio_resid;
        !           328:         iov = uio->uio_iov;
        !           329:
        !           330:        if (resid > map->_dm_size)
        !           331:                return (EINVAL);
        !           332:
        !           333:         if (uio->uio_segflg == UIO_USERSPACE) {
        !           334:                 p = uio->uio_procp;
        !           335: #ifdef DIAGNOSTIC
        !           336:                 if (p == NULL)
        !           337:                         panic("bus_dmamap_load_uio: USERSPACE but no proc");
        !           338: #endif
        !           339:         }
        !           340:
        !           341:         first = 1;
        !           342:         seg = 0;
        !           343:         error = 0;
        !           344:         for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
        !           345:                 /*
        !           346:                  * Now at the first iovec to load.  Load each iovec
        !           347:                  * until we have exhausted the residual count.
        !           348:                  */
        !           349:                 minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
        !           350:                 addr = (caddr_t)iov[i].iov_base;
        !           351:
        !           352:                 error = _bus_dmamap_load_buffer(t, map, addr, minlen,
        !           353:                     p, flags, &lastaddr, &seg, first);
        !           354:                 first = 0;
        !           355:
        !           356:                 resid -= minlen;
        !           357:         }
        !           358:         if (error == 0) {
        !           359:                 map->dm_mapsize = uio->uio_resid;
        !           360:                 map->dm_nsegs = seg + 1;
        !           361:         }
        !           362:         return (error);
        !           363: }
        !           364:
        !           365: /*
        !           366:  * Like bus_dmamap_load(), but for raw memory allocated with
        !           367:  * bus_dmamem_alloc().
        !           368:  */
        !           369: int
        !           370: bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
        !           371:        bus_dma_tag_t t;
        !           372:        bus_dmamap_t map;
        !           373:        bus_dma_segment_t *segs;
        !           374:        int nsegs;
        !           375:        bus_size_t size;
        !           376:        int flags;
        !           377: {
        !           378:        if (nsegs > map->_dm_segcnt || size > map->_dm_size)
        !           379:                return (EINVAL);
        !           380:
        !           381:        /*
        !           382:         * Make sure we don't cross any boundaries.
        !           383:         */
        !           384:        if (map->_dm_boundary) {
        !           385:                bus_addr_t bmask = ~(map->_dm_boundary - 1);
        !           386:                int i;
        !           387:
        !           388:                for (i = 0; i < nsegs; i++) {
        !           389:                        if (segs[i].ds_len > map->_dm_maxsegsz)
        !           390:                                return (EINVAL);
        !           391:                        if ((segs[i].ds_addr & bmask) !=
        !           392:                            ((segs[i].ds_addr + segs[i].ds_len - 1) & bmask))
        !           393:                                return (EINVAL);
        !           394:                }
        !           395:        }
        !           396:
        !           397:        bcopy(segs, map->dm_segs, nsegs * sizeof(*segs));
        !           398:        map->dm_nsegs = nsegs;
        !           399:        return (0);
        !           400: }
        !           401:
        !           402: /*
        !           403:  * Common function for unloading a DMA map.  May be called by
        !           404:  * chipset-specific DMA map unload functions.
        !           405:  */
        !           406: void
        !           407: bus_dmamap_unload(t, map)
        !           408:         bus_dma_tag_t t;
        !           409:         bus_dmamap_t map;
        !           410: {
        !           411:
        !           412:         /*
        !           413:          * No resources to free; just mark the mappings as
        !           414:          * invalid.
        !           415:          */
        !           416:         map->dm_mapsize = 0;
        !           417:         map->dm_nsegs = 0;
        !           418: }
        !           419:
        !           420: /*
        !           421:  * Common function for DMA map synchronization.  May be called
        !           422:  * by chipset-specific DMA map synchronization functions.
        !           423:  */
        !           424:
        !           425: void
        !           426: bus_dmamap_sync(t, map, offset, len, op)
        !           427:         bus_dma_tag_t t;
        !           428:         bus_dmamap_t map;
        !           429:        bus_addr_t offset;
        !           430:        bus_size_t len;
        !           431:        int op;
        !           432: {
        !           433:        u_int nsegs;
        !           434:        bus_dma_segment_t *seg;
        !           435:
        !           436:        if (op & BUS_DMASYNC_PREREAD)
        !           437:                op = DMA_CACHE_SYNC_INVAL;
        !           438:        else if (op & BUS_DMASYNC_PREWRITE)
        !           439:                op = DMA_CACHE_SYNC;
        !           440:        else if (op & BUS_DMASYNC_POSTREAD)
        !           441:                op = DMA_CACHE_INV;
        !           442:        else
        !           443:                return;
        !           444:
        !           445:        nsegs = map->dm_nsegs;
        !           446:        seg = map->dm_segs;
        !           447:        while (nsegs != 0 && len != 0) {
        !           448:                if (offset >= seg->ds_len) {
        !           449:                        offset -= seg->ds_len;
        !           450:                } else {
        !           451:                        bus_addr_t addr;
        !           452:                        bus_size_t sublen;
        !           453:
        !           454:                        addr = seg->ds_addr + offset;
        !           455:                        sublen = seg->ds_len - offset;
        !           456:                        if (sublen > len)
        !           457:                                sublen = len;
        !           458:
        !           459:                        dma_cachectl_pa(addr, sublen, op);
        !           460:
        !           461:                        offset = 0;
        !           462:                        len -= sublen;
        !           463:                }
        !           464:                seg++;
        !           465:                nsegs--;
        !           466:        }
        !           467: }
        !           468:
        !           469: /*
        !           470:  * Common function for DMA-safe memory allocation.  May be called
        !           471:  * by bus-specific DMA memory allocation functions.
        !           472:  */
        !           473: int
        !           474: bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
        !           475:         bus_dma_tag_t t;
        !           476:         bus_size_t size, alignment, boundary;
        !           477:         bus_dma_segment_t *segs;
        !           478:         int nsegs;
        !           479:         int *rsegs;
        !           480:         int flags;
        !           481: {
        !           482:         paddr_t avail_start = (paddr_t)-1, avail_end = 0;
        !           483:         int bank;
        !           484:
        !           485:         for (bank = 0; bank < vm_nphysseg; bank++) {
        !           486:                 if (avail_start > vm_physmem[bank].avail_start << PGSHIFT)
        !           487:                         avail_start = vm_physmem[bank].avail_start << PGSHIFT;
        !           488:                 if (avail_end < vm_physmem[bank].avail_end << PGSHIFT)
        !           489:                         avail_end = vm_physmem[bank].avail_end << PGSHIFT;
        !           490:         }
        !           491:
        !           492:         return _bus_dmamem_alloc_range(t, size, alignment, boundary, segs,
        !           493:             nsegs, rsegs, flags, avail_start, avail_end - PAGE_SIZE);
        !           494: }
        !           495:
        !           496: /*
        !           497:  * Common function for freeing DMA-safe memory.  May be called by
        !           498:  * bus-specific DMA memory free functions.
        !           499:  */
        !           500: void
        !           501: bus_dmamem_free(t, segs, nsegs)
        !           502:         bus_dma_tag_t t;
        !           503:         bus_dma_segment_t *segs;
        !           504:         int nsegs;
        !           505: {
        !           506:         struct vm_page *m;
        !           507:         bus_addr_t addr;
        !           508:         struct pglist mlist;
        !           509:         int curseg;
        !           510:
        !           511:         /*
        !           512:          * Build a list of pages to free back to the VM system.
        !           513:          */
        !           514:         TAILQ_INIT(&mlist);
        !           515:         for (curseg = 0; curseg < nsegs; curseg++) {
        !           516:                 for (addr = segs[curseg].ds_addr;
        !           517:                     addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
        !           518:                     addr += PAGE_SIZE) {
        !           519:                         m = PHYS_TO_VM_PAGE(addr);
        !           520:                         TAILQ_INSERT_TAIL(&mlist, m, pageq);
        !           521:                 }
        !           522:         }
        !           523:
        !           524:         uvm_pglistfree(&mlist);
        !           525: }
        !           526:
        !           527: /*
        !           528:  * Common function for mapping DMA-safe memory.  May be called by
        !           529:  * bus-specific DMA memory map functions.
        !           530:  */
        !           531: int
        !           532: bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
        !           533:         bus_dma_tag_t t;
        !           534:         bus_dma_segment_t *segs;
        !           535:         int nsegs;
        !           536:         size_t size;
        !           537:         caddr_t *kvap;
        !           538:         int flags;
        !           539: {
        !           540:         vaddr_t va;
        !           541:         bus_addr_t addr;
        !           542:         int curseg;
        !           543:
        !           544:         size = round_page(size);
        !           545:
        !           546:         va = uvm_km_valloc(kernel_map, size);
        !           547:
        !           548:         if (va == 0)
        !           549:                 return (ENOMEM);
        !           550:
        !           551:         *kvap = (caddr_t)va;
        !           552:
        !           553:         for (curseg = 0; curseg < nsegs; curseg++) {
        !           554:                 for (addr = segs[curseg].ds_addr;
        !           555:                     addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
        !           556:                     addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) {
        !           557:                         if (size == 0)
        !           558:                                 panic("bus_dmamem_map: size botch");
        !           559:                         pmap_enter(pmap_kernel(), va, addr,
        !           560:                             VM_PROT_READ | VM_PROT_WRITE,
        !           561:                             VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
        !           562:                 }
        !           563:         }
        !           564:        pmap_update(pmap_kernel());
        !           565:
        !           566:         return (0);
        !           567: }
        !           568:
        !           569: /*
        !           570:  * Common function for unmapping DMA-safe memory.  May be called by
        !           571:  * bus-specific DMA memory unmapping functions.
        !           572:  */
        !           573: void
        !           574: bus_dmamem_unmap(t, kva, size)
        !           575:         bus_dma_tag_t t;
        !           576:         caddr_t kva;
        !           577:         size_t size;
        !           578: {
        !           579:
        !           580: #ifdef DIAGNOSTIC
        !           581:         if ((u_long)kva & PGOFSET)
        !           582:                 panic("bus_dmamem_unmap");
        !           583: #endif
        !           584:
        !           585:         size = round_page(size);
        !           586:         uvm_km_free(kernel_map, (vaddr_t)kva, size);
        !           587: }
        !           588:
        !           589: /*
        !           590:  * Common functin for mmap(2)'ing DMA-safe memory.  May be called by
        !           591:  * bus-specific DMA mmap(2)'ing functions.
        !           592:  */
        !           593: paddr_t
        !           594: bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
        !           595:         bus_dma_tag_t t;
        !           596:         bus_dma_segment_t *segs;
        !           597:         int nsegs;
        !           598:         off_t off;
        !           599:         int prot, flags;
        !           600: {
        !           601:         int i;
        !           602:
        !           603:         for (i = 0; i < nsegs; i++) {
        !           604: #ifdef DIAGNOSTIC
        !           605:                 if (off & PGOFSET)
        !           606:                         panic("bus_dmamem_mmap: offset unaligned");
        !           607:                 if (segs[i].ds_addr & PGOFSET)
        !           608:                         panic("bus_dmamem_mmap: segment unaligned");
        !           609:                 if (segs[i].ds_len & PGOFSET)
        !           610:                         panic("bus_dmamem_mmap: segment size not multiple"
        !           611:                             " of page size");
        !           612: #endif
        !           613:                 if (off >= segs[i].ds_len) {
        !           614:                         off -= segs[i].ds_len;
        !           615:                         continue;
        !           616:                 }
        !           617:
        !           618:                 return (atop(segs[i].ds_addr + off));
        !           619:         }
        !           620:
        !           621:         /* Page not found. */
        !           622:         return (-1);
        !           623: }
        !           624:
        !           625: /*
        !           626:  * Allocate physical memory from the given physical address range.
        !           627:  * Called by DMA-safe memory allocation methods.
        !           628:  */
        !           629: int
        !           630: _bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs,
        !           631:     flags, low, high)
        !           632:         bus_dma_tag_t t;
        !           633:         bus_size_t size, alignment, boundary;
        !           634:         bus_dma_segment_t *segs;
        !           635:         int nsegs;
        !           636:         int *rsegs;
        !           637:         int flags;
        !           638:         paddr_t low;
        !           639:         paddr_t high;
        !           640: {
        !           641:         paddr_t curaddr, lastaddr;
        !           642:         struct vm_page *m;
        !           643:         struct pglist mlist;
        !           644:         int curseg, error;
        !           645:
        !           646:         /* Always round the size. */
        !           647:         size = round_page(size);
        !           648:
        !           649:         /*
        !           650:          * Allocate pages from the VM system.
        !           651:          */
        !           652:         TAILQ_INIT(&mlist);
        !           653:         error = uvm_pglistalloc(size, low, high, alignment, boundary,
        !           654:             &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
        !           655:         if (error)
        !           656:                 return (error);
        !           657:
        !           658:         /*
        !           659:          * Compute the location, size, and number of segments actually
        !           660:          * returned by the VM code.
        !           661:          */
        !           662:         m = TAILQ_FIRST(&mlist);
        !           663:         curseg = 0;
        !           664:         lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
        !           665:         segs[curseg].ds_len = PAGE_SIZE;
        !           666:        m = TAILQ_NEXT(m, pageq);
        !           667:
        !           668:        for (; m != TAILQ_END(&mlist); m = TAILQ_NEXT(m, pageq)) {
        !           669:                 curaddr = VM_PAGE_TO_PHYS(m);
        !           670: #ifdef DIAGNOSTIC
        !           671:                 if (curaddr < low || curaddr >= high) {
        !           672:                         panic("_bus_dmamem_alloc_range: uvm_pglistalloc "
        !           673:                            "returned non-sensical address 0x%lx\n", curaddr);
        !           674:                 }
        !           675: #endif
        !           676:                 if (curaddr == (lastaddr + PAGE_SIZE))
        !           677:                         segs[curseg].ds_len += PAGE_SIZE;
        !           678:                 else {
        !           679:                         curseg++;
        !           680:                         segs[curseg].ds_addr = curaddr;
        !           681:                         segs[curseg].ds_len = PAGE_SIZE;
        !           682:                 }
        !           683:                 lastaddr = curaddr;
        !           684:         }
        !           685:
        !           686:         *rsegs = curseg + 1;
        !           687:
        !           688:         return (0);
        !           689: }

CVSweb