2014-11-12 15:25:54

by David Vrabel

[permalink] [raw]
Subject: [PATCHv2 0/3]: dma,x86,xen: reduce SWIOTLB usage in Xen guests

On systems where DMA addresses and physical addresses are not 1:1
(such as Xen PV guests), the generic dma_get_required_mask() will not
return the correct mask (since it uses max_pfn).

Some device drivers (such as mptsas, mpt2sas) use
dma_get_required_mask() to set the device's DMA mask to allow them to use
only 32-bit DMA addresses in hardware structures. This results in
unnecessary use of the SWIOTLB if DMA addresses are more than 32-bits,
impacting performance significantly.

This series allows Xen PV guests to override the default
dma_get_required_mask() with one that calculated the DMA mask from the
maximum MFN (and not the PFN).

The first patch removes a duplicated function between ia64 and common
since we want a common implementation usage by ia64 and x86.

Changes in v2:
- split x86 and xen changes into separate patches

David


2014-11-12 15:25:43

by David Vrabel

[permalink] [raw]
Subject: [PATCH 2/3] x86: allow dma_get_required_mask() to be overridden

Use dma_ops->get_required_mask() if provided, defaulting to
dma_get_requried_mask_from_max_pfn().

This is needed on systems (such as Xen PV guests) where the DMA
address and the physical address are not equal.

Signed-off-by: David Vrabel <[email protected]>
---
arch/x86/include/asm/device.h | 2 ++
arch/x86/kernel/pci-dma.c | 8 ++++++++
2 files changed, 10 insertions(+)

diff --git a/arch/x86/include/asm/device.h b/arch/x86/include/asm/device.h
index 03dd729..10bc628 100644
--- a/arch/x86/include/asm/device.h
+++ b/arch/x86/include/asm/device.h
@@ -13,4 +13,6 @@ struct dev_archdata {
struct pdev_archdata {
};

+#define ARCH_HAS_DMA_GET_REQUIRED_MASK
+
#endif /* _ASM_X86_DEVICE_H */
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index a25e202..5154400 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -140,6 +140,14 @@ void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr,
free_pages((unsigned long)vaddr, get_order(size));
}

+u64 dma_get_required_mask(struct device *dev)
+{
+ if (dma_ops->get_required_mask)
+ return dma_ops->get_required_mask(dev);
+ return dma_get_required_mask_from_max_pfn(dev);
+}
+EXPORT_SYMBOL_GPL(dma_get_required_mask);
+
/*
* See <Documentation/x86/x86_64/boot-options.txt> for the iommu kernel
* parameter documentation.
--
1.7.10.4

2014-11-12 15:25:46

by David Vrabel

[permalink] [raw]
Subject: [PATCH 3/3] x86/xen: use the maximum MFN to calculate the required DMA mask

On a Xen PV guest the DMA addresses and physical addresses are not 1:1
(such as Xen PV guests) and the generic dma_get_required_mask() does
not return the correct mask (since it uses max_pfn).

Some device drivers (such as mptsas, mpt2sas) use
dma_get_required_mask() to set the device's DMA mask to allow them to
use only 32-bit DMA addresses in hardware structures. This results in
unnecessary use of the SWIOTLB if DMA addresses are more than 32-bits,
impacting performance significantly.

Provide a get_required_mask op that uses the maximum MFN to calculate
the DMA mask.

Signed-off-by: David Vrabel <[email protected]>
---
arch/x86/xen/pci-swiotlb-xen.c | 1 +
drivers/xen/swiotlb-xen.c | 13 +++++++++++++
include/xen/swiotlb-xen.h | 4 ++++
3 files changed, 18 insertions(+)

diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c
index 0e98e5d..a5d180a 100644
--- a/arch/x86/xen/pci-swiotlb-xen.c
+++ b/arch/x86/xen/pci-swiotlb-xen.c
@@ -31,6 +31,7 @@ static struct dma_map_ops xen_swiotlb_dma_ops = {
.map_page = xen_swiotlb_map_page,
.unmap_page = xen_swiotlb_unmap_page,
.dma_supported = xen_swiotlb_dma_supported,
+ .get_required_mask = xen_swiotlb_get_required_mask,
};

/*
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index ebd8f21..472fd52 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -42,9 +42,11 @@
#include <xen/page.h>
#include <xen/xen-ops.h>
#include <xen/hvc-console.h>
+#include <xen/interface/memory.h>

#include <asm/dma-mapping.h>
#include <asm/xen/page-coherent.h>
+#include <asm/xen/hypercall.h>

#include <trace/events/swiotlb.h>
/*
@@ -683,3 +685,14 @@ xen_swiotlb_set_dma_mask(struct device *dev, u64 dma_mask)
return 0;
}
EXPORT_SYMBOL_GPL(xen_swiotlb_set_dma_mask);
+
+u64
+xen_swiotlb_get_required_mask(struct device *dev)
+{
+ u64 max_mfn;
+
+ max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
+
+ return DMA_BIT_MASK(fls64(max_mfn << PAGE_SHIFT) + 1);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_get_required_mask);
diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h
index 8b2eb93..6408888 100644
--- a/include/xen/swiotlb-xen.h
+++ b/include/xen/swiotlb-xen.h
@@ -58,4 +58,8 @@ xen_swiotlb_dma_supported(struct device *hwdev, u64 mask);

extern int
xen_swiotlb_set_dma_mask(struct device *dev, u64 dma_mask);
+
+extern u64
+xen_swiotlb_get_required_mask(struct device *dev);
+
#endif /* __LINUX_SWIOTLB_XEN_H */
--
1.7.10.4

2014-11-12 15:26:41

by David Vrabel

[permalink] [raw]
Subject: [PATCH 1/3] dma,ia64: add dma_get_required_mask_from_max_pfn()

ia64 provides a duplicate of the generic dma_get_required_mask()
because it has ARCH_HAS_GET_REQUIRED_MASK. Provide a common
dma_get_require_mask_max_pfn() instead.

Signed-off-by: David Vrabel <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Fenghua Yu <[email protected]>
Cc: [email protected]
---
arch/ia64/include/asm/machvec.h | 2 +-
arch/ia64/include/asm/machvec_init.h | 1 -
arch/ia64/pci/pci.c | 20 --------------------
drivers/base/platform.c | 10 ++++++++--
include/linux/dma-mapping.h | 1 +
5 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/arch/ia64/include/asm/machvec.h b/arch/ia64/include/asm/machvec.h
index 9c39bdf..beaa47d 100644
--- a/arch/ia64/include/asm/machvec.h
+++ b/arch/ia64/include/asm/machvec.h
@@ -287,7 +287,7 @@ extern struct dma_map_ops *dma_get_ops(struct device *);
# define platform_dma_get_ops dma_get_ops
#endif
#ifndef platform_dma_get_required_mask
-# define platform_dma_get_required_mask ia64_dma_get_required_mask
+# define platform_dma_get_required_mask dma_get_required_mask_from_max_pfn
#endif
#ifndef platform_irq_to_vector
# define platform_irq_to_vector __ia64_irq_to_vector
diff --git a/arch/ia64/include/asm/machvec_init.h b/arch/ia64/include/asm/machvec_init.h
index 37a4698..ef964b2 100644
--- a/arch/ia64/include/asm/machvec_init.h
+++ b/arch/ia64/include/asm/machvec_init.h
@@ -3,7 +3,6 @@

extern ia64_mv_send_ipi_t ia64_send_ipi;
extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge;
-extern ia64_mv_dma_get_required_mask ia64_dma_get_required_mask;
extern ia64_mv_irq_to_vector __ia64_irq_to_vector;
extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq;
extern ia64_mv_pci_get_legacy_mem_t ia64_pci_get_legacy_mem;
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 291a582..79da21b 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -791,26 +791,6 @@ static void __init set_pci_dfl_cacheline_size(void)
pci_dfl_cache_line_size = (1 << cci.pcci_line_size) / 4;
}

-u64 ia64_dma_get_required_mask(struct device *dev)
-{
- u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
- u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
- u64 mask;
-
- if (!high_totalram) {
- /* convert to mask just covering totalram */
- low_totalram = (1 << (fls(low_totalram) - 1));
- low_totalram += low_totalram - 1;
- mask = low_totalram;
- } else {
- high_totalram = (1 << (fls(high_totalram) - 1));
- high_totalram += high_totalram - 1;
- mask = (((u64)high_totalram) << 32) + 0xffffffff;
- }
- return mask;
-}
-EXPORT_SYMBOL_GPL(ia64_dma_get_required_mask);
-
u64 dma_get_required_mask(struct device *dev)
{
return platform_dma_get_required_mask(dev);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index b2afc29..f9f3930 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -1009,8 +1009,7 @@ int __init platform_bus_init(void)
return error;
}

-#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
-u64 dma_get_required_mask(struct device *dev)
+u64 dma_get_required_mask_from_max_pfn(struct device *dev)
{
u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
@@ -1028,6 +1027,13 @@ u64 dma_get_required_mask(struct device *dev)
}
return mask;
}
+EXPORT_SYMBOL_GPL(dma_get_required_mask_from_max_pfn);
+
+#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
+u64 dma_get_required_mask(struct device *dev)
+{
+ return dma_get_required_mask_from_max_pfn(dev);
+}
EXPORT_SYMBOL_GPL(dma_get_required_mask);
#endif

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index d5d3881..6e2fdfc 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -127,6 +127,7 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)
return dma_set_mask_and_coherent(dev, mask);
}

+extern u64 dma_get_required_mask_from_max_pfn(struct device *dev);
extern u64 dma_get_required_mask(struct device *dev);

#ifndef set_arch_dma_coherent_ops
--
1.7.10.4

2014-11-12 15:55:30

by Jan Beulich

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 3/3] x86/xen: use the maximum MFN to calculate the required DMA mask

>>> On 12.11.14 at 16:25, <[email protected]> wrote:
> +u64
> +xen_swiotlb_get_required_mask(struct device *dev)
> +{
> + u64 max_mfn;
> +
> + max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
> +
> + return DMA_BIT_MASK(fls64(max_mfn << PAGE_SHIFT) + 1);
> +}

The value the hypercall returns is exclusive and an unsigned long.
Hence I'd suggest

u64
xen_swiotlb_get_required_mask(struct device *dev)
{
unsigned long max_mfn;

max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);

return DMA_BIT_MASK(__fls(max_mfn - 1) + 1 + PAGE_SHIFT);
}

Jan

2014-11-12 16:59:20

by David Vrabel

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 3/3] x86/xen: use the maximum MFN to calculate the required DMA mask

On 12/11/14 15:55, Jan Beulich wrote:
>>>> On 12.11.14 at 16:25, <[email protected]> wrote:
>> +u64
>> +xen_swiotlb_get_required_mask(struct device *dev)
>> +{
>> + u64 max_mfn;
>> +
>> + max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
>> +
>> + return DMA_BIT_MASK(fls64(max_mfn << PAGE_SHIFT) + 1);
>> +}
>
> The value the hypercall returns is exclusive and an unsigned long.

The docs in include/public/memory.h say:

"Returns the maximum machine frame number of mapped RAM in this system."

Which sounds inclusive to me... Do we need a doc update here?

> Hence I'd suggest
>
> u64
> xen_swiotlb_get_required_mask(struct device *dev)
> {
> unsigned long max_mfn;
>
> max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
>
> return DMA_BIT_MASK(__fls(max_mfn - 1) + 1 + PAGE_SHIFT);
> }
>
> Jan
>

2014-11-12 17:18:41

by Jan Beulich

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 3/3] x86/xen: use the maximum MFN to calculate the required DMA mask

>>> On 12.11.14 at 17:59, <[email protected]> wrote:
> On 12/11/14 15:55, Jan Beulich wrote:
>>>>> On 12.11.14 at 16:25, <[email protected]> wrote:
>>> +u64
>>> +xen_swiotlb_get_required_mask(struct device *dev)
>>> +{
>>> + u64 max_mfn;
>>> +
>>> + max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
>>> +
>>> + return DMA_BIT_MASK(fls64(max_mfn << PAGE_SHIFT) + 1);
>>> +}
>>
>> The value the hypercall returns is exclusive and an unsigned long.
>
> The docs in include/public/memory.h say:
>
> "Returns the maximum machine frame number of mapped RAM in this system."
>
> Which sounds inclusive to me... Do we need a doc update here?

Possibly - the origin of this is Linux'es mis-named "max_page" I believe.
And in any event I'd expect you to base your code changes on reality,
not just on documentation...

Jan

2014-11-13 09:57:44

by Jan Beulich

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 3/3] x86/xen: use the maximum MFN to calculate the required DMA mask

>>> On 12.11.14 at 16:55, <[email protected]> wrote:
>>>> On 12.11.14 at 16:25, <[email protected]> wrote:
>> +u64
>> +xen_swiotlb_get_required_mask(struct device *dev)
>> +{
>> + u64 max_mfn;
>> +
>> + max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
>> +
>> + return DMA_BIT_MASK(fls64(max_mfn << PAGE_SHIFT) + 1);
>> +}
>
> The value the hypercall returns is exclusive and an unsigned long.

The latter has further relevance: For one, HYPERVISOR_memory_op()
returns "int" currently - this needs to become "long" for the purpose
here (also for eventual future uses of XENMEM_maximum_gpfn and
XENMEM_{current,maximum}_reservation).

And then, using u64 rather than unsigned long for max_mfn would
still cause problems for 32-bit kernels on systems with memory
extending beyond the 8Tb boundary (since the long -> u64
conversion really goes long -> s64 -> u64).

Jan

2014-11-13 10:25:32

by Jan Beulich

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 2/3] x86: allow dma_get_required_mask() to be overridden

>>> On 12.11.14 at 16:25, <[email protected]> wrote:
> --- a/arch/x86/include/asm/device.h
> +++ b/arch/x86/include/asm/device.h
> @@ -13,4 +13,6 @@ struct dev_archdata {
> struct pdev_archdata {
> };
>
> +#define ARCH_HAS_DMA_GET_REQUIRED_MASK

Is there a particular reason you put this here rather than in
dma-mapping.h?

Jan

2014-11-13 10:30:21

by David Vrabel

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 2/3] x86: allow dma_get_required_mask() to be overridden

On 13/11/14 10:25, Jan Beulich wrote:
>>>> On 12.11.14 at 16:25, <[email protected]> wrote:
>> --- a/arch/x86/include/asm/device.h
>> +++ b/arch/x86/include/asm/device.h
>> @@ -13,4 +13,6 @@ struct dev_archdata {
>> struct pdev_archdata {
>> };
>>
>> +#define ARCH_HAS_DMA_GET_REQUIRED_MASK
>
> Is there a particular reason you put this here rather than in
> dma-mapping.h?

I was because asm/dma-mapping is included too late for it to work, but
looking at the current code it looks like it ought to work.

David

2014-11-13 10:32:17

by Jan Beulich

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 2/3] x86: allow dma_get_required_mask() to be overridden

>>> On 13.11.14 at 11:25, <[email protected]> wrote:
>>>> On 12.11.14 at 16:25, <[email protected]> wrote:
>> --- a/arch/x86/include/asm/device.h
>> +++ b/arch/x86/include/asm/device.h
>> @@ -13,4 +13,6 @@ struct dev_archdata {
>> struct pdev_archdata {
>> };
>>
>> +#define ARCH_HAS_DMA_GET_REQUIRED_MASK
>
> Is there a particular reason you put this here rather than in
> dma-mapping.h?

Never mind - I see you need it that way so that struct dma_map_ops
gets the get_required_mask field defined, other than e.g. ia64 which
handles through another abstraction layer.

Jan

2014-11-13 10:38:39

by Andrew Cooper

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 3/3] x86/xen: use the maximum MFN to calculate the required DMA mask

On 12/11/14 15:55, Jan Beulich wrote:
>>>> On 12.11.14 at 16:25, <[email protected]> wrote:
>> +u64
>> +xen_swiotlb_get_required_mask(struct device *dev)
>> +{
>> + u64 max_mfn;
>> +
>> + max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
>> +
>> + return DMA_BIT_MASK(fls64(max_mfn << PAGE_SHIFT) + 1);
>> +}
> The value the hypercall returns is exclusive and an unsigned long.

All hypercalls return long, despite lack of clarity, or in some cases,
documentation to the contrary.

Almost all hypercalls need the ability to return errors in the form of
negative numbers, and those which don't should not be treated any
differently. Furthermore, the overflow conditions for the compat
version of XENMEM_maximum_ram_page specifically truncate to INT_MAX and
INT_MIN as boundaries, making the return value signed.

~Andrew

2014-11-13 10:53:26

by Jan Beulich

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 3/3] x86/xen: use the maximum MFN to calculate the required DMA mask

>>> On 13.11.14 at 11:38, <[email protected]> wrote:
> On 12/11/14 15:55, Jan Beulich wrote:
>>>>> On 12.11.14 at 16:25, <[email protected]> wrote:
>>> +u64
>>> +xen_swiotlb_get_required_mask(struct device *dev)
>>> +{
>>> + u64 max_mfn;
>>> +
>>> + max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
>>> +
>>> + return DMA_BIT_MASK(fls64(max_mfn << PAGE_SHIFT) + 1);
>>> +}
>> The value the hypercall returns is exclusive and an unsigned long.
>
> All hypercalls return long, despite lack of clarity, or in some cases,
> documentation to the contrary.

The emphasis wasn't on "unsigned" but on "long". But see also my
later reply to that same mail.

Jan

2014-11-14 15:12:52

by Stefano Stabellini

[permalink] [raw]
Subject: Re: [Xen-devel] [PATCH 1/3] dma, ia64: add dma_get_required_mask_from_max_pfn()

On Wed, 12 Nov 2014, David Vrabel wrote:
> ia64 provides a duplicate of the generic dma_get_required_mask()
> because it has ARCH_HAS_GET_REQUIRED_MASK. Provide a common
> dma_get_require_mask_max_pfn() instead.
>
> Signed-off-by: David Vrabel <[email protected]>
> Cc: Tony Luck <[email protected]>
> Cc: Fenghua Yu <[email protected]>
> Cc: [email protected]

Reviewed-by: Stefano Stabellini <[email protected]>


> arch/ia64/include/asm/machvec.h | 2 +-
> arch/ia64/include/asm/machvec_init.h | 1 -
> arch/ia64/pci/pci.c | 20 --------------------
> drivers/base/platform.c | 10 ++++++++--
> include/linux/dma-mapping.h | 1 +
> 5 files changed, 10 insertions(+), 24 deletions(-)
>
> diff --git a/arch/ia64/include/asm/machvec.h b/arch/ia64/include/asm/machvec.h
> index 9c39bdf..beaa47d 100644
> --- a/arch/ia64/include/asm/machvec.h
> +++ b/arch/ia64/include/asm/machvec.h
> @@ -287,7 +287,7 @@ extern struct dma_map_ops *dma_get_ops(struct device *);
> # define platform_dma_get_ops dma_get_ops
> #endif
> #ifndef platform_dma_get_required_mask
> -# define platform_dma_get_required_mask ia64_dma_get_required_mask
> +# define platform_dma_get_required_mask dma_get_required_mask_from_max_pfn
> #endif
> #ifndef platform_irq_to_vector
> # define platform_irq_to_vector __ia64_irq_to_vector
> diff --git a/arch/ia64/include/asm/machvec_init.h b/arch/ia64/include/asm/machvec_init.h
> index 37a4698..ef964b2 100644
> --- a/arch/ia64/include/asm/machvec_init.h
> +++ b/arch/ia64/include/asm/machvec_init.h
> @@ -3,7 +3,6 @@
>
> extern ia64_mv_send_ipi_t ia64_send_ipi;
> extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge;
> -extern ia64_mv_dma_get_required_mask ia64_dma_get_required_mask;
> extern ia64_mv_irq_to_vector __ia64_irq_to_vector;
> extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq;
> extern ia64_mv_pci_get_legacy_mem_t ia64_pci_get_legacy_mem;
> diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
> index 291a582..79da21b 100644
> --- a/arch/ia64/pci/pci.c
> +++ b/arch/ia64/pci/pci.c
> @@ -791,26 +791,6 @@ static void __init set_pci_dfl_cacheline_size(void)
> pci_dfl_cache_line_size = (1 << cci.pcci_line_size) / 4;
> }
>
> -u64 ia64_dma_get_required_mask(struct device *dev)
> -{
> - u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
> - u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
> - u64 mask;
> -
> - if (!high_totalram) {
> - /* convert to mask just covering totalram */
> - low_totalram = (1 << (fls(low_totalram) - 1));
> - low_totalram += low_totalram - 1;
> - mask = low_totalram;
> - } else {
> - high_totalram = (1 << (fls(high_totalram) - 1));
> - high_totalram += high_totalram - 1;
> - mask = (((u64)high_totalram) << 32) + 0xffffffff;
> - }
> - return mask;
> -}
> -EXPORT_SYMBOL_GPL(ia64_dma_get_required_mask);
> -
> u64 dma_get_required_mask(struct device *dev)
> {
> return platform_dma_get_required_mask(dev);
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index b2afc29..f9f3930 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -1009,8 +1009,7 @@ int __init platform_bus_init(void)
> return error;
> }
>
> -#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
> -u64 dma_get_required_mask(struct device *dev)
> +u64 dma_get_required_mask_from_max_pfn(struct device *dev)
> {
> u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
> u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
> @@ -1028,6 +1027,13 @@ u64 dma_get_required_mask(struct device *dev)
> }
> return mask;
> }
> +EXPORT_SYMBOL_GPL(dma_get_required_mask_from_max_pfn);
> +
> +#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
> +u64 dma_get_required_mask(struct device *dev)
> +{
> + return dma_get_required_mask_from_max_pfn(dev);
> +}
> EXPORT_SYMBOL_GPL(dma_get_required_mask);
> #endif
> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> index d5d3881..6e2fdfc 100644
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -127,6 +127,7 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)
> return dma_set_mask_and_coherent(dev, mask);
> }
>
> +extern u64 dma_get_required_mask_from_max_pfn(struct device *dev);
> extern u64 dma_get_required_mask(struct device *dev);
>
> #ifndef set_arch_dma_coherent_ops
> --
> 1.7.10.4
>
>
> _______________________________________________
> Xen-devel mailing list
> [email protected]
> http://lists.xen.org/xen-devel
>

2014-11-14 15:20:06

by Stefano Stabellini

[permalink] [raw]
Subject: Re: [PATCH 2/3] x86: allow dma_get_required_mask() to be overridden

On Wed, 12 Nov 2014, David Vrabel wrote:
> Use dma_ops->get_required_mask() if provided, defaulting to
> dma_get_requried_mask_from_max_pfn().
>
> This is needed on systems (such as Xen PV guests) where the DMA
> address and the physical address are not equal.
>
> Signed-off-by: David Vrabel <[email protected]>

Reviewed-by: Stefano Stabellini <[email protected]>


> arch/x86/include/asm/device.h | 2 ++
> arch/x86/kernel/pci-dma.c | 8 ++++++++
> 2 files changed, 10 insertions(+)
>
> diff --git a/arch/x86/include/asm/device.h b/arch/x86/include/asm/device.h
> index 03dd729..10bc628 100644
> --- a/arch/x86/include/asm/device.h
> +++ b/arch/x86/include/asm/device.h
> @@ -13,4 +13,6 @@ struct dev_archdata {
> struct pdev_archdata {
> };
>
> +#define ARCH_HAS_DMA_GET_REQUIRED_MASK
> +
> #endif /* _ASM_X86_DEVICE_H */
> diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
> index a25e202..5154400 100644
> --- a/arch/x86/kernel/pci-dma.c
> +++ b/arch/x86/kernel/pci-dma.c
> @@ -140,6 +140,14 @@ void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr,
> free_pages((unsigned long)vaddr, get_order(size));
> }
>
> +u64 dma_get_required_mask(struct device *dev)
> +{
> + if (dma_ops->get_required_mask)
> + return dma_ops->get_required_mask(dev);
> + return dma_get_required_mask_from_max_pfn(dev);
> +}
> +EXPORT_SYMBOL_GPL(dma_get_required_mask);
> +
> /*
> * See <Documentation/x86/x86_64/boot-options.txt> for the iommu kernel
> * parameter documentation.
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://secure-web.cisco.com/1ixXdBDpz1KdvMlO1aynlM5N1jrQ7I1zdB_g1CPo0rimcVM76xTOPAvm484tRhqPosYwwpXnvHtyzSn_CZ4-EcYzELZhn5abgWc7e5fB0Ki0nE024_U4cvFTVoR2qflul0tkkVvivUWBl8v3vMWMTT6wuEYW3UcP3Bt3ttSORXPc/http%3A%2F%2Fwww.tux.org%2Flkml%2F
>