FROMLIST: iommu: dma-iommu: use common implementation also on ARM architecture

This patch replaces ARM-specific IOMMU-based DMA-mapping implementation
with generic IOMMU DMA-mapping code shared with ARM64 architecture. The
side-effect of this change is a switch from bitmap-based IO address space
management to tree-based code. There should be no functional changes
for drivers, which rely on initialization from generic arch_setup_dna_ops()
interface. Code, which used old arm_iommu_* functions must be updated to
new interface.

To avoid build failed on ARCH arm,we mannually fix the following two files that
to use arch_set_dma_ops API

arch/arm/mach-highbank/highbank.c
arch/arm/mach-mvebu/coherency.c

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Conflicts:
	arch/arm/mm/dma-mapping.c

Change-Id: Iffad16a7a511d50cc8e422bc61497f117279c66d
Signed-off-by: Simon <xxm@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
(am from https://patchwork.freedesktop.org/patch/74409/)
This commit is contained in:
Marek Szyprowski 2016-02-19 09:22:44 +01:00 committed by Huang, Tao
parent 7178c0f93e
commit e11b4aa8cd
10 changed files with 84 additions and 1215 deletions

View File

@ -105,27 +105,7 @@ config ARM_DMA_USE_IOMMU
bool
select ARM_HAS_SG_CHAIN
select NEED_SG_DMA_LENGTH
if ARM_DMA_USE_IOMMU
config ARM_DMA_IOMMU_ALIGNMENT
int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers"
range 4 9
default 8
help
DMA mapping framework by default aligns all buffers to the smallest
PAGE_SIZE order which is greater than or equal to the requested buffer
size. This works well for buffers up to a few hundreds kilobytes, but
for larger buffers it just a waste of address space. Drivers which has
relatively small addressing window (like 64Mib) might run out of
virtual space with just a few allocations.
With this parameter you can specify the maximum PAGE_SIZE order for
DMA IOMMU buffers. Larger buffers will be aligned only to this
specified order. The order is expressed as a power of two multiplied
by the PAGE_SIZE.
endif
select IOMMU_DMA
config MIGHT_HAVE_PCI
bool

View File

@ -13,9 +13,6 @@ struct dev_archdata {
#endif
#ifdef CONFIG_IOMMU_API
void *iommu; /* private IOMMU data */
#endif
#ifdef CONFIG_ARM_DMA_USE_IOMMU
struct dma_iommu_mapping *mapping;
#endif
bool dma_coherent;
};
@ -28,10 +25,4 @@ struct pdev_archdata {
#endif
};
#ifdef CONFIG_ARM_DMA_USE_IOMMU
#define to_dma_iommu_mapping(dev) ((dev)->archdata.mapping)
#else
#define to_dma_iommu_mapping(dev) NULL
#endif
#endif

View File

@ -1,37 +0,0 @@
#ifndef ASMARM_DMA_IOMMU_H
#define ASMARM_DMA_IOMMU_H
#ifdef __KERNEL__
#include <linux/mm_types.h>
#include <linux/scatterlist.h>
#include <linux/dma-debug.h>
#include <linux/kmemcheck.h>
#include <linux/kref.h>
struct dma_iommu_mapping {
/* iommu specific data */
struct iommu_domain *domain;
unsigned long **bitmaps; /* array of bitmaps */
unsigned int nr_bitmaps; /* nr of elements in array */
unsigned int extensions;
size_t bitmap_size; /* size of a single bitmap */
size_t bits; /* per bitmap */
dma_addr_t base;
spinlock_t lock;
struct kref kref;
};
struct dma_iommu_mapping *
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size);
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
int arm_iommu_attach_device(struct device *dev,
struct dma_iommu_mapping *mapping);
void arm_iommu_detach_device(struct device *dev);
#endif /* __KERNEL__ */
#endif

View File

@ -8,6 +8,7 @@
#include <linux/dma-attrs.h>
#include <linux/dma-debug.h>
#include <asm/cacheflush.h>
#include <asm/memory.h>
#include <xen/xen.h>
@ -32,7 +33,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
return __generic_dma_ops(dev);
}
static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
static inline void arch_set_dma_ops(struct device *dev, struct dma_map_ops *ops)
{
BUG_ON(!dev);
dev->archdata.dma_ops = ops;
@ -282,5 +283,61 @@ extern int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
struct dma_attrs *attrs);
/*
* The DMA API is built upon the notion of "buffer ownership". A buffer
* is either exclusively owned by the CPU (and therefore may be accessed
* by it) or exclusively owned by the DMA device. These helper functions
* represent the transitions between these two ownership states.
*
* Note, however, that on later ARMs, this notion does not work due to
* speculative prefetches. We model our approach on the assumption that
* the CPU does do speculative prefetches, which means we clean caches
* before transfers and delay cache invalidation until transfer completion.
*
*/
extern void __dma_page_cpu_to_dev(struct page *, unsigned long, size_t,
enum dma_data_direction);
extern void __dma_page_dev_to_cpu(struct page *, unsigned long, size_t,
enum dma_data_direction);
static inline void arch_flush_page(struct device *dev, const void *virt,
phys_addr_t phys)
{
dmac_flush_range(virt, virt + PAGE_SIZE);
outer_flush_range(phys, phys + PAGE_SIZE);
}
static inline void arch_dma_map_area(phys_addr_t phys, size_t size,
enum dma_data_direction dir)
{
unsigned int offset = phys & ~PAGE_MASK;
__dma_page_cpu_to_dev(phys_to_page(phys & PAGE_MASK), offset, size, dir);
}
static inline void arch_dma_unmap_area(phys_addr_t phys, size_t size,
enum dma_data_direction dir)
{
unsigned int offset = phys & ~PAGE_MASK;
__dma_page_dev_to_cpu(phys_to_page(phys & PAGE_MASK), offset, size, dir);
}
static inline pgprot_t arch_get_dma_pgprot(struct dma_attrs *attrs,
pgprot_t prot, bool coherent)
{
if (coherent)
return prot;
prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
pgprot_writecombine(prot) :
pgprot_dmacoherent(prot);
return prot;
}
extern void *arch_alloc_from_atomic_pool(size_t size, struct page **ret_page,
gfp_t flags);
extern bool arch_in_atomic_pool(void *start, size_t size);
extern int arch_free_from_atomic_pool(void *start, size_t size);
#endif /* __KERNEL__ */
#endif

View File

@ -110,7 +110,7 @@ static int highbank_platform_notifier(struct notifier_block *nb,
if (of_property_read_bool(dev->of_node, "dma-coherent")) {
val = readl(sregs_base + reg);
writel(val | 0xff01, sregs_base + reg);
set_dma_ops(dev, &arm_coherent_dma_ops);
arch_set_dma_ops(dev, &arm_coherent_dma_ops);
}
return NOTIFY_OK;

View File

@ -98,7 +98,7 @@ static int mvebu_hwcc_notifier(struct notifier_block *nb,
if (event != BUS_NOTIFY_ADD_DEVICE)
return NOTIFY_DONE;
set_dma_ops(dev, &arm_coherent_dma_ops);
arch_set_dma_ops(dev, &arm_coherent_dma_ops);
return NOTIFY_OK;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
config DRM_ROCKCHIP
tristate "DRM Support for Rockchip"
depends on BROKEN
depends on DRM && ROCKCHIP_IOMMU
depends on RESET_CONTROLLER
select DRM_KMS_HELPER

View File

@ -369,6 +369,7 @@ config SHMOBILE_IOMMU_L1SIZE
config IPMMU_VMSA
bool "Renesas VMSA-compatible IPMMU"
depends on BROKEN
depends on ARM_LPAE
depends on ARCH_SHMOBILE || COMPILE_TEST
select IOMMU_API

View File

@ -88,6 +88,7 @@ config VIDEO_OMAP3
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
depends on HAS_DMA && OF
depends on OMAP_IOMMU
depends on BROKEN
select ARM_DMA_USE_IOMMU
select VIDEOBUF2_DMA_CONTIG
select MFD_SYSCON