#include <linux/module.h>
#include <linux/version.h>
#include <linux/scatterlist.h>
+#include <linux/swiotlb.h>
#include <linux/io.h>
#include <linux/bug.h>
} while (0)
+static int max_dma_bits = 32;
+
void xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
{
- unsigned order = get_order(size);
-
- printk(KERN_DEBUG "xen_swiotlb_fixup: buf=%p size=%zu order=%u\n",
- buf, size, order);
-
- if (WARN_ON(size != (PAGE_SIZE << order)))
- return;
-
- if (xen_create_contiguous_region((unsigned long)buf,
- order, DMA_BIT_MASK(32)))
- printk(KERN_ERR "xen_create_contiguous_region failed\n");
+ int i, rc;
+ int dma_bits;
+
+ printk(KERN_DEBUG "xen_swiotlb_fixup: buf=%p size=%zu\n",
+ buf, size);
+
+ dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
+ for (i = 0; i < nslabs; i += IO_TLB_SEGSIZE) {
+ do {
+ rc = xen_create_contiguous_region(
+ (unsigned long)buf + (i << IO_TLB_SHIFT),
+ get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT),
+ dma_bits);
+ } while (rc && dma_bits++ < max_dma_bits);
+ if (rc)
+ panic(KERN_ERR "xen_create_contiguous_region failed\n");
+ }
}
+
static inline int address_needs_mapping(struct device *hwdev,
dma_addr_t addr)
{