]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/parisc/ccio-dma.c
iommu: parisc: make the IOMMUs respect the segment boundary limits
[linux-2.6-omap-h63xx.git] / drivers / parisc / ccio-dma.c
index d08b284de196b2e807518ac656d678e585f9560c..60d338cd80090ff02dd20cc9e1fec5b684e8f588 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/scatterlist.h>
+#include <linux/iommu-helper.h>
 
 #include <asm/byteorder.h>
 #include <asm/cache.h>         /* for L1_CACHE_BYTES */
@@ -302,13 +303,17 @@ static int ioc_count;
 */
 #define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size)  \
        for(; res_ptr < res_end; ++res_ptr) { \
-               if(0 == (*res_ptr & mask)) { \
-                       *res_ptr |= mask; \
-                       res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
-                       ioc->res_hint = res_idx + (size >> 3); \
-                       goto resource_found; \
-               } \
-       }
+               int ret;\
+               unsigned int idx;\
+               idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
+               ret = iommu_is_span_boundary(idx << 3, pages_needed, 0, boundary_size);\
+               if ((0 == (*res_ptr & mask)) && !ret) { \
+                       *res_ptr |= mask; \
+                       res_idx = idx;\
+                       ioc->res_hint = res_idx + (size >> 3); \
+                       goto resource_found; \
+               } \
+       }
 
 #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \
        u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
@@ -341,10 +346,11 @@ static int ioc_count;
  * of available pages for the requested size.
  */
 static int
-ccio_alloc_range(struct ioc *ioc, size_t size)
+ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
 {
        unsigned int pages_needed = size >> IOVP_SHIFT;
        unsigned int res_idx;
+       unsigned long boundary_size;
 #ifdef CCIO_SEARCH_TIME
        unsigned long cr_start = mfctl(16);
 #endif
@@ -360,6 +366,9 @@ ccio_alloc_range(struct ioc *ioc, size_t size)
        ** ggg sacrifices another 710 to the computer gods.
        */
 
+       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 1 << IOVP_SHIFT);
+       boundary_size >>= IOVP_SHIFT;
+
        if (pages_needed <= 8) {
                /*
                 * LAN traffic will not thrash the TLB IFF the same NIC
@@ -760,7 +769,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
        ioc->msingle_pages += size >> IOVP_SHIFT;
 #endif
 
-       idx = ccio_alloc_range(ioc, size);
+       idx = ccio_alloc_range(ioc, dev, size);
        iovp = (dma_addr_t)MKIOVP(idx);
 
        pdir_start = &(ioc->pdir_base[idx]);