#include <linux/nodemask.h>
 #include <linux/bitops.h>         /* hweight64() */
 #include <linux/crash_dump.h>
+#include <linux/iommu-helper.h>
 
 #include <asm/delay.h>         /* ia64_get_itc() */
 #include <asm/io.h>
        return order;
 }
 
+static unsigned long ptr_to_pide(struct ioc *ioc, unsigned long *res_ptr,
+                                unsigned int bitshiftcnt)
+{
+       return (((unsigned long)res_ptr - (unsigned long)ioc->res_map) << 3)
+               + bitshiftcnt;
+}
+
 /**
  * sba_search_bitmap - find free space in IO PDIR resource bitmap
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * Cool perf optimization: search for log2(size) bits at a time.
  */
 static SBA_INLINE unsigned long
-sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint)
+sba_search_bitmap(struct ioc *ioc, struct device *dev,
+                 unsigned long bits_wanted, int use_hint)
 {
        unsigned long *res_ptr;
        unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
-       unsigned long flags, pide = ~0UL;
+       unsigned long flags, pide = ~0UL, tpide;
+       unsigned long boundary_size;
+       unsigned long shift;
+       int ret;
 
        ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
        ASSERT(res_ptr < res_end);
 
+       boundary_size = (unsigned long long)dma_get_seg_boundary(dev) + 1;
+       boundary_size = ALIGN(boundary_size, 1ULL << iovp_shift) >> iovp_shift;
+
+       BUG_ON(ioc->ibase & ~iovp_mask);
+       shift = ioc->ibase >> iovp_shift;
+
        spin_lock_irqsave(&ioc->res_lock, flags);
 
        /* Allow caller to force a search through the entire resource space */
                        if (likely(*res_ptr != ~0UL)) {
                                bitshiftcnt = ffz(*res_ptr);
                                *res_ptr |= (1UL << bitshiftcnt);
-                               pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
-                               pide <<= 3;     /* convert to bit address */
-                               pide += bitshiftcnt;
+                               pide = ptr_to_pide(ioc, res_ptr, bitshiftcnt);
                                ioc->res_bitshift = bitshiftcnt + bits_wanted;
                                goto found_it;
                        }
                        DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
                        ASSERT(0 != mask);
                        for (; mask ; mask <<= o, bitshiftcnt += o) {
-                               if(0 == ((*res_ptr) & mask)) {
+                               tpide = ptr_to_pide(ioc, res_ptr, bitshiftcnt);
+                               ret = iommu_is_span_boundary(tpide, bits_wanted,
+                                                            shift,
+                                                            boundary_size);
+                               if ((0 == ((*res_ptr) & mask)) && !ret) {
                                        *res_ptr |= mask;     /* mark resources busy! */
-                                       pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
-                                       pide <<= 3;     /* convert to bit address */
-                                       pide += bitshiftcnt;
+                                       pide = tpide;
                                        ioc->res_bitshift = bitshiftcnt + bits_wanted;
                                        goto found_it;
                                }
                end = res_end - qwords;
 
                for (; res_ptr < end; res_ptr++) {
+                       tpide = ptr_to_pide(ioc, res_ptr, 0);
+                       ret = iommu_is_span_boundary(tpide, bits_wanted,
+                                                    shift, boundary_size);
+                       if (ret)
+                               goto next_ptr;
                        for (i = 0 ; i < qwords ; i++) {
                                if (res_ptr[i] != 0)
                                        goto next_ptr;
                                res_ptr[i] = ~0UL;
                        res_ptr[i] |= RESMAP_MASK(bits);
 
-                       pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
-                       pide <<= 3;     /* convert to bit address */
+                       pide = tpide;
                        res_ptr += qwords;
                        ioc->res_bitshift = bits;
                        goto found_it;
  * resource bit map.
  */
 static int
-sba_alloc_range(struct ioc *ioc, size_t size)
+sba_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
 {
        unsigned int pages_needed = size >> iovp_shift;
 #ifdef PDIR_SEARCH_TIMING
        /*
        ** "seek and ye shall find"...praying never hurts either...
        */
-       pide = sba_search_bitmap(ioc, pages_needed, 1);
+       pide = sba_search_bitmap(ioc, dev, pages_needed, 1);
        if (unlikely(pide >= (ioc->res_size << 3))) {
-               pide = sba_search_bitmap(ioc, pages_needed, 0);
+               pide = sba_search_bitmap(ioc, dev, pages_needed, 0);
                if (unlikely(pide >= (ioc->res_size << 3))) {
 #if DELAYED_RESOURCE_CNT > 0
                        unsigned long flags;
                        }
                        spin_unlock_irqrestore(&ioc->saved_lock, flags);
 
-                       pide = sba_search_bitmap(ioc, pages_needed, 0);
+                       pide = sba_search_bitmap(ioc, dev, pages_needed, 0);
                        if (unlikely(pide >= (ioc->res_size << 3)))
                                panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n",
                                      ioc->ioc_hpa);
        spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
-       pide = sba_alloc_range(ioc, size);
+       pide = sba_alloc_range(ioc, dev, size);
 
        iovp = (dma_addr_t) pide << iovp_shift;
 
                dma_len = (dma_len + dma_offset + ~iovp_mask) & iovp_mask;
                ASSERT(dma_len <= DMA_CHUNK_SIZE);
                dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG
-                       | (sba_alloc_range(ioc, dma_len) << iovp_shift)
+                       | (sba_alloc_range(ioc, dev, dma_len) << iovp_shift)
                        | dma_offset);
                n_mappings++;
        }