summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2004-01-13 00:12:16 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2004-01-13 00:12:16 +0000
commitf0a51cf628ef210ed16eb4e7b25b9ad59beee2cd (patch)
treeb86cc9cbd1ad31816502772bd7e441e102d62ff1 /sys
parent96ed41a04504e15bd8cf28c643c2432eeb94d96e (diff)
support mbuf handling in alpha sgmap dma maps; from netbsd
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/alpha/dev/sgmap_typedep.c373
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;
}