aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/iommu.c
diff options
context:
space:
mode:
authorJake Moilanen <moilanen@austin.ibm.com>2007-03-02 16:49:43 -0500
committerPaul Mackerras <paulus@samba.org>2007-03-08 23:03:25 -0500
commit618d3adc351a24c4c48437c767befb88ca2d199d (patch)
tree73f74f50e89fb20a9829d5f971c0838a79324177 /arch/powerpc/kernel/iommu.c
parent723ec731de880a76a004a304b62bf8d0f96435d8 (diff)
[POWERPC] DMA 4GB boundary protection
There are many adapters which can not handle DMAing acrosss any 4 GB boundary. For instance the latest Emulex adapters. This normally is not an issue as firmware gives us dma-windows under 4gigs. However, some of the new System-P boxes have dma-windows above 4gigs, and this present a problem. I propose fixing it in the IOMMU allocation instead of making each driver protect against it as it is more efficient, and won't require changing every driver which has not considered this issue. This patch checks to see if the mapping spans a 4 gig boundary, and if it does, retries the allocation. It tries the next allocation at the start of the crossed 4 gig boundary. Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/iommu.c')
-rw-r--r--arch/powerpc/kernel/iommu.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 95edad4faf26..c50d7072f305 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -76,6 +76,7 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
76 unsigned int align_order) 76 unsigned int align_order)
77{ 77{
78 unsigned long n, end, i, start; 78 unsigned long n, end, i, start;
79 unsigned long start_addr, end_addr;
79 unsigned long limit; 80 unsigned long limit;
80 int largealloc = npages > 15; 81 int largealloc = npages > 15;
81 int pass = 0; 82 int pass = 0;
@@ -146,6 +147,15 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
146 } 147 }
147 } 148 }
148 149
150 /* DMA cannot cross 4 GB boundary */
151 start_addr = (n + tbl->it_offset) << PAGE_SHIFT;
152 end_addr = (end + tbl->it_offset) << PAGE_SHIFT;
153 if ((start_addr >> 32) != (end_addr >> 32)) {
154 end_addr &= 0xffffffff00000000l;
155 start = (end_addr >> PAGE_SHIFT) - tbl->it_offset;
156 goto again;
157 }
158
149 for (i = n; i < end; i++) 159 for (i = n; i < end; i++)
150 if (test_bit(i, tbl->it_map)) { 160 if (test_bit(i, tbl->it_map)) {
151 start = i+1; 161 start = i+1;