2014-04-24 15:31:06

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent

Here is an updated v3 of the series. Series introduces support for setting up
dma parameters based on device tree properties like 'dma-ranges' and
'dma-coherent' and also update to ARM 32 bit port. Earlier version of the
series can be found here [3], [2] and [1].

The 'dma-ranges' helps to take care of few DMAable system memory restrictions
by use of dma_pfn_offset which we maintain now per device. Arch code then
uses it for dma address translations for such cases. We update the
dma_pfn_offset accordingly during DT the device creation process.The
'dma-coherent' property is used to setup arch's coherent dma_ops.

Hopefully with acks, tested-by this version can get into 3.16 queue. I will
post a followup series for Keystone SOC which will use this infrastructure.
Linus W also wants to use this for ARM integrator platform dma offset issue.

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Russell King <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Linus Walleij <[email protected]>
Cc: Grygorii Strashko <[email protected]>

Grygorii Strashko (2):
of: introduce of_dma_get_range() helper
ARM: dma: Use dma_pfn_offset for dma address translation

Santosh Shilimkar (5):
device: introduce per device dma_pfn_offset
of: introduce of_dma_is_coherent() helper
of: configure the platform device dma parameters
ARM: dma: implement set_arch_dma_coherent_ops()
ARM: dma: use phys_addr_t in __dma_page_[cpu_to_dev/dev_to_cpu]

arch/arm/include/asm/dma-mapping.h | 28 ++++++++++--
arch/arm/mm/dma-mapping.c | 4 +-
drivers/of/address.c | 87 ++++++++++++++++++++++++++++++++++++
drivers/of/platform.c | 71 +++++++++++++++++++++++++++--
include/linux/device.h | 2 +
include/linux/dma-mapping.h | 7 +++
include/linux/of_address.h | 8 ++++
include/linux/of_platform.h | 6 +++
8 files changed, 204 insertions(+), 9 deletions(-)

Regards,
Santosh

[1] http://www.spinics.net/lists/arm-kernel/msg311678.html
[2] https://lkml.org/lkml/2014/3/6/186
[3] https://lkml.org/lkml/2014/4/19/80
--
1.7.9.5


2014-04-24 15:31:51

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 6/7] ARM: dma: implement set_arch_dma_coherent_ops()

Implement the set_arch_dma_coherent_ops() for ARM architecture.

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Russell King <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Linus Walleij <[email protected]>
Signed-off-by: Grygorii Strashko <[email protected]>
Signed-off-by: Santosh Shilimkar <[email protected]>
---
arch/arm/include/asm/dma-mapping.h | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 424fda9..1965cd8 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -118,6 +118,13 @@ static inline unsigned long dma_max_pfn(struct device *dev)
}
#define dma_max_pfn(dev) dma_max_pfn(dev)

+static inline int set_arch_dma_coherent_ops(struct device *dev)
+{
+ set_dma_ops(dev, &arm_coherent_dma_ops);
+ return 0;
+}
+#define set_arch_dma_coherent_ops(dev) set_arch_dma_coherent_ops(dev)
+
static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
{
unsigned int offset = paddr & ~PAGE_MASK;
--
1.7.9.5

2014-04-24 15:31:48

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 7/7] ARM: dma: use phys_addr_t in __dma_page_[cpu_to_dev/dev_to_cpu]

On a 32 bit ARM architecture with LPAE extension physical addresses
cannot fit into unsigned long variable.

So fix it by using phys_addr_t instead of unsigned long.

Cc: Nicolas Pitre <[email protected]>
Cc: Russell King - ARM Linux <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Signed-off-by: Santosh Shilimkar <[email protected]>
---
arch/arm/mm/dma-mapping.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index f62aa06..5260f43 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -885,7 +885,7 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
{
- unsigned long paddr;
+ phys_addr_t paddr;

dma_cache_maint_page(page, off, size, dir, dmac_map_area);

@@ -901,7 +901,7 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
{
- unsigned long paddr = page_to_phys(page) + off;
+ phys_addr_t paddr = page_to_phys(page) + off;

/* FIXME: non-speculating: not required */
/* don't bother invalidating if DMA to device */
--
1.7.9.5

2014-04-24 15:31:44

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 3/7] of: introduce of_dma_is_coherent() helper

The of_dma_is_coherent() helper parses the given DT device
node to see if the "dma-coherent" property is supported and
returns true or false accordingly.

If the arch is always coherent or always noncoherent, then the default
DMA ops has to be specified accordingly.

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Russell King <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Linus Walleij <[email protected]>
Signed-off-by: Santosh Shilimkar <[email protected]>
Signed-off-by: Grygorii Strashko <[email protected]>
---
drivers/of/platform.c | 23 +++++++++++++++++++++++
include/linux/of_platform.h | 6 ++++++
2 files changed, 29 insertions(+)

diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 404d1da..48de98f 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -485,4 +485,27 @@ int of_platform_populate(struct device_node *root,
return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
+
+/**
+ * of_dma_is_coherent - Check if device is coherent
+ * @np: device node
+ *
+ * It returns true if "dma-coherent" property was found
+ * for this device in DT.
+ */
+bool of_dma_is_coherent(struct device_node *np)
+{
+ struct device_node *node = of_node_get(np);
+
+ while (node) {
+ if (of_property_read_bool(node, "dma-coherent")) {
+ of_node_put(node);
+ return true;
+ }
+ node = of_get_next_parent(node);
+ }
+ of_node_put(node);
+ return false;
+}
+EXPORT_SYMBOL_GPL(of_dma_is_coherent);
#endif /* CONFIG_OF_ADDRESS */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 05cb4a9..b9a3cb2 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -72,6 +72,7 @@ extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
+extern bool of_dma_is_coherent(struct device_node *np);
#else
static inline int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
@@ -80,6 +81,11 @@ static inline int of_platform_populate(struct device_node *root,
{
return -ENODEV;
}
+
+static inline bool of_dma_is_coherent(struct device_node *np)
+{
+ return false;
+}
#endif

#endif /* _LINUX_OF_PLATFORM_H */
--
1.7.9.5

2014-04-24 15:32:58

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 5/7] ARM: dma: Use dma_pfn_offset for dma address translation

From: Grygorii Strashko <[email protected]>

In most of cases DMA addresses can be performed using offset value of
Bus address space relatively to physical address space as following:

PFN->DMA:
__pfn_to_phys(pfn + [-]dma_pfn_offset)

DMA->PFN:
__phys_to_pfn(dma_addr) + [-]dma_pfn_offset

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Russell King <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Linus Walleij <[email protected]>
Signed-off-by: Grygorii Strashko <[email protected]>
Signed-off-by: Santosh Shilimkar <[email protected]>
---
arch/arm/include/asm/dma-mapping.h | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index e701a4d..424fda9 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -58,22 +58,35 @@ static inline int dma_set_mask(struct device *dev, u64 mask)
#ifndef __arch_pfn_to_dma
static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
{
- return (dma_addr_t)__pfn_to_bus(pfn);
+ if (!dev)
+ return (dma_addr_t)__pfn_to_bus(pfn);
+ else
+ return (dma_addr_t)__pfn_to_bus(pfn - dev->dma_pfn_offset);
}

static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)
{
- return __bus_to_pfn(addr);
+ if (!dev)
+ return __bus_to_pfn(addr);
+ else
+ return __bus_to_pfn(addr) + dev->dma_pfn_offset;
}

static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
{
- return (void *)__bus_to_virt((unsigned long)addr);
+ if (!dev)
+ return (void *)__bus_to_virt((unsigned long)addr);
+ else
+ return (void *)__bus_to_virt(__pfn_to_bus(dma_to_pfn(dev, addr)));
}

static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
{
- return (dma_addr_t)__virt_to_bus((unsigned long)(addr));
+ if (!dev)
+ return (dma_addr_t)__virt_to_bus((unsigned long)(addr));
+ else
+ return pfn_to_dma(dev,
+ __bus_to_pfn(__virt_to_bus((unsigned long)(addr))));
}

#else
--
1.7.9.5

2014-04-24 15:31:39

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 4/7] of: configure the platform device dma parameters

Retrieve DMA configuration from DT and setup platform device's DMA
parameters. The DMA configuration in DT has to be specified using
"dma-ranges" and "dma-coherent" properties if supported.

We setup dma_pfn_offset using "dma-ranges" and dma_coherent_ops
using "dma-coherent" device tree properties.

The set_arch_dma_coherent_ops macro has to be defined by arch if
it supports coherent dma_ops. Otherwise, set_arch_dma_coherent_ops() is
declared as nop.

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Russell King <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Linus Walleij <[email protected]>
Signed-off-by: Grygorii Strashko <[email protected]>
Signed-off-by: Santosh Shilimkar <[email protected]>
---
drivers/of/platform.c | 48 ++++++++++++++++++++++++++++++++++++++++---
include/linux/dma-mapping.h | 7 +++++++
2 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 48de98f..270c0b9 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -187,6 +187,50 @@ struct platform_device *of_device_alloc(struct device_node *np,
EXPORT_SYMBOL(of_device_alloc);

/**
+ * of_dma_configure - Setup DMA configuration
+ * @dev: Device to apply DMA configuration
+ *
+ * Try to get devices's DMA configuration from DT and update it
+ * accordingly.
+ *
+ * In case if platform code need to use own special DMA configuration,it
+ * can use Platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE event
+ * to fix up DMA configuration.
+ */
+static void of_dma_configure(struct device *dev)
+{
+ u64 dma_addr, paddr, size;
+ int ret;
+
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ if (!dev->dma_mask)
+ dev->dma_mask = &dev->coherent_dma_mask;
+
+ /*
+ * if dma-coherent property exist, call arch hook to setup
+ * dma coherent operations.
+ */
+ if (of_dma_is_coherent(dev->of_node)) {
+ set_arch_dma_coherent_ops(dev);
+ dev_dbg(dev, "device is dma coherent\n");
+ }
+
+ /*
+ * if dma-ranges property doesn't exist - just return else
+ * setup the dma offset
+ */
+ ret = of_dma_get_range(dev->of_node, &dma_addr, &paddr, &size);
+ if ((ret == -ENODEV) || (ret < 0)) {
+ dev_dbg(dev, "no dma range information to setup\n");
+ return;
+ }
+
+ /* DMA ranges found. Calculate and set dma_pfn_offset */
+ dev->dma_pfn_offset = PFN_DOWN(paddr - dma_addr);
+ dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset);
+}
+
+/**
* of_platform_device_create_pdata - Alloc, initialize and register an of_device
* @np: pointer to node to create device for
* @bus_id: name to assign device
@@ -214,9 +258,7 @@ static struct platform_device *of_platform_device_create_pdata(
#if defined(CONFIG_MICROBLAZE)
dev->archdata.dma_mask = 0xffffffffUL;
#endif
- dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- if (!dev->dev.dma_mask)
- dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+ of_dma_configure(&dev->dev);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index fd4aee2..c7d9b1b 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -123,6 +123,13 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)

extern u64 dma_get_required_mask(struct device *dev);

+#ifndef set_arch_dma_coherent_ops
+static inline int set_arch_dma_coherent_ops(struct device *dev)
+{
+ return 0;
+}
+#endif
+
static inline unsigned int dma_get_max_seg_size(struct device *dev)
{
return dev->dma_parms ? dev->dma_parms->max_segment_size : 65536;
--
1.7.9.5

2014-04-24 15:31:36

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 1/7] device: introduce per device dma_pfn_offset

On few architectures, there are few restrictions on DMAble area of system
RAM. That also means that devices needs to know about this restrictions so
that the dma_masks can be updated accordingly and dma address translation
helpers can add/subtract the dma offset.

In most of cases DMA addresses can be performed using offset value of
Bus address space relatively to physical address space as following:

PFN->DMA: __pfn_to_phys(pfn + [-]dma_pfn_offset)
DMA->PFN: __phys_to_pfn(dma_addr) + [-]dma_pfn_offset

So we introduce per device dma_pfn_offset which can be popullated
by architecture init code while creating the devices.

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Russell King <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Linus Walleij <[email protected]>
Signed-off-by: Grygorii Strashko <[email protected]>
Signed-off-by: Santosh Shilimkar <[email protected]>
---
include/linux/device.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/device.h b/include/linux/device.h
index 233bbbe..85a52d6 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -691,6 +691,7 @@ struct acpi_dev_node {
* @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
* hardware supports 64-bit addresses for consistent allocations
* such descriptors.
+ * @dma_pfn_offset: offset of DMA memory range relatively of RAM
* @dma_parms: A low level driver may set these to teach IOMMU code about
* segment limitations.
* @dma_pools: Dma pools (if dma'ble device).
@@ -756,6 +757,7 @@ struct device {
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
+ unsigned long dma_pfn_offset;

struct device_dma_parameters *dma_parms;

--
1.7.9.5

2014-04-24 15:34:57

by Santosh Shilimkar

[permalink] [raw]
Subject: [PATCH v3 2/7] of: introduce of_dma_get_range() helper

From: Grygorii Strashko <[email protected]>

The of_dma_get_range() allows to find "dma-range" property for
the specified device and parse it.
dma-ranges format:
DMA addr (dma_addr) : naddr cells
CPU addr (phys_addr_t) : pna cells
size : nsize cells

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Russell King <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Linus Walleij <[email protected]>
Signed-off-by: Grygorii Strashko <[email protected]>
Signed-off-by: Santosh Shilimkar <[email protected]>
---
drivers/of/address.c | 87 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_address.h | 8 ++++
2 files changed, 95 insertions(+)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index cb4242a..c54baee 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -721,3 +721,90 @@ void __iomem *of_iomap(struct device_node *np, int index)
return ioremap(res.start, resource_size(&res));
}
EXPORT_SYMBOL(of_iomap);
+
+/**
+ * of_dma_get_range - Get DMA range info
+ * @np: device node to get DMA range info
+ * @dma_addr: pointer to store initial DMA address of DMA range
+ * @paddr: pointer to store initial CPU address of DMA range
+ * @size: pointer to store size of DMA range
+ *
+ * Look in bottom up direction for the first "dma-ranges" property
+ * and parse it.
+ * dma-ranges format:
+ * DMA addr (dma_addr) : naddr cells
+ * CPU addr (phys_addr_t) : pna cells
+ * size : nsize cells
+ *
+ * It returns -ENODEV if "dma-ranges" property was not found
+ * for this device in DT.
+ */
+int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size)
+{
+ struct device_node *node = of_node_get(np);
+ const __be32 *ranges = NULL;
+ int len, naddr, nsize, pna;
+ int ret = 0;
+ u64 dmaaddr;
+
+ if (!node)
+ return -EINVAL;
+
+ while (1) {
+ naddr = of_n_addr_cells(node);
+ nsize = of_n_size_cells(node);
+ node = of_get_next_parent(node);
+ if (!node)
+ break;
+
+ ranges = of_get_property(node, "dma-ranges", &len);
+
+ /* Ignore empty ranges, they imply no translation required */
+ if (ranges && len > 0)
+ break;
+
+ /*
+ * At least empty ranges has to be defined for parent node if
+ * DMA is supported
+ */
+ if (!ranges)
+ break;
+ }
+
+ if (!ranges) {
+ pr_debug("%s: no dma-ranges found for node(%s)\n",
+ __func__, np->full_name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ len /= sizeof(u32);
+
+ pna = of_n_addr_cells(node);
+
+ /* dma-ranges format:
+ * DMA addr : naddr cells
+ * CPU addr : pna cells
+ * size : nsize cells
+ */
+ dmaaddr = of_read_number(ranges, naddr);
+ *paddr = of_translate_dma_address(np, ranges);
+ if (*paddr == OF_BAD_ADDR) {
+ pr_err("%s: translation of DMA address(%pad) to CPU address failed node(%s)\n",
+ __func__, dma_addr, np->full_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ *dma_addr = dmaaddr;
+
+ *size = of_read_number(ranges + naddr + pna, nsize);
+
+ pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
+ *dma_addr, *paddr, *size);
+
+out:
+ of_node_put(node);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_dma_get_range);
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 5f6ed6b..4d7b325 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -63,6 +63,8 @@ extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
extern struct of_pci_range *of_pci_range_parser_one(
struct of_pci_range_parser *parser,
struct of_pci_range *range);
+extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
+ u64 *paddr, u64 *size);
#else /* CONFIG_OF_ADDRESS */
static inline struct device_node *of_find_matching_node_by_address(
struct device_node *from,
@@ -90,6 +92,12 @@ static inline struct of_pci_range *of_pci_range_parser_one(
{
return NULL;
}
+
+static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
+ u64 *paddr, u64 *size)
+{
+ return -ENODEV;
+}
#endif /* CONFIG_OF_ADDRESS */

#ifdef CONFIG_OF
--
1.7.9.5

2014-04-24 15:45:59

by Will Deacon

[permalink] [raw]
Subject: Re: [PATCH v3 7/7] ARM: dma: use phys_addr_t in __dma_page_[cpu_to_dev/dev_to_cpu]

On Thu, Apr 24, 2014 at 04:30:07PM +0100, Santosh Shilimkar wrote:
> On a 32 bit ARM architecture with LPAE extension physical addresses
> cannot fit into unsigned long variable.
>
> So fix it by using phys_addr_t instead of unsigned long.
>
> Cc: Nicolas Pitre <[email protected]>
> Cc: Russell King - ARM Linux <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Signed-off-by: Santosh Shilimkar <[email protected]>
> ---
> arch/arm/mm/dma-mapping.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)

Acked-by: Will Deacon <[email protected]>

Will

> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index f62aa06..5260f43 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -885,7 +885,7 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
> static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
> size_t size, enum dma_data_direction dir)
> {
> - unsigned long paddr;
> + phys_addr_t paddr;
>
> dma_cache_maint_page(page, off, size, dir, dmac_map_area);
>
> @@ -901,7 +901,7 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
> static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
> size_t size, enum dma_data_direction dir)
> {
> - unsigned long paddr = page_to_phys(page) + off;
> + phys_addr_t paddr = page_to_phys(page) + off;
>
> /* FIXME: non-speculating: not required */
> /* don't bother invalidating if DMA to device */
> --
> 1.7.9.5
>
>

2014-04-29 14:41:54

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH v3 4/7] of: configure the platform device dma parameters

On Thu, 24 Apr 2014 11:30:04 -0400, Santosh Shilimkar <[email protected]> wrote:
> Retrieve DMA configuration from DT and setup platform device's DMA
> parameters. The DMA configuration in DT has to be specified using
> "dma-ranges" and "dma-coherent" properties if supported.
>
> We setup dma_pfn_offset using "dma-ranges" and dma_coherent_ops
> using "dma-coherent" device tree properties.
>
> The set_arch_dma_coherent_ops macro has to be defined by arch if
> it supports coherent dma_ops. Otherwise, set_arch_dma_coherent_ops() is
> declared as nop.
>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: Arnd Bergmann <[email protected]>
> Cc: Olof Johansson <[email protected]>
> Cc: Grant Likely <[email protected]>
> Cc: Rob Herring <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Linus Walleij <[email protected]>
> Signed-off-by: Grygorii Strashko <[email protected]>
> Signed-off-by: Santosh Shilimkar <[email protected]>
> ---
> drivers/of/platform.c | 48 ++++++++++++++++++++++++++++++++++++++++---
> include/linux/dma-mapping.h | 7 +++++++
> 2 files changed, 52 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 48de98f..270c0b9 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -187,6 +187,50 @@ struct platform_device *of_device_alloc(struct device_node *np,
> EXPORT_SYMBOL(of_device_alloc);
>
> /**
> + * of_dma_configure - Setup DMA configuration
> + * @dev: Device to apply DMA configuration
> + *
> + * Try to get devices's DMA configuration from DT and update it
> + * accordingly.
> + *
> + * In case if platform code need to use own special DMA configuration,it
> + * can use Platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE event
> + * to fix up DMA configuration.
> + */
> +static void of_dma_configure(struct device *dev)
> +{
> + u64 dma_addr, paddr, size;
> + int ret;
> +
> + dev->coherent_dma_mask = DMA_BIT_MASK(32);
> + if (!dev->dma_mask)
> + dev->dma_mask = &dev->coherent_dma_mask;
> +
> + /*
> + * if dma-coherent property exist, call arch hook to setup
> + * dma coherent operations.
> + */
> + if (of_dma_is_coherent(dev->of_node)) {
> + set_arch_dma_coherent_ops(dev);
> + dev_dbg(dev, "device is dma coherent\n");
> + }
> +
> + /*
> + * if dma-ranges property doesn't exist - just return else
> + * setup the dma offset
> + */
> + ret = of_dma_get_range(dev->of_node, &dma_addr, &paddr, &size);
> + if ((ret == -ENODEV) || (ret < 0)) {
> + dev_dbg(dev, "no dma range information to setup\n");
> + return;
> + }
> +
> + /* DMA ranges found. Calculate and set dma_pfn_offset */
> + dev->dma_pfn_offset = PFN_DOWN(paddr - dma_addr);
> + dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset);

I've got two concerns here. of_dma_get_range() retrieves only the first
tuple from the dma-ranges property, but it is perfectly valid for
dma-ranges to contain multiple tuples. How should we handle it if a
device has multiple ranges it can DMA from?

Second, while the pfn offset is being determined, I don't see anything
making use of either the base address or size. How is the device
constrained to only getting DMA buffers from within that range? Is the
driver expected to manage that directly?

g.

> +}
> +
> +/**
> * of_platform_device_create_pdata - Alloc, initialize and register an of_device
> * @np: pointer to node to create device for
> * @bus_id: name to assign device
> @@ -214,9 +258,7 @@ static struct platform_device *of_platform_device_create_pdata(
> #if defined(CONFIG_MICROBLAZE)
> dev->archdata.dma_mask = 0xffffffffUL;
> #endif
> - dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> - if (!dev->dev.dma_mask)
> - dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
> + of_dma_configure(&dev->dev);
> dev->dev.bus = &platform_bus_type;
> dev->dev.platform_data = platform_data;
>
> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> index fd4aee2..c7d9b1b 100644
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -123,6 +123,13 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)
>
> extern u64 dma_get_required_mask(struct device *dev);
>
> +#ifndef set_arch_dma_coherent_ops
> +static inline int set_arch_dma_coherent_ops(struct device *dev)
> +{
> + return 0;
> +}
> +#endif
> +
> static inline unsigned int dma_get_max_seg_size(struct device *dev)
> {
> return dev->dma_parms ? dev->dma_parms->max_segment_size : 65536;
> --
> 1.7.9.5
>

2014-04-30 14:20:00

by Santosh Shilimkar

[permalink] [raw]
Subject: Re: [PATCH v3 4/7] of: configure the platform device dma parameters

Hi Grant,

On Tuesday 29 April 2014 10:41 AM, Grant Likely wrote:
> On Thu, 24 Apr 2014 11:30:04 -0400, Santosh Shilimkar <[email protected]> wrote:
>> Retrieve DMA configuration from DT and setup platform device's DMA
>> parameters. The DMA configuration in DT has to be specified using
>> "dma-ranges" and "dma-coherent" properties if supported.
>>
>> We setup dma_pfn_offset using "dma-ranges" and dma_coherent_ops
>> using "dma-coherent" device tree properties.
>>
>> The set_arch_dma_coherent_ops macro has to be defined by arch if
>> it supports coherent dma_ops. Otherwise, set_arch_dma_coherent_ops() is
>> declared as nop.
>>
>> Cc: Greg Kroah-Hartman <[email protected]>
>> Cc: Russell King <[email protected]>
>> Cc: Arnd Bergmann <[email protected]>
>> Cc: Olof Johansson <[email protected]>
>> Cc: Grant Likely <[email protected]>
>> Cc: Rob Herring <[email protected]>
>> Cc: Catalin Marinas <[email protected]>
>> Cc: Linus Walleij <[email protected]>
>> Signed-off-by: Grygorii Strashko <[email protected]>
>> Signed-off-by: Santosh Shilimkar <[email protected]>
>> ---
>> drivers/of/platform.c | 48 ++++++++++++++++++++++++++++++++++++++++---
>> include/linux/dma-mapping.h | 7 +++++++
>> 2 files changed, 52 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
>> index 48de98f..270c0b9 100644
>> --- a/drivers/of/platform.c
>> +++ b/drivers/of/platform.c
>> @@ -187,6 +187,50 @@ struct platform_device *of_device_alloc(struct device_node *np,
>> EXPORT_SYMBOL(of_device_alloc);
>>
>> /**
>> + * of_dma_configure - Setup DMA configuration
>> + * @dev: Device to apply DMA configuration
>> + *
>> + * Try to get devices's DMA configuration from DT and update it
>> + * accordingly.
>> + *
>> + * In case if platform code need to use own special DMA configuration,it
>> + * can use Platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE event
>> + * to fix up DMA configuration.
>> + */
>> +static void of_dma_configure(struct device *dev)
>> +{
>> + u64 dma_addr, paddr, size;
>> + int ret;
>> +
>> + dev->coherent_dma_mask = DMA_BIT_MASK(32);
>> + if (!dev->dma_mask)
>> + dev->dma_mask = &dev->coherent_dma_mask;
>> +
>> + /*
>> + * if dma-coherent property exist, call arch hook to setup
>> + * dma coherent operations.
>> + */
>> + if (of_dma_is_coherent(dev->of_node)) {
>> + set_arch_dma_coherent_ops(dev);
>> + dev_dbg(dev, "device is dma coherent\n");
>> + }
>> +
>> + /*
>> + * if dma-ranges property doesn't exist - just return else
>> + * setup the dma offset
>> + */
>> + ret = of_dma_get_range(dev->of_node, &dma_addr, &paddr, &size);
>> + if ((ret == -ENODEV) || (ret < 0)) {
>> + dev_dbg(dev, "no dma range information to setup\n");
>> + return;
>> + }
>> +
>> + /* DMA ranges found. Calculate and set dma_pfn_offset */
>> + dev->dma_pfn_offset = PFN_DOWN(paddr - dma_addr);
>> + dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset);
>
> I've got two concerns here. of_dma_get_range() retrieves only the first
> tuple from the dma-ranges property, but it is perfectly valid for
> dma-ranges to contain multiple tuples. How should we handle it if a
> device has multiple ranges it can DMA from?
>

We've not found any cases in current Linux where more than one dma-ranges
would be used. Moreover, The MM (definitely for ARM) isn't supported such
cases at all (if i understand everything right).
- there are only one arm_dma_pfn_limit
- there is only one MM zone is used for ARM
- some arches like x86,mips can support 2 zones (per arch - not per device or bus)
DMA & DMA32, but they configured once and forever per arch.

Example:
static void *loongson_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
{
...

/* ignore region specifiers */
gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);

#ifdef CONFIG_ISA
if (dev == NULL)
gfp |= __GFP_DMA;
else
#endif
#ifdef CONFIG_ZONE_DMA
if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
gfp |= __GFP_DMA;
else
#endif
#ifdef CONFIG_ZONE_DMA32
if (dev->coherent_dma_mask < DMA_BIT_MASK(40))
gfp |= __GFP_DMA32;
else
#endif
...
}

Any ways, it can be added later if we have an usecase for
that.

> Second, while the pfn offset is being determined, I don't see anything
> making use of either the base address or size. How is the device
> constrained to only getting DMA buffers from within that range? Is the
> driver expected to manage that directly?
>
Drivers don't have to do anything special apart from setting
the correct mask. The pfn_offset case, we use DMA_ZONE which takes
care of masks already. Size is suppose to be used for dma_mask
setup which we discussed in previous threads.

Regards,
Santosh

2014-06-02 06:37:31

by Shawn Guo

[permalink] [raw]
Subject: Re: [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent

On Thu, Apr 24, 2014 at 11:30:00AM -0400, Santosh Shilimkar wrote:
> Here is an updated v3 of the series. Series introduces support for setting up
> dma parameters based on device tree properties like 'dma-ranges' and
> 'dma-coherent' and also update to ARM 32 bit port. Earlier version of the
> series can be found here [3], [2] and [1].

Are these two generic device tree properties documented somewhere under
Documentation/devicetree/bindings?

Shawn

2014-06-02 13:25:54

by Santosh Shilimkar

[permalink] [raw]
Subject: Re: [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent

On Monday 02 June 2014 02:37 AM, Shawn Guo wrote:
> On Thu, Apr 24, 2014 at 11:30:00AM -0400, Santosh Shilimkar wrote:
>> Here is an updated v3 of the series. Series introduces support for setting up
>> dma parameters based on device tree properties like 'dma-ranges' and
>> 'dma-coherent' and also update to ARM 32 bit port. Earlier version of the
>> series can be found here [3], [2] and [1].
>
> Are these two generic device tree properties documented somewhere under
> Documentation/devicetree/bindings?
>
These bindings have been already in use before this series. But looks like
they have not been documented. I will do a patch to add description for those
couple of parameters.

Regards,
Santosh

2014-06-02 15:06:41

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent

On Monday 02 June 2014 09:24:50 Santosh Shilimkar wrote:
> On Monday 02 June 2014 02:37 AM, Shawn Guo wrote:
> > On Thu, Apr 24, 2014 at 11:30:00AM -0400, Santosh Shilimkar wrote:
> >> Here is an updated v3 of the series. Series introduces support for setting up
> >> dma parameters based on device tree properties like 'dma-ranges' and
> >> 'dma-coherent' and also update to ARM 32 bit port. Earlier version of the
> >> series can be found here [3], [2] and [1].
> >
> > Are these two generic device tree properties documented somewhere under
> > Documentation/devicetree/bindings?
> >
> These bindings have been already in use before this series. But looks like
> they have not been documented. I will do a patch to add description for those
> couple of parameters.

dma-ranges is part of ePAPR, and was documented in some ieee-1275 addenda
before that, but I agree it would be nice to have something in kernel as
well, at the minimum something pointing to the relevant documents.

Arnd

2014-06-02 15:55:30

by Santosh Shilimkar

[permalink] [raw]
Subject: Re: [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent

Arnd,

On Monday 02 June 2014 11:06 AM, Arnd Bergmann wrote:
> On Monday 02 June 2014 09:24:50 Santosh Shilimkar wrote:
>> On Monday 02 June 2014 02:37 AM, Shawn Guo wrote:
>>> On Thu, Apr 24, 2014 at 11:30:00AM -0400, Santosh Shilimkar wrote:
>>>> Here is an updated v3 of the series. Series introduces support for setting up
>>>> dma parameters based on device tree properties like 'dma-ranges' and
>>>> 'dma-coherent' and also update to ARM 32 bit port. Earlier version of the
>>>> series can be found here [3], [2] and [1].
>>>
>>> Are these two generic device tree properties documented somewhere under
>>> Documentation/devicetree/bindings?
>>>
>> These bindings have been already in use before this series. But looks like
>> they have not been documented. I will do a patch to add description for those
>> couple of parameters.
>
> dma-ranges is part of ePAPR, and was documented in some ieee-1275 addenda
> before that, but I agree it would be nice to have something in kernel as
> well, at the minimum something pointing to the relevant documents.
>
We are thinking of updating 'Documentation/devicetree/bindings/dma/dma.txt'
to add the information for these extra two parameters.

Is that fine or any other suggestion ?

Regards,
Santosh

2014-06-02 19:00:46

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent

On Monday 02 June 2014 11:54:36 Santosh Shilimkar wrote:
>
> On Monday 02 June 2014 11:06 AM, Arnd Bergmann wrote:
> > On Monday 02 June 2014 09:24:50 Santosh Shilimkar wrote:
> >> On Monday 02 June 2014 02:37 AM, Shawn Guo wrote:
> >>> On Thu, Apr 24, 2014 at 11:30:00AM -0400, Santosh Shilimkar wrote:
> >>>> Here is an updated v3 of the series. Series introduces support for setting up
> >>>> dma parameters based on device tree properties like 'dma-ranges' and
> >>>> 'dma-coherent' and also update to ARM 32 bit port. Earlier version of the
> >>>> series can be found here [3], [2] and [1].
> >>>
> >>> Are these two generic device tree properties documented somewhere under
> >>> Documentation/devicetree/bindings?
> >>>
> >> These bindings have been already in use before this series. But looks like
> >> they have not been documented. I will do a patch to add description for those
> >> couple of parameters.
> >
> > dma-ranges is part of ePAPR, and was documented in some ieee-1275 addenda
> > before that, but I agree it would be nice to have something in kernel as
> > well, at the minimum something pointing to the relevant documents.
> >
> We are thinking of updating 'Documentation/devicetree/bindings/dma/dma.txt'
> to add the information for these extra two parameters.
>
> Is that fine or any other suggestion ?

I think that's the wrong place. That entire directory currently deals with
the specific case of DMA engines, as opposed to the more DMA bus mastering
in general. We could rename that to
Documentation/devicetree/bindings/dmaengine, but renames tend to cause
extra patch conficts, so I'd prefer finding another location for this.

How about a section in the top-level
Documentation/devicetree/booting-without-of.txt file? After all, this
is very generic and can impact any device that acts as a bus master.

Arnd

2014-06-02 19:09:15

by Santosh Shilimkar

[permalink] [raw]
Subject: Re: [PATCH v3 0/7] of: setup dma parameters using dma-ranges and dma-coherent

On Monday 02 June 2014 03:00 PM, Arnd Bergmann wrote:
> On Monday 02 June 2014 11:54:36 Santosh Shilimkar wrote:
>>
>> On Monday 02 June 2014 11:06 AM, Arnd Bergmann wrote:
>>> On Monday 02 June 2014 09:24:50 Santosh Shilimkar wrote:
>>>> On Monday 02 June 2014 02:37 AM, Shawn Guo wrote:
>>>>> On Thu, Apr 24, 2014 at 11:30:00AM -0400, Santosh Shilimkar wrote:
>>>>>> Here is an updated v3 of the series. Series introduces support for setting up
>>>>>> dma parameters based on device tree properties like 'dma-ranges' and
>>>>>> 'dma-coherent' and also update to ARM 32 bit port. Earlier version of the
>>>>>> series can be found here [3], [2] and [1].
>>>>>
>>>>> Are these two generic device tree properties documented somewhere under
>>>>> Documentation/devicetree/bindings?
>>>>>
>>>> These bindings have been already in use before this series. But looks like
>>>> they have not been documented. I will do a patch to add description for those
>>>> couple of parameters.
>>>
>>> dma-ranges is part of ePAPR, and was documented in some ieee-1275 addenda
>>> before that, but I agree it would be nice to have something in kernel as
>>> well, at the minimum something pointing to the relevant documents.
>>>
>> We are thinking of updating 'Documentation/devicetree/bindings/dma/dma.txt'
>> to add the information for these extra two parameters.
>>
>> Is that fine or any other suggestion ?
>
> I think that's the wrong place. That entire directory currently deals with
> the specific case of DMA engines, as opposed to the more DMA bus mastering
> in general. We could rename that to
> Documentation/devicetree/bindings/dmaengine, but renames tend to cause
> extra patch conficts, so I'd prefer finding another location for this.
>
ok.

> How about a section in the top-level
> Documentation/devicetree/booting-without-of.txt file? After all, this
> is very generic and can impact any device that acts as a bus master.
>
Sounds good. I can add it a section there with heading something like below.

VIII - Specifying dma bus information

Regards,
Santosh