Simplify the SGMAP code a bit, and move SGVA allocation out of a

common routine into the individual load routines, since each load
routine needs to muddle with the "internals" of this operation.

Add a `prefetch threshold' member to the bus_dma_tag_t, so that
eventually we can determine whether or not to allocate a spill
page on a per-mapping basis.
This commit is contained in:
thorpej 2001-07-19 04:27:37 +00:00
parent fd5247de51
commit 8617f2c7f5
4 changed files with 106 additions and 240 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: sgmap_common.c,v 1.17 2001/07/12 23:25:40 thorpej Exp $ */
/* $NetBSD: sgmap_common.c,v 1.18 2001/07/19 04:27:37 thorpej Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -39,7 +39,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: sgmap_common.c,v 1.17 2001/07/12 23:25:40 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: sgmap_common.c,v 1.18 2001/07/19 04:27:37 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -142,78 +142,6 @@ alpha_sgmap_init(bus_dma_tag_t t, struct alpha_sgmap *sgmap, const char *name,
panic("alpha_sgmap_init");
}
int
alpha_sgmap_alloc(bus_dmamap_t map, bus_size_t origlen,
struct alpha_sgmap *sgmap, int flags)
{
int error;
bus_size_t len = origlen, boundary, alignment;
#ifdef DIAGNOSTIC
if (map->_dm_flags & DMAMAP_HAS_SGMAP)
panic("alpha_sgmap_alloc: already have sgva space");
#endif
/*
* Add a range for spill page.
*/
len += NBPG;
/*
* And add an additional amount in case of ALLOCNOW.
*/
if (flags & BUS_DMA_ALLOCNOW)
len += NBPG;
map->_dm_sgvalen = round_page(len);
/*
* ARGH! If the addition of spill pages bumped us over our
* boundary, we have to 2x the boundary limit.
*/
boundary = map->_dm_boundary;
if (boundary && boundary < map->_dm_sgvalen) {
alignment = boundary;
do {
boundary <<= 1;
} while (boundary < map->_dm_sgvalen);
} else
alignment = NBPG;
#if 0
printf("len %x -> %x, _dm_sgvalen %x _dm_boundary %x boundary %x -> ",
origlen, len, map->_dm_sgvalen, map->_dm_boundary, boundary);
#endif
error = extent_alloc(sgmap->aps_ex, map->_dm_sgvalen, alignment,
boundary, (flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK,
&map->_dm_sgva);
#if 0
printf("error %d _dm_sgva %x\n", error, map->_dm_sgva);
#endif
if (error == 0)
map->_dm_flags |= DMAMAP_HAS_SGMAP;
else
map->_dm_flags &= ~DMAMAP_HAS_SGMAP;
return (error);
}
void
alpha_sgmap_free(bus_dmamap_t map, struct alpha_sgmap *sgmap)
{
#ifdef DIAGNOSTIC
if ((map->_dm_flags & DMAMAP_HAS_SGMAP) == 0)
panic("alpha_sgmap_free: no sgva space to free");
#endif
if (extent_free(sgmap->aps_ex, map->_dm_sgva, map->_dm_sgvalen,
EX_NOWAIT))
panic("alpha_sgmap_free");
map->_dm_flags &= ~DMAMAP_HAS_SGMAP;
}
int
alpha_sgmap_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
@ -226,9 +154,7 @@ alpha_sgmap_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
if (error)
return (error);
if (flags & BUS_DMA_ALLOCNOW)
error = alpha_sgmap_alloc(map, round_page(size),
t->_sgmap, flags);
/* XXX BUS_DMA_ALLOCNOW */
if (error == 0)
*dmamp = map;
@ -242,8 +168,7 @@ void
alpha_sgmap_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
{
if (map->_dm_flags & DMAMAP_HAS_SGMAP)
alpha_sgmap_free(map, t->_sgmap);
KASSERT(map->dm_mapsize == 0);
_bus_dmamap_destroy(t, map);
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: sgmap_typedep.c,v 1.16 2001/07/12 23:35:43 thorpej Exp $ */
/* $NetBSD: sgmap_typedep.c,v 1.17 2001/07/19 04:27:37 thorpej Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -37,24 +37,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
__KERNEL_RCSID(0, "$NetBSD: sgmap_typedep.c,v 1.16 2001/07/12 23:35:43 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: sgmap_typedep.c,v 1.17 2001/07/19 04:27:37 thorpej Exp $");
#include "opt_ddb.h"
#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
@ -76,13 +62,10 @@ __C(SGMAP_TYPE,_load)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
{
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.
@ -104,65 +87,70 @@ __C(SGMAP_TYPE,_load)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
* 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, boundary,
(flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK, &sgva);
#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[0].ds_addr = sgmap->aps_wbase | sgva | dmaoffset;
map->dm_segs[0].ds_len = buflen;
#ifdef SGMAP_DEBUG
if (__C(SGMAP_TYPE,_debug))
@ -172,24 +160,16 @@ __C(SGMAP_TYPE,_load)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
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)
(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))
@ -198,33 +178,21 @@ __C(SGMAP_TYPE,_load)(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
#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();
#ifdef SGMAP_LOG
if (panicstr == NULL) {
sl.sl_ptecnt = map->_dm_ptecnt;
memcpy(&__C(SGMAP_TYPE,_log)[__C(SGMAP_TYPE,_log_next)], &sl,
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
#if defined(SGMAP_DEBUG) && defined(DDB)
if (__C(SGMAP_TYPE,_debug) > 1)
Debugger();
@ -264,51 +232,42 @@ __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;
bus_addr_t osgva, sgva, esgva;
int spill, seg, pteidx;
if (panicstr == NULL) {
sl = &__C(SGMAP_TYPE,_log)[__C(SGMAP_TYPE,_log_next)];
for (seg = 0; seg < map->dm_nsegs; seg++) {
/* XXX Always have a spill page for now... */
spill = 1;
memset(sl, 0, 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;
sgva = map->dm_segs[seg].ds_addr & ~sgmap->aps_wbase;
__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
esgva = round_page(sgva + map->dm_segs[seg].ds_len);
osgva = sgva = trunc_page(sgva);
/*
* 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]) {
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;
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: sgmapvar.h,v 1.12 2001/01/03 20:29:58 thorpej Exp $ */
/* $NetBSD: sgmapvar.h,v 1.13 2001/07/19 04:27:37 thorpej Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -67,20 +67,6 @@ struct alpha_sgmap {
bus_addr_t aps_wbase; /* base of the dma window */
};
/*
* Log entry, used for debugging SGMAPs.
*/
struct sgmap_log_entry {
int sl_op; /* op; 1 = load, 0 = unload */
struct alpha_sgmap *sl_sgmap; /* sgmap for entry */
void *sl_origbuf; /* original buffer */
u_long sl_pgoffset; /* page offset of buffer start */
u_long sl_origlen; /* length of transfer */
u_long sl_sgva; /* sgva of transfer */
u_long sl_dmaaddr; /* dma address */
int sl_ptecnt; /* pte count */
};
extern vaddr_t alpha_sgmap_prefetch_spill_page_va;
extern bus_addr_t alpha_sgmap_prefetch_spill_page_pa;
@ -88,10 +74,6 @@ void alpha_sgmap_init(bus_dma_tag_t, struct alpha_sgmap *,
const char *, bus_addr_t, bus_addr_t, bus_size_t, size_t, void *,
bus_size_t);
int alpha_sgmap_alloc(bus_dmamap_t, bus_size_t,
struct alpha_sgmap *, int);
void alpha_sgmap_free(bus_dmamap_t, struct alpha_sgmap *);
int alpha_sgmap_dmamap_create(bus_dma_tag_t, bus_size_t, int,
bus_size_t, bus_size_t, int, bus_dmamap_t *);
void alpha_sgmap_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);

View File

@ -1,4 +1,4 @@
/* $NetBSD: bus.h,v 1.43 2001/06/21 12:15:03 wiz Exp $ */
/* $NetBSD: bus.h,v 1.44 2001/07/19 04:27:37 thorpej Exp $ */
/*-
* Copyright (c) 1997, 1998, 2000, 2001 The NetBSD Foundation, Inc.
@ -506,7 +506,6 @@ do { \
*/
#define DMAMAP_NO_COALESCE 0x40000000 /* don't coalesce adjacent
segments */
#define DMAMAP_HAS_SGMAP 0x80000000 /* sgva/len are valid */
/* Forwards needed by prototypes below. */
struct mbuf;
@ -595,6 +594,16 @@ struct alpha_bus_dma_tag {
*/
struct alpha_sgmap *_sgmap;
/*
* The SGMAP MMU implements a prefetch FIFO to keep data
* moving down the pipe, when doing host->bus DMA writes.
* The threshold (distance until the next page) used to
* trigger the prefetch is differnet on different chipsets,
* and we need to know what it is in order to know whether
* or not to allocate a spill page.
*/
bus_size_t _pfthresh;
/*
* Internal-use only utility methods. NOT TO BE USED BY
* MACHINE-INDEPENDENT CODE!
@ -678,15 +687,6 @@ struct alpha_bus_dmamap {
bus_size_t _dm_boundary; /* don't cross this */
int _dm_flags; /* misc. flags */
/*
* This is used only for SGMAP-mapped DMA, but we keep it
* here to avoid pointless indirection.
*/
int _dm_pteidx; /* PTE index */
int _dm_ptecnt; /* PTE count */
u_long _dm_sgva; /* allocated sgva */
bus_size_t _dm_sgvalen; /* svga length */
/*
* Private cookie to be used by the DMA back-end.
*/