]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge branch 'stable/late-swiotlb.v3.3' into stable/for-linus-3.7
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Sun, 23 Sep 2012 00:01:16 +0000 (20:01 -0400)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Sun, 23 Sep 2012 00:01:24 +0000 (20:01 -0400)
* stable/late-swiotlb.v3.3:
  xen/swiotlb: Fix compile warnings when using plain integer instead of NULL pointer.
  xen/swiotlb: Remove functions not needed anymore.
  xen/pcifront: Use Xen-SWIOTLB when initting if required.
  xen/swiotlb: For early initialization, return zero on success.
  xen/swiotlb: Use the swiotlb_late_init_with_tbl to init Xen-SWIOTLB late when PV PCI is used.
  xen/swiotlb: Move the error strings to its own function.
  xen/swiotlb: Move the nr_tbl determination in its own function.
  swiotlb: add the late swiotlb initialization function with iotlb memory
  xen/swiotlb: With more than 4GB on 64-bit, disable the native SWIOTLB.
  xen/swiotlb: Simplify the logic.

Conflicts:
arch/x86/xen/pci-swiotlb-xen.c

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
arch/x86/include/asm/xen/swiotlb-xen.h
arch/x86/xen/pci-swiotlb-xen.c
drivers/pci/xen-pcifront.c
drivers/xen/swiotlb-xen.c
include/linux/swiotlb.h
include/xen/swiotlb-xen.h
lib/swiotlb.c

index 1be1ab7d6a4120d945aa22abf98a523f617196d8..ee52fcac6f72211ec3ac06e0e295193bc0e44817 100644 (file)
@@ -5,10 +5,12 @@
 extern int xen_swiotlb;
 extern int __init pci_xen_swiotlb_detect(void);
 extern void __init pci_xen_swiotlb_init(void);
+extern int pci_xen_swiotlb_init_late(void);
 #else
 #define xen_swiotlb (0)
 static inline int __init pci_xen_swiotlb_detect(void) { return 0; }
 static inline void __init pci_xen_swiotlb_init(void) { }
+static inline int pci_xen_swiotlb_init_late(void) { return -ENXIO; }
 #endif
 
 #endif /* _ASM_X86_SWIOTLB_XEN_H */
index 1ab45941502d6ca71238ca2f33897dd3e75b496e..969570491c3964d0023dc82a231ff683ee88f735 100644 (file)
@@ -8,7 +8,14 @@
 #include <xen/xen.h>
 #include <asm/iommu_table.h>
 
+
 #include <asm/xen/swiotlb-xen.h>
+#ifdef CONFIG_X86_64
+#include <asm/iommu.h>
+#include <asm/dma.h>
+#endif
+#include <linux/export.h>
+
 int xen_swiotlb __read_mostly;
 
 static struct dma_map_ops xen_swiotlb_dma_ops = {
@@ -35,33 +42,63 @@ static struct dma_map_ops xen_swiotlb_dma_ops = {
 int __init pci_xen_swiotlb_detect(void)
 {
 
+       if (!xen_pv_domain())
+               return 0;
+
        /* If running as PV guest, either iommu=soft, or swiotlb=force will
         * activate this IOMMU. If running as PV privileged, activate it
         * irregardless.
         */
-       if ((xen_initial_domain() || swiotlb || swiotlb_force) &&
-           (xen_pv_domain()))
+       if ((xen_initial_domain() || swiotlb || swiotlb_force))
                xen_swiotlb = 1;
 
        /* If we are running under Xen, we MUST disable the native SWIOTLB.
         * Don't worry about swiotlb_force flag activating the native, as
         * the 'swiotlb' flag is the only one turning it on. */
-       if (xen_pv_domain())
-               swiotlb = 0;
+       swiotlb = 0;
 
+#ifdef CONFIG_X86_64
+       /* pci_swiotlb_detect_4gb turns on native SWIOTLB if no_iommu == 0
+        * (so no iommu=X command line over-writes).
+        * Considering that PV guests do not want the *native SWIOTLB* but
+        * only Xen SWIOTLB it is not useful to us so set no_iommu=1 here.
+        */
+       if (max_pfn > MAX_DMA32_PFN)
+               no_iommu = 1;
+#endif
        return xen_swiotlb;
 }
 
 void __init pci_xen_swiotlb_init(void)
 {
        if (xen_swiotlb) {
-               xen_swiotlb_init(1);
+               xen_swiotlb_init(1, true /* early */);
                dma_ops = &xen_swiotlb_dma_ops;
 
                /* Make sure ACS will be enabled */
                pci_request_acs();
        }
 }
+
+int pci_xen_swiotlb_init_late(void)
+{
+       int rc;
+
+       if (xen_swiotlb)
+               return 0;
+
+       rc = xen_swiotlb_init(1, false /* late */);
+       if (rc)
+               return rc;
+
+       dma_ops = &xen_swiotlb_dma_ops;
+       /* Make sure ACS will be enabled */
+       pci_request_acs();
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pci_xen_swiotlb_init_late);
+
 IOMMU_INIT_FINISH(pci_xen_swiotlb_detect,
                  NULL,
                  pci_xen_swiotlb_init,
index a4d901def8f282dccc66cc2ba61929eb35428671..7d6773535b67dce135840b36e36ce1e93476aa7d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/bitops.h>
 #include <linux/time.h>
 
+#include <asm/xen/swiotlb-xen.h>
 #define INVALID_GRANT_REF (0)
 #define INVALID_EVTCHN    (-1)
 
@@ -668,7 +669,7 @@ static irqreturn_t pcifront_handler_aer(int irq, void *dev)
        schedule_pcifront_aer_op(pdev);
        return IRQ_HANDLED;
 }
-static int pcifront_connect(struct pcifront_device *pdev)
+static int pcifront_connect_and_init_dma(struct pcifront_device *pdev)
 {
        int err = 0;
 
@@ -681,9 +682,13 @@ static int pcifront_connect(struct pcifront_device *pdev)
                dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
                err = -EEXIST;
        }
-
        spin_unlock(&pcifront_dev_lock);
 
+       if (!err && !swiotlb_nr_tbl()) {
+               err = pci_xen_swiotlb_init_late();
+               if (err)
+                       dev_err(&pdev->xdev->dev, "Could not setup SWIOTLB!\n");
+       }
        return err;
 }
 
@@ -842,10 +847,10 @@ static int __devinit pcifront_try_connect(struct pcifront_device *pdev)
            XenbusStateInitialised)
                goto out;
 
-       err = pcifront_connect(pdev);
+       err = pcifront_connect_and_init_dma(pdev);
        if (err) {
                xenbus_dev_fatal(pdev->xdev, err,
-                                "Error connecting PCI Frontend");
+                                "Error setting up PCI Frontend");
                goto out;
        }
 
index 2e74dba6a04d184844e3104b164a5175f2c83ac3..58db6df866ef3338f6fc787acd552fe03d0a0b69 100644 (file)
@@ -144,31 +144,72 @@ 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,
+       XEN_SWIOTLB_ENOMEM,
+       XEN_SWIOTLB_EFIXUP
+};
 
-void __init xen_swiotlb_init(int verbose)
+static const char *xen_swiotlb_error(enum xen_swiotlb_err err)
 {
-       unsigned long bytes;
+       switch (err) {
+       case XEN_SWIOTLB_ENOMEM:
+               return "Cannot allocate Xen-SWIOTLB buffer\n";
+       case XEN_SWIOTLB_EFIXUP:
+               return "Failed to get contiguous memory for DMA from Xen!\n"\
+                   "You either: don't have the permissions, do not have"\
+                   " enough free memory under 4GB, or the hypervisor memory"\
+                   " is too fragmented!";
+       default:
+               break;
+       }
+       return "";
+}
+int __ref xen_swiotlb_init(int verbose, bool early)
+{
+       unsigned long bytes, order;
        int rc = -ENOMEM;
-       unsigned long nr_tbl;
-       char *m = NULL;
+       enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN;
        unsigned int repeat = 3;
 
-       nr_tbl = swiotlb_nr_tbl();
-       if (nr_tbl)
-               xen_io_tlb_nslabs = nr_tbl;
-       else {
-               xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
-               xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
-       }
+       xen_io_tlb_nslabs = swiotlb_nr_tbl();
 retry:
-       bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
-
+       bytes = xen_set_nslabs(xen_io_tlb_nslabs);
+       order = get_order(xen_io_tlb_nslabs << IO_TLB_SHIFT);
        /*
         * Get IO TLB memory from any location.
         */
-       xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
+       if (early)
+               xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
+       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 *)__get_free_pages(__GFP_NOWARN, 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;
+               }
+       }
        if (!xen_io_tlb_start) {
-               m = "Cannot allocate Xen-SWIOTLB buffer!\n";
+               m_ret = XEN_SWIOTLB_ENOMEM;
                goto error;
        }
        xen_io_tlb_end = xen_io_tlb_start + bytes;
@@ -179,17 +220,22 @@ retry:
                               bytes,
                               xen_io_tlb_nslabs);
        if (rc) {
-               free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes));
-               m = "Failed to get contiguous memory for DMA from Xen!\n"\
-                   "You either: don't have the permissions, do not have"\
-                   " enough free memory under 4GB, or the hypervisor memory"\
-                   "is too fragmented!";
+               if (early)
+                       free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes));
+               else {
+                       free_pages((unsigned long)xen_io_tlb_start, order);
+                       xen_io_tlb_start = NULL;
+               }
+               m_ret = XEN_SWIOTLB_EFIXUP;
                goto error;
        }
        start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
-       swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
-
-       return;
+       if (early) {
+               swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
+               rc = 0;
+       } else
+               rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs);
+       return rc;
 error:
        if (repeat--) {
                xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */
@@ -198,10 +244,13 @@ error:
                      (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
                goto retry;
        }
-       xen_raw_printk("%s (rc:%d)", m, rc);
-       panic("%s (rc:%d)", m, rc);
+       pr_err("%s (rc:%d)", 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);
+       return rc;
 }
-
 void *
 xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                           dma_addr_t *dma_handle, gfp_t flags,
index e872526fdc5fbb371ca0e420a961aec4738fdfa2..8d08b3ed406db688c6fa8c1cfe10d921870d2e72 100644 (file)
@@ -25,6 +25,7 @@ extern int swiotlb_force;
 extern void swiotlb_init(int verbose);
 extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
 extern unsigned long swiotlb_nr_tbl(void);
+extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs);
 
 /*
  * Enumeration for sync targets
index c050b6b9de38a04dc224475f5f4291a126f12551..de8bcc641c49ae64c6971c11b792b696216cce0a 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <linux/swiotlb.h>
 
-extern void xen_swiotlb_init(int verbose);
+extern int xen_swiotlb_init(int verbose, bool early);
 
 extern void
 *xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
index 45bc1f83a5ada665297bc0b9dcd3a6ad72e2ec72..f114bf6a8e1363dc812cfa4fd8e6ae66a1411575 100644 (file)
@@ -170,7 +170,7 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
  * Statically reserve bounce buffer space and initialize bounce buffer data
  * structures for the software IO TLB used to implement the DMA API.
  */
-void __init
+static void __init
 swiotlb_init_with_default_size(size_t default_size, int verbose)
 {
        unsigned long bytes;
@@ -206,8 +206,9 @@ swiotlb_init(int verbose)
 int
 swiotlb_late_init_with_default_size(size_t default_size)
 {
-       unsigned long i, bytes, req_nslabs = io_tlb_nslabs;
+       unsigned long bytes, req_nslabs = io_tlb_nslabs;
        unsigned int order;
+       int rc = 0;
 
        if (!io_tlb_nslabs) {
                io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
@@ -229,16 +230,32 @@ swiotlb_late_init_with_default_size(size_t default_size)
                order--;
        }
 
-       if (!io_tlb_start)
-               goto cleanup1;
-
+       if (!io_tlb_start) {
+               io_tlb_nslabs = req_nslabs;
+               return -ENOMEM;
+       }
        if (order != get_order(bytes)) {
                printk(KERN_WARNING "Warning: only able to allocate %ld MB "
                       "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
                io_tlb_nslabs = SLABS_PER_PAGE << order;
-               bytes = io_tlb_nslabs << IO_TLB_SHIFT;
        }
+       rc = swiotlb_late_init_with_tbl(io_tlb_start, io_tlb_nslabs);
+       if (rc)
+               free_pages((unsigned long)io_tlb_start, order);
+       return rc;
+}
+
+int
+swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
+{
+       unsigned long i, bytes;
+
+       bytes = nslabs << IO_TLB_SHIFT;
+
+       io_tlb_nslabs = nslabs;
+       io_tlb_start = tlb;
        io_tlb_end = io_tlb_start + bytes;
+
        memset(io_tlb_start, 0, bytes);
 
        /*
@@ -288,10 +305,8 @@ cleanup3:
        io_tlb_list = NULL;
 cleanup2:
        io_tlb_end = NULL;
-       free_pages((unsigned long)io_tlb_start, order);
        io_tlb_start = NULL;
-cleanup1:
-       io_tlb_nslabs = req_nslabs;
+       io_tlb_nslabs = 0;
        return -ENOMEM;
 }