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

Annotation of sys/arch/alpha/dev/sgmap_typedep.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: sgmap_typedep.c,v 1.10 2006/05/21 01:42:43 brad Exp $ */
                      2: /* $NetBSD: sgmap_typedep.c,v 1.17 2001/07/19 04:27:37 thorpej Exp $ */
                      3:
                      4: /*-
                      5:  * Copyright (c) 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: #ifdef SGMAP_DEBUG
                     42: int                    __C(SGMAP_TYPE,_debug) = 0;
                     43: #endif
                     44:
                     45: SGMAP_PTE_TYPE         __C(SGMAP_TYPE,_prefetch_spill_page_pte);
                     46:
                     47: int                    __C(SGMAP_TYPE,_load_buffer)(bus_dma_tag_t,
                     48:                            bus_dmamap_t, void *buf, size_t buflen,
                     49:                            struct proc *, int, int, struct alpha_sgmap *);
                     50:
                     51: void
                     52: __C(SGMAP_TYPE,_init_spill_page_pte)(void)
                     53: {
                     54:
                     55:        __C(SGMAP_TYPE,_prefetch_spill_page_pte) =
                     56:            (alpha_sgmap_prefetch_spill_page_pa >>
                     57:             SGPTE_PGADDR_SHIFT) | SGPTE_VALID;
                     58: }
                     59:
                     60: int
                     61: __C(SGMAP_TYPE,_load_buffer)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
                     62:     size_t buflen, struct proc *p, int flags, int seg,
                     63:     struct alpha_sgmap *sgmap)
                     64: {
                     65:        vaddr_t endva, va = (vaddr_t)buf;
                     66:        paddr_t pa;
                     67:        bus_addr_t dmaoffset, sgva;
                     68:        bus_size_t sgvalen, boundary, alignment;
                     69:        SGMAP_PTE_TYPE *pte, *page_table = sgmap->aps_pt;
                     70:        int s, pteidx, error, spill;
                     71:
                     72:        /* Initialize the spill page PTE if it hasn't been already. */
                     73:        if (__C(SGMAP_TYPE,_prefetch_spill_page_pte) == 0)
                     74:                __C(SGMAP_TYPE,_init_spill_page_pte)();
                     75:
                     76:        /*
                     77:         * Remember the offset into the first page and the total
                     78:         * transfer length.
                     79:         */
                     80:        dmaoffset = ((u_long)buf) & PGOFSET;
                     81:
                     82: #ifdef SGMAP_DEBUG
                     83:        if (__C(SGMAP_TYPE,_debug)) {
                     84:                printf("sgmap_load: ----- buf = %p -----\n", buf);
                     85:                printf("sgmap_load: dmaoffset = 0x%lx, buflen = 0x%lx\n",
                     86:                    dmaoffset, buflen);
                     87:        }
                     88: #endif
                     89:
                     90:        /*
                     91:         * Allocate the necessary virtual address space for the
                     92:         * mapping.  Round the size, since we deal with whole pages.
                     93:         */
                     94:
                     95:        /*
                     96:         * XXX Always allocate a spill page for now.  Note
                     97:         * the spill page is not needed for an in-bound-only
                     98:         * transfer.
                     99:         */
                    100:        if ((flags & BUS_DMA_READ) == 0)
                    101:                spill = 1;
                    102:        else
                    103:                spill = 0;
                    104:
                    105:        endva = round_page(va + buflen);
                    106:        va = trunc_page(va);
                    107:
                    108:        boundary = map->_dm_boundary;
                    109:        alignment = PAGE_SIZE;
                    110:
                    111:        sgvalen = (endva - va);
                    112:        if (spill) {
                    113:                sgvalen += PAGE_SIZE;
                    114:
                    115:                /*
                    116:                 * ARGH!  If the addition of the spill page bumped us
                    117:                 * over our boundary, we have to 2x the boundary limit.
                    118:                 */
                    119:                if (boundary && boundary < sgvalen) {
                    120:                        alignment = boundary;
                    121:                        do {
                    122:                                boundary <<= 1;
                    123:                        } while (boundary < sgvalen);
                    124:                }
                    125:        }
                    126:
                    127: #if 0
                    128:        printf("len 0x%lx -> 0x%lx, boundary 0x%lx -> 0x%lx -> ",
                    129:            (endva - va), sgvalen, map->_dm_boundary, boundary);
                    130: #endif
                    131:
                    132:        s = splvm();
                    133:        error = extent_alloc(sgmap->aps_ex, sgvalen, alignment, 0, boundary,
                    134:            (flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK, &sgva);
                    135:        splx(s);
                    136:        if (error)
                    137:                return (error);
                    138:
                    139: #if 0
                    140:        printf("error %d sgva 0x%lx\n", error, sgva);
                    141: #endif
                    142:
                    143:        pteidx = sgva >> SGMAP_ADDR_PTEIDX_SHIFT;
                    144:        pte = &page_table[pteidx * SGMAP_PTE_SPACING];
                    145:
                    146: #ifdef SGMAP_DEBUG
                    147:        if (__C(SGMAP_TYPE,_debug))
                    148:                printf("sgmap_load: sgva = 0x%lx, pteidx = %d, "
                    149:                    "pte = %p (pt = %p)\n", sgva, pteidx, pte,
                    150:                    page_table);
                    151: #endif
                    152:
                    153:        /* Generate the DMA address. */
                    154:        map->dm_segs[seg].ds_addr = sgmap->aps_wbase | sgva | dmaoffset;
                    155:        map->dm_segs[seg].ds_len = buflen;
                    156:
                    157: #ifdef SGMAP_DEBUG
                    158:        if (__C(SGMAP_TYPE,_debug))
                    159:                printf("sgmap_load: wbase = 0x%lx, vpage = 0x%x, "
                    160:                    "dma addr = 0x%lx\n", sgmap->aps_wbase, sgva,
                    161:                    map->dm_segs[seg].ds_addr);
                    162: #endif
                    163:
                    164:        for (; va < endva; va += PAGE_SIZE, pteidx++,
                    165:             pte = &page_table[pteidx * SGMAP_PTE_SPACING]) {
                    166:                /* Get the physical address for this segment. */
                    167:                if (p != NULL)
                    168:                        (void) pmap_extract(p->p_vmspace->vm_map.pmap, va, &pa);
                    169:                else
                    170:                        pa = vtophys(va);
                    171:
                    172:                /* Load the current PTE with this page. */
                    173:                *pte = (pa >> SGPTE_PGADDR_SHIFT) | SGPTE_VALID;
                    174: #ifdef SGMAP_DEBUG
                    175:                if (__C(SGMAP_TYPE,_debug))
                    176:                        printf("sgmap_load:     pa = 0x%lx, pte = %p, "
                    177:                            "*pte = 0x%lx\n", pa, pte, (u_long)(*pte));
                    178: #endif
                    179:        }
                    180:
                    181:        if (spill) {
                    182:                /* ...and the prefetch-spill page. */
                    183:                *pte = __C(SGMAP_TYPE,_prefetch_spill_page_pte);
                    184: #ifdef SGMAP_DEBUG
                    185:                if (__C(SGMAP_TYPE,_debug)) {
                    186:                        printf("sgmap_load:     spill page, pte = %p, "
                    187:                            "*pte = 0x%lx\n", pte, *pte);
                    188:                        printf("sgmap_load:     pte count = %d\n",
                    189:                            map->_dm_ptecnt);
                    190:                }
                    191: #endif
                    192:        }
                    193:
                    194:        return (0);
                    195: }
                    196:
                    197: int
                    198: __C(SGMAP_TYPE,_load)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
                    199:     bus_size_t buflen, struct proc *p, int flags, struct alpha_sgmap *sgmap)
                    200: {
                    201:        int seg, error;
                    202:
                    203:        /*
                    204:         * Make sure that on error condition we return "no valid mappings".
                    205:         */
                    206:        map->dm_mapsize = 0;
                    207:        map->dm_nsegs = 0;
                    208:
                    209:        if (buflen > map->_dm_size)
                    210:                return (EINVAL);
                    211:
                    212:        KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
                    213:        KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
                    214:            (BUS_DMA_READ|BUS_DMA_WRITE));
                    215:
                    216:        map->_dm_flags |= flags & (BUS_DMA_READ|BUS_DMA_WRITE);
                    217:
                    218:        seg = 0;
                    219:        error = __C(SGMAP_TYPE,_load_buffer)(t, map, buf, buflen, p,
                    220:            flags, seg, sgmap);
                    221:
                    222:        alpha_mb();
                    223:
                    224: #if defined(SGMAP_DEBUG) && defined(DDB)
                    225:        if (__C(SGMAP_TYPE,_debug) > 1)
                    226:                Debugger();
                    227: #endif
                    228:
                    229:        if (error == 0) {
                    230:                map->dm_mapsize = buflen;
                    231:                map->dm_nsegs = 1;
                    232:                map->_dm_window = t;
                    233:        } else {
                    234:                map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
                    235:                if (t->_next_window != NULL) {
                    236:                        /* Give the next window a chance. */
                    237:                        error = bus_dmamap_load(t->_next_window, map, buf,
                    238:                            buflen, p, flags);
                    239:                }
                    240:        }
                    241:        return (error);
                    242: }
                    243:
                    244: int
                    245: __C(SGMAP_TYPE,_load_mbuf)(bus_dma_tag_t t, bus_dmamap_t map,
                    246:     struct mbuf *m0, int flags, struct alpha_sgmap *sgmap)
                    247: {
                    248:        struct mbuf *m;
                    249:        int seg, error;
                    250:
                    251:        /*
                    252:         * Make sure that on error condition we return "no valid mappings".
                    253:         */
                    254:        map->dm_mapsize = 0;
                    255:        map->dm_nsegs = 0;
                    256:
                    257: #ifdef DIAGNOSTIC
                    258:        if ((m0->m_flags & M_PKTHDR) == 0)
                    259:                panic(__S(__C(SGMAP_TYPE,_load_mbuf)) ": no packet header");
                    260: #endif
                    261:
                    262:        if (m0->m_pkthdr.len > map->_dm_size)
                    263:                return (EINVAL);
                    264:
                    265:        KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
                    266:        KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
                    267:            (BUS_DMA_READ|BUS_DMA_WRITE));
                    268:
                    269:        map->_dm_flags |= flags & (BUS_DMA_READ|BUS_DMA_WRITE);
                    270:
                    271:        seg = 0;
                    272:        error = 0;
                    273:        for (m = m0; m != NULL && error == 0; m = m->m_next) {
                    274:                if (m->m_len == 0)
                    275:                        continue;
                    276:                error = __C(SGMAP_TYPE,_load_buffer)(t, map,
                    277:                    m->m_data, m->m_len, NULL, flags, seg, sgmap);
                    278:                seg++;
                    279:        }
                    280:
                    281:        alpha_mb();
                    282:
                    283: #if defined(SGMAP_DEBUG) && defined(DDB)
                    284:        if (__C(SGMAP_TYPE,_debug) > 1)
                    285:                Debugger();
                    286: #endif
                    287:
                    288:        if (error == 0) {
                    289:                map->dm_mapsize = m0->m_pkthdr.len;
                    290:                map->dm_nsegs = seg;
                    291:                map->_dm_window = t;
                    292:        } else {
                    293:                /* Need to back out what we've done so far. */
                    294:                map->dm_nsegs = seg - 1;
                    295:                __C(SGMAP_TYPE,_unload)(t, map, sgmap);
                    296:                map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
                    297:                if (t->_next_window != NULL) {
                    298:                        /* Give the next window a chance. */
                    299:                        error = bus_dmamap_load_mbuf(t->_next_window, map,
                    300:                            m0, flags);
                    301:                }
                    302:        }
                    303:
                    304:        return (error);
                    305: }
                    306:
                    307: int
                    308: __C(SGMAP_TYPE,_load_uio)(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
                    309:     int flags, struct alpha_sgmap *sgmap)
                    310: {
                    311:        bus_size_t minlen, resid;
                    312:        struct proc *p = NULL;
                    313:        struct iovec *iov;
                    314:        caddr_t addr;
                    315:        int i, seg, error;
                    316:
                    317:        /*
                    318:         * Make sure that on error condition we return "no valid mappings".
                    319:         */
                    320:        map->dm_mapsize = 0;
                    321:        map->dm_nsegs = 0;
                    322:
                    323:        KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
                    324:        KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
                    325:            (BUS_DMA_READ|BUS_DMA_WRITE));
                    326:
                    327:        map->_dm_flags |= flags & (BUS_DMA_READ|BUS_DMA_WRITE);
                    328:
                    329:        resid = uio->uio_resid;
                    330:        iov = uio->uio_iov;
                    331:
                    332:        if (uio->uio_segflg == UIO_USERSPACE) {
                    333:                p = uio->uio_procp;
                    334: #ifdef DIAGNOSTIC
                    335:                if (p == NULL)
                    336:                        panic(__S(__C(SGMAP_TYPE,_load_uio))
                    337:                            ": USERSPACE but no proc");
                    338: #endif
                    339:        }
                    340:
                    341:        seg = 0;
                    342:        error = 0;
                    343:        for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0;
                    344:             i++, seg++) {
                    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 = __C(SGMAP_TYPE,_load_buffer)(t, map,
                    353:                    addr, minlen, p, flags, seg, sgmap);
                    354:
                    355:                resid -= minlen;
                    356:        }
                    357:
                    358:        alpha_mb();
                    359:
                    360: #if defined(SGMAP_DEBUG) && defined(DDB)
                    361:        if (__C(SGMAP_TYPE,_debug) > 1)
                    362:                Debugger();
                    363: #endif
                    364:
                    365:        if (error == 0) {
                    366:                map->dm_mapsize = uio->uio_resid;
                    367:                map->dm_nsegs = seg;
                    368:        } else {
                    369:                /* Need to back out what we've done so far. */
                    370:                map->dm_nsegs = seg - 1;
                    371:                __C(SGMAP_TYPE,_unload)(t, map, sgmap);
                    372:                map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
                    373:                if (t->_next_window != NULL) {
                    374:                        /* Give the next window a chance. */
                    375:                        error = bus_dmamap_load_uio(t->_next_window, map,
                    376:                            uio, flags);
                    377:                }
                    378:        }
                    379:
                    380:        return (error);
                    381: }
                    382:
                    383: int
                    384: __C(SGMAP_TYPE,_load_raw)(bus_dma_tag_t t, bus_dmamap_t map,
                    385:     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags,
                    386:     struct alpha_sgmap *sgmap)
                    387: {
                    388:        KASSERT((map->_dm_flags & (BUS_DMA_READ|BUS_DMA_WRITE)) == 0);
                    389:        KASSERT((flags & (BUS_DMA_READ|BUS_DMA_WRITE)) !=
                    390:            (BUS_DMA_READ|BUS_DMA_WRITE));
                    391:
                    392:        panic(__S(__C(SGMAP_TYPE,_load_raw)) ": not implemented");
                    393: }
                    394:
                    395: void
                    396: __C(SGMAP_TYPE,_unload)(bus_dma_tag_t t, bus_dmamap_t map,
                    397:     struct alpha_sgmap *sgmap)
                    398: {
                    399:        SGMAP_PTE_TYPE *pte, *page_table = sgmap->aps_pt;
                    400:        bus_addr_t osgva, sgva, esgva;
                    401:        int s, error, spill, seg, pteidx;
                    402:
                    403:        for (seg = 0; seg < map->dm_nsegs; seg++) {
                    404:                /*
                    405:                 * XXX Always allocate a spill page for now.  Note
                    406:                 * the spill page is not needed for an in-bound-only
                    407:                 * transfer.
                    408:                 */
                    409:                if ((map->_dm_flags & BUS_DMA_READ) == 0)
                    410:                        spill = 1;
                    411:                else
                    412:                        spill = 0;
                    413:
                    414:                sgva = map->dm_segs[seg].ds_addr & ~sgmap->aps_wbase;
                    415:
                    416:                esgva = round_page(sgva + map->dm_segs[seg].ds_len);
                    417:                osgva = sgva = trunc_page(sgva);
                    418:
                    419:                if (spill)
                    420:                        esgva += PAGE_SIZE;
                    421:
                    422:                /* Invalidate the PTEs for the mapping. */
                    423:                for (pteidx = sgva >> SGMAP_ADDR_PTEIDX_SHIFT;
                    424:                     sgva < esgva; sgva += PAGE_SIZE, pteidx++) {
                    425:                        pte = &page_table[pteidx * SGMAP_PTE_SPACING];
                    426: #ifdef SGMAP_DEBUG
                    427:                        if (__C(SGMAP_TYPE,_debug))
                    428:                                printf("sgmap_unload:     pte = %p, "
                    429:                                    "*pte = 0x%lx\n", pte, (u_long)(*pte));
                    430: #endif
                    431:                        *pte = 0;
                    432:                }
                    433:
                    434:                alpha_mb();
                    435:
                    436:                /* Free the virtual address space used by the mapping. */
                    437:                s = splvm();
                    438:                error = extent_free(sgmap->aps_ex, osgva, (esgva - osgva),
                    439:                    EX_NOWAIT);
                    440:                splx(s);
                    441:                if (error != 0)
                    442:                        panic(__S(__C(SGMAP_TYPE,_unload)));
                    443:        }
                    444:
                    445:        map->_dm_flags &= ~(BUS_DMA_READ|BUS_DMA_WRITE);
                    446:
                    447:        /* Mark the mapping invalid. */
                    448:        map->dm_mapsize = 0;
                    449:        map->dm_nsegs = 0;
                    450:        map->_dm_window = NULL;
                    451: }

CVSweb