diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2004-01-13 00:12:16 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2004-01-13 00:12:16 +0000 |
commit | f0a51cf628ef210ed16eb4e7b25b9ad59beee2cd (patch) | |
tree | b86cc9cbd1ad31816502772bd7e441e102d62ff1 /sys | |
parent | 96ed41a04504e15bd8cf28c643c2432eeb94d96e (diff) |
support mbuf handling in alpha sgmap dma maps; from netbsd
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/alpha/dev/sgmap_typedep.c | 373 |
1 files changed, 190 insertions, 183 deletions
diff --git a/sys/arch/alpha/dev/sgmap_typedep.c b/sys/arch/alpha/dev/sgmap_typedep.c index 1b14b54f588..cacd69661d1 100644 --- a/sys/arch/alpha/dev/sgmap_typedep.c +++ b/sys/arch/alpha/dev/sgmap_typedep.c @@ -1,5 +1,5 @@ -/* $OpenBSD: sgmap_typedep.c,v 1.2 2001/06/08 08:08:40 art Exp $ */ -/* $NetBSD: sgmap_typedep.c,v 1.13 1999/07/08 18:05:23 thorpej Exp $ */ +/* $OpenBSD: sgmap_typedep.c,v 1.3 2004/01/13 00:12:15 deraadt Exp $ */ +/* $NetBSD: sgmap_typedep.c,v 1.17 2001/07/19 04:27:37 thorpej Exp $ */ /*- * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. @@ -38,28 +38,19 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifdef SGMAP_LOG - -#ifndef SGMAP_LOGSIZE -#define SGMAP_LOGSIZE 4096 -#endif - -struct sgmap_log_entry __C(SGMAP_TYPE,_log)[SGMAP_LOGSIZE]; -int __C(SGMAP_TYPE,_log_next); -int __C(SGMAP_TYPE,_log_last); -u_long __C(SGMAP_TYPE,_log_loads); -u_long __C(SGMAP_TYPE,_log_unloads); - -#endif /* SGMAP_LOG */ - #ifdef SGMAP_DEBUG int __C(SGMAP_TYPE,_debug) = 0; #endif SGMAP_PTE_TYPE __C(SGMAP_TYPE,_prefetch_spill_page_pte); +int __C(SGMAP_TYPE,_load_buffer)(bus_dma_tag_t, + bus_dmamap_t, void *buf, size_t buflen, + struct proc *, int, int *, + struct alpha_sgmap *); + void -__C(SGMAP_TYPE,_init_spill_page_pte)() +__C(SGMAP_TYPE,_init_spill_page_pte)(void) { __C(SGMAP_TYPE,_prefetch_spill_page_pte) = @@ -68,130 +59,110 @@ __C(SGMAP_TYPE,_init_spill_page_pte)() } int -__C(SGMAP_TYPE,_load)(t, map, buf, buflen, p, flags, sgmap) - bus_dma_tag_t t; - bus_dmamap_t map; - void *buf; - bus_size_t buflen; - struct proc *p; - int flags; - struct alpha_sgmap *sgmap; +__C(SGMAP_TYPE,_load_buffer)(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + size_t buflen, struct proc *p, int flags, int *segp, + struct alpha_sgmap *sgmap) { vaddr_t endva, va = (vaddr_t)buf; paddr_t pa; - bus_addr_t dmaoffset; - bus_size_t dmalen; + bus_addr_t dmaoffset, sgva; + bus_size_t sgvalen, boundary, alignment; SGMAP_PTE_TYPE *pte, *page_table = sgmap->aps_pt; - int pteidx, error; -#ifdef SGMAP_LOG - struct sgmap_log_entry sl; -#endif + int pteidx, error, spill; - /* - * Initialize the spill page PTE if that hasn't already been done. - */ + /* Initialize the spill page PTE if it hasn't been already. */ if (__C(SGMAP_TYPE,_prefetch_spill_page_pte) == 0) __C(SGMAP_TYPE,_init_spill_page_pte)(); /* - * Make sure that on error condition we return "no valid mappings". - */ - map->dm_mapsize = 0; - map->dm_nsegs = 0; - - if (buflen > map->_dm_size) - return (EINVAL); - - /* * Remember the offset into the first page and the total * transfer length. */ dmaoffset = ((u_long)buf) & PGOFSET; - dmalen = buflen; #ifdef SGMAP_DEBUG if (__C(SGMAP_TYPE,_debug)) { printf("sgmap_load: ----- buf = %p -----\n", buf); - printf("sgmap_load: dmaoffset = 0x%lx, dmalen = 0x%lx\n", - dmaoffset, dmalen); - } -#endif - -#ifdef SGMAP_LOG - if (panicstr == NULL) { - sl.sl_op = 1; - sl.sl_sgmap = sgmap; - sl.sl_origbuf = buf; - sl.sl_pgoffset = dmaoffset; - sl.sl_origlen = dmalen; + printf("sgmap_load: dmaoffset = 0x%lx, buflen = 0x%lx\n", + dmaoffset, buflen); } #endif /* * Allocate the necessary virtual address space for the * mapping. Round the size, since we deal with whole pages. - * - * alpha_sgmap_alloc will deal with the appropriate spill page - * allocations. - * */ + + /* XXX Always allocate a spill page for now. */ + spill = 1; + endva = round_page(va + buflen); va = trunc_page(va); - if ((map->_dm_flags & DMAMAP_HAS_SGMAP) == 0) { - error = alpha_sgmap_alloc(map, (endva - va), sgmap, flags); - if (error) - return (error); + + boundary = map->_dm_boundary; + alignment = NBPG; + + sgvalen = (endva - va); + if (spill) { + sgvalen += NBPG; + + /* + * ARGH! If the addition of the spill page bumped us + * over our boundary, we have to 2x the boundary limit. + */ + if (boundary && boundary < sgvalen) { + alignment = boundary; + do { + boundary <<= 1; + } while (boundary < sgvalen); + } } - pteidx = map->_dm_sgva >> PGSHIFT; +#if 0 + printf("len 0x%lx -> 0x%lx, boundary 0x%lx -> 0x%lx -> ", + (endva - va), sgvalen, map->_dm_boundary, boundary); +#endif + + error = extent_alloc(sgmap->aps_ex, sgvalen, alignment, 0, boundary, + (flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK, &sgva); + if (error) + return (error); + +#if 0 + printf("error %d sgva 0x%lx\n", error, sgva); +#endif + + pteidx = sgva >> SGMAP_ADDR_PTEIDX_SHIFT; pte = &page_table[pteidx * SGMAP_PTE_SPACING]; #ifdef SGMAP_DEBUG if (__C(SGMAP_TYPE,_debug)) printf("sgmap_load: sgva = 0x%lx, pteidx = %d, " - "pte = %p (pt = %p)\n", map->_dm_sgva, pteidx, pte, + "pte = %p (pt = %p)\n", sgva, pteidx, pte, page_table); #endif - /* - * Generate the DMA address. - */ - map->dm_segs[0].ds_addr = sgmap->aps_wbase | - (pteidx << SGMAP_ADDR_PTEIDX_SHIFT) | dmaoffset; - map->dm_segs[0].ds_len = dmalen; - -#ifdef SGMAP_LOG - if (panicstr == NULL) { - sl.sl_sgva = map->_dm_sgva; - sl.sl_dmaaddr = map->dm_segs[0].ds_addr; - } -#endif + /* Generate the DMA address. */ + map->dm_segs[*segp].ds_addr = sgmap->aps_wbase | sgva | dmaoffset; + map->dm_segs[*segp].ds_len = buflen; #ifdef SGMAP_DEBUG if (__C(SGMAP_TYPE,_debug)) printf("sgmap_load: wbase = 0x%lx, vpage = 0x%x, " - "dma addr = 0x%lx\n", sgmap->aps_wbase, - (pteidx << SGMAP_ADDR_PTEIDX_SHIFT), + "dma addr = 0x%lx\n", sgmap->aps_wbase, sgva, map->dm_segs[0].ds_addr); #endif - map->_dm_pteidx = pteidx; - map->_dm_ptecnt = 0; - for (; va < endva; va += NBPG, pteidx++, - pte = &page_table[pteidx * SGMAP_PTE_SPACING], - map->_dm_ptecnt++) { - /* - * Get the physical address for this segment. - */ + pte = &page_table[pteidx * SGMAP_PTE_SPACING]) { + /* Get the physical address for this segment. */ if (p != NULL) - pmap_extract(p->p_vmspace->vm_map.pmap, va, &pa); + (void) pmap_extract(p->p_vmspace->vm_map.pmap, va, + &pa); else pa = vtophys(va); - /* - * Load the current PTE with this page. - */ + /* Load the current PTE with this page. */ *pte = (pa >> SGPTE_PGADDR_SHIFT) | SGPTE_VALID; #ifdef SGMAP_DEBUG if (__C(SGMAP_TYPE,_debug)) @@ -200,132 +171,168 @@ __C(SGMAP_TYPE,_load)(t, map, buf, buflen, p, flags, sgmap) #endif } - /* - * ...and the prefetch-spill page. - */ - *pte = __C(SGMAP_TYPE,_prefetch_spill_page_pte); - map->_dm_ptecnt++; + if (spill) { + /* ...and the prefetch-spill page. */ + *pte = __C(SGMAP_TYPE,_prefetch_spill_page_pte); #ifdef SGMAP_DEBUG - if (__C(SGMAP_TYPE,_debug)) { - printf("sgmap_load: spill page, pte = %p, *pte = 0x%lx\n", - pte, *pte); - printf("sgmap_load: pte count = %d\n", map->_dm_ptecnt); - } + if (__C(SGMAP_TYPE,_debug)) { + printf("sgmap_load: spill page, pte = %p, " + "*pte = 0x%lx\n", pte, *pte); + printf("sgmap_load: pte count = %d\n", + map->_dm_ptecnt); + } #endif + } - alpha_mb(); + return (0); +} -#ifdef SGMAP_LOG - if (panicstr == NULL) { - sl.sl_ptecnt = map->_dm_ptecnt; - bcopy(&sl, &__C(SGMAP_TYPE,_log)[__C(SGMAP_TYPE,_log_next)], - sizeof(sl)); - __C(SGMAP_TYPE,_log_last) = __C(SGMAP_TYPE,_log_next); - if (++__C(SGMAP_TYPE,_log_next) == SGMAP_LOGSIZE) - __C(SGMAP_TYPE,_log_next) = 0; - __C(SGMAP_TYPE,_log_loads)++; - } -#endif +int +__C(SGMAP_TYPE,_load)(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags, struct alpha_sgmap *sgmap) +{ + int seg, error; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + if (buflen > map->_dm_size) + return (EINVAL); + + seg = 0; + error = __C(SGMAP_TYPE,_load_buffer)(t, map, buf, buflen, p, + flags, &seg, sgmap); + + alpha_mb(); #if defined(SGMAP_DEBUG) && defined(DDB) if (__C(SGMAP_TYPE,_debug) > 1) Debugger(); #endif - map->dm_mapsize = buflen; - map->dm_nsegs = 1; - return (0); + + if (error == 0) { + map->dm_mapsize = buflen; + map->dm_nsegs = 1; + } else if (t->_next_window != NULL) { + /* Give the next window a chance. */ + error = bus_dmamap_load(t->_next_window, map, buf, buflen, + p, flags); + } + return (error); } int -__C(SGMAP_TYPE,_load_mbuf)(t, map, m, flags, sgmap) - bus_dma_tag_t t; - bus_dmamap_t map; - struct mbuf *m; - int flags; - struct alpha_sgmap *sgmap; +__C(SGMAP_TYPE,_load_mbuf)(bus_dma_tag_t t, bus_dmamap_t map, + struct mbuf *m0, int flags, struct alpha_sgmap *sgmap) { + struct mbuf *m; + int seg, error; - panic(__S(__C(SGMAP_TYPE,_load_mbuf)) ": not implemented"); + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + +#ifdef DIAGNOSTIC + if ((m0->m_flags & M_PKTHDR) == 0) + panic(__S(__C(SGMAP_TYPE,_load_mbuf)) ": no packet header"); +#endif + + if (m0->m_pkthdr.len > map->_dm_size) + return (EINVAL); + + seg = 0; + error = 0; + for (m = m0; m != NULL && error == 0; m = m->m_next, seg++) + error = __C(SGMAP_TYPE,_load_buffer)(t, map, + m->m_data, m->m_len, NULL, flags, &seg, sgmap); + + alpha_mb(); + +#if defined(SGMAP_DEBUG) && defined(DDB) + if (__C(SGMAP_TYPE,_debug) > 1) + Debugger(); +#endif + + if (error == 0) { + map->dm_mapsize = m0->m_pkthdr.len; + map->dm_nsegs = seg; + } else { + /* Need to back out what we've done so far. */ + map->dm_nsegs = seg - 1; + __C(SGMAP_TYPE,_unload)(t, map, sgmap); + if (t->_next_window != NULL) { + /* Give the next window a chance. */ + error = bus_dmamap_load_mbuf(t->_next_window, map, + m0, flags); + } + } + + return (error); } int -__C(SGMAP_TYPE,_load_uio)(t, map, uio, flags, sgmap) - bus_dma_tag_t t; - bus_dmamap_t map; - struct uio *uio; - int flags; - struct alpha_sgmap *sgmap; +__C(SGMAP_TYPE,_load_uio)(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, + int flags, struct alpha_sgmap *sgmap) { panic(__S(__C(SGMAP_TYPE,_load_uio)) ": not implemented"); } int -__C(SGMAP_TYPE,_load_raw)(t, map, segs, nsegs, size, flags, sgmap) - bus_dma_tag_t t; - bus_dmamap_t map; - bus_dma_segment_t *segs; - int nsegs; - bus_size_t size; - int flags; - struct alpha_sgmap *sgmap; +__C(SGMAP_TYPE,_load_raw)(bus_dma_tag_t t, bus_dmamap_t map, + bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags, + struct alpha_sgmap *sgmap) { panic(__S(__C(SGMAP_TYPE,_load_raw)) ": not implemented"); } void -__C(SGMAP_TYPE,_unload)(t, map, sgmap) - bus_dma_tag_t t; - bus_dmamap_t map; - struct alpha_sgmap *sgmap; +__C(SGMAP_TYPE,_unload)(bus_dma_tag_t t, bus_dmamap_t map, + struct alpha_sgmap *sgmap) { SGMAP_PTE_TYPE *pte, *page_table = sgmap->aps_pt; - int ptecnt, pteidx; -#ifdef SGMAP_LOG - struct sgmap_log_entry *sl; - - if (panicstr == NULL) { - sl = &__C(SGMAP_TYPE,_log)[__C(SGMAP_TYPE,_log_next)]; - - bzero(sl, sizeof(*sl)); - sl->sl_op = 0; - sl->sl_sgmap = sgmap; - sl->sl_sgva = map->_dm_sgva; - sl->sl_dmaaddr = map->dm_segs[0].ds_addr; - - __C(SGMAP_TYPE,_log_last) = __C(SGMAP_TYPE,_log_next); - if (++__C(SGMAP_TYPE,_log_next) == SGMAP_LOGSIZE) - __C(SGMAP_TYPE,_log_next) = 0; - __C(SGMAP_TYPE,_log_unloads)++; - } -#endif + bus_addr_t osgva, sgva, esgva; + int spill, seg, pteidx; - /* - * Invalidate the PTEs for the mapping. - */ - for (ptecnt = map->_dm_ptecnt, pteidx = map->_dm_pteidx, - pte = &page_table[pteidx * SGMAP_PTE_SPACING]; - ptecnt != 0; - ptecnt--, pteidx++, - pte = &page_table[pteidx * SGMAP_PTE_SPACING]) { + for (seg = 0; seg < map->dm_nsegs; seg++) { + /* XXX Always have a spill page for now... */ + spill = 1; + + sgva = map->dm_segs[seg].ds_addr & ~sgmap->aps_wbase; + + esgva = round_page(sgva + map->dm_segs[seg].ds_len); + osgva = sgva = trunc_page(sgva); + + if (spill) + esgva += NBPG; + + /* Invalidate the PTEs for the mapping. */ + for (pteidx = sgva >> SGMAP_ADDR_PTEIDX_SHIFT; + sgva < esgva; sgva += NBPG, pteidx++) { + pte = &page_table[pteidx * SGMAP_PTE_SPACING]; #ifdef SGMAP_DEBUG - if (__C(SGMAP_TYPE,_debug)) - printf("sgmap_unload: pte = %p, *pte = 0x%lx\n", - pte, (u_long)(*pte)); + if (__C(SGMAP_TYPE,_debug)) + printf("sgmap_unload: pte = %p, " + "*pte = 0x%lx\n", pte, (u_long)(*pte)); #endif - *pte = 0; + *pte = 0; + } + + alpha_mb(); + + /* Free the virtual address space used by the mapping. */ + if (extent_free(sgmap->aps_ex, osgva, (esgva - osgva), + EX_NOWAIT) != 0) + panic(__S(__C(SGMAP_TYPE,_unload))); } - /* - * Free the virtual address space used by the mapping - * if necessary. - */ - if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) - alpha_sgmap_free(map, sgmap); - /* - * Mark the mapping invalid. - */ + /* Mark the mapping invalid. */ map->dm_mapsize = 0; map->dm_nsegs = 0; } |