@@ -1715,6 +1715,23 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
return arm_coherent_iommu_map_page(dev, page, offset, size, dir, attrs);
}
+static dma_addr_t arm_iommu_map_page_at(struct device *dev, struct page *page,
+ dma_addr_t dma_addr, unsigned long offset, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ int ret, len = PAGE_ALIGN(size + offset);
+
+ if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+
+ ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, 0);
+ if (ret < 0)
+ return DMA_ERROR_CODE;
+
+ return dma_addr + offset;
+}
+
/**
* arm_coherent_iommu_unmap_page
* @dev: valid struct device pointer
@@ -1813,6 +1830,7 @@ struct dma_map_ops iommu_ops = {
.get_sgtable = arm_iommu_get_sgtable,
.map_page = arm_iommu_map_page,
+ .map_page_at = arm_iommu_map_page_at,
.unmap_page = arm_iommu_unmap_page,
.sync_single_for_cpu = arm_iommu_sync_single_for_cpu,
.sync_single_for_device = arm_iommu_sync_single_for_device,
@@ -26,6 +26,23 @@ static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
return addr;
}
+static inline dma_addr_t dma_map_single_at_attrs(struct device *dev, void *ptr,
+ dma_addr_t handle,
+ size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ dma_addr_t addr;
+
+ kmemcheck_mark_initialized(ptr, size);
+ BUG_ON(!valid_dma_direction(dir));
+ addr = ops->map_page_at(dev, virt_to_page(ptr), handle,
+ (unsigned long)ptr & ~PAGE_MASK, size,
+ dir, attrs);
+ return addr;
+}
+
static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
size_t size,
enum dma_data_direction dir,
@@ -172,6 +189,8 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
}
#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
+#define dma_map_single_at(d, a, h, s, r) \
+ dma_map_single_at_attrs(d, a, h, s, r, NULL)
#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
@@ -25,6 +25,13 @@ struct dma_map_ops {
unsigned long offset, size_t size,
enum dma_data_direction dir,
struct dma_attrs *attrs);
+
+ dma_addr_t (*map_page_at)(struct device *dev, struct page *page,
+ dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs);
+
void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs);
Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com> --- arch/arm/mm/dma-mapping.c | 18 ++++++++++++++++++ include/asm-generic/dma-mapping-common.h | 19 +++++++++++++++++++ include/linux/dma-mapping.h | 7 +++++++ 3 files changed, 44 insertions(+), 0 deletions(-)