Make is_dvmaend point to the last DVMA map address not the next

address, and fix off by one errors.

Also, do some optimization.
This commit is contained in:
nakayama 2009-12-06 13:15:25 +00:00
parent 37469dacdd
commit 0db9becb3d
1 changed files with 25 additions and 20 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: iommu.c,v 1.89 2009/12/05 16:48:26 jdc Exp $ */
/* $NetBSD: iommu.c,v 1.90 2009/12/06 13:15:25 nakayama Exp $ */
/*
* Copyright (c) 1999, 2000 Matthew R. Green
@ -59,7 +59,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.89 2009/12/05 16:48:26 jdc Exp $");
__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.90 2009/12/06 13:15:25 nakayama Exp $");
#include "opt_ddb.h"
@ -86,8 +86,10 @@ __KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.89 2009/12/05 16:48:26 jdc Exp $");
#define IDB_SYNC 0x8
int iommudebug = 0x0;
#define DPRINTF(l, s) do { if (iommudebug & l) printf s; } while (0)
#define IOTTE_DEBUG(n) (n)
#else
#define DPRINTF(l, s)
#define IOTTE_DEBUG(n) 0
#endif
#define iommu_strbuf_flush(i, v) do { \
@ -136,10 +138,10 @@ iommu_init(char *name, struct iommu_state *is, int tsbsize, uint32_t iovabase)
is->is_tsbsize = tsbsize;
if (iovabase == -1) {
is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize);
is->is_dvmaend = IOTSB_VEND;
is->is_dvmaend = IOTSB_VEND - 1;
} else {
is->is_dvmabase = iovabase;
is->is_dvmaend = iovabase + IOTSB_VSIZE(tsbsize);
is->is_dvmaend = iovabase + IOTSB_VSIZE(tsbsize) - 1;
}
/*
@ -207,9 +209,9 @@ iommu_init(char *name, struct iommu_state *is, int tsbsize, uint32_t iovabase)
(unsigned int)is->is_dvmaend);
printf("IOTSB: %llx to %llx\n",
(unsigned long long)is->is_ptsb,
(unsigned long long)(is->is_ptsb + size));
(unsigned long long)(is->is_ptsb + size - 1));
is->is_dvmamap = extent_create(name,
is->is_dvmabase, is->is_dvmaend - PAGE_SIZE,
is->is_dvmabase, is->is_dvmaend,
M_DEVBUF, 0, 0, EX_NOWAIT);
}
@ -305,7 +307,7 @@ iommu_extract(struct iommu_state *is, vaddr_t dva)
{
int64_t tte = 0;
if (dva >= is->is_dvmabase && dva < is->is_dvmaend)
if (dva >= is->is_dvmabase && dva <= is->is_dvmaend)
tte = is->is_tsb[IOTSBSLOT(dva, is->is_tsbsize)];
if ((tte & IOTTE_V) == 0)
@ -435,7 +437,7 @@ iommu_dvmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
int err;
bus_size_t sgsize;
paddr_t curaddr;
u_long dvmaddr, sgstart, sgend;
u_long dvmaddr, sgstart, sgend, bmask;
bus_size_t align, boundary, len;
vaddr_t vaddr = (vaddr_t)buf;
int seg;
@ -510,7 +512,8 @@ iommu_dvmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
DPRINTF(IDB_INFO, ("iommu_dvmamap_load: boundary %lx boundary - 1 %lx "
"~(boundary - 1) %lx\n", (long)boundary, (long)(boundary - 1),
(long)~(boundary - 1)));
while ((sgstart & ~(boundary - 1)) != (sgend & ~(boundary - 1))) {
bmask = ~(boundary - 1);
while ((sgstart & bmask) != (sgend & bmask)) {
/* Oops. We crossed a boundary. Split the xfer. */
len = boundary - (sgstart & (boundary - 1));
map->dm_segs[seg].ds_len = len;
@ -572,7 +575,7 @@ iommu_dvmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
map, (void *)vaddr, (long)dvmaddr,
(long)trunc_page(curaddr)));
iommu_enter(sb, trunc_page(dvmaddr), trunc_page(curaddr),
flags|0x4000);
flags | IOTTE_DEBUG(0x4000));
dvmaddr += PAGE_SIZE;
vaddr += sgsize;
@ -647,10 +650,12 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
bus_size_t sgsize;
paddr_t pa;
bus_size_t boundary, align;
u_long dvmaddr, sgstart, sgend;
u_long dvmaddr, sgstart, sgend, bmask;
struct pglist *pglist;
int pagesz = PAGE_SIZE;
int npg = 0; /* DEBUG */
const int pagesz = PAGE_SIZE;
#ifdef DEBUG
int npg = 0;
#endif
if (map->dm_nsegs) {
/* Already in use?? */
@ -717,6 +722,7 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
map->_dm_dvmastart = dvmaddr;
map->_dm_dvmasize = sgsize;
bmask = ~(boundary - 1);
if ((pglist = segs[0]._ds_mlist) == NULL) {
u_long prev_va = 0UL;
paddr_t prev_pa = 0;
@ -776,8 +782,7 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
end = (offset + left) & PGOFSET;
/* Check for boundary issues */
while ((sgstart & ~(boundary - 1)) !=
(sgend & ~(boundary - 1))) {
while ((sgstart & bmask) != (sgend & bmask)) {
/* Need a new segment. */
map->dm_segs[j].ds_len =
boundary - (sgstart & (boundary - 1));
@ -807,8 +812,8 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
/* Enter it if we haven't before. */
if (prev_va != dvmaddr)
iommu_enter(sb, prev_va = dvmaddr,
prev_pa = pa,
flags | (++npg << 12));
prev_pa = pa,
flags | IOTTE_DEBUG(++npg << 12));
dvmaddr += pagesz;
pa += pagesz;
}
@ -845,7 +850,7 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
sgstart = dvmaddr;
sgend = sgstart + size - 1;
map->dm_segs[i].ds_addr = sgstart;
while ((sgstart & ~(boundary - 1)) != (sgend & ~(boundary - 1))) {
while ((sgstart & bmask) != (sgend & bmask)) {
/* Oops. We crossed a boundary. Split the xfer. */
map->dm_segs[i].ds_len = boundary - (sgstart & (boundary - 1));
DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: "
@ -879,7 +884,7 @@ iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
DPRINTF(IDB_BUSDMA,
("iommu_dvmamap_load_raw: map %p loading va %lx at pa %lx\n",
map, (long)dvmaddr, (long)(pa)));
iommu_enter(sb, dvmaddr, pa, flags|0x8000);
iommu_enter(sb, dvmaddr, pa, flags | IOTTE_DEBUG(0x8000));
dvmaddr += pagesz;
sgsize -= pagesz;
@ -927,7 +932,7 @@ iommu_dvmamap_sync_range(struct strbuf_ctl *sb, vaddr_t va, bus_size_t len)
return (0);
}
vaend = round_page(va + len);
vaend = round_page(va + len) - 1;
va = trunc_page(va);
#ifdef DIAGNOSTIC