forked from luck/tmp_suning_uos_patched
Merge branch 'stable/late-swiotlb.v3.3' into stable/for-linus-3.7
* 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>
This commit is contained in:
commit
a5f9515570
|
@ -5,10 +5,12 @@
|
||||||
extern int xen_swiotlb;
|
extern int xen_swiotlb;
|
||||||
extern int __init pci_xen_swiotlb_detect(void);
|
extern int __init pci_xen_swiotlb_detect(void);
|
||||||
extern void __init pci_xen_swiotlb_init(void);
|
extern void __init pci_xen_swiotlb_init(void);
|
||||||
|
extern int pci_xen_swiotlb_init_late(void);
|
||||||
#else
|
#else
|
||||||
#define xen_swiotlb (0)
|
#define xen_swiotlb (0)
|
||||||
static inline int __init pci_xen_swiotlb_detect(void) { return 0; }
|
static inline int __init pci_xen_swiotlb_detect(void) { return 0; }
|
||||||
static inline void __init pci_xen_swiotlb_init(void) { }
|
static inline void __init pci_xen_swiotlb_init(void) { }
|
||||||
|
static inline int pci_xen_swiotlb_init_late(void) { return -ENXIO; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _ASM_X86_SWIOTLB_XEN_H */
|
#endif /* _ASM_X86_SWIOTLB_XEN_H */
|
||||||
|
|
|
@ -8,7 +8,14 @@
|
||||||
#include <xen/xen.h>
|
#include <xen/xen.h>
|
||||||
#include <asm/iommu_table.h>
|
#include <asm/iommu_table.h>
|
||||||
|
|
||||||
|
|
||||||
#include <asm/xen/swiotlb-xen.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;
|
int xen_swiotlb __read_mostly;
|
||||||
|
|
||||||
static struct dma_map_ops xen_swiotlb_dma_ops = {
|
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)
|
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
|
/* If running as PV guest, either iommu=soft, or swiotlb=force will
|
||||||
* activate this IOMMU. If running as PV privileged, activate it
|
* activate this IOMMU. If running as PV privileged, activate it
|
||||||
* irregardless.
|
* irregardless.
|
||||||
*/
|
*/
|
||||||
if ((xen_initial_domain() || swiotlb || swiotlb_force) &&
|
if ((xen_initial_domain() || swiotlb || swiotlb_force))
|
||||||
(xen_pv_domain()))
|
|
||||||
xen_swiotlb = 1;
|
xen_swiotlb = 1;
|
||||||
|
|
||||||
/* If we are running under Xen, we MUST disable the native SWIOTLB.
|
/* If we are running under Xen, we MUST disable the native SWIOTLB.
|
||||||
* Don't worry about swiotlb_force flag activating the native, as
|
* Don't worry about swiotlb_force flag activating the native, as
|
||||||
* the 'swiotlb' flag is the only one turning it on. */
|
* 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;
|
return xen_swiotlb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init pci_xen_swiotlb_init(void)
|
void __init pci_xen_swiotlb_init(void)
|
||||||
{
|
{
|
||||||
if (xen_swiotlb) {
|
if (xen_swiotlb) {
|
||||||
xen_swiotlb_init(1);
|
xen_swiotlb_init(1, true /* early */);
|
||||||
dma_ops = &xen_swiotlb_dma_ops;
|
dma_ops = &xen_swiotlb_dma_ops;
|
||||||
|
|
||||||
/* Make sure ACS will be enabled */
|
/* Make sure ACS will be enabled */
|
||||||
pci_request_acs();
|
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,
|
IOMMU_INIT_FINISH(pci_xen_swiotlb_detect,
|
||||||
NULL,
|
NULL,
|
||||||
pci_xen_swiotlb_init,
|
pci_xen_swiotlb_init,
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
|
|
||||||
|
#include <asm/xen/swiotlb-xen.h>
|
||||||
#define INVALID_GRANT_REF (0)
|
#define INVALID_GRANT_REF (0)
|
||||||
#define INVALID_EVTCHN (-1)
|
#define INVALID_EVTCHN (-1)
|
||||||
|
|
||||||
|
@ -668,7 +669,7 @@ static irqreturn_t pcifront_handler_aer(int irq, void *dev)
|
||||||
schedule_pcifront_aer_op(pdev);
|
schedule_pcifront_aer_op(pdev);
|
||||||
return IRQ_HANDLED;
|
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;
|
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");
|
dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&pcifront_dev_lock);
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,10 +847,10 @@ static int __devinit pcifront_try_connect(struct pcifront_device *pdev)
|
||||||
XenbusStateInitialised)
|
XenbusStateInitialised)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = pcifront_connect(pdev);
|
err = pcifront_connect_and_init_dma(pdev);
|
||||||
if (err) {
|
if (err) {
|
||||||
xenbus_dev_fatal(pdev->xdev, err,
|
xenbus_dev_fatal(pdev->xdev, err,
|
||||||
"Error connecting PCI Frontend");
|
"Error setting up PCI Frontend");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,31 +144,72 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
|
||||||
} while (i < nslabs);
|
} while (i < nslabs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static unsigned long xen_set_nslabs(unsigned long nr_tbl)
|
||||||
void __init xen_swiotlb_init(int verbose)
|
|
||||||
{
|
{
|
||||||
unsigned long bytes;
|
if (!nr_tbl) {
|
||||||
int rc = -ENOMEM;
|
|
||||||
unsigned long nr_tbl;
|
|
||||||
char *m = NULL;
|
|
||||||
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 = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
|
||||||
xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
|
xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
|
||||||
}
|
} else
|
||||||
retry:
|
xen_io_tlb_nslabs = nr_tbl;
|
||||||
bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
|
|
||||||
|
|
||||||
|
return xen_io_tlb_nslabs << IO_TLB_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum xen_swiotlb_err {
|
||||||
|
XEN_SWIOTLB_UNKNOWN = 0,
|
||||||
|
XEN_SWIOTLB_ENOMEM,
|
||||||
|
XEN_SWIOTLB_EFIXUP
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *xen_swiotlb_error(enum xen_swiotlb_err err)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN;
|
||||||
|
unsigned int repeat = 3;
|
||||||
|
|
||||||
|
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);
|
||||||
/*
|
/*
|
||||||
* Get IO TLB memory from any location.
|
* 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) {
|
if (!xen_io_tlb_start) {
|
||||||
m = "Cannot allocate Xen-SWIOTLB buffer!\n";
|
m_ret = XEN_SWIOTLB_ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
xen_io_tlb_end = xen_io_tlb_start + bytes;
|
xen_io_tlb_end = xen_io_tlb_start + bytes;
|
||||||
|
@ -179,17 +220,22 @@ void __init xen_swiotlb_init(int verbose)
|
||||||
bytes,
|
bytes,
|
||||||
xen_io_tlb_nslabs);
|
xen_io_tlb_nslabs);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes));
|
if (early)
|
||||||
m = "Failed to get contiguous memory for DMA from Xen!\n"\
|
free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes));
|
||||||
"You either: don't have the permissions, do not have"\
|
else {
|
||||||
" enough free memory under 4GB, or the hypervisor memory"\
|
free_pages((unsigned long)xen_io_tlb_start, order);
|
||||||
"is too fragmented!";
|
xen_io_tlb_start = NULL;
|
||||||
|
}
|
||||||
|
m_ret = XEN_SWIOTLB_EFIXUP;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
|
start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
|
||||||
swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
|
if (early) {
|
||||||
|
swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
|
||||||
return;
|
rc = 0;
|
||||||
|
} else
|
||||||
|
rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs);
|
||||||
|
return rc;
|
||||||
error:
|
error:
|
||||||
if (repeat--) {
|
if (repeat--) {
|
||||||
xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */
|
xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */
|
||||||
|
@ -198,10 +244,13 @@ void __init xen_swiotlb_init(int verbose)
|
||||||
(xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
|
(xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
xen_raw_printk("%s (rc:%d)", m, rc);
|
pr_err("%s (rc:%d)", xen_swiotlb_error(m_ret), rc);
|
||||||
panic("%s (rc:%d)", m, 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 *
|
void *
|
||||||
xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
|
xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
|
||||||
dma_addr_t *dma_handle, gfp_t flags,
|
dma_addr_t *dma_handle, gfp_t flags,
|
||||||
|
|
|
@ -25,6 +25,7 @@ extern int swiotlb_force;
|
||||||
extern void swiotlb_init(int verbose);
|
extern void swiotlb_init(int verbose);
|
||||||
extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
|
extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
|
||||||
extern unsigned long swiotlb_nr_tbl(void);
|
extern unsigned long swiotlb_nr_tbl(void);
|
||||||
|
extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enumeration for sync targets
|
* Enumeration for sync targets
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <linux/swiotlb.h>
|
#include <linux/swiotlb.h>
|
||||||
|
|
||||||
extern void xen_swiotlb_init(int verbose);
|
extern int xen_swiotlb_init(int verbose, bool early);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
*xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
|
*xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
|
||||||
|
|
|
@ -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
|
* Statically reserve bounce buffer space and initialize bounce buffer data
|
||||||
* structures for the software IO TLB used to implement the DMA API.
|
* 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)
|
swiotlb_init_with_default_size(size_t default_size, int verbose)
|
||||||
{
|
{
|
||||||
unsigned long bytes;
|
unsigned long bytes;
|
||||||
|
@ -206,8 +206,9 @@ swiotlb_init(int verbose)
|
||||||
int
|
int
|
||||||
swiotlb_late_init_with_default_size(size_t default_size)
|
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;
|
unsigned int order;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
if (!io_tlb_nslabs) {
|
if (!io_tlb_nslabs) {
|
||||||
io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
|
io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
|
||||||
|
@ -229,16 +230,32 @@ swiotlb_late_init_with_default_size(size_t default_size)
|
||||||
order--;
|
order--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!io_tlb_start)
|
if (!io_tlb_start) {
|
||||||
goto cleanup1;
|
io_tlb_nslabs = req_nslabs;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
if (order != get_order(bytes)) {
|
if (order != get_order(bytes)) {
|
||||||
printk(KERN_WARNING "Warning: only able to allocate %ld MB "
|
printk(KERN_WARNING "Warning: only able to allocate %ld MB "
|
||||||
"for software IO TLB\n", (PAGE_SIZE << order) >> 20);
|
"for software IO TLB\n", (PAGE_SIZE << order) >> 20);
|
||||||
io_tlb_nslabs = SLABS_PER_PAGE << order;
|
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;
|
io_tlb_end = io_tlb_start + bytes;
|
||||||
|
|
||||||
memset(io_tlb_start, 0, bytes);
|
memset(io_tlb_start, 0, bytes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -288,10 +305,8 @@ swiotlb_late_init_with_default_size(size_t default_size)
|
||||||
io_tlb_list = NULL;
|
io_tlb_list = NULL;
|
||||||
cleanup2:
|
cleanup2:
|
||||||
io_tlb_end = NULL;
|
io_tlb_end = NULL;
|
||||||
free_pages((unsigned long)io_tlb_start, order);
|
|
||||||
io_tlb_start = NULL;
|
io_tlb_start = NULL;
|
||||||
cleanup1:
|
io_tlb_nslabs = 0;
|
||||||
io_tlb_nslabs = req_nslabs;
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user