summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64/dev/iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sparc64/dev/iommu.c')
-rw-r--r--sys/arch/sparc64/dev/iommu.c589
1 files changed, 298 insertions, 291 deletions
diff --git a/sys/arch/sparc64/dev/iommu.c b/sys/arch/sparc64/dev/iommu.c
index e3829d1763e..9b75a86c311 100644
--- a/sys/arch/sparc64/dev/iommu.c
+++ b/sys/arch/sparc64/dev/iommu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: iommu.c,v 1.23 2002/10/12 01:09:43 krw Exp $ */
+/* $OpenBSD: iommu.c,v 1.24 2003/02/17 01:29:20 henric Exp $ */
/* $NetBSD: iommu.c,v 1.47 2002/02/08 20:03:45 eeh Exp $ */
/*
@@ -68,19 +68,21 @@ int iommudebug = 0x0;
int iommu_dvmamap_sync_seg(bus_dma_tag_t, struct iommu_state *,
bus_dma_segment_t *, bus_addr_t, bus_size_t, int);
+int iommu_dvmamap_sync_range(struct iommu_state *, vaddr_t, bus_size_t);
-#define iommu_strbuf_flush(i,v) do { \
- if ((i)->is_sb[0]) \
- bus_space_write_8((i)->is_bustag, \
- (bus_space_handle_t)(u_long) \
- &(i)->is_sb[0]->strbuf_pgflush, \
- 0, (v)); \
- if ((i)->is_sb[1]) \
- bus_space_write_8((i)->is_bustag, \
- (bus_space_handle_t)(u_long) \
- &(i)->is_sb[1]->strbuf_pgflush, \
- 0, (v)); \
- } while (0)
+static inline void
+iommu_strbuf_flush(struct iommu_state* is, vaddr_t va)
+{
+ int i;
+ for(i = 0; i < 2; ++i) {
+ struct strbuf_ctl *sb = is->is_sb[i];
+ if(sb == NULL || sb->sb_flush == NULL)
+ continue;
+
+ bus_space_write_8(sb->sb_bustag, sb->sb_sb,
+ STRBUFREG(strbuf_pgflush), va);
+ }
+}
static int iommu_strbuf_flush_done(struct iommu_state *);
int64_t iommu_tsb_entry(struct iommu_state *, vaddr_t);
@@ -94,11 +96,7 @@ static int iommu_tv_comp(struct timeval *, struct timeval *);
* - create a private DVMA map.
*/
void
-iommu_init(name, is, tsbsize, iovabase)
- char *name;
- struct iommu_state *is;
- int tsbsize;
- u_int32_t iovabase;
+iommu_init(char *name, struct iommu_state *is, int tsbsize, u_int32_t iovabase)
{
psize_t size;
vaddr_t va;
@@ -137,7 +135,7 @@ iommu_init(name, is, tsbsize, iovabase)
* contiguous.
*/
- size = NBPG<<(is->is_tsbsize);
+ size = NBPG << is->is_tsbsize;
TAILQ_INIT(&mlist);
if (uvm_pglistalloc((psize_t)size, (paddr_t)0, (paddr_t)-1,
(paddr_t)NBPG, (paddr_t)0, &mlist, 1, 0) != 0)
@@ -160,39 +158,39 @@ iommu_init(name, is, tsbsize, iovabase)
va += NBPG;
}
pmap_update(pmap_kernel());
- bzero(is->is_tsb, size);
+ memset(is->is_tsb, 0, size);
#ifdef DEBUG
- if (iommudebug & IDB_INFO)
- {
+ if (iommudebug & IDB_INFO) {
/* Probe the iommu */
- struct iommureg *regs = is->is_iommu;
-
+ /* The address or contents of the regs...? */
printf("iommu regs at: cr=%lx tsb=%lx flush=%lx\n",
- (u_long)&regs->iommu_cr,
- (u_long)&regs->iommu_tsb,
- (u_long)&regs->iommu_flush);
- printf("iommu cr=%llx tsb=%llx\n", (unsigned long long)regs->iommu_cr, (unsigned long long)regs->iommu_tsb);
- printf("TSB base %p phys %llx\n", (void *)is->is_tsb, (unsigned long long)is->is_ptsb);
+ (u_long)bus_space_vaddr(is->is_bustag, is->is_iommu) +
+ IOMMUREG(iommu_cr),
+ (u_long)bus_space_vaddr(is->is_bustag, is->is_iommu) +
+ IOMMUREG(iommu_tsb),
+ (u_long)bus_space_vaddr(is->is_bustag, is->is_iommu) +
+ IOMMUREG(iommu_flush));
+ printf("iommu cr=%llx tsb=%llx\n",
+ IOMMUREG_READ(is, iommu_cr),
+ IOMMUREG_READ(is, iommu_tsb));
+ printf("TSB base %p phys %llx\n",
+ (void *)is->is_tsb, (unsigned long long)is->is_ptsb);
delay(1000000); /* 1 s */
}
#endif
/*
- * Initialize streaming buffer, if it is there.
- */
- if (is->is_sb[0] || is->is_sb[1])
- (void)pmap_extract(pmap_kernel(), (vaddr_t)&is->is_flush[0],
- &is->is_flushpa);
-
- /*
* now actually start up the IOMMU
+ * Don't start the thing until it can see all the TSB data
*/
+ membar(MemIssue);
iommu_reset(is);
/*
* Now all the hardware's working we need to allocate a dvma map.
*/
+ printf("DVMA map: %x to %x\n", is->is_dvmabase, is->is_dvmaend);
printf("IOTDB: %llx to %llx\n",
(unsigned long long)is->is_ptsb,
(unsigned long long)(is->is_ptsb + size));
@@ -207,33 +205,40 @@ iommu_init(name, is, tsbsize, iovabase)
* they aren't there when the STRBUF_EN bit does not remain.
*/
void
-iommu_reset(is)
- struct iommu_state *is;
+iommu_reset(struct iommu_state *is)
{
- struct iommu_strbuf *sb;
int i;
/* Need to do 64-bit stores */
- bus_space_write_8(is->is_bustag,
- (bus_space_handle_t)(u_long)&is->is_iommu->iommu_tsb,
- 0, is->is_ptsb);
+
+ IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb);
+
/* Enable IOMMU in diagnostic mode */
- bus_space_write_8(is->is_bustag,
- (bus_space_handle_t)(u_long)&is->is_iommu->iommu_cr, 0,
- is->is_cr|IOMMUCR_DE);
-
- for (i=0; i<2; i++) {
- if ((sb = is->is_sb[i]) != NULL) {
- /* Enable diagnostics mode? */
- bus_space_write_8(is->is_bustag,
- (bus_space_handle_t)(u_long)&sb->strbuf_ctl,
- 0, STRBUF_EN);
-
- /* No streaming buffers? Disable them */
- if (bus_space_read_8(is->is_bustag,
- (bus_space_handle_t)(u_long)&sb->strbuf_ctl,
- 0) == 0)
- is->is_sb[i] = 0;
+ IOMMUREG_WRITE(is, iommu_cr, is->is_cr | IOMMUCR_DE);
+
+ for (i = 0; i < 2; i++) {
+ struct strbuf_ctl *sb = is->is_sb[i];
+
+ if(sb == NULL || sb->sb_flush == NULL)
+ continue;
+
+ /* Enable diagnostics mode? */
+ bus_space_write_8(sb->sb_bustag, sb->sb_sb,
+ STRBUFREG(strbuf_ctl), STRBUF_EN);
+
+ membar(Lookaside);
+
+ /* No streaming buffers? Disable them */
+ if (bus_space_read_8(sb->sb_bustag, sb->sb_sb,
+ STRBUFREG(strbuf_ctl)) == 0) {
+ sb->sb_flush = NULL;
+ } else {
+ /*
+ * locate the pa of the flush buffer
+ */
+
+ pmap_extract(pmap_kernel(),
+ (vaddr_t)sb->sb_flush, &sb->sb_flushpa);
}
}
}
@@ -242,71 +247,74 @@ iommu_reset(is)
* Here are the iommu control routines.
*/
void
-iommu_enter(is, va, pa, flags)
- struct iommu_state *is;
- vaddr_t va;
- int64_t pa;
- int flags;
+iommu_enter(struct iommu_state *is, vaddr_t va, int64_t pa, int flags)
{
int64_t tte;
+ int strbuf = flags & BUS_DMA_STREAMING;
#ifdef DIAGNOSTIC
if (va < is->is_dvmabase || va > is->is_dvmaend)
panic("iommu_enter: va %#lx not in DVMA space", va);
#endif
- tte = MAKEIOTTE(pa, !(flags&BUS_DMA_NOWRITE), !(flags&BUS_DMA_NOCACHE),
- (flags&BUS_DMA_STREAMING));
-tte |= (flags & 0xff000LL)<<(4*8);/* DEBUG */
-
/* Is the streamcache flush really needed? */
- if (is->is_sb[0] || is->is_sb[1]) {
+ if (is->is_sb[0] != NULL || is->is_sb[1] != NULL) {
iommu_strbuf_flush(is, va);
iommu_strbuf_flush_done(is);
}
+ else
+ strbuf = 0;
+
+ tte = MAKEIOTTE(pa, !(flags & BUS_DMA_NOWRITE),
+ !(flags & BUS_DMA_NOCACHE), (strbuf));
+#ifdef DEBUG
+ tte |= (flags & 0xff000LL) << (4 * 8); /* DEBUG */
+#endif /* DEBUG */
+
+
DPRINTF(IDB_IOMMU, ("Clearing TSB slot %d for va %p\n",
(int)IOTSBSLOT(va,is->is_tsbsize), (void *)(u_long)va));
is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)] = tte;
- bus_space_write_8(is->is_bustag, (bus_space_handle_t)(u_long)
- &is->is_iommu->iommu_flush, 0, va);
+ /* Make is->is_tsb[] change globally visible. Needed? */
+ membar(MemIssue);
+ IOMMUREG_WRITE(is, iommu_flush, va);
+
DPRINTF(IDB_IOMMU, ("iommu_enter: va %lx pa %lx TSB[%lx]@%p=%lx\n",
va, (long)pa, (u_long)IOTSBSLOT(va,is->is_tsbsize),
- (void *)(u_long)&is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
+ (void *)(u_long)
+ &is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
(u_long)tte));
}
-
/*
* Find the value of a DVMA address (debug routine).
*/
paddr_t
-iommu_extract(is, dva)
- struct iommu_state *is;
- vaddr_t dva;
+iommu_extract(struct iommu_state *is, vaddr_t dva)
{
int64_t tte = 0;
if (dva >= is->is_dvmabase && dva < is->is_dvmaend)
- tte = is->is_tsb[IOTSBSLOT(dva,is->is_tsbsize)];
+ tte = is->is_tsb[IOTSBSLOT(dva, is->is_tsbsize)];
- if ((tte&IOTTE_V) == 0)
+ if ((tte & IOTTE_V) == 0)
return ((paddr_t)-1L);
- return (tte&IOTTE_PAMASK);
+ return (tte & IOTTE_PAMASK);
}
/*
* Fetch a tsb entry with some sanity checking.
*/
int64_t
-iommu_tsb_entry(is, dva)
- struct iommu_state *is;
- vaddr_t dva;
+iommu_tsb_entry(struct iommu_state *is, vaddr_t dva)
{
int64_t tte;
if (dva < is->is_dvmabase && dva >= is->is_dvmaend)
panic("invalid dva: %llx", (long long)dva);
+ membar(Lookaside);
+
tte = is->is_tsb[IOTSBSLOT(dva,is->is_tsbsize)];
if ((tte & IOTTE_V) == 0)
@@ -323,10 +331,7 @@ iommu_tsb_entry(is, dva)
* XXX: this function needs better internal error checking.
*/
void
-iommu_remove(is, va, len)
- struct iommu_state *is;
- vaddr_t va;
- size_t len;
+iommu_remove(struct iommu_state *is, vaddr_t va, size_t len)
{
#ifdef DIAGNOSTIC
if (va < is->is_dvmabase || va > is->is_dvmaend)
@@ -343,21 +348,34 @@ iommu_remove(is, va, len)
va, (u_long)IOTSBSLOT(va,is->is_tsbsize),
&is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)]));
while (len > 0) {
- DPRINTF(IDB_IOMMU, ("iommu_remove: clearing TSB slot %d for va %p size %lx\n",
- (int)IOTSBSLOT(va,is->is_tsbsize), (void *)(u_long)va, (u_long)len));
- if (is->is_sb[0] || is->is_sb[0]) {
- DPRINTF(IDB_IOMMU, ("iommu_remove: flushing va %p TSB[%lx]@%p=%lx, %lu bytes left\n",
- (void *)(u_long)va, (long)IOTSBSLOT(va,is->is_tsbsize),
- (void *)(u_long)&is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
- (long)(is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)]),
+ /* NetBSD does *not* flush the streaming buffer (here, anyway) */
+ DPRINTF(IDB_IOMMU,
+ ("iommu_remove: clearing TSB slot %d for va %p size %lx\n",
+ (int)IOTSBSLOT(va,is->is_tsbsize),
+ (void *)(u_long)va, (u_long)len));
+ if (is->is_sb[0] != NULL || is->is_sb[1] != NULL) {
+ DPRINTF(IDB_IOMMU,
+ ("iommu_remove: flushing va %p TSB[%lx]@%p=%lx, "
+ "%lu bytes left\n",
+ (void *)(u_long)va,
+ (long)IOTSBSLOT(va,is->is_tsbsize),
+ (void *)(u_long)
+ &is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
+ (long)
+ (is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)]),
(u_long)len));
iommu_strbuf_flush(is, va);
if (len <= NBPG)
iommu_strbuf_flush_done(is);
- DPRINTF(IDB_IOMMU, ("iommu_remove: flushed va %p TSB[%lx]@%p=%lx, %lu bytes left\n",
- (void *)(u_long)va, (long)IOTSBSLOT(va,is->is_tsbsize),
- (void *)(u_long)&is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
- (long)(is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)]),
+ DPRINTF(IDB_IOMMU,
+ ("iommu_remove: flushed va %p TSB[%lx]@%p=%lx, "
+ "%lu bytes left\n",
+ (void *)(u_long)va,
+ (long)IOTSBSLOT(va,is->is_tsbsize),
+ (void *)(u_long)
+ &is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
+ (long)
+ (is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)]),
(u_long)len));
}
@@ -367,16 +385,15 @@ iommu_remove(is, va, len)
len -= NBPG;
/* XXX Zero-ing the entry would not require RMW */
- is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)] &= ~IOTTE_V;
- bus_space_write_8(is->is_bustag, (bus_space_handle_t)(u_long)
- &is->is_iommu->iommu_flush, 0, va);
+ is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)] &= ~IOTTE_V;
+ membar(MemIssue); /* Needed? */
+ IOMMUREG_WRITE(is, iommu_flush, va);
va += NBPG;
}
}
static int
-iommu_tv_comp(t1, t2)
- struct timeval *t1, *t2;
+iommu_tv_comp(struct timeval *t1, struct timeval *t2)
{
if (t1->tv_sec < t2->tv_sec)
return (-1);
@@ -391,12 +408,22 @@ iommu_tv_comp(t1, t2)
}
static int
-iommu_strbuf_flush_done(is)
- struct iommu_state *is;
+iommu_strbuf_flush_done(struct iommu_state *is)
{
struct timeval cur, flushtimeout;
+ struct timeval to = { 0, 500000 };
+ u_int64_t flush[2];
+ struct strbuf_ctl *sb[2];
+ int i;
+ int present[2];
+
+ for(i = 0; i < 2; ++i) {
+ sb[i] = is->is_sb[i];
+ present[i] =
+ (sb[i] == NULL || sb[i]->sb_flush == NULL) ? 0 : 1;
+ }
- if (!is->is_sb[0] && !is->is_sb[1])
+ if (!present[0] && !present[1])
return (0);
/*
@@ -411,74 +438,86 @@ iommu_strbuf_flush_done(is)
* If it takes more than .5 sec, something
* went wrong.
*/
- is->is_flush[0] = (is->is_sb[0] == NULL) ? 1 : 0;
- is->is_flush[1] = (is->is_sb[1] == NULL) ? 1 : 0;
- membar_memissue();
-
- if (is->is_sb[0]) {
- bus_space_write_8(is->is_bustag, (bus_space_handle_t)(u_long)
- &is->is_sb[0]->strbuf_flushsync, 0, is->is_flushpa);
- bus_space_barrier(is->is_bustag, (bus_space_handle_t)(u_long)
- &is->is_sb[0]->strbuf_flushsync, 0, sizeof(u_int64_t),
- BUS_SPACE_BARRIER_WRITE);
- }
- if (is->is_sb[1]) {
- bus_space_write_8(is->is_bustag, (bus_space_handle_t)(u_long)
- &is->is_sb[1]->strbuf_flushsync, 0, is->is_flushpa + 8);
- bus_space_barrier(is->is_bustag, (bus_space_handle_t)(u_long)
- &is->is_sb[1]->strbuf_flushsync, 0, sizeof(u_int64_t),
- BUS_SPACE_BARRIER_WRITE);
+ /*
+ * If we're reading from the ASI_PHYS_CACHED, then we'll write to
+ * it too. No need to tempt fate or learn about Si bugs or such.
+ * FreeBSD just uses normal "volatile" reads/writes...
+ */
+
+ for(i = 0; i < 2; ++i)
+ if(present[i])
+ stxa(sb[i]->sb_flushpa, ASI_PHYS_CACHED, 0);
+
+ /*
+ * Insure any previous strbuf operations are complete and that
+ * memory is initialized before the IOMMU uses it
+ */
+ membar(MemIssue);
+
+ for(i = 0; i < 2; ++i) {
+ if (present[i])
+ bus_space_write_8(sb[i]->sb_bustag, sb[i]->sb_sb,
+ STRBUFREG(strbuf_flushsync), sb[i]->sb_flushpa);
}
microtime(&cur);
- flushtimeout.tv_usec = cur.tv_usec + 500000; /* 1/2 sec */
- if (flushtimeout.tv_usec >= 1000000) {
- flushtimeout.tv_usec -= 1000000;
- flushtimeout.tv_sec = cur.tv_sec + 1;
- } else
- flushtimeout.tv_sec = cur.tv_sec;
+ timeradd(&cur, &to, &flushtimeout);
- DPRINTF(IDB_IOMMU, ("iommu_strbuf_flush_done: flush = %lx at va = %lx pa = %lx now=%lx:%lx until = %lx:%lx\n",
- (long)is->is_flush, (long)&is->is_flush,
- (long)is->is_flushpa, cur.tv_sec, cur.tv_usec,
- flushtimeout.tv_sec, flushtimeout.tv_usec));
+ DPRINTF(IDB_IOMMU,
+ ("iommu_strbuf_flush_done: flush[0] = %lx flush[1] = %lx "
+ "pa[0] = %lx pa[1] = %lx now=%lx:%lx until = %lx:%lx\n",
+ (long)present[0] ?
+ ldxa(sb[0]->sb_flushpa, ASI_PHYS_CACHED) : 1,
+ (long)present[1] ?
+ ldxa(sb[1]->sb_flushpa, ASI_PHYS_CACHED) : 1,
+ (long)sb[0]->sb_flushpa,
+ (long)sb[1]->sb_flushpa, cur.tv_sec, cur.tv_usec,
+ flushtimeout.tv_sec, flushtimeout.tv_usec));
+
+ membar(MemIssue | Lookaside);
/* Bypass non-coherent D$ */
- while (((ldxa(is->is_flushpa, ASI_PHYS_CACHED) == 0) ||
- (ldxa(is->is_flushpa + 8, ASI_PHYS_CACHED) == 0)) &&
- (iommu_tv_comp(&cur, &flushtimeout) <= 0)) {
+ /* non-coherent...? Huh? */
+ for(;;) {
+ membar(LoadLoad);
+
+ flush[0] =
+ present[0] ? ldxa(sb[0]->sb_flushpa, ASI_PHYS_CACHED) : 1;
+ flush[1] =
+ present[1] ? ldxa(sb[1]->sb_flushpa, ASI_PHYS_CACHED) : 1;
+
+ if(flush[0] && flush[1])
+ break;
+
microtime(&cur);
+ /* Use existing time compare macros? */
+ if(iommu_tv_comp(&cur, &flushtimeout) <= 0)
+ break;
}
#ifdef DIAGNOSTIC
- if (((is->is_sb[0] != NULL) && (ldxa(is->is_flushpa, ASI_PHYS_CACHED) == 0)) ||
- ((is->is_sb[1] != NULL) && (ldxa(is->is_flushpa + 8, ASI_PHYS_CACHED) == 0))) {
- printf("iommu_strbuf_flush_done: flush timeout %p,%p at %p\n",
- (void *)(u_long)is->is_flush[0],
- (void *)(u_long)is->is_flush[1],
- (void *)(u_long)is->is_flushpa); /* panic? */
+ if (flush[0] == 0 || flush[1] == 0) {
+ printf("iommu_strbuf_flush_done: flush timeout %p/%llx, "
+ "%p/%llx\n",
+ (void *)sb[0]->sb_flushpa, flush[0],
+ (void *)sb[1]->sb_flushpa, flush[1]);
+ /* panic? */
#ifdef DDB
Debugger();
#endif
}
#endif
DPRINTF(IDB_IOMMU, ("iommu_strbuf_flush_done: flushed\n"));
- return (is->is_flush[0] && is->is_flush[1]);
+ return (flush[0] && flush[1]);
}
/*
* IOMMU DVMA operations, common to SBUS and PCI.
*/
int
-iommu_dvmamap_load(t, is, map, buf, buflen, p, flags)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_dmamap_t map;
- void *buf;
- bus_size_t buflen;
- struct proc *p;
- int flags;
+iommu_dvmamap_load(bus_dma_tag_t t, struct iommu_state *is, bus_dmamap_t map,
+ void *buf, bus_size_t buflen, struct proc *p, int flags)
{
int s;
int err;
@@ -526,19 +565,18 @@ iommu_dvmamap_load(t, is, map, buf, buflen, p, flags)
sgstart = is->is_dvmamap->ex_start;
sgend = is->is_dvmamap->ex_end;
}
- s = splhigh();
/*
* If our segment size is larger than the boundary we need to
* split the transfer up int little pieces ourselves.
*/
+ s = splhigh();
err = extent_alloc_subregion(is->is_dvmamap, sgstart, sgend,
sgsize, align, 0, (sgsize > boundary) ? 0 : boundary,
- EX_NOWAIT|EX_BOUNDZERO, (u_long *)&dvmaddr);
+ EX_NOWAIT | EX_BOUNDZERO, (u_long *)&dvmaddr);
splx(s);
#ifdef DEBUG
- if (err || (dvmaddr == (bus_addr_t)-1))
- {
+ if (err || (dvmaddr == (bus_addr_t)-1)) {
printf("iommu_dvmamap_load(): extent_alloc(%d, %x) failed!\n",
(int)sgsize, flags);
#ifdef DDB
@@ -594,7 +632,7 @@ iommu_dvmamap_load(t, is, map, buf, buflen, p, flags)
DPRINTF(IDB_INFO, ("iommu_dvmamap_load: "
"seg %d start %lx size %lx\n", seg,
(long)map->dm_segs[seg].ds_addr, map->dm_segs[seg].ds_len));
- map->dm_nsegs = seg+1;
+ map->dm_nsegs = seg + 1;
map->dm_mapsize = buflen;
if (p != NULL)
@@ -624,7 +662,7 @@ iommu_dvmamap_load(t, is, map, buf, buflen, p, flags)
map, (void *)vaddr, (long)dvmaddr,
(long)(curaddr&~(NBPG-1))));
iommu_enter(is, trunc_page(dvmaddr), trunc_page(curaddr),
- flags|0x4000);
+ flags | 0x4000); /* 0x4000? Magic...? */
dvmaddr += PAGE_SIZE;
vaddr += sgsize;
@@ -648,10 +686,7 @@ iommu_dvmamap_load(t, is, map, buf, buflen, p, flags)
void
-iommu_dvmamap_unload(t, is, map)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_dmamap_t map;
+iommu_dvmamap_unload(bus_dma_tag_t t, struct iommu_state *is, bus_dmamap_t map)
{
int error, s;
bus_size_t sgsize;
@@ -673,7 +708,9 @@ iommu_dvmamap_unload(t, is, map)
/* Mark the mappings as invalid. */
map->dm_mapsize = 0;
map->dm_nsegs = 0;
-
+
+ sgsize = map->_dm_dvmasize;
+
s = splhigh();
error = extent_free(is->is_dvmamap, map->_dm_dvmastart,
map->_dm_dvmasize, EX_NOWAIT);
@@ -688,14 +725,9 @@ iommu_dvmamap_unload(t, is, map)
int
-iommu_dvmamap_load_raw(t, is, map, segs, nsegs, flags, size)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_dmamap_t map;
- bus_dma_segment_t *segs;
- int nsegs;
- int flags;
- bus_size_t size;
+iommu_dvmamap_load_raw(bus_dma_tag_t t, struct iommu_state *is,
+ bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, int flags,
+ bus_size_t size)
{
struct vm_page *m;
int i, j, s;
@@ -734,7 +766,7 @@ iommu_dvmamap_load_raw(t, is, map, segs, nsegs, flags, size)
pa = segs[0].ds_addr;
sgsize = 0;
left = size;
- for (i=0; left && i<nsegs; i++) {
+ for (i = 0; left && i < nsegs; i++) {
if (round_page(pa) != round_page(segs[i].ds_addr))
sgsize = round_page(sgsize);
sgsize += min(left, segs[i].ds_len);
@@ -757,17 +789,16 @@ iommu_dvmamap_load_raw(t, is, map, segs, nsegs, flags, size)
*/
err = extent_alloc_subregion(is->is_dvmamap, sgstart, sgend,
sgsize, align, 0, (sgsize > boundary) ? 0 : boundary,
- EX_NOWAIT|EX_BOUNDZERO, (u_long *)&dvmaddr);
+ EX_NOWAIT | EX_BOUNDZERO, (u_long *)&dvmaddr);
splx(s);
if (err != 0)
return (err);
#ifdef DEBUG
- if (dvmaddr == (bus_addr_t)-1)
- {
- printf("iommu_dvmamap_load_raw(): extent_alloc(%d, %x) failed!\n",
- (int)sgsize, flags);
+ if (dvmaddr == (bus_addr_t)-1) {
+ printf("iommu_dvmamap_load_raw(): extent_alloc(%d, %x) "
+ "failed!\n", (int)sgsize, flags);
#ifdef DDB
Debugger();
#else
@@ -858,7 +889,7 @@ printf("appending offset %x pa %lx, prev %lx dva %lx prev %lx\n",
DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: "
"seg %d start %lx size %lx\n", j,
(long)map->dm_segs[j].ds_addr,
- map->dm_segs[j].ds_len));
+ (long)map->dm_segs[j].ds_len));
if (++j >= map->_dm_segcnt) {
iommu_dvmamap_unload(t, is, map);
return (E2BIG);
@@ -884,7 +915,8 @@ printf("appending offset %x pa %lx, prev %lx dva %lx prev %lx\n",
{ if (iommudebug & 0x10) printf("seg %d:5d entering dvma %lx, prev %lx pa %lx\n", i, j, dvmaddr, prev_va, pa);
#endif
iommu_enter(is, prev_va = dvmaddr,
- prev_pa = pa, flags|(++npg<<12));
+ prev_pa = pa,
+ flags | (++npg << 12));
#ifdef DEBUG
} else if (iommudebug & 0x10) printf("seg %d:%d skipping dvma %lx, prev %lx\n", i, j, dvmaddr, prev_va);
#endif
@@ -899,13 +931,17 @@ printf("appending offset %x pa %lx, prev %lx dva %lx prev %lx\n",
map->dm_nsegs = j;
#ifdef DIAGNOSTIC
- {
+ { /* Scope */
int seg;
for (seg = 0; seg < map->dm_nsegs; seg++) {
- if (map->dm_segs[seg].ds_addr < is->is_dvmabase ||
- map->dm_segs[seg].ds_addr > is->is_dvmaend) {
- printf("seg %d dvmaddr %lx out of range %x - %x\n",
- seg, (long)map->dm_segs[seg].ds_addr,
+ if (map->dm_segs[seg].ds_addr <
+ is->is_dvmabase ||
+ map->dm_segs[seg].ds_addr >
+ is->is_dvmaend) {
+ printf("seg %d dvmaddr %lx out of "
+ "range %x - %x\n",
+ seg,
+ (long)map->dm_segs[seg].ds_addr,
is->is_dvmabase, is->is_dvmaend);
#ifdef DDB
Debugger();
@@ -957,22 +993,24 @@ printf("appending offset %x pa %lx, prev %lx dva %lx prev %lx\n",
pa = VM_PAGE_TO_PHYS(m);
DPRINTF(IDB_BUSDMA,
- ("iommu_dvmamap_load_raw: map %p loading va %lx at pa %lx\n",
+ ("iommu_dvmamap_load_raw: map %p loading va %lx at "
+ "pa %lx\n",
map, (long)dvmaddr, (long)(pa)));
- iommu_enter(is, dvmaddr, pa, flags|0x8000);
+ iommu_enter(is, dvmaddr, pa, flags | 0x8000); /* Magic 0x8000? */
dvmaddr += pagesz;
sgsize -= pagesz;
}
map->dm_mapsize = size;
- map->dm_nsegs = i+1;
+ map->dm_nsegs = i + 1;
#ifdef DIAGNOSTIC
{
int seg;
for (seg = 0; seg < map->dm_nsegs; seg++) {
if (map->dm_segs[seg].ds_addr < is->is_dvmabase ||
map->dm_segs[seg].ds_addr > is->is_dvmaend) {
- printf("seg %d dvmaddr %lx out of range %x - %x\n",
+ printf("seg %d dvmaddr %lx out of range %x "
+ "- %x\n",
seg, (long)map->dm_segs[seg].ds_addr,
is->is_dvmabase, is->is_dvmaend);
#ifdef DDB
@@ -986,17 +1024,15 @@ printf("appending offset %x pa %lx, prev %lx dva %lx prev %lx\n",
}
void
-iommu_dvmamap_sync(t, is, map, offset, len, ops)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_dmamap_t map;
- bus_addr_t offset;
- bus_size_t len;
- int ops;
+iommu_dvmamap_sync(bus_dma_tag_t t, struct iommu_state *is, bus_dmamap_t map,
+ bus_addr_t offset, bus_size_t len, int ops)
{
bus_size_t count;
int i, needsflush = 0;
+ if (is->is_sb[0] == NULL && is->is_sb[1] == NULL)
+ return;
+
for (i = 0; i < map->dm_nsegs; i++) {
if (offset < map->dm_segs[i].ds_len)
break;
@@ -1008,8 +1044,9 @@ iommu_dvmamap_sync(t, is, map, offset, len, ops)
for (; len > 0 && i < map->dm_nsegs; i++) {
count = min(map->dm_segs[i].ds_len - offset, len);
- needsflush += iommu_dvmamap_sync_seg(t, is, &map->dm_segs[i],
- offset, count, ops);
+ if(iommu_dvmamap_sync_seg(t, is, &map->dm_segs[i],
+ offset, count, ops))
+ needsflush = 1;
len -= count;
}
@@ -1024,109 +1061,87 @@ iommu_dvmamap_sync(t, is, map, offset, len, ops)
* Flush an individual dma segment, returns non-zero if the streaming buffers
* need flushing afterwards.
*/
+
+int
+iommu_dvmamap_sync_range(struct iommu_state *is, vaddr_t va, bus_size_t len)
+{
+ vaddr_t vaend;
+
+ if (is->is_sb[0] == NULL && is->is_sb[1] == NULL)
+ return (0);
+
+#ifdef DIAGNOSTIC
+ if (va < is->is_dvmabase || va >= is->is_dvmaend)
+ panic("invalid va: %llx", (long long)va);
+#endif
+
+ if ((is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)] & IOTTE_STREAM) == 0)
+ return (0);
+
+ vaend = (va + len + PGOFSET) & ~PGOFSET;
+ va &= ~PGOFSET;
+
+#ifdef DIAGNOSTIC
+ if (va < is->is_dvmabase || vaend >= is->is_dvmaend)
+ panic("invalid va range: %llx to %llx (%x to %x)",
+ (long long)va, (long long)vaend,
+ is->is_dvmabase,
+ is->is_dvmaend);
+#endif
+
+ for( ; va <= vaend; va += NBPG) {
+ DPRINTF(IDB_BUSDMA,
+ ("iommu_dvmamap_sync_range: flushing va %p\n",
+ (void *)(u_long)va));
+ iommu_strbuf_flush(is, va);
+ }
+
+ return (1);
+}
+
int
-iommu_dvmamap_sync_seg(t, is, seg, offset, len, ops)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_dma_segment_t *seg;
- bus_addr_t offset;
- bus_size_t len;
- int ops;
+iommu_dvmamap_sync_seg(bus_dma_tag_t t, struct iommu_state *is,
+ bus_dma_segment_t *seg, bus_addr_t offset, bus_size_t len, int ops)
{
int needsflush = 0;
vaddr_t va = seg->ds_addr + offset;
- if (len == 0)
- goto out;
+ DPRINTF(IDB_SYNC,
+ ("iommu_dvmamap_sync_seg: syncing va %p len %lu (%x)\n",
+ (void *)(u_long)va, (u_long)len, ops));
- len += offset & PGOFSET;
-
- if (ops & BUS_DMASYNC_PREREAD) {
- DPRINTF(IDB_SYNC,
- ("iommu_dvmamap_sync_seg: syncing va %p len %lu "
- "BUS_DMASYNC_PREREAD\n", (void *)(u_long)va, (u_long)len));
+ if (len == 0)
+ return (0);
+ if (ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_POSTWRITE)) {
/* Nothing to do */;
}
- if (ops & BUS_DMASYNC_POSTREAD) {
- DPRINTF(IDB_SYNC,
- ("iommu_dvmamap_sync_seg: syncing va %p len %lu "
- "BUS_DMASYNC_POSTREAD\n", (void *)(u_long)va, (u_long)len));
- /* if we have a streaming buffer, flush it here first */
- if (is->is_sb[0] || is->is_sb[1])
- while (len > 0) {
- DPRINTF(IDB_BUSDMA,
- ("iommu_dvmamap_sync_seg: flushing va %p, %lu "
- "bytes left\n", (void *)(u_long)va, (u_long)len));
- if (iommu_tsb_entry(is, va) & IOTTE_STREAM) {
- iommu_strbuf_flush(is, va);
- needsflush = 1;
- }
- if (len <= NBPG)
- len = 0;
- else
- len -= NBPG;
- va += NBPG;
- }
- }
- if (ops & BUS_DMASYNC_PREWRITE) {
- DPRINTF(IDB_SYNC,
- ("iommu_dvmamap_sync_seg: syncing va %p len %lu "
- "BUS_DMASYNC_PREWRITE\n", (void *)(u_long)va, (u_long)len));
- /* if we have a streaming buffer, flush it here first */
- if (is->is_sb[0] || is->is_sb[1])
- while (len > 0) {
- DPRINTF(IDB_BUSDMA,
- ("iommu_dvmamap_sync_seg: flushing va %p, %lu "
- "bytes left\n", (void *)(u_long)va, (u_long)len));
- if (iommu_tsb_entry(is, va) & IOTTE_STREAM) {
- iommu_strbuf_flush(is, va);
- needsflush = 1;
- }
- if (len <= NBPG)
- len = 0;
- else
- len -= NBPG;
- va += NBPG;
- }
- }
- if (ops & BUS_DMASYNC_POSTWRITE) {
- DPRINTF(IDB_SYNC,
- ("iommu_dvmamap_sync_seg: syncing va %p len %lu "
- "BUS_DMASYNC_POSTWRITE\n", (void *)(u_long)va, (u_long)len));
- /* Nothing to do */;
+ if (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE)) {
+ if (iommu_dvmamap_sync_range(is, va, len))
+ needsflush = 1;
}
-out:
return (needsflush);
}
int
-iommu_dvmamem_alloc(t, is, size, alignment, boundary, segs, nsegs, rsegs, flags)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_size_t size, alignment, boundary;
- bus_dma_segment_t *segs;
- int nsegs;
- int *rsegs;
- int flags;
+iommu_dvmamem_alloc(bus_dma_tag_t t, struct iommu_state *is, bus_size_t size,
+ bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
+ int nsegs, int *rsegs, int flags)
{
- DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_alloc: sz %llx align %llx bound %llx "
- "segp %p flags %d\n", (unsigned long long)size,
- (unsigned long long)alignment, (unsigned long long)boundary,
- segs, flags));
+ DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_alloc: sz %llx align %llx "
+ "bound %llx segp %p flags %d\n", (unsigned long long)size,
+ (unsigned long long)alignment, (unsigned long long)boundary,
+ segs, flags));
return (bus_dmamem_alloc(t->_parent, size, alignment, boundary,
- segs, nsegs, rsegs, flags|BUS_DMA_DVMA));
+ segs, nsegs, rsegs, flags | BUS_DMA_DVMA));
}
void
-iommu_dvmamem_free(t, is, segs, nsegs)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_dma_segment_t *segs;
- int nsegs;
+iommu_dvmamem_free(bus_dma_tag_t t, struct iommu_state *is,
+ bus_dma_segment_t *segs, int nsegs)
{
DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_free: segp %p nsegs %d\n",
@@ -1139,20 +1154,14 @@ iommu_dvmamem_free(t, is, segs, nsegs)
* Check the flags to see whether we're streaming or coherent.
*/
int
-iommu_dvmamem_map(t, is, segs, nsegs, size, kvap, flags)
- bus_dma_tag_t t;
- struct iommu_state *is;
- bus_dma_segment_t *segs;
- int nsegs;
- size_t size;
- caddr_t *kvap;
- int flags;
+iommu_dvmamem_map(bus_dma_tag_t t, struct iommu_state *is,
+ bus_dma_segment_t *segs, int nsegs, size_t size, caddr_t *kvap, int flags)
{
struct vm_page *m;
vaddr_t va;
bus_addr_t addr;
struct pglist *mlist;
- int cbit;
+ bus_addr_t cbit = 0;
DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_map: segp %p nsegs %d size %lx\n",
segs, nsegs, size));
@@ -1171,7 +1180,6 @@ iommu_dvmamem_map(t, is, segs, nsegs, size, kvap, flags)
/*
* digest flags:
*/
- cbit = 0;
if (flags & BUS_DMA_COHERENT) /* Disable vcache */
cbit |= PMAP_NVC;
if (flags & BUS_DMA_NOCACHE) /* sideffects */
@@ -1188,7 +1196,8 @@ iommu_dvmamem_map(t, is, segs, nsegs, size, kvap, flags)
#endif
addr = VM_PAGE_TO_PHYS(m);
DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_map: "
- "mapping va %lx at %llx\n", va, (unsigned long long)addr | cbit));
+ "mapping va %lx at %llx\n", va,
+ (unsigned long long)addr | cbit));
pmap_enter(pmap_kernel(), va, addr | cbit,
VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
@@ -1204,11 +1213,8 @@ iommu_dvmamem_map(t, is, segs, nsegs, size, kvap, flags)
* Unmap DVMA mappings from kernel
*/
void
-iommu_dvmamem_unmap(t, is, kva, size)
- bus_dma_tag_t t;
- struct iommu_state *is;
- caddr_t kva;
- size_t size;
+iommu_dvmamem_unmap(bus_dma_tag_t t, struct iommu_state *is, caddr_t kva,
+ size_t size)
{
DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_unmap: kvm %p size %lx\n",
@@ -1224,3 +1230,4 @@ iommu_dvmamem_unmap(t, is, kva, size)
pmap_update(pmap_kernel());
uvm_km_free(kernel_map, (vaddr_t)kva, size);
}
+