Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c5a3621 authored by Akinobu Mita's avatar Akinobu Mita Committed by Linus Torvalds
Browse files

x86: enable DMA CMA with swiotlb



The DMA Contiguous Memory Allocator support on x86 is disabled when
swiotlb config option is enabled.  So DMA CMA is always disabled on
x86_64 because swiotlb is always enabled.  This attempts to support for
DMA CMA with enabling swiotlb config option.

The contiguous memory allocator on x86 is integrated in the function
dma_generic_alloc_coherent() which is .alloc callback in nommu_dma_ops
for dma_alloc_coherent().

x86_swiotlb_alloc_coherent() which is .alloc callback in swiotlb_dma_ops
tries to allocate with dma_generic_alloc_coherent() firstly and then
swiotlb_alloc_coherent() is called as a fallback.

The main part of supporting DMA CMA with swiotlb is that changing
x86_swiotlb_free_coherent() which is .free callback in swiotlb_dma_ops
for dma_free_coherent() so that it can distinguish memory allocated by
dma_generic_alloc_coherent() from one allocated by
swiotlb_alloc_coherent() and release it with dma_generic_free_coherent()
which can handle contiguous memory.  This change requires making
is_swiotlb_buffer() global function.

This also needs to change .free callback in the dma_map_ops for amd_gart
and sta2x11, because these dma_ops are also using
dma_generic_alloc_coherent().

Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Acked-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Acked-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Don Dutile <ddutile@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d92ef66c
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -41,7 +41,7 @@ config X86
	select ARCH_WANT_OPTIONAL_GPIOLIB
	select ARCH_WANT_OPTIONAL_GPIOLIB
	select ARCH_WANT_FRAME_POINTERS
	select ARCH_WANT_FRAME_POINTERS
	select HAVE_DMA_ATTRS
	select HAVE_DMA_ATTRS
	select HAVE_DMA_CONTIGUOUS if !SWIOTLB
	select HAVE_DMA_CONTIGUOUS
	select HAVE_KRETPROBES
	select HAVE_KRETPROBES
	select GENERIC_EARLY_IOREMAP
	select GENERIC_EARLY_IOREMAP
	select HAVE_OPTPROBES
	select HAVE_OPTPROBES
+7 −0
Original line number Original line Diff line number Diff line
@@ -29,4 +29,11 @@ static inline void pci_swiotlb_late_init(void)


static inline void dma_mark_clean(void *addr, size_t size) {}
static inline void dma_mark_clean(void *addr, size_t size) {}


extern void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
					dma_addr_t *dma_handle, gfp_t flags,
					struct dma_attrs *attrs);
extern void x86_swiotlb_free_coherent(struct device *dev, size_t size,
					void *vaddr, dma_addr_t dma_addr,
					struct dma_attrs *attrs);

#endif /* _ASM_X86_SWIOTLB_H */
#endif /* _ASM_X86_SWIOTLB_H */
+1 −1
Original line number Original line Diff line number Diff line
@@ -512,7 +512,7 @@ gart_free_coherent(struct device *dev, size_t size, void *vaddr,
		   dma_addr_t dma_addr, struct dma_attrs *attrs)
		   dma_addr_t dma_addr, struct dma_attrs *attrs)
{
{
	gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL);
	gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL);
	free_pages((unsigned long)vaddr, get_order(size));
	dma_generic_free_coherent(dev, size, vaddr, dma_addr, attrs);
}
}


static int gart_mapping_error(struct device *dev, dma_addr_t dma_addr)
static int gart_mapping_error(struct device *dev, dma_addr_t dma_addr)
+6 −3
Original line number Original line Diff line number Diff line
@@ -14,7 +14,7 @@
#include <asm/iommu_table.h>
#include <asm/iommu_table.h>
int swiotlb __read_mostly;
int swiotlb __read_mostly;


static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
void *x86_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,
					struct dma_attrs *attrs)
					struct dma_attrs *attrs)
{
{
@@ -28,11 +28,14 @@ static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
	return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags);
	return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags);
}
}


static void x86_swiotlb_free_coherent(struct device *dev, size_t size,
void x86_swiotlb_free_coherent(struct device *dev, size_t size,
				      void *vaddr, dma_addr_t dma_addr,
				      void *vaddr, dma_addr_t dma_addr,
				      struct dma_attrs *attrs)
				      struct dma_attrs *attrs)
{
{
	if (is_swiotlb_buffer(dma_to_phys(dev, dma_addr)))
		swiotlb_free_coherent(dev, size, vaddr, dma_addr);
		swiotlb_free_coherent(dev, size, vaddr, dma_addr);
	else
		dma_generic_free_coherent(dev, size, vaddr, dma_addr, attrs);
}
}


static struct dma_map_ops swiotlb_dma_ops = {
static struct dma_map_ops swiotlb_dma_ops = {
+2 −4
Original line number Original line Diff line number Diff line
@@ -173,9 +173,7 @@ static void *sta2x11_swiotlb_alloc_coherent(struct device *dev,
{
{
	void *vaddr;
	void *vaddr;


	vaddr = dma_generic_alloc_coherent(dev, size, dma_handle, flags, attrs);
	vaddr = x86_swiotlb_alloc_coherent(dev, size, dma_handle, flags, attrs);
	if (!vaddr)
		vaddr = swiotlb_alloc_coherent(dev, size, dma_handle, flags);
	*dma_handle = p2a(*dma_handle, to_pci_dev(dev));
	*dma_handle = p2a(*dma_handle, to_pci_dev(dev));
	return vaddr;
	return vaddr;
}
}
@@ -183,7 +181,7 @@ static void *sta2x11_swiotlb_alloc_coherent(struct device *dev,
/* We have our own dma_ops: the same as swiotlb but from alloc (above) */
/* We have our own dma_ops: the same as swiotlb but from alloc (above) */
static struct dma_map_ops sta2x11_dma_ops = {
static struct dma_map_ops sta2x11_dma_ops = {
	.alloc = sta2x11_swiotlb_alloc_coherent,
	.alloc = sta2x11_swiotlb_alloc_coherent,
	.free = swiotlb_free_coherent,
	.free = x86_swiotlb_free_coherent,
	.map_page = swiotlb_map_page,
	.map_page = swiotlb_map_page,
	.unmap_page = swiotlb_unmap_page,
	.unmap_page = swiotlb_unmap_page,
	.map_sg = swiotlb_map_sg_attrs,
	.map_sg = swiotlb_map_sg_attrs,
Loading