aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig4
-rw-r--r--arch/powerpc/include/asm/dma-mapping.h93
-rw-r--r--arch/powerpc/kernel/dma.c26
3 files changed, 92 insertions, 31 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 525c13a4de9..be4f99b7cbb 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -285,6 +285,10 @@ config IOMMU_VMERGE
config IOMMU_HELPER
def_bool PPC64
+config PPC_NEED_DMA_SYNC_OPS
+ def_bool y
+ depends on NOT_COHERENT_CACHE
+
config HOTPLUG_CPU
bool "Support for enabling/disabling CPUs"
depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index 3c4a2c21d60..9063184fa6f 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -76,6 +76,22 @@ struct dma_mapping_ops {
dma_addr_t dma_address, size_t size,
enum dma_data_direction direction,
struct dma_attrs *attrs);
+#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
+ void (*sync_single_range_for_cpu)(struct device *hwdev,
+ dma_addr_t dma_handle, unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction);
+ void (*sync_single_range_for_device)(struct device *hwdev,
+ dma_addr_t dma_handle, unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction);
+ void (*sync_sg_for_cpu)(struct device *hwdev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction);
+ void (*sync_sg_for_device)(struct device *hwdev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction);
+#endif
};
/*
@@ -282,47 +298,78 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL);
}
+#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
static inline void dma_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction direction)
{
- BUG_ON(direction == DMA_NONE);
- __dma_sync(bus_to_virt(dma_handle), size, direction);
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0,
+ size, direction);
}
static inline void dma_sync_single_for_device(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction direction)
{
- BUG_ON(direction == DMA_NONE);
- __dma_sync(bus_to_virt(dma_handle), size, direction);
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->sync_single_range_for_device(dev, dma_handle,
+ 0, size, direction);
}
static inline void dma_sync_sg_for_cpu(struct device *dev,
struct scatterlist *sgl, int nents,
enum dma_data_direction direction)
{
- struct scatterlist *sg;
- int i;
-
- BUG_ON(direction == DMA_NONE);
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- for_each_sg(sgl, sg, nents, i)
- __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+ BUG_ON(!dma_ops);
+ dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction);
}
static inline void dma_sync_sg_for_device(struct device *dev,
struct scatterlist *sgl, int nents,
enum dma_data_direction direction)
{
- struct scatterlist *sg;
- int i;
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- BUG_ON(direction == DMA_NONE);
+ BUG_ON(!dma_ops);
+ dma_ops->sync_sg_for_device(dev, sgl, nents, direction);
+}
+
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- for_each_sg(sgl, sg, nents, i)
- __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+ BUG_ON(!dma_ops);
+ dma_ops->sync_single_range_for_cpu(dev, dma_handle,
+ offset, size, direction);
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->sync_single_range_for_device(dev, dma_handle, offset,
+ size, direction);
}
+#else /* CONFIG_PPC_NEED_DMA_SYNC_OPS */
+#define dma_sync_single_for_cpu(d, h, s, dir) ((void)0)
+#define dma_sync_single_for_device(d, h, s, dir) ((void)0)
+#define dma_sync_single_range_for_cpu(d, h, o, s, dir) ((void)0)
+#define dma_sync_single_range_for_device(d, h, o, s, dir) ((void)0)
+#define dma_sync_sg_for_cpu(d, s, n, dir) ((void)0)
+#define dma_sync_sg_for_device(d, s, n, dir) ((void)0)
+#endif
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
@@ -356,22 +403,6 @@ static inline int dma_get_cache_alignment(void)
#endif
}
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
- dma_addr_t dma_handle, unsigned long offset, size_t size,
- enum dma_data_direction direction)
-{
- /* just sync everything for now */
- dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction);
-}
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
- dma_addr_t dma_handle, unsigned long offset, size_t size,
- enum dma_data_direction direction)
-{
- /* just sync everything for now */
- dma_sync_single_for_device(dev, dma_handle, offset + size, direction);
-}
-
static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 3a6eaa876ee..1c5c8a6fc12 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -120,6 +120,26 @@ static inline void dma_direct_unmap_page(struct device *dev,
{
}
+#ifdef CONFIG_NOT_COHERENT_CACHE
+static inline void dma_direct_sync_sg(struct device *dev,
+ struct scatterlist *sgl, int nents,
+ enum dma_data_direction direction)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgl, sg, nents, i)
+ __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+}
+
+static inline void dma_direct_sync_single_range(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ __dma_sync(bus_to_virt(dma_handle+offset), size, direction);
+}
+#endif
+
struct dma_mapping_ops dma_direct_ops = {
.alloc_coherent = dma_direct_alloc_coherent,
.free_coherent = dma_direct_free_coherent,
@@ -128,5 +148,11 @@ struct dma_mapping_ops dma_direct_ops = {
.dma_supported = dma_direct_dma_supported,
.map_page = dma_direct_map_page,
.unmap_page = dma_direct_unmap_page,
+#ifdef CONFIG_NOT_COHERENT_CACHE
+ .sync_single_range_for_cpu = dma_direct_sync_single_range,
+ .sync_single_range_for_device = dma_direct_sync_single_range,
+ .sync_sg_for_cpu = dma_direct_sync_sg,
+ .sync_sg_for_device = dma_direct_sync_sg,
+#endif
};
EXPORT_SYMBOL(dma_direct_ops);