Module Name:    src
Committed By:   mrg
Date:           Sun Mar 20 21:26:36 UTC 2011

Modified Files:
        src/sys/arch/sparc64/dev: iommu.c

Log Message:
re-add most of the pryo-supporting code, and some general clean up:
- handle setting tsb size in the ptsb via IOMMU_TSBSIZE_IN_PTSB (partly from
  openbsd)
- fix IDB_INFO for systems without a STC that fault on accesses to the
  flush register (like pyro)
- move iommu_reset() to the end of iommu_init()
- use IOMMUREG_WRITE() in a few places
- add a missing membar_lookaside() (from openbsd)
- if pmap_extract() on the flush buffer fails, disable flushing (from openbsd)
- flush the pyro-style iommu when IOMMU_FLUSH_CACHE is set (partly from openbsd)
- clear up a bit of debugging code so it spew a little less (sometimes you will
  get kernel lock spinouts due to long scrolling printfs)
- use __func__ in several places


To generate a diff of this commit:
cvs rdiff -u -r1.102 -r1.103 src/sys/arch/sparc64/dev/iommu.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/sparc64/dev/iommu.c
diff -u src/sys/arch/sparc64/dev/iommu.c:1.102 src/sys/arch/sparc64/dev/iommu.c:1.103
--- src/sys/arch/sparc64/dev/iommu.c:1.102	Wed Mar 16 05:49:43 2011
+++ src/sys/arch/sparc64/dev/iommu.c	Sun Mar 20 21:26:36 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: iommu.c,v 1.102 2011/03/16 05:49:43 mrg Exp $	*/
+/*	$NetBSD: iommu.c,v 1.103 2011/03/20 21:26:36 mrg Exp $	*/
 
 /*
  * Copyright (c) 1999, 2000 Matthew R. Green
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.102 2011/03/16 05:49:43 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.103 2011/03/20 21:26:36 mrg Exp $");
 
 #include "opt_ddb.h"
 
@@ -134,7 +134,7 @@
 	 * be hard-wired, so we read the start and size from the PROM and
 	 * just use those values.
 	 */
-	is->is_cr = (tsbsize << 16) | IOMMUCR_EN;
+	is->is_cr = IOMMUCR_EN;
 	is->is_tsbsize = tsbsize;
 	if (iovabase == -1) {
 		is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize);
@@ -176,20 +176,13 @@
 	{
 		/* Probe the iommu */
 
-		printf("iommu regs at: cr=%lx tsb=%lx flush=%lx\n",
-			(u_long)bus_space_read_8(is->is_bustag, is->is_iommu,
-				offsetof (struct iommureg, iommu_cr)),
-			(u_long)bus_space_read_8(is->is_bustag, is->is_iommu,
-				offsetof (struct iommureg, iommu_tsb)),
-			(u_long)bus_space_read_8(is->is_bustag, is->is_iommu,
-				offsetof (struct iommureg, iommu_flush)));
 		printf("iommu cr=%llx tsb=%llx\n",
 			(unsigned long long)bus_space_read_8(is->is_bustag,
 				is->is_iommu,
-				offsetof (struct iommureg, iommu_cr)),
+				offsetof(struct iommureg, iommu_cr)),
 			(unsigned long long)bus_space_read_8(is->is_bustag,
 				is->is_iommu,
-				offsetof (struct iommureg, iommu_tsb)));
+				offsetof(struct iommureg, iommu_tsb)));
 		printf("TSB base %p phys %llx\n", (void *)is->is_tsb,
 			(unsigned long long)is->is_ptsb);
 		delay(1000000); /* 1 s */
@@ -197,11 +190,6 @@
 #endif
 
 	/*
-	 * now actually start up the IOMMU
-	 */
-	iommu_reset(is);
-
-	/*
 	 * Now all the hardware's working we need to allocate a dvma map.
 	 */
 	aprint_debug("DVMA map: %x to %x\n",
@@ -214,6 +202,20 @@
 	    is->is_dvmabase, is->is_dvmaend,
 	    M_DEVBUF, 0, 0, EX_NOWAIT);
 	/* XXXMRG Check is_dvmamap is valid. */
+
+	/*
+	 * Set the TSB size.  The relevant bits were moved to the TSB
+	 * base register in the PCIe host bridges.
+	 */
+	if (is->is_flags & IOMMU_TSBSIZE_IN_PTSB)
+		is->is_ptsb |= is->is_tsbsize;
+	else
+		is->is_cr |= (is->is_tsbsize << 16);
+
+	/*
+	 * now actually start up the IOMMU
+	 */
+	iommu_reset(is);
 }
 
 /*
@@ -227,13 +229,10 @@
 	int i;
 	struct strbuf_ctl *sb;
 
-	/* Need to do 64-bit stores */
-	bus_space_write_8(is->is_bustag, is->is_iommu, IOMMUREG(iommu_tsb),
-		is->is_ptsb);
+	IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb);
 
 	/* Enable IOMMU in diagnostic mode */
-	bus_space_write_8(is->is_bustag, is->is_iommu, IOMMUREG(iommu_cr),
-		is->is_cr|IOMMUCR_DE);
+	IOMMUREG_WRITE(is, iommu_cr, is->is_cr|IOMMUCR_DE);
 
 	for (i = 0; i < 2; i++) {
 		if ((sb = is->is_sb[i])) {
@@ -242,6 +241,8 @@
 			bus_space_write_8(is->is_bustag, is->is_sb[i]->sb_sb,
 				STRBUFREG(strbuf_ctl), STRBUF_EN);
 
+			membar_lookaside();
+
 			/* No streaming buffers? Disable them */
 			if (bus_space_read_8(is->is_bustag,
 				is->is_sb[i]->sb_sb,
@@ -252,12 +253,16 @@
 				/*
 				 * locate the pa of the flush buffer.
 				 */
-				(void)pmap_extract(pmap_kernel(),
-					(vaddr_t)is->is_sb[i]->sb_flush,
-					&is->is_sb[i]->sb_flushpa);
+				if (pmap_extract(pmap_kernel(),
+				     (vaddr_t)is->is_sb[i]->sb_flush,
+				     &is->is_sb[i]->sb_flushpa) == FALSE)
+					is->is_sb[i]->sb_flush = NULL;
 			}
 		}
 	}
+
+	if (is->is_flags & IOMMU_FLUSH_CACHE)
+		IOMMUREG_WRITE(is, iommu_cache_invalidate, -1ULL);
 }
 
 /*
@@ -288,12 +293,11 @@
 	tte |= (flags & 0xff000LL)<<(4*8);
 #endif
 
-	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, is->is_iommu,
 		IOMMUREG(iommu_flush), va);
-	DPRINTF(IDB_IOMMU, ("iommu_enter: va %lx pa %lx TSB[%lx]@%p=%lx\n",
+	DPRINTF(IDB_IOMMU, ("iommu_enter: slot %d va %lx pa %lx "
+		"TSB[%lx]@%p=%lx\n", (int)IOTSBSLOT(va,is->is_tsbsize),
 		va, (long)pa, (u_long)IOTSBSLOT(va,is->is_tsbsize),
 		(void *)(u_long)&is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)],
 		(u_long)tte));
@@ -325,6 +329,7 @@
 void
 iommu_remove(struct iommu_state *is, vaddr_t va, size_t len)
 {
+	int slot;
 
 #ifdef DIAGNOSTIC
 	if (va < is->is_dvmabase || va > is->is_dvmaend)
@@ -363,8 +368,15 @@
 		is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)] &= ~IOTTE_V;
 		membar_storestore();
 #endif
-		bus_space_write_8(is->is_bustag, is->is_iommu,
-			IOMMUREG(iommu_flush), va);
+		IOMMUREG_WRITE(is, iommu_flush, va);
+
+		/* Flush cache if necessary. */
+		slot = IOTSBSLOT(trunc_page(va), is->is_tsbsize);
+		if ((is->is_flags & IOMMU_FLUSH_CACHE) &&
+		    (len == 0 || (slot % 8) == 7))
+			IOMMUREG_WRITE(is, iommu_cache_flush,
+			    is->is_ptsb + slot * 8);
+
 		va += PAGE_SIZE;
 	}
 }
@@ -410,8 +422,8 @@
 	cur = flushtimeout;
 	BUMPTIME(&flushtimeout, 500000); /* 1/2 sec */
 
-	DPRINTF(IDB_IOMMU, ("iommu_strbuf_flush_done: flush = %lx "
-		"at va = %lx pa = %lx now=%"PRIx64":%"PRIx32" until = %"PRIx64":%"PRIx32"\n",
+	DPRINTF(IDB_IOMMU, ("%s: flush = %lx at va = %lx pa = %lx now="
+		"%"PRIx64":%"PRIx32" until = %"PRIx64":%"PRIx32"\n", __func__,
 		(long)*sb->sb_flush, (long)sb->sb_flush, (long)sb->sb_flushpa,
 		cur.tv_sec, cur.tv_usec,
 		flushtimeout.tv_sec, flushtimeout.tv_usec));
@@ -423,7 +435,7 @@
 
 #ifdef DIAGNOSTIC
 	if (!ldxa(sb->sb_flushpa, ASI_PHYS_CACHED)) {
-		printf("iommu_strbuf_flush_done: flush timeout %p, at %p\n",
+		printf("%s: flush timeout %p, at %p\n", __func__,
 			(void *)(u_long)*sb->sb_flush,
 			(void *)(u_long)sb->sb_flushpa); /* panic? */
 #ifdef DDB
@@ -431,7 +443,7 @@
 #endif
 	}
 #endif
-	DPRINTF(IDB_IOMMU, ("iommu_strbuf_flush_done: flushed\n"));
+	DPRINTF(IDB_IOMMU, ("%s: flushed\n", __func__));
 	return (*sb->sb_flush);
 }
 
@@ -453,6 +465,7 @@
 	vaddr_t vaddr = (vaddr_t)buf;
 	int seg;
 	struct pmap *pmap;
+	int slot;
 
 	if (map->dm_nsegs) {
 		/* Already in use?? */
@@ -489,6 +502,7 @@
 	 * If our segment size is larger than the boundary we need to
 	 * split the transfer up int little pieces ourselves.
 	 */
+	KASSERT(is->is_dvmamap);
 	s = splhigh();
 	err = extent_alloc(is->is_dvmamap, sgsize, align,
 	    (sgsize > boundary) ? 0 : boundary,
@@ -597,9 +611,17 @@
 		    flags | IOTTE_DEBUG(0x4000));
 		needsflush = 1;
 
-		dvmaddr += PAGE_SIZE;
 		vaddr += sgsize;
 		buflen -= sgsize;
+
+		/* Flush cache if necessary. */
+		slot = IOTSBSLOT(trunc_page(dvmaddr), is->is_tsbsize);
+		if ((is->is_flags & IOMMU_FLUSH_CACHE) &&
+		    (buflen <= 0 || (slot % 8) == 7))
+			IOMMUREG_WRITE(is, iommu_cache_flush,
+			    is->is_ptsb + slot * 8);
+
+		dvmaddr += PAGE_SIZE;
 	}
 	if (needsflush)
 		iommu_strbuf_flush_done(sb);
@@ -672,6 +694,7 @@
 	u_long dvmaddr, sgstart, sgend, bmask;
 	struct pglist *pglist;
 	const int pagesz = PAGE_SIZE;
+	int slot;
 #ifdef DEBUG
 	int npg = 0;
 #endif
@@ -841,7 +864,15 @@
 					    prev_pa = pa,
 					    flags | IOTTE_DEBUG(++npg << 12));
 					needsflush = 1;
+
+					/* Flush cache if necessary. */
+					slot = IOTSBSLOT(trunc_page(dvmaddr), is->is_tsbsize);
+					if ((is->is_flags & IOMMU_FLUSH_CACHE) &&
+					    ((dvmaddr + pagesz) > sgend || (slot % 8) == 7))
+						IOMMUREG_WRITE(is, iommu_cache_flush,
+						    is->is_ptsb + slot * 8);
 				}
+
 				dvmaddr += pagesz;
 				pa += pagesz;
 				last_va = dvmaddr;
@@ -859,7 +890,7 @@
 		{ 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) {
+		    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);
@@ -912,8 +943,16 @@
 		iommu_enter(sb, dvmaddr, pa, flags | IOTTE_DEBUG(0x8000));
 		needsflush = 1;
 
-		dvmaddr += pagesz;
 		sgsize -= pagesz;
+
+		/* Flush cache if necessary. */
+		slot = IOTSBSLOT(trunc_page(dvmaddr), is->is_tsbsize);
+		if ((is->is_flags & IOMMU_FLUSH_CACHE) &&
+		    (sgsize == 0 || (slot % 8) == 7))
+			IOMMUREG_WRITE(is, iommu_cache_flush,
+			    is->is_ptsb + slot * 8);
+
+		dvmaddr += pagesz;
 	}
 	if (needsflush)
 		iommu_strbuf_flush_done(sb);
@@ -966,7 +1005,7 @@
 #endif
 
 	if ((is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)] & IOTTE_STREAM) == 0) {
-		DPRINTF(IDB_BUSDMA, 
+		DPRINTF(IDB_SYNC, 
 			("iommu_dvmamap_sync_range: attempting to flush "
 			 "non-streaming entry\n"));
 		return (0);
@@ -984,7 +1023,7 @@
 #endif
 
 	for ( ; va <= vaend; va += PAGE_SIZE) {
-		DPRINTF(IDB_BUSDMA,
+		DPRINTF(IDB_SYNC,
 		    ("iommu_dvmamap_sync_range: flushing va %p\n",
 		    (void *)(u_long)va));
 		iommu_strbuf_flush(sb, va);
@@ -1011,7 +1050,7 @@
 	}
 
 	if (i == map->dm_nsegs)
-		panic("iommu_dvmamap_sync: segment too short %llu", 
+		panic("%s: segment too short %llu", __func__,
 		    (unsigned long long)offset);
 
 	if (ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_POSTWRITE)) {
@@ -1031,7 +1070,7 @@
 		}
 #ifdef DIAGNOSTIC
 		if (i == map->dm_nsegs && len > 0)
-			panic("iommu_dvmamap_sync: leftover %llu",
+			panic("%s: leftover %llu", __func__,
 			    (unsigned long long)len);
 #endif
 

Reply via email to