[PATCH] ppc64: iommu cleanup 2/2

Benjamin Herrenschmidt benh at kernel.crashing.org
Tue Sep 6 15:34:03 EST 2005


There are potential cases in the future where the IOMMU might be mapping smaller
pages than the regular MMU is using. Keep the allocator working on MMU pagesizes,
but the low-level mapping functions need to map more than one TCE entry per page
to deal with this.


Signed-off-by: Olof Johansson <olof at lixom.net>
Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>

Index: linux-work/arch/ppc64/kernel/pSeries_iommu.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/pSeries_iommu.c	2005-09-01 13:22:18.000000000 +1000
+++ linux-work/arch/ppc64/kernel/pSeries_iommu.c	2005-09-01 13:23:02.000000000 +1000
@@ -60,6 +60,9 @@
 	union tce_entry t;
 	union tce_entry *tp;
 
+	index <<= TCE_PAGE_FACTOR;
+	npages <<= TCE_PAGE_FACTOR;
+
 	t.te_word = 0;
 	t.te_rdwr = 1; // Read allowed 
 
@@ -70,11 +73,11 @@
 
 	while (npages--) {
 		/* can't move this out since we might cross LMB boundary */
-		t.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT;
+		t.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
 	
 		tp->te_word = t.te_word;
 
-		uaddr += PAGE_SIZE;
+		uaddr += TCE_PAGE_SIZE;
 		tp++;
 	}
 }
@@ -85,6 +88,9 @@
 	union tce_entry t;
 	union tce_entry *tp;
 
+	npages <<= TCE_PAGE_FACTOR;
+	index <<= TCE_PAGE_FACTOR;
+
 	t.te_word = 0;
 	tp  = ((union tce_entry *)tbl->it_base) + index;
 		
@@ -104,7 +110,7 @@
 	union tce_entry tce;
 
 	tce.te_word = 0;
-	tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT;
+	tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
 	tce.te_rdwr = 1;
 	if (direction != DMA_TO_DEVICE)
 		tce.te_pciwr = 1;
@@ -137,6 +143,9 @@
 	union tce_entry tce, *tcep;
 	long l, limit;
 
+	tcenum <<= TCE_PAGE_FACTOR;
+	npages <<= TCE_PAGE_FACTOR;
+
 	if (npages == 1)
 		return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
 					   direction);
@@ -156,7 +165,7 @@
 	}
 
 	tce.te_word = 0;
-	tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT;
+	tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
 	tce.te_rdwr = 1;
 	if (direction != DMA_TO_DEVICE)
 		tce.te_pciwr = 1;
@@ -167,7 +176,7 @@
 		 * Set up the page with TCE data, looping through and setting
 		 * the values.
 		 */
-		limit = min_t(long, npages, PAGE_SIZE/sizeof(union tce_entry));
+		limit = min_t(long, npages, 4096/sizeof(union tce_entry));
 
 		for (l = 0; l < limit; l++) {
 			tcep[l] = tce;
@@ -197,6 +206,9 @@
 	u64 rc;
 	union tce_entry tce;
 
+	tcenum <<= TCE_PAGE_FACTOR;
+	npages <<= TCE_PAGE_FACTOR;
+
 	tce.te_word = 0;
 
 	while (npages--) {
@@ -222,6 +234,9 @@
 	u64 rc;
 	union tce_entry tce;
 
+	tcenum <<= TCE_PAGE_FACTOR;
+	npages <<= TCE_PAGE_FACTOR;
+
 	tce.te_word = 0;
 
 	rc = plpar_tce_stuff((u64)tbl->it_index,
Index: linux-work/include/asm-ppc64/tce.h
===================================================================
--- linux-work.orig/include/asm-ppc64/tce.h	2005-09-01 13:21:52.000000000 +1000
+++ linux-work/include/asm-ppc64/tce.h	2005-09-01 13:23:02.000000000 +1000
@@ -28,6 +28,13 @@
 #define TCE_VB  0
 #define TCE_PCI 1
 
+/* TCE page size is 4096 bytes (1 << 12) */
+
+#define TCE_SHIFT	12
+#define TCE_PAGE_SIZE	(1 << TCE_SHIFT)
+#define TCE_PAGE_FACTOR	(PAGE_SHIFT - TCE_SHIFT)
+
+
 /* tce_entry
  * Used by pSeries (SMP) and iSeries/pSeries LPAR, but there it's
  * abstracted so layout is irrelevant.
Index: linux-work/arch/ppc64/kernel/u3_iommu.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/u3_iommu.c	2005-09-01 13:21:52.000000000 +1000
+++ linux-work/arch/ppc64/kernel/u3_iommu.c	2005-09-01 13:23:02.000000000 +1000
@@ -125,18 +125,21 @@
 
 	DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr);
 
+	index <<= DART_PAGE_FACTOR;
+	npages <<= DART_PAGE_FACTOR;
+
 	dp = ((unsigned int*)tbl->it_base) + index;
 	
 	/* On U3, all memory is contigous, so we can move this
 	 * out of the loop.
 	 */
 	while (npages--) {
-		rpn = virt_to_abs(uaddr) >> PAGE_SHIFT;
+		rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT;
 
 		*(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK);
 
 		rpn++;
-		uaddr += PAGE_SIZE;
+		uaddr += DART_PAGE_SIZE;
 	}
 
 	dart_dirty = 1;
@@ -154,6 +157,9 @@
 
 	DBG("dart: free at: %lx, %lx\n", index, npages);
 
+	index <<= DART_PAGE_FACTOR;
+	npages <<= DART_PAGE_FACTOR;
+
 	dp  = ((unsigned int *)tbl->it_base) + index;
 		
 	while (npages--)
@@ -182,10 +188,10 @@
 	 * that to work around what looks like a problem with the HT bridge
 	 * prefetching into invalid pages and corrupting data
 	 */
-	tmp = lmb_alloc(PAGE_SIZE, PAGE_SIZE);
+	tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
 	if (!tmp)
 		panic("U3-DART: Cannot allocate spare page!");
-	dart_emptyval = DARTMAP_VALID | ((tmp >> PAGE_SHIFT) & DARTMAP_RPNMASK);
+	dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK);
 
 	/* Map in DART registers. FIXME: Use device node to get base address */
 	dart = ioremap(DART_BASE, 0x7000);
@@ -196,8 +202,8 @@
 	 * table size and enable bit
 	 */
 	regword = DARTCNTL_ENABLE | 
-		((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
-		(((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
+		((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
+		(((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
 				 << DARTCNTL_SIZE_SHIFT);
 	dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
 
Index: linux-work/include/asm-ppc64/dart.h
===================================================================
--- linux-work.orig/include/asm-ppc64/dart.h	2005-09-01 13:21:52.000000000 +1000
+++ linux-work/include/asm-ppc64/dart.h	2005-09-01 13:23:02.000000000 +1000
@@ -51,5 +51,9 @@
 #define DARTMAP_RPNMASK 0x00ffffff
 
 
+#define DART_SHIFT		12
+#define DART_PAGE_SIZE		(1 << DART_SHIFT)
+#define DART_PAGE_FACTOR	(PAGE_SHIFT - DART_SHIFT)
+
 
 #endif





More information about the Linuxppc64-dev mailing list