[PATCH] ppc64: Updated Olof iommu updates 2/3
authorOlof Johansson <olof@lixom.net>
Tue, 20 Sep 2005 03:46:44 +0000 (13:46 +1000)
committerPaul Mackerras <paulus@samba.org>
Wed, 21 Sep 2005 09:21:07 +0000 (19:21 +1000)
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@lixom.net>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/ppc64/kernel/pSeries_iommu.c
arch/ppc64/kernel/u3_iommu.c
include/asm-ppc64/dart.h
include/asm-ppc64/tce.h

index 7f7947c3e12f8a66502c2467c74b89194c2a98a1..2b5e622732f4e4b4234ec69cffffdd8d23cb83e5 100644 (file)
@@ -60,6 +60,9 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index,
        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 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index,
 
        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 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)
        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 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
        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 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
        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 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
        }
 
        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 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
                 * 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 @@ static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages
        u64 rc;
        union tce_entry tce;
 
+       tcenum <<= TCE_PAGE_FACTOR;
+       npages <<= TCE_PAGE_FACTOR;
+
        tce.te_word = 0;
 
        while (npages--) {
@@ -222,6 +234,9 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
        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 115cbdf3b13b79d39ecd33c9d3bc688297e6ac70..df9c775f495568f0c6df62ab0e02f2bfffa8b733 100644 (file)
@@ -125,18 +125,21 @@ static void dart_build(struct iommu_table *tbl, long index,
 
        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 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
 
        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 @@ static int dart_init(struct device_node *dart_node)
         * 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 @@ static int dart_init(struct device_node *dart_node)
         * 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 306799a31a5db19876c238ce9488a7a49d637faa..a9000de8a2e3832f1c262bff3193d6add132258b 100644 (file)
@@ -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
index 636504c62c8870fbf2f4ad34194975a17f2be20a..d40b6b42ab359900bd417e8ad818fb3ce83da003 100644 (file)
 #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.