Commit d0035c62 authored by Olof Johansson's avatar Olof Johansson Committed by Paul Mackerras

[PATCH] ppc64: Updated Olof iommu updates 2/3

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: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent c707ffcf
...@@ -60,6 +60,9 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index, ...@@ -60,6 +60,9 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index,
union tce_entry t; union tce_entry t;
union tce_entry *tp; union tce_entry *tp;
index <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
t.te_word = 0; t.te_word = 0;
t.te_rdwr = 1; // Read allowed t.te_rdwr = 1; // Read allowed
...@@ -70,11 +73,11 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index, ...@@ -70,11 +73,11 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index,
while (npages--) { while (npages--) {
/* can't move this out since we might cross LMB boundary */ /* 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; tp->te_word = t.te_word;
uaddr += PAGE_SIZE; uaddr += TCE_PAGE_SIZE;
tp++; tp++;
} }
} }
...@@ -85,6 +88,9 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) ...@@ -85,6 +88,9 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)
union tce_entry t; union tce_entry t;
union tce_entry *tp; union tce_entry *tp;
npages <<= TCE_PAGE_FACTOR;
index <<= TCE_PAGE_FACTOR;
t.te_word = 0; t.te_word = 0;
tp = ((union tce_entry *)tbl->it_base) + index; tp = ((union tce_entry *)tbl->it_base) + index;
...@@ -104,7 +110,7 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, ...@@ -104,7 +110,7 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
union tce_entry tce; union tce_entry tce;
tce.te_word = 0; 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; tce.te_rdwr = 1;
if (direction != DMA_TO_DEVICE) if (direction != DMA_TO_DEVICE)
tce.te_pciwr = 1; tce.te_pciwr = 1;
...@@ -137,6 +143,9 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, ...@@ -137,6 +143,9 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
union tce_entry tce, *tcep; union tce_entry tce, *tcep;
long l, limit; long l, limit;
tcenum <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
if (npages == 1) if (npages == 1)
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
direction); direction);
...@@ -156,7 +165,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, ...@@ -156,7 +165,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
} }
tce.te_word = 0; 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; tce.te_rdwr = 1;
if (direction != DMA_TO_DEVICE) if (direction != DMA_TO_DEVICE)
tce.te_pciwr = 1; tce.te_pciwr = 1;
...@@ -167,7 +176,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, ...@@ -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 * Set up the page with TCE data, looping through and setting
* the values. * 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++) { for (l = 0; l < limit; l++) {
tcep[l] = tce; tcep[l] = tce;
...@@ -197,6 +206,9 @@ static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages ...@@ -197,6 +206,9 @@ static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages
u64 rc; u64 rc;
union tce_entry tce; union tce_entry tce;
tcenum <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
tce.te_word = 0; tce.te_word = 0;
while (npages--) { while (npages--) {
...@@ -222,6 +234,9 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n ...@@ -222,6 +234,9 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
u64 rc; u64 rc;
union tce_entry tce; union tce_entry tce;
tcenum <<= TCE_PAGE_FACTOR;
npages <<= TCE_PAGE_FACTOR;
tce.te_word = 0; tce.te_word = 0;
rc = plpar_tce_stuff((u64)tbl->it_index, rc = plpar_tce_stuff((u64)tbl->it_index,
......
...@@ -125,18 +125,21 @@ static void dart_build(struct iommu_table *tbl, long index, ...@@ -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); 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; dp = ((unsigned int*)tbl->it_base) + index;
/* On U3, all memory is contigous, so we can move this /* On U3, all memory is contigous, so we can move this
* out of the loop. * out of the loop.
*/ */
while (npages--) { while (npages--) {
rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT;
*(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK);
rpn++; rpn++;
uaddr += PAGE_SIZE; uaddr += DART_PAGE_SIZE;
} }
dart_dirty = 1; dart_dirty = 1;
...@@ -154,6 +157,9 @@ static void dart_free(struct iommu_table *tbl, long index, long npages) ...@@ -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); DBG("dart: free at: %lx, %lx\n", index, npages);
index <<= DART_PAGE_FACTOR;
npages <<= DART_PAGE_FACTOR;
dp = ((unsigned int *)tbl->it_base) + index; dp = ((unsigned int *)tbl->it_base) + index;
while (npages--) while (npages--)
...@@ -182,10 +188,10 @@ static int dart_init(struct device_node *dart_node) ...@@ -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 * that to work around what looks like a problem with the HT bridge
* prefetching into invalid pages and corrupting data * 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) if (!tmp)
panic("U3-DART: Cannot allocate spare page!"); 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 */ /* Map in DART registers. FIXME: Use device node to get base address */
dart = ioremap(DART_BASE, 0x7000); dart = ioremap(DART_BASE, 0x7000);
...@@ -196,8 +202,8 @@ static int dart_init(struct device_node *dart_node) ...@@ -196,8 +202,8 @@ static int dart_init(struct device_node *dart_node)
* table size and enable bit * table size and enable bit
*/ */
regword = DARTCNTL_ENABLE | regword = DARTCNTL_ENABLE |
((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | ((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
(((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK) (((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
<< DARTCNTL_SIZE_SHIFT); << DARTCNTL_SIZE_SHIFT);
dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
......
...@@ -51,5 +51,9 @@ ...@@ -51,5 +51,9 @@
#define DARTMAP_RPNMASK 0x00ffffff #define DARTMAP_RPNMASK 0x00ffffff
#define DART_SHIFT 12
#define DART_PAGE_SIZE (1 << DART_SHIFT)
#define DART_PAGE_FACTOR (PAGE_SHIFT - DART_SHIFT)
#endif #endif
...@@ -28,6 +28,13 @@ ...@@ -28,6 +28,13 @@
#define TCE_VB 0 #define TCE_VB 0
#define TCE_PCI 1 #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 /* tce_entry
* Used by pSeries (SMP) and iSeries/pSeries LPAR, but there it's * Used by pSeries (SMP) and iSeries/pSeries LPAR, but there it's
* abstracted so layout is irrelevant. * abstracted so layout is irrelevant.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment