Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-microblaze.git] / drivers / xen / swiotlb-xen.c
index 2b385c1..4c89afc 100644 (file)
 
 #include <trace/events/swiotlb.h>
 #define MAX_DMA_BITS 32
-/*
- * Used to do a quick range check in swiotlb_tbl_unmap_single and
- * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
- * API.
- */
 
-static char *xen_io_tlb_start, *xen_io_tlb_end;
-static unsigned long xen_io_tlb_nslabs;
 /*
  * Quick lookup value of the bus address of the IOTLB.
  */
@@ -82,11 +75,6 @@ static inline phys_addr_t xen_dma_to_phys(struct device *dev,
        return xen_bus_to_phys(dev, dma_to_phys(dev, dma_addr));
 }
 
-static inline dma_addr_t xen_virt_to_bus(struct device *dev, void *address)
-{
-       return xen_phys_to_dma(dev, virt_to_phys(address));
-}
-
 static inline int range_straddles_page_boundary(phys_addr_t p, size_t size)
 {
        unsigned long next_bfn, xen_pfn = XEN_PFN_DOWN(p);
@@ -111,15 +99,12 @@ static int is_xen_swiotlb_buffer(struct device *dev, dma_addr_t dma_addr)
         * have the same virtual address as another address
         * in our domain. Therefore _only_ check address within our domain.
         */
-       if (pfn_valid(PFN_DOWN(paddr))) {
-               return paddr >= virt_to_phys(xen_io_tlb_start) &&
-                      paddr < virt_to_phys(xen_io_tlb_end);
-       }
+       if (pfn_valid(PFN_DOWN(paddr)))
+               return is_swiotlb_buffer(paddr);
        return 0;
 }
 
-static int
-xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
+static int xen_swiotlb_fixup(void *buf, unsigned long nslabs)
 {
        int i, rc;
        int dma_bits;
@@ -145,16 +130,6 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
        } while (i < nslabs);
        return 0;
 }
-static unsigned long xen_set_nslabs(unsigned long nr_tbl)
-{
-       if (!nr_tbl) {
-               xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
-               xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
-       } else
-               xen_io_tlb_nslabs = nr_tbl;
-
-       return xen_io_tlb_nslabs << IO_TLB_SHIFT;
-}
 
 enum xen_swiotlb_err {
        XEN_SWIOTLB_UNKNOWN = 0,
@@ -177,102 +152,109 @@ static const char *xen_swiotlb_error(enum xen_swiotlb_err err)
        }
        return "";
 }
-int __ref xen_swiotlb_init(int verbose, bool early)
+
+#define DEFAULT_NSLABS         ALIGN(SZ_64M >> IO_TLB_SHIFT, IO_TLB_SEGSIZE)
+
+int __ref xen_swiotlb_init(void)
 {
-       unsigned long bytes, order;
-       int rc = -ENOMEM;
        enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN;
-       unsigned int repeat = 3;
+       unsigned long bytes = swiotlb_size_or_default();
+       unsigned long nslabs = bytes >> IO_TLB_SHIFT;
+       unsigned int order, repeat = 3;
+       int rc = -ENOMEM;
+       char *start;
 
-       xen_io_tlb_nslabs = swiotlb_nr_tbl();
 retry:
-       bytes = xen_set_nslabs(xen_io_tlb_nslabs);
-       order = get_order(xen_io_tlb_nslabs << IO_TLB_SHIFT);
-
-       /*
-        * IO TLB memory already allocated. Just use it.
-        */
-       if (io_tlb_start != 0) {
-               xen_io_tlb_start = phys_to_virt(io_tlb_start);
-               goto end;
-       }
+       m_ret = XEN_SWIOTLB_ENOMEM;
+       order = get_order(bytes);
 
        /*
         * Get IO TLB memory from any location.
         */
-       if (early) {
-               xen_io_tlb_start = memblock_alloc(PAGE_ALIGN(bytes),
-                                                 PAGE_SIZE);
-               if (!xen_io_tlb_start)
-                       panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
-                             __func__, PAGE_ALIGN(bytes), PAGE_SIZE);
-       } else {
 #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
 #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
-               while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
-                       xen_io_tlb_start = (void *)xen_get_swiotlb_free_pages(order);
-                       if (xen_io_tlb_start)
-                               break;
-                       order--;
-               }
-               if (order != get_order(bytes)) {
-                       pr_warn("Warning: only able to allocate %ld MB for software IO TLB\n",
-                               (PAGE_SIZE << order) >> 20);
-                       xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
-                       bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
-               }
+       while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
+               start = (void *)xen_get_swiotlb_free_pages(order);
+               if (start)
+                       break;
+               order--;
        }
-       if (!xen_io_tlb_start) {
-               m_ret = XEN_SWIOTLB_ENOMEM;
+       if (!start)
                goto error;
+       if (order != get_order(bytes)) {
+               pr_warn("Warning: only able to allocate %ld MB for software IO TLB\n",
+                       (PAGE_SIZE << order) >> 20);
+               nslabs = SLABS_PER_PAGE << order;
+               bytes = nslabs << IO_TLB_SHIFT;
        }
+
        /*
         * And replace that memory with pages under 4GB.
         */
-       rc = xen_swiotlb_fixup(xen_io_tlb_start,
-                              bytes,
-                              xen_io_tlb_nslabs);
+       rc = xen_swiotlb_fixup(start, nslabs);
        if (rc) {
-               if (early)
-                       memblock_free(__pa(xen_io_tlb_start),
-                                     PAGE_ALIGN(bytes));
-               else {
-                       free_pages((unsigned long)xen_io_tlb_start, order);
-                       xen_io_tlb_start = NULL;
-               }
+               free_pages((unsigned long)start, order);
                m_ret = XEN_SWIOTLB_EFIXUP;
                goto error;
        }
-       if (early) {
-               if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs,
-                        verbose))
-                       panic("Cannot allocate SWIOTLB buffer");
-               rc = 0;
-       } else
-               rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs);
-
-end:
-       xen_io_tlb_end = xen_io_tlb_start + bytes;
-       if (!rc)
-               swiotlb_set_max_segment(PAGE_SIZE);
-
-       return rc;
+       rc = swiotlb_late_init_with_tbl(start, nslabs);
+       if (rc)
+               return rc;
+       swiotlb_set_max_segment(PAGE_SIZE);
+       return 0;
 error:
        if (repeat--) {
-               xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */
-                                       (xen_io_tlb_nslabs >> 1));
+               /* Min is 2MB */
+               nslabs = max(1024UL, (nslabs >> 1));
                pr_info("Lowering to %luMB\n",
-                       (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
+                       (nslabs << IO_TLB_SHIFT) >> 20);
                goto retry;
        }
        pr_err("%s (rc:%d)\n", xen_swiotlb_error(m_ret), rc);
-       if (early)
-               panic("%s (rc:%d)", xen_swiotlb_error(m_ret), rc);
-       else
-               free_pages((unsigned long)xen_io_tlb_start, order);
+       free_pages((unsigned long)start, order);
        return rc;
 }
 
+#ifdef CONFIG_X86
+void __init xen_swiotlb_init_early(void)
+{
+       unsigned long bytes = swiotlb_size_or_default();
+       unsigned long nslabs = bytes >> IO_TLB_SHIFT;
+       unsigned int repeat = 3;
+       char *start;
+       int rc;
+
+retry:
+       /*
+        * Get IO TLB memory from any location.
+        */
+       start = memblock_alloc(PAGE_ALIGN(bytes), PAGE_SIZE);
+       if (!start)
+               panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
+                     __func__, PAGE_ALIGN(bytes), PAGE_SIZE);
+
+       /*
+        * And replace that memory with pages under 4GB.
+        */
+       rc = xen_swiotlb_fixup(start, nslabs);
+       if (rc) {
+               memblock_free(__pa(start), PAGE_ALIGN(bytes));
+               if (repeat--) {
+                       /* Min is 2MB */
+                       nslabs = max(1024UL, (nslabs >> 1));
+                       bytes = nslabs << IO_TLB_SHIFT;
+                       pr_info("Lowering to %luMB\n", bytes >> 20);
+                       goto retry;
+               }
+               panic("%s (rc:%d)", xen_swiotlb_error(XEN_SWIOTLB_EFIXUP), rc);
+       }
+
+       if (swiotlb_init_with_tbl(start, nslabs, false))
+               panic("Cannot allocate SWIOTLB buffer");
+       swiotlb_set_max_segment(PAGE_SIZE);
+}
+#endif /* CONFIG_X86 */
+
 static void *
 xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                           dma_addr_t *dma_handle, gfp_t flags,
@@ -406,7 +388,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
         * Ensure that the address returned is DMA'ble
         */
        if (unlikely(!dma_capable(dev, dev_addr, size, true))) {
-               swiotlb_tbl_unmap_single(dev, map, size, size, dir,
+               swiotlb_tbl_unmap_single(dev, map, size, dir,
                                attrs | DMA_ATTR_SKIP_CPU_SYNC);
                return DMA_MAPPING_ERROR;
        }
@@ -445,7 +427,7 @@ static void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
 
        /* NOTE: We use dev_addr here, not paddr! */
        if (is_xen_swiotlb_buffer(hwdev, dev_addr))
-               swiotlb_tbl_unmap_single(hwdev, paddr, size, size, dir, attrs);
+               swiotlb_tbl_unmap_single(hwdev, paddr, size, dir, attrs);
 }
 
 static void
@@ -462,7 +444,7 @@ xen_swiotlb_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr,
        }
 
        if (is_xen_swiotlb_buffer(dev, dma_addr))
-               swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_CPU);
+               swiotlb_sync_single_for_cpu(dev, paddr, size, dir);
 }
 
 static void
@@ -472,7 +454,7 @@ xen_swiotlb_sync_single_for_device(struct device *dev, dma_addr_t dma_addr,
        phys_addr_t paddr = xen_dma_to_phys(dev, dma_addr);
 
        if (is_xen_swiotlb_buffer(dev, dma_addr))
-               swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_DEVICE);
+               swiotlb_sync_single_for_device(dev, paddr, size, dir);
 
        if (!dev_is_dma_coherent(dev)) {
                if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dma_addr))))
@@ -560,7 +542,7 @@ xen_swiotlb_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
 static int
 xen_swiotlb_dma_supported(struct device *hwdev, u64 mask)
 {
-       return xen_virt_to_bus(hwdev, xen_io_tlb_end - 1) <= mask;
+       return xen_phys_to_dma(hwdev, io_tlb_default_mem->end - 1) <= mask;
 }
 
 const struct dma_map_ops xen_swiotlb_dma_ops = {