* [PATCH v7 1/4] drivers: dma-contiguous: clean source code and prepare for device tree
2013-08-26 14:39 [PATCH v7 0/4] Device Tree support for CMA (Contiguous Memory Allocator) Marek Szyprowski
@ 2013-08-26 14:39 ` Marek Szyprowski
2013-08-26 14:39 ` [PATCH v7 2/4] drivers: of: add function to scan fdt nodes given by path Marek Szyprowski
` (2 subsequent siblings)
3 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2013-08-26 14:39 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
Grant Likely, Marc, Kyungmin Park, Sylwester Nawrocki, Kumar Gala,
Olof Johansson, Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
This patch cleans the initialization of dma contiguous framework. The
all-in-one dma_declare_contiguous() function is now separated into
dma_contiguous_reserve_area() which only steals the the memory from
memblock allocator and dma_contiguous_add_device() function, which
assigns given device to the specified reserved memory area. This improves
the flexibility in defining contiguous memory areas and assigning device
to them, because now it is possible to assign more than one device to
the given contiguous memory area. Such split in initialization procedure
is also required for upcoming device tree support.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Tomasz Figa <t.figa@samsung.com>
---
arch/arm/include/asm/dma-contiguous.h | 1 -
arch/x86/include/asm/dma-contiguous.h | 1 -
drivers/base/dma-contiguous.c | 119 ++++++++++++---------------------
include/asm-generic/dma-contiguous.h | 28 --------
include/linux/device.h | 2 +-
include/linux/dma-contiguous.h | 62 ++++++++++++++++-
6 files changed, 105 insertions(+), 108 deletions(-)
delete mode 100644 include/asm-generic/dma-contiguous.h
diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h
index e072bb2..4f8e9e5 100644
--- a/arch/arm/include/asm/dma-contiguous.h
+++ b/arch/arm/include/asm/dma-contiguous.h
@@ -5,7 +5,6 @@
#ifdef CONFIG_DMA_CMA
#include <linux/types.h>
-#include <asm-generic/dma-contiguous.h>
void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
diff --git a/arch/x86/include/asm/dma-contiguous.h b/arch/x86/include/asm/dma-contiguous.h
index c092416..b4b38ba 100644
--- a/arch/x86/include/asm/dma-contiguous.h
+++ b/arch/x86/include/asm/dma-contiguous.h
@@ -4,7 +4,6 @@
#ifdef __KERNEL__
#include <linux/types.h>
-#include <asm-generic/dma-contiguous.h>
static inline void
dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { }
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 0ca5442..4b94c91 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -96,7 +96,7 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
#endif
/**
- * dma_contiguous_reserve() - reserve area for contiguous memory handling
+ * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling
* @limit: End address of the reserved memory (optional, 0 for any).
*
* This function reserves memory from early allocator. It should be
@@ -124,22 +124,29 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
#endif
}
- if (selected_size) {
+ if (selected_size && !dma_contiguous_default_area) {
pr_debug("%s: reserving %ld MiB for global area\n", __func__,
(unsigned long)selected_size / SZ_1M);
- dma_declare_contiguous(NULL, selected_size, 0, limit);
+ dma_contiguous_reserve_area(selected_size, 0, limit,
+ &dma_contiguous_default_area);
}
};
static DEFINE_MUTEX(cma_mutex);
-static __init int cma_activate_area(unsigned long base_pfn, unsigned long count)
+static __init int cma_activate_area(struct cma *cma)
{
- unsigned long pfn = base_pfn;
- unsigned i = count >> pageblock_order;
+ int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long);
+ unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
+ unsigned i = cma->count >> pageblock_order;
struct zone *zone;
+ cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+
+ if (!cma->bitmap)
+ return -ENOMEM;
+
WARN_ON_ONCE(!pfn_valid(pfn));
zone = page_zone(pfn_to_page(pfn));
@@ -153,92 +160,53 @@ static __init int cma_activate_area(unsigned long base_pfn, unsigned long count)
}
init_cma_reserved_pageblock(pfn_to_page(base_pfn));
} while (--i);
- return 0;
-}
-
-static __init struct cma *cma_create_area(unsigned long base_pfn,
- unsigned long count)
-{
- int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
- struct cma *cma;
- int ret = -ENOMEM;
-
- pr_debug("%s(base %08lx, count %lx)\n", __func__, base_pfn, count);
-
- cma = kmalloc(sizeof *cma, GFP_KERNEL);
- if (!cma)
- return ERR_PTR(-ENOMEM);
-
- cma->base_pfn = base_pfn;
- cma->count = count;
- cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
- if (!cma->bitmap)
- goto no_mem;
-
- ret = cma_activate_area(base_pfn, count);
- if (ret)
- goto error;
-
- pr_debug("%s: returned %p\n", __func__, (void *)cma);
- return cma;
-
-error:
- kfree(cma->bitmap);
-no_mem:
- kfree(cma);
- return ERR_PTR(ret);
+ return 0;
}
-static struct cma_reserved {
- phys_addr_t start;
- unsigned long size;
- struct device *dev;
-} cma_reserved[MAX_CMA_AREAS] __initdata;
-static unsigned cma_reserved_count __initdata;
+static struct cma cma_areas[MAX_CMA_AREAS];
+static unsigned cma_area_count;
static int __init cma_init_reserved_areas(void)
{
- struct cma_reserved *r = cma_reserved;
- unsigned i = cma_reserved_count;
-
- pr_debug("%s()\n", __func__);
+ int i;
- for (; i; --i, ++r) {
- struct cma *cma;
- cma = cma_create_area(PFN_DOWN(r->start),
- r->size >> PAGE_SHIFT);
- if (!IS_ERR(cma))
- dev_set_cma_area(r->dev, cma);
+ for (i = 0; i < cma_area_count; i++) {
+ int ret = cma_activate_area(&cma_areas[i]);
+ if (ret)
+ return ret;
}
+
return 0;
}
core_initcall(cma_init_reserved_areas);
/**
- * dma_declare_contiguous() - reserve area for contiguous memory handling
- * for particular device
- * @dev: Pointer to device structure.
- * @size: Size of the reserved memory.
- * @base: Start address of the reserved memory (optional, 0 for any).
+ * dma_contiguous_reserve_area() - reserve custom contiguous area
+ * @size: Size of the reserved area (in bytes),
+ * @base: Base address of the reserved area optional, use 0 for any
* @limit: End address of the reserved memory (optional, 0 for any).
+ * @res_cma: Pointer to store the created cma region.
*
- * This function reserves memory for specified device. It should be
- * called by board specific code when early allocator (memblock or bootmem)
- * is still activate.
+ * This function reserves memory from early allocator. It should be
+ * called by arch specific code once the early allocator (memblock or bootmem)
+ * has been activated and all other subsystems have already allocated/reserved
+ * memory. This function allows to create custom reserved areas for specific
+ * devices.
*/
-int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
- phys_addr_t base, phys_addr_t limit)
+int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+ phys_addr_t limit, struct cma **res_cma)
{
- struct cma_reserved *r = &cma_reserved[cma_reserved_count];
+ struct cma *cma = &cma_areas[cma_area_count];
phys_addr_t alignment;
+ int ret = 0;
pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
(unsigned long)size, (unsigned long)base,
(unsigned long)limit);
/* Sanity checks */
- if (cma_reserved_count == ARRAY_SIZE(cma_reserved)) {
+ if (cma_area_count == ARRAY_SIZE(cma_areas)) {
pr_err("Not enough slots for CMA reserved regions!\n");
return -ENOSPC;
}
@@ -256,7 +224,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
if (base) {
if (memblock_is_region_reserved(base, size) ||
memblock_reserve(base, size) < 0) {
- base = -EBUSY;
+ ret = -EBUSY;
goto err;
}
} else {
@@ -266,7 +234,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
*/
phys_addr_t addr = __memblock_alloc_base(size, alignment, limit);
if (!addr) {
- base = -ENOMEM;
+ ret = -ENOMEM;
goto err;
} else {
base = addr;
@@ -277,10 +245,11 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
* Each reserved area must be initialised later, when more kernel
* subsystems (like slab allocator) are available.
*/
- r->start = base;
- r->size = size;
- r->dev = dev;
- cma_reserved_count++;
+ cma->base_pfn = PFN_DOWN(base);
+ cma->count = size >> PAGE_SHIFT;
+ *res_cma = cma;
+ cma_area_count++;
+
pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
(unsigned long)base);
@@ -289,7 +258,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
return 0;
err:
pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
- return base;
+ return ret;
}
/**
diff --git a/include/asm-generic/dma-contiguous.h b/include/asm-generic/dma-contiguous.h
deleted file mode 100644
index 294b1e7..0000000
--- a/include/asm-generic/dma-contiguous.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef ASM_DMA_CONTIGUOUS_H
-#define ASM_DMA_CONTIGUOUS_H
-
-#ifdef __KERNEL__
-#ifdef CONFIG_CMA
-
-#include <linux/device.h>
-#include <linux/dma-contiguous.h>
-
-static inline struct cma *dev_get_cma_area(struct device *dev)
-{
- if (dev && dev->cma_area)
- return dev->cma_area;
- return dma_contiguous_default_area;
-}
-
-static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
-{
- if (dev)
- dev->cma_area = cma;
- if (!dev && !dma_contiguous_default_area)
- dma_contiguous_default_area = cma;
-}
-
-#endif
-#endif
-
-#endif
diff --git a/include/linux/device.h b/include/linux/device.h
index 22b546a..8b2e2c0 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -727,7 +727,7 @@ struct device {
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
-#ifdef CONFIG_CMA
+#ifdef CONFIG_DMA_CMA
struct cma *cma_area; /* contiguous memory area for dma
allocations */
#endif
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 00141d3..3b28f93 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -67,9 +67,53 @@ struct device;
extern struct cma *dma_contiguous_default_area;
+static inline struct cma *dev_get_cma_area(struct device *dev)
+{
+ if (dev && dev->cma_area)
+ return dev->cma_area;
+ return dma_contiguous_default_area;
+}
+
+static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
+{
+ if (dev)
+ dev->cma_area = cma;
+}
+
+static inline void dma_contiguous_set_default(struct cma *cma)
+{
+ dma_contiguous_default_area = cma;
+}
+
void dma_contiguous_reserve(phys_addr_t addr_limit);
-int dma_declare_contiguous(struct device *dev, phys_addr_t size,
- phys_addr_t base, phys_addr_t limit);
+
+int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+ phys_addr_t limit, struct cma **res_cma);
+
+/**
+ * dma_declare_contiguous() - reserve area for contiguous memory handling
+ * for particular device
+ * @dev: Pointer to device structure.
+ * @size: Size of the reserved memory.
+ * @base: Start address of the reserved memory (optional, 0 for any).
+ * @limit: End address of the reserved memory (optional, 0 for any).
+ *
+ * This function reserves memory for specified device. It should be
+ * called by board specific code when early allocator (memblock or bootmem)
+ * is still activate.
+ */
+
+static inline int dma_declare_contiguous(struct device *dev, phys_addr_t size,
+ phys_addr_t base, phys_addr_t limit)
+{
+ struct cma *cma;
+ int ret;
+ ret = dma_contiguous_reserve_area(size, base, limit, &cma);
+ if (ret == 0)
+ dev_set_cma_area(dev, cma);
+
+ return ret;
+}
struct page *dma_alloc_from_contiguous(struct device *dev, int count,
unsigned int order);
@@ -80,8 +124,22 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
#define MAX_CMA_AREAS (0)
+static inline struct cma *dev_get_cma_area(struct device *dev)
+{
+ return NULL;
+}
+
+static inline void dev_set_cma_area(struct device *dev, struct cma *cma) { }
+
+static inline void dma_contiguous_set_default(struct cma *cma) { }
+
static inline void dma_contiguous_reserve(phys_addr_t limit) { }
+static inline int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+ phys_addr_t limit, struct cma **res_cma) {
+ return -ENOSYS;
+}
+
static inline
int dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v7 2/4] drivers: of: add function to scan fdt nodes given by path
2013-08-26 14:39 [PATCH v7 0/4] Device Tree support for CMA (Contiguous Memory Allocator) Marek Szyprowski
2013-08-26 14:39 ` [PATCH v7 1/4] drivers: dma-contiguous: clean source code and prepare for device tree Marek Szyprowski
@ 2013-08-26 14:39 ` Marek Szyprowski
2013-08-29 21:40 ` Grant Likely
2013-08-26 14:39 ` [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory Marek Szyprowski
2013-08-26 14:39 ` [PATCH v7 4/4] ARM: init: add support for reserved memory defined by device tree Marek Szyprowski
3 siblings, 1 reply; 27+ messages in thread
From: Marek Szyprowski @ 2013-08-26 14:39 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
Grant Likely, Marc, Kyungmin Park, Sylwester Nawrocki, Kumar Gala,
Olof Johansson, Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
Add a function to scan the flattened device-tree starting from the
node given by the path. It is used to extract information (like reserved
memory), which is required on early boot before we can unflatten the tree.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Tomasz Figa <t.figa@samsung.com>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
---
drivers/of/fdt.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_fdt.h | 3 ++
2 files changed, 79 insertions(+)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index b10ba00..4fb06f3 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -545,6 +545,82 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
return of_fdt_match(initial_boot_params, node, compat);
}
+struct fdt_scan_status {
+ const char *name;
+ int namelen;
+ int depth;
+ int found;
+ int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
+ void *data;
+};
+
+/**
+ * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
+ */
+static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ struct fdt_scan_status *st = data;
+
+ /*
+ * if scan at the requested fdt node has been completed,
+ * return -ENXIO to abort further scanning
+ */
+ if (depth <= st->depth)
+ return -ENXIO;
+
+ /* requested fdt node has been found, so call iterator function */
+ if (st->found)
+ return st->iterator(node, uname, depth, st->data);
+
+ /* check if scanning automata is entering next level of fdt nodes */
+ if (depth == st->depth + 1 &&
+ strncmp(st->name, uname, st->namelen) == 0 &&
+ uname[st->namelen] == 0) {
+ st->depth += 1;
+ if (st->name[st->namelen] == 0) {
+ st->found = 1;
+ } else {
+ const char *next = st->name + st->namelen + 1;
+ st->name = next;
+ st->namelen = strcspn(next, "/");
+ }
+ return 0;
+ }
+
+ /* scan next fdt node */
+ return 0;
+}
+
+/**
+ * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
+ * child of the given path.
+ * @path: path to start searching for children
+ * @it: callback function
+ * @data: context data pointer
+ *
+ * This function is used to scan the flattened device-tree starting from the
+ * node given by path. It is used to extract information (like reserved
+ * memory), which is required on ealy boot before we can unflatten the tree.
+ */
+int __init of_scan_flat_dt_by_path(const char *path,
+ int (*it)(unsigned long node, const char *name, int depth, void *data),
+ void *data)
+{
+ struct fdt_scan_status st = {path, 0, -1, 0, it, data};
+ int ret = 0;
+
+ if (initial_boot_params)
+ ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
+
+ if (!st.found)
+ return -ENOENT;
+ else if (ret == -ENXIO) /* scan has been completed */
+ return 0;
+ else
+ return ret;
+}
+
#ifdef CONFIG_BLK_DEV_INITRD
/**
* early_init_dt_check_for_initrd - Decode initrd location from flat tree
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index ed136ad..19f26f8 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -90,6 +90,9 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
extern int of_flat_dt_match(unsigned long node, const char *const *matches);
extern unsigned long of_get_flat_dt_root(void);
+extern int of_scan_flat_dt_by_path(const char *path,
+ int (*it)(unsigned long node, const char *name, int depth, void *data),
+ void *data);
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v7 2/4] drivers: of: add function to scan fdt nodes given by path
2013-08-26 14:39 ` [PATCH v7 2/4] drivers: of: add function to scan fdt nodes given by path Marek Szyprowski
@ 2013-08-29 21:40 ` Grant Likely
2013-08-30 10:42 ` Marek Szyprowski
0 siblings, 1 reply; 27+ messages in thread
From: Grant Likely @ 2013-08-29 21:40 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz, Marc,
Kyungmin Park, Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
On Mon, 26 Aug 2013 16:39:17 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Add a function to scan the flattened device-tree starting from the
> node given by the path. It is used to extract information (like reserved
> memory), which is required on early boot before we can unflatten the tree.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Acked-by: Michal Nazarewicz <mina86@mina86.com>
> Acked-by: Tomasz Figa <t.figa@samsung.com>
> Reviewed-by: Rob Herring <rob.herring@calxeda.com>
Some nits below, but otherwise:
Acked-by: Grant Likely <grant.likely@secretlab.ca>
I'm happy to take this through the DT tree, or have you take it via the
CMA tree.
> ---
> drivers/of/fdt.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/of_fdt.h | 3 ++
> 2 files changed, 79 insertions(+)
>
> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> index b10ba00..4fb06f3 100644
> --- a/drivers/of/fdt.c
> +++ b/drivers/of/fdt.c
> @@ -545,6 +545,82 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
> return of_fdt_match(initial_boot_params, node, compat);
> }
>
> +struct fdt_scan_status {
> + const char *name;
> + int namelen;
> + int depth;
> + int found;
> + int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
> + void *data;
> +};
> +
> +/**
> + * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
> + */
> +static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
> + int depth, void *data)
Nit: since this is an iterator, I'd like to see "iter" in the function
name.
> +{
> + struct fdt_scan_status *st = data;
> +
> + /*
> + * if scan at the requested fdt node has been completed,
> + * return -ENXIO to abort further scanning
> + */
> + if (depth <= st->depth)
> + return -ENXIO;
> +
> + /* requested fdt node has been found, so call iterator function */
> + if (st->found)
> + return st->iterator(node, uname, depth, st->data);
> +
> + /* check if scanning automata is entering next level of fdt nodes */
> + if (depth == st->depth + 1 &&
> + strncmp(st->name, uname, st->namelen) == 0 &&
> + uname[st->namelen] == 0) {
> + st->depth += 1;
> + if (st->name[st->namelen] == 0) {
> + st->found = 1;
> + } else {
> + const char *next = st->name + st->namelen + 1;
> + st->name = next;
> + st->namelen = strcspn(next, "/");
> + }
> + return 0;
The above return statement is redundant.
> + }
> +
> + /* scan next fdt node */
> + return 0;
> +}
> +
> +/**
> + * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
> + * child of the given path.
> + * @path: path to start searching for children
> + * @it: callback function
> + * @data: context data pointer
> + *
> + * This function is used to scan the flattened device-tree starting from the
> + * node given by path. It is used to extract information (like reserved
> + * memory), which is required on ealy boot before we can unflatten the tree.
> + */
> +int __init of_scan_flat_dt_by_path(const char *path,
> + int (*it)(unsigned long node, const char *name, int depth, void *data),
> + void *data)
Nit: Please match the indentation convention used by of_scan_flat_dt().
This current version is really hard to read.
> +{
> + struct fdt_scan_status st = {path, 0, -1, 0, it, data};
This is a little fragile. If the structure gets modified, this line
will break. I know it results in more text, but please use explicit data
member assignments in initializers.
> + int ret = 0;
> +
> + if (initial_boot_params)
Nit:
if (!initial_boot_params)
return 0;
> + ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
Nit: inconsitent indentation (tabs vs. spaces)
> +
> + if (!st.found)
> + return -ENOENT;
> + else if (ret == -ENXIO) /* scan has been completed */
> + return 0;
> + else
> + return ret;
Both uses of 'else' above are redundant. The only way the execution will
pass that point is if it was the else case!
> +}
> +
> #ifdef CONFIG_BLK_DEV_INITRD
> /**
> * early_init_dt_check_for_initrd - Decode initrd location from flat tree
> diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
> index ed136ad..19f26f8 100644
> --- a/include/linux/of_fdt.h
> +++ b/include/linux/of_fdt.h
> @@ -90,6 +90,9 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
> extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
> extern int of_flat_dt_match(unsigned long node, const char *const *matches);
> extern unsigned long of_get_flat_dt_root(void);
> +extern int of_scan_flat_dt_by_path(const char *path,
> + int (*it)(unsigned long node, const char *name, int depth, void *data),
> + void *data);
>
> extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
> int depth, void *data);
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 2/4] drivers: of: add function to scan fdt nodes given by path
2013-08-29 21:40 ` Grant Likely
@ 2013-08-30 10:42 ` Marek Szyprowski
2013-08-30 10:46 ` Grant Likely
0 siblings, 1 reply; 27+ messages in thread
From: Marek Szyprowski @ 2013-08-30 10:42 UTC (permalink / raw)
To: Grant Likely
Cc: Mark Rutland, devicetree, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
linaro-mm-sig, Marc, Kyungmin Park, Sylwester Nawrocki,
Kumar Gala, Olof Johansson, Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel, Ian Campbell
Hello,
On 8/29/2013 11:40 PM, Grant Likely wrote:
> On Mon, 26 Aug 2013 16:39:17 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> > Add a function to scan the flattened device-tree starting from the
> > node given by the path. It is used to extract information (like reserved
> > memory), which is required on early boot before we can unflatten the tree.
> >
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > Acked-by: Michal Nazarewicz <mina86@mina86.com>
> > Acked-by: Tomasz Figa <t.figa@samsung.com>
> > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
>
> Some nits below, but otherwise:
>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
Thanks!
> I'm happy to take this through the DT tree, or have you take it via the
> CMA tree.
I have already put the whole patchset in linux-next via my
dma-mapping/cma tree,
so I would like to keep it there to avoid further confusion.
I only wonder how to handle the patches to get them merged to v3.12-rc1.
After your review there will be some changes to the binding, its
documentation
and the code itself. Would you mind if I send pull request with the current
version and then provide incremental patches to fix the issues you have
reported? Or should we delay this patchset till v3.13-rc1?
> > ---
> > drivers/of/fdt.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
> > include/linux/of_fdt.h | 3 ++
> > 2 files changed, 79 insertions(+)
> >
> > diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> > index b10ba00..4fb06f3 100644
> > --- a/drivers/of/fdt.c
> > +++ b/drivers/of/fdt.c
> > @@ -545,6 +545,82 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
> > return of_fdt_match(initial_boot_params, node, compat);
> > }
> >
> > +struct fdt_scan_status {
> > + const char *name;
> > + int namelen;
> > + int depth;
> > + int found;
> > + int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
> > + void *data;
> > +};
> > +
> > +/**
> > + * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
> > + */
> > +static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
> > + int depth, void *data)
>
> Nit: since this is an iterator, I'd like to see "iter" in the function
> name.
>
> > +{
> > + struct fdt_scan_status *st = data;
> > +
> > + /*
> > + * if scan at the requested fdt node has been completed,
> > + * return -ENXIO to abort further scanning
> > + */
> > + if (depth <= st->depth)
> > + return -ENXIO;
> > +
> > + /* requested fdt node has been found, so call iterator function */
> > + if (st->found)
> > + return st->iterator(node, uname, depth, st->data);
> > +
> > + /* check if scanning automata is entering next level of fdt nodes */
> > + if (depth == st->depth + 1 &&
> > + strncmp(st->name, uname, st->namelen) == 0 &&
> > + uname[st->namelen] == 0) {
> > + st->depth += 1;
> > + if (st->name[st->namelen] == 0) {
> > + st->found = 1;
> > + } else {
> > + const char *next = st->name + st->namelen + 1;
> > + st->name = next;
> > + st->namelen = strcspn(next, "/");
> > + }
> > + return 0;
>
> The above return statement is redundant.
>
> > + }
> > +
> > + /* scan next fdt node */
> > + return 0;
> > +}
> > +
> > +/**
> > + * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
> > + * child of the given path.
> > + * @path: path to start searching for children
> > + * @it: callback function
> > + * @data: context data pointer
> > + *
> > + * This function is used to scan the flattened device-tree starting from the
> > + * node given by path. It is used to extract information (like reserved
> > + * memory), which is required on ealy boot before we can unflatten the tree.
> > + */
> > +int __init of_scan_flat_dt_by_path(const char *path,
> > + int (*it)(unsigned long node, const char *name, int depth, void *data),
> > + void *data)
>
> Nit: Please match the indentation convention used by of_scan_flat_dt().
> This current version is really hard to read.
>
> > +{
> > + struct fdt_scan_status st = {path, 0, -1, 0, it, data};
>
> This is a little fragile. If the structure gets modified, this line
> will break. I know it results in more text, but please use explicit data
> member assignments in initializers.
>
> > + int ret = 0;
> > +
> > + if (initial_boot_params)
>
> Nit:
> if (!initial_boot_params)
> return 0;
>
> > + ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
>
> Nit: inconsitent indentation (tabs vs. spaces)
>
> > +
> > + if (!st.found)
> > + return -ENOENT;
> > + else if (ret == -ENXIO) /* scan has been completed */
> > + return 0;
> > + else
> > + return ret;
>
> Both uses of 'else' above are redundant. The only way the execution will
> pass that point is if it was the else case!
>
> > +}
> > +
> > #ifdef CONFIG_BLK_DEV_INITRD
> > /**
> > * early_init_dt_check_for_initrd - Decode initrd location from flat tree
> > diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
> > index ed136ad..19f26f8 100644
> > --- a/include/linux/of_fdt.h
> > +++ b/include/linux/of_fdt.h
> > @@ -90,6 +90,9 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
> > extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
> > extern int of_flat_dt_match(unsigned long node, const char *const *matches);
> > extern unsigned long of_get_flat_dt_root(void);
> > +extern int of_scan_flat_dt_by_path(const char *path,
> > + int (*it)(unsigned long node, const char *name, int depth, void *data),
> > + void *data);
> >
> > extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
> > int depth, void *data);
> > --
> > 1.7.9.5
> >
>
>
Best regards
--
Marek Szyprowski
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 2/4] drivers: of: add function to scan fdt nodes given by path
2013-08-30 10:42 ` Marek Szyprowski
@ 2013-08-30 10:46 ` Grant Likely
0 siblings, 0 replies; 27+ messages in thread
From: Grant Likely @ 2013-08-30 10:46 UTC (permalink / raw)
To: Marek Szyprowski
Cc: Mark Rutland, devicetree@vger.kernel.org, Laura Abbott,
Pawel Moll, Arnd Bergmann, Stephen Warren, Tomasz Figa,
Tomasz Figa, Michal Nazarewicz, linaro-mm-sig, Marc,
Kyungmin Park, Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel@lists.infradead.org, Ian Campbell
On Fri, Aug 30, 2013 at 11:42 AM, Marek Szyprowski
<m.szyprowski@samsung.com> wrote:
> Hello,
>
>
> On 8/29/2013 11:40 PM, Grant Likely wrote:
>>
>> On Mon, 26 Aug 2013 16:39:17 +0200, Marek Szyprowski
>> <m.szyprowski@samsung.com> wrote:
>> > Add a function to scan the flattened device-tree starting from the
>> > node given by the path. It is used to extract information (like reserved
>> > memory), which is required on early boot before we can unflatten the
>> > tree.
>> >
>> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> > Acked-by: Michal Nazarewicz <mina86@mina86.com>
>> > Acked-by: Tomasz Figa <t.figa@samsung.com>
>> > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
>>
>> Some nits below, but otherwise:
>>
>> Acked-by: Grant Likely <grant.likely@secretlab.ca>
>
>
> Thanks!
>
>
>> I'm happy to take this through the DT tree, or have you take it via the
>> CMA tree.
>
>
> I have already put the whole patchset in linux-next via my dma-mapping/cma
> tree,
> so I would like to keep it there to avoid further confusion.
>
> I only wonder how to handle the patches to get them merged to v3.12-rc1.
> After your review there will be some changes to the binding, its
> documentation
> and the code itself. Would you mind if I send pull request with the current
> version and then provide incremental patches to fix the issues you have
> reported? Or should we delay this patchset till v3.13-rc1?
Merge the series as-is and send follow-on patches. If you can get the
fixups done quickly, then we can get them merged for v3.12 also.
g.
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-08-26 14:39 [PATCH v7 0/4] Device Tree support for CMA (Contiguous Memory Allocator) Marek Szyprowski
2013-08-26 14:39 ` [PATCH v7 1/4] drivers: dma-contiguous: clean source code and prepare for device tree Marek Szyprowski
2013-08-26 14:39 ` [PATCH v7 2/4] drivers: of: add function to scan fdt nodes given by path Marek Szyprowski
@ 2013-08-26 14:39 ` Marek Szyprowski
2013-08-29 22:46 ` Grant Likely
` (2 more replies)
2013-08-26 14:39 ` [PATCH v7 4/4] ARM: init: add support for reserved memory defined by device tree Marek Szyprowski
3 siblings, 3 replies; 27+ messages in thread
From: Marek Szyprowski @ 2013-08-26 14:39 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
Grant Likely, Marc, Kyungmin Park, Sylwester Nawrocki, Kumar Gala,
Olof Johansson, Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
This patch adds device tree support for contiguous and reserved memory
regions defined in device tree.
Large memory blocks can be reliably reserved only during early boot.
This must happen before the whole memory management subsystem is
initialized, because we need to ensure that the given contiguous blocks
are not yet allocated by kernel. Also it must happen before kernel
mappings for the whole low memory are created, to ensure that there will
be no mappings (for reserved blocks) or mapping with special properties
can be created (for CMA blocks). This all happens before device tree
structures are unflattened, so we need to get reserved memory layout
directly from fdt.
Later, those reserved memory regions are assigned to devices on each
device structure initialization.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
---
Documentation/devicetree/bindings/memory.txt | 168 +++++++++++++++++++++++++
drivers/of/Kconfig | 6 +
drivers/of/Makefile | 1 +
drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++
drivers/of/platform.c | 4 +
include/linux/of_reserved_mem.h | 14 +++
6 files changed, 368 insertions(+)
create mode 100644 Documentation/devicetree/bindings/memory.txt
create mode 100644 drivers/of/of_reserved_mem.c
create mode 100644 include/linux/of_reserved_mem.h
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
new file mode 100644
index 0000000..eb24693
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -0,0 +1,168 @@
+*** Memory binding ***
+
+The /memory node provides basic information about the address and size
+of the physical memory. This node is usually filled or updated by the
+bootloader, depending on the actual memory configuration of the given
+hardware.
+
+The memory layout is described by the following node:
+
+/ {
+ #address-cells = <(n)>;
+ #size-cells = <(m)>;
+ memory {
+ device_type = "memory";
+ reg = <(baseaddr1) (size1)
+ (baseaddr2) (size2)
+ ...
+ (baseaddrN) (sizeN)>;
+ };
+ ...
+};
+
+A memory node follows the typical device tree rules for "reg" property:
+n: number of cells used to store base address value
+m: number of cells used to store size value
+baseaddrX: defines a base address of the defined memory bank
+sizeX: the size of the defined memory bank
+
+
+More than one memory bank can be defined.
+
+
+*** Reserved memory regions ***
+
+In /memory/reserved-memory node one can create child nodes describing
+particular reserved (excluded from normal use) memory regions. Such
+memory regions are usually designed for the special usage by various
+device drivers. A good example are contiguous memory allocations or
+memory sharing with other operating system on the same hardware board.
+Those special memory regions might depend on the board configuration and
+devices used on the target system.
+
+Parameters for each memory region can be encoded into the device tree
+with the following convention:
+
+[(label):] (name) {
+ compatible = "linux,contiguous-memory-region", "reserved-memory-region";
+ reg = <(address) (size)>;
+ (linux,default-contiguous-region);
+};
+
+compatible: one or more of:
+ - "linux,contiguous-memory-region" - enables binding of this
+ region to Contiguous Memory Allocator (special region for
+ contiguous memory allocations, shared with movable system
+ memory, Linux kernel-specific).
+ - "reserved-memory-region" - compatibility is defined, given
+ region is assigned for exclusive usage for by the respective
+ devices.
+
+reg: standard property defining the base address and size of
+ the memory region
+
+linux,default-contiguous-region: property indicating that the region
+ is the default region for all contiguous memory
+ allocations, Linux specific (optional)
+
+It is optional to specify the base address, so if one wants to use
+autoconfiguration of the base address, '0' can be specified as a base
+address in the 'reg' property.
+
+The /memory/reserved-memory node must contain the same #address-cells
+and #size-cells value as the root node.
+
+
+*** Device node's properties ***
+
+Once regions in the /memory/reserved-memory node have been defined, they
+may be referenced by other device nodes. Bindings that wish to reference
+memory regions should explicitly document their use of the following
+property:
+
+memory-region = <&phandle_to_defined_region>;
+
+This property indicates that the device driver should use the memory
+region pointed by the given phandle.
+
+
+*** Example ***
+
+This example defines a memory consisting of 4 memory banks. 3 contiguous
+regions are defined for Linux kernel, one default of all device drivers
+(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the
+framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB)
+and one for multimedia processing (labelled multimedia_mem, placed at
+0x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000
+device for DMA memory allocations (Linux kernel drivers will use CMA is
+available or dma-exclusive usage otherwise). 'multimedia_mem' is
+assigned to scaler@12500000 and codec@12600000 devices for contiguous
+memory allocations when CMA driver is enabled.
+
+The reason for creating a separate region for framebuffer device is to
+match the framebuffer base address to the one configured by bootloader,
+so once Linux kernel drivers starts no glitches on the displayed boot
+logo appears. Scaller and codec drivers should share the memory
+allocations.
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* ... */
+
+ memory {
+ reg = <0x40000000 0x10000000
+ 0x50000000 0x10000000
+ 0x60000000 0x10000000
+ 0x70000000 0x10000000>;
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /*
+ * global autoconfigured region for contiguous allocations
+ * (used only with Contiguous Memory Allocator)
+ */
+ contig_region@0 {
+ compatible = "linux,contiguous-memory-region";
+ reg = <0x0 0x4000000>;
+ linux,default-contiguous-region;
+ };
+
+ /*
+ * special region for framebuffer
+ */
+ display_region: region@78000000 {
+ compatible = "linux,contiguous-memory-region", "reserved-memory-region";
+ reg = <0x78000000 0x800000>;
+ };
+
+ /*
+ * special region for multimedia processing devices
+ */
+ multimedia_region: region@77000000 {
+ compatible = "linux,contiguous-memory-region";
+ reg = <0x77000000 0x4000000>;
+ };
+ };
+ };
+
+ /* ... */
+
+ fb0: fb@12300000 {
+ status = "okay";
+ memory-region = <&display_region>;
+ };
+
+ scaler: scaler@12500000 {
+ status = "okay";
+ memory-region = <&multimedia_region>;
+ };
+
+ codec: codec@12600000 {
+ status = "okay";
+ memory-region = <&multimedia_region>;
+ };
+};
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 80e5c13..f7107fa 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -80,4 +80,10 @@ config OF_MTD
depends on MTD
def_bool y
+config OF_RESERVED_MEM
+ depends on DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK)
+ def_bool y
+ help
+ Initialization code for DMA reserved memory
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 1f9c0c4..e7e3322 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
+obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
new file mode 100644
index 0000000..a754b84
--- /dev/null
+++ b/drivers/of/of_reserved_mem.c
@@ -0,0 +1,175 @@
+/*
+ * Device tree based initialization code for reserved memory.
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License or (at your optional) any later version of the license.
+ */
+
+#include <asm/dma-contiguous.h>
+
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+#include <linux/mm_types.h>
+#include <linux/dma-contiguous.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_reserved_mem.h>
+
+#define MAX_RESERVED_REGIONS 16
+struct reserved_mem {
+ phys_addr_t base;
+ unsigned long size;
+ struct cma *cma;
+ char name[32];
+};
+static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
+static int reserved_mem_count;
+
+static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
+ phys_addr_t base, size;
+ int is_cma, is_reserved;
+ unsigned long len;
+ const char *status;
+ __be32 *prop;
+
+ is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
+ of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
+ is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
+
+ if (!is_reserved && !is_cma) {
+ /* ignore node and scan next one */
+ return 0;
+ }
+
+ status = of_get_flat_dt_prop(node, "status", &len);
+ if (status && strcmp(status, "okay") != 0) {
+ /* ignore disabled node nad scan next one */
+ return 0;
+ }
+
+ prop = of_get_flat_dt_prop(node, "reg", &len);
+ if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
+ sizeof(__be32))) {
+ pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
+ uname);
+ /* ignore node and scan next one */
+ return 0;
+ }
+ base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+ if (!size) {
+ /* ignore node and scan next one */
+ return 0;
+ }
+
+ pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
+ uname, (unsigned long)base, (unsigned long)size / SZ_1M);
+
+ if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
+ return -ENOSPC;
+
+ rmem->base = base;
+ rmem->size = size;
+ strlcpy(rmem->name, uname, sizeof(rmem->name));
+
+ if (is_cma) {
+ struct cma *cma;
+ if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
+ rmem->cma = cma;
+ reserved_mem_count++;
+ if (of_get_flat_dt_prop(node,
+ "linux,default-contiguous-region",
+ NULL))
+ dma_contiguous_set_default(cma);
+ }
+ } else if (is_reserved) {
+ if (memblock_remove(base, size) == 0)
+ reserved_mem_count++;
+ else
+ pr_err("Failed to reserve memory for %s\n", uname);
+ }
+
+ return 0;
+}
+
+static struct reserved_mem *get_dma_memory_region(struct device *dev)
+{
+ struct device_node *node;
+ const char *name;
+ int i;
+
+ node = of_parse_phandle(dev->of_node, "memory-region", 0);
+ if (!node)
+ return NULL;
+
+ name = kbasename(node->full_name);
+ for (i = 0; i < reserved_mem_count; i++)
+ if (strcmp(name, reserved_mem[i].name) == 0)
+ return &reserved_mem[i];
+ return NULL;
+}
+
+/**
+ * of_reserved_mem_device_init() - assign reserved memory region to given device
+ *
+ * This function assign memory region pointed by "memory-region" device tree
+ * property to the given device.
+ */
+void of_reserved_mem_device_init(struct device *dev)
+{
+ struct reserved_mem *region = get_dma_memory_region(dev);
+ if (!region)
+ return;
+
+ if (region->cma) {
+ dev_set_cma_area(dev, region->cma);
+ pr_info("Assigned CMA %s to %s device\n", region->name,
+ dev_name(dev));
+ } else {
+ if (dma_declare_coherent_memory(dev, region->base, region->base,
+ region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
+ pr_info("Declared reserved memory %s to %s device\n",
+ region->name, dev_name(dev));
+ }
+}
+
+/**
+ * of_reserved_mem_device_release() - release reserved memory device structures
+ *
+ * This function releases structures allocated for memory region handling for
+ * the given device.
+ */
+void of_reserved_mem_device_release(struct device *dev)
+{
+ struct reserved_mem *region = get_dma_memory_region(dev);
+ if (!region && !region->cma)
+ dma_release_declared_memory(dev);
+}
+
+/**
+ * early_init_dt_scan_reserved_mem() - create reserved memory regions
+ *
+ * This function grabs memory from early allocator for device exclusive use
+ * defined in device tree structures. It should be called by arch specific code
+ * once the early allocator (memblock) has been activated and all other
+ * subsystems have already allocated/reserved memory.
+ */
+void __init early_init_dt_scan_reserved_mem(void)
+{
+ of_scan_flat_dt_by_path("/memory/reserved-memory",
+ fdt_scan_reserved_mem, NULL);
+}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e0a6514..eeca8a5 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -21,6 +21,7 @@
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
const struct of_device_id of_default_bus_match_table[] = {
@@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
+ of_reserved_mem_device_init(&dev->dev);
+
/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such, possibly using a device notifier
@@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
if (of_device_add(dev) != 0) {
platform_device_put(dev);
+ of_reserved_mem_device_release(&dev->dev);
return NULL;
}
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
new file mode 100644
index 0000000..c841282
--- /dev/null
+++ b/include/linux/of_reserved_mem.h
@@ -0,0 +1,14 @@
+#ifndef __OF_RESERVED_MEM_H
+#define __OF_RESERVED_MEM_H
+
+#ifdef CONFIG_OF_RESERVED_MEM
+void of_reserved_mem_device_init(struct device *dev);
+void of_reserved_mem_device_release(struct device *dev);
+void early_init_dt_scan_reserved_mem(void);
+#else
+static inline void of_reserved_mem_device_init(struct device *dev) { }
+static inline void of_reserved_mem_device_release(struct device *dev) { }
+static inline void early_init_dt_scan_reserved_mem(void) { }
+#endif
+
+#endif /* __OF_RESERVED_MEM_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-08-26 14:39 ` [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory Marek Szyprowski
@ 2013-08-29 22:46 ` Grant Likely
2013-08-30 12:39 ` Marek Szyprowski
2013-08-29 22:48 ` Grant Likely
[not found] ` <1377527959-5080-4-git-send-email-m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2 siblings, 1 reply; 27+ messages in thread
From: Grant Likely @ 2013-08-29 22:46 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz, Marc,
Kyungmin Park, Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> This patch adds device tree support for contiguous and reserved memory
> regions defined in device tree.
>
> Large memory blocks can be reliably reserved only during early boot.
> This must happen before the whole memory management subsystem is
> initialized, because we need to ensure that the given contiguous blocks
> are not yet allocated by kernel. Also it must happen before kernel
> mappings for the whole low memory are created, to ensure that there will
> be no mappings (for reserved blocks) or mapping with special properties
> can be created (for CMA blocks). This all happens before device tree
> structures are unflattened, so we need to get reserved memory layout
> directly from fdt.
>
> Later, those reserved memory regions are assigned to devices on each
> device structure initialization.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Acked-by: Michal Nazarewicz <mina86@mina86.com>
> Acked-by: Tomasz Figa <t.figa@samsung.com>
> Acked-by: Stephen Warren <swarren@nvidia.com>
> Reviewed-by: Rob Herring <rob.herring@calxeda.com>
Hi Marek,
This patch is in good shape, but I have some comments below and a few
concerns about the binding....
g.
> ---
> Documentation/devicetree/bindings/memory.txt | 168 +++++++++++++++++++++++++
> drivers/of/Kconfig | 6 +
> drivers/of/Makefile | 1 +
> drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++
> drivers/of/platform.c | 4 +
> include/linux/of_reserved_mem.h | 14 +++
> 6 files changed, 368 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/memory.txt
> create mode 100644 drivers/of/of_reserved_mem.c
> create mode 100644 include/linux/of_reserved_mem.h
>
> diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
> new file mode 100644
> index 0000000..eb24693
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/memory.txt
> @@ -0,0 +1,168 @@
> +*** Memory binding ***
> +
> +The /memory node provides basic information about the address and size
> +of the physical memory. This node is usually filled or updated by the
> +bootloader, depending on the actual memory configuration of the given
> +hardware.
> +
> +The memory layout is described by the following node:
> +
> +/ {
> + #address-cells = <(n)>;
> + #size-cells = <(m)>;
> + memory {
> + device_type = "memory";
> + reg = <(baseaddr1) (size1)
> + (baseaddr2) (size2)
> + ...
> + (baseaddrN) (sizeN)>;
> + };
> + ...
> +};
> +
> +A memory node follows the typical device tree rules for "reg" property:
> +n: number of cells used to store base address value
> +m: number of cells used to store size value
> +baseaddrX: defines a base address of the defined memory bank
> +sizeX: the size of the defined memory bank
> +
> +
> +More than one memory bank can be defined.
> +
> +
> +*** Reserved memory regions ***
> +
> +In /memory/reserved-memory node one can create child nodes describing
> +particular reserved (excluded from normal use) memory regions. Such
> +memory regions are usually designed for the special usage by various
> +device drivers. A good example are contiguous memory allocations or
> +memory sharing with other operating system on the same hardware board.
> +Those special memory regions might depend on the board configuration and
> +devices used on the target system.
> +
> +Parameters for each memory region can be encoded into the device tree
> +with the following convention:
> +
> +[(label):] (name) {
> + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
> + reg = <(address) (size)>;
> + (linux,default-contiguous-region);
> +};
> +
> +compatible: one or more of:
It's unclear what the meaning of having both values means for the
kernel. Does it mean the regions is sharable with the kernel or not? I
would think they are mutually exclusive.
> + - "linux,contiguous-memory-region" - enables binding of this
> + region to Contiguous Memory Allocator (special region for
> + contiguous memory allocations, shared with movable system
> + memory, Linux kernel-specific).
As mentioned in the older thread, you can drop the 'linux,' prefix here.
Perhaps something like "shareable-memory-region" or merely
"memory-region". It is reasonable for any kernel (not just Linux) to use
marked regions for movable pages until it gets requested by a driver, in
which case a rather generic "memory-region" makes a lot of sense as a
name.
> + - "reserved-memory-region" - compatibility is defined, given
> + region is assigned for exclusive usage for by the respective
> + devices.
BTW, just so you're aware there is already a binding for marking regions
as reserved. It was recently added to arch/powerpc/kernel/prom.c.
Unfortunately it doesn't look like it got documented. Search for
"reserved-ranges". However, I don't think it blocks your work here. That
binding doesn't provide any way for matching devices to reserved ranges.
It is only for telling the kernel "hands of that memory".
> +
> +reg: standard property defining the base address and size of
> + the memory region
> +
> +linux,default-contiguous-region: property indicating that the region
> + is the default region for all contiguous memory
> + allocations, Linux specific (optional)
> +
> +It is optional to specify the base address, so if one wants to use
> +autoconfiguration of the base address, '0' can be specified as a base
> +address in the 'reg' property.
I don't understand this. What does autoconfiguration of the base address
actually do? If this is intended to dynamically allocate a region of RAM
for contiguous allocations, then don't use 'reg'. Use a different
property that only specifies the size.
> +The /memory/reserved-memory node must contain the same #address-cells
> +and #size-cells value as the root node.
That seems to be an arbitrary restriction. Why does the reserved-memory
node need to have exactly the same #address/size values? The 'reg'
property binding quite easily handles different values at different
levels of the tree. More below....
> +/ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + /* ... */
> +
> + memory {
> + reg = <0x40000000 0x10000000
> + 0x50000000 0x10000000
> + 0x60000000 0x10000000
> + 0x70000000 0x10000000>;
> +
> + reserved-memory {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + /*
> + * global autoconfigured region for contiguous allocations
> + * (used only with Contiguous Memory Allocator)
> + */
> + contig_region@0 {
I would expect this to be "region@0", not "contig_region". Also, the '_'
character is strongly discouraged in node names.
> + compatible = "linux,contiguous-memory-region";
> + reg = <0x0 0x4000000>;
As written, this example tree is abusing the 'reg' binding. Whenever a
node has a mappable 'reg' propertie, then all of the parent nodes above
it need to have 'ranges' properties. In this case it is pretty easy to
fix by simply adding "ranges;" to the reserved-memory and memory nodes.
An empty ranges property simply means that all addresses are 1:1 mapped
if #address/size are the same between each parent/child.
The documentation above should specify that both memory and
reserved-memory need to have 'ranges', but can suggest that the best
use-case is for ranges to be empty.
I mentioned above that #address/#size can actually be different. If
someone wants to do that, then they need to have a fully specified
ranges property that declares the mapping from one address space to
another.
I'm okay with the implementation as it currently stands, but only if you
make it test for the presence of an empty ranges property. If ranges is
missing, or if it has data in it then it should throw an error that it
cannot be parsed.
> + linux,default-contiguous-region;
> + };
> +
> + /*
> + * special region for framebuffer
> + */
> + display_region: region@78000000 {
> + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
> + reg = <0x78000000 0x800000>;
> + };
> +
> + /*
> + * special region for multimedia processing devices
> + */
> + multimedia_region: region@77000000 {
> + compatible = "linux,contiguous-memory-region";
> + reg = <0x77000000 0x4000000>;
> + };
> + };
> + };
> +
> + /* ... */
> +
> + fb0: fb@12300000 {
> + status = "okay";
> + memory-region = <&display_region>;
> + };
> +
> + scaler: scaler@12500000 {
> + status = "okay";
> + memory-region = <&multimedia_region>;
> + };
> +
> + codec: codec@12600000 {
> + status = "okay";
> + memory-region = <&multimedia_region>;
> + };
> +};
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index 80e5c13..f7107fa 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -80,4 +80,10 @@ config OF_MTD
> depends on MTD
> def_bool y
>
> +config OF_RESERVED_MEM
> + depends on DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK)
> + def_bool y
> + help
> + Initialization code for DMA reserved memory
> +
> endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index 1f9c0c4..e7e3322 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
> obj-$(CONFIG_OF_PCI) += of_pci.o
> obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> obj-$(CONFIG_OF_MTD) += of_mtd.o
> +obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
> new file mode 100644
> index 0000000..a754b84
> --- /dev/null
> +++ b/drivers/of/of_reserved_mem.c
> @@ -0,0 +1,175 @@
> +/*
> + * Device tree based initialization code for reserved memory.
> + *
> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> + * http://www.samsung.com
> + * Author: Marek Szyprowski <m.szyprowski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License or (at your optional) any later version of the license.
> + */
> +
> +#include <asm/dma-contiguous.h>
> +
> +#include <linux/memblock.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
> +#include <linux/mm.h>
> +#include <linux/sizes.h>
> +#include <linux/mm_types.h>
> +#include <linux/dma-contiguous.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/of_reserved_mem.h>
> +
> +#define MAX_RESERVED_REGIONS 16
Nit: This seems a little arbitrary. I would expect the reserved_mem
array to be dynamically allocated. I'm not going to force you to change
this, but it should be revisited with a follow-on patch.
> +struct reserved_mem {
> + phys_addr_t base;
> + unsigned long size;
> + struct cma *cma;
> + char name[32];
Why is name a fixed size string? And why is it a magic size of 32?
> +};
> +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
> +static int reserved_mem_count;
> +
> +static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
> + int depth, void *data)
> +{
> + struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
> + phys_addr_t base, size;
> + int is_cma, is_reserved;
> + unsigned long len;
> + const char *status;
> + __be32 *prop;
> +
> + is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
> + of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
Nit: Indentation by tabs.
> + is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
> +
> + if (!is_reserved && !is_cma) {
> + /* ignore node and scan next one */
> + return 0;
> + }
> +
> + status = of_get_flat_dt_prop(node, "status", &len);
> + if (status && strcmp(status, "okay") != 0) {
> + /* ignore disabled node nad scan next one */
> + return 0;
> + }
> +
> + prop = of_get_flat_dt_prop(node, "reg", &len);
> + if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
> + sizeof(__be32))) {
> + pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
> + uname);
> + /* ignore node and scan next one */
> + return 0;
> + }
> + base = dt_mem_next_cell(dt_root_addr_cells, &prop);
> + size = dt_mem_next_cell(dt_root_size_cells, &prop);
> +
> + if (!size) {
> + /* ignore node and scan next one */
> + return 0;
> + }
> +
> + pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
> + uname, (unsigned long)base, (unsigned long)size / SZ_1M);
> +
> + if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
> + return -ENOSPC;
> +
> + rmem->base = base;
> + rmem->size = size;
> + strlcpy(rmem->name, uname, sizeof(rmem->name));
If I'm reading the code correctly, uname is directly from the flattened
device tree and is safe to keep a pointer to. Can you make rmem->name a
char* and merely do a rmem->name = uname;?
> +
> + if (is_cma) {
> + struct cma *cma;
> + if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
> + rmem->cma = cma;
> + reserved_mem_count++;
> + if (of_get_flat_dt_prop(node,
> + "linux,default-contiguous-region",
> + NULL))
> + dma_contiguous_set_default(cma);
> + }
> + } else if (is_reserved) {
> + if (memblock_remove(base, size) == 0)
> + reserved_mem_count++;
> + else
> + pr_err("Failed to reserve memory for %s\n", uname);
> + }
> +
> + return 0;
> +}
> +
> +static struct reserved_mem *get_dma_memory_region(struct device *dev)
> +{
> + struct device_node *node;
> + const char *name;
> + int i;
> +
> + node = of_parse_phandle(dev->of_node, "memory-region", 0);
> + if (!node)
> + return NULL;
> +
> + name = kbasename(node->full_name);
> + for (i = 0; i < reserved_mem_count; i++)
> + if (strcmp(name, reserved_mem[i].name) == 0)
> + return &reserved_mem[i];
> + return NULL;
> +}
> +
> +/**
> + * of_reserved_mem_device_init() - assign reserved memory region to given device
> + *
> + * This function assign memory region pointed by "memory-region" device tree
> + * property to the given device.
> + */
> +void of_reserved_mem_device_init(struct device *dev)
> +{
> + struct reserved_mem *region = get_dma_memory_region(dev);
> + if (!region)
> + return;
> +
> + if (region->cma) {
> + dev_set_cma_area(dev, region->cma);
> + pr_info("Assigned CMA %s to %s device\n", region->name,
> + dev_name(dev));
> + } else {
> + if (dma_declare_coherent_memory(dev, region->base, region->base,
> + region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
> + pr_info("Declared reserved memory %s to %s device\n",
> + region->name, dev_name(dev));
> + }
> +}
> +
> +/**
> + * of_reserved_mem_device_release() - release reserved memory device structures
> + *
> + * This function releases structures allocated for memory region handling for
> + * the given device.
> + */
> +void of_reserved_mem_device_release(struct device *dev)
> +{
> + struct reserved_mem *region = get_dma_memory_region(dev);
> + if (!region && !region->cma)
> + dma_release_declared_memory(dev);
> +}
> +
> +/**
> + * early_init_dt_scan_reserved_mem() - create reserved memory regions
> + *
> + * This function grabs memory from early allocator for device exclusive use
> + * defined in device tree structures. It should be called by arch specific code
> + * once the early allocator (memblock) has been activated and all other
> + * subsystems have already allocated/reserved memory.
> + */
> +void __init early_init_dt_scan_reserved_mem(void)
> +{
> + of_scan_flat_dt_by_path("/memory/reserved-memory",
> + fdt_scan_reserved_mem, NULL);
> +}
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index e0a6514..eeca8a5 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -21,6 +21,7 @@
> #include <linux/of_device.h>
> #include <linux/of_irq.h>
> #include <linux/of_platform.h>
> +#include <linux/of_reserved_mem.h>
> #include <linux/platform_device.h>
>
> const struct of_device_id of_default_bus_match_table[] = {
> @@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
> dev->dev.bus = &platform_bus_type;
> dev->dev.platform_data = platform_data;
>
> + of_reserved_mem_device_init(&dev->dev);
> +
> /* We do not fill the DMA ops for platform devices by default.
> * This is currently the responsibility of the platform code
> * to do such, possibly using a device notifier
> @@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
>
> if (of_device_add(dev) != 0) {
> platform_device_put(dev);
> + of_reserved_mem_device_release(&dev->dev);
> return NULL;
> }
>
> diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
> new file mode 100644
> index 0000000..c841282
> --- /dev/null
> +++ b/include/linux/of_reserved_mem.h
> @@ -0,0 +1,14 @@
> +#ifndef __OF_RESERVED_MEM_H
> +#define __OF_RESERVED_MEM_H
> +
> +#ifdef CONFIG_OF_RESERVED_MEM
> +void of_reserved_mem_device_init(struct device *dev);
> +void of_reserved_mem_device_release(struct device *dev);
> +void early_init_dt_scan_reserved_mem(void);
> +#else
> +static inline void of_reserved_mem_device_init(struct device *dev) { }
> +static inline void of_reserved_mem_device_release(struct device *dev) { }
> +static inline void early_init_dt_scan_reserved_mem(void) { }
> +#endif
> +
> +#endif /* __OF_RESERVED_MEM_H */
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-08-29 22:46 ` Grant Likely
@ 2013-08-30 12:39 ` Marek Szyprowski
2013-08-30 20:26 ` Kumar Gala
2013-09-09 13:05 ` Grant Likely
0 siblings, 2 replies; 27+ messages in thread
From: Marek Szyprowski @ 2013-08-30 12:39 UTC (permalink / raw)
To: Grant Likely
Cc: Mark Rutland, devicetree, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
linaro-mm-sig, Marc, Kyungmin Park, Sylwester Nawrocki,
Kumar Gala, Olof Johansson, Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel, Ian Campbell
Hello,
On 8/30/2013 12:46 AM, Grant Likely wrote:
> On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> > This patch adds device tree support for contiguous and reserved memory
> > regions defined in device tree.
> >
> > Large memory blocks can be reliably reserved only during early boot.
> > This must happen before the whole memory management subsystem is
> > initialized, because we need to ensure that the given contiguous blocks
> > are not yet allocated by kernel. Also it must happen before kernel
> > mappings for the whole low memory are created, to ensure that there will
> > be no mappings (for reserved blocks) or mapping with special properties
> > can be created (for CMA blocks). This all happens before device tree
> > structures are unflattened, so we need to get reserved memory layout
> > directly from fdt.
> >
> > Later, those reserved memory regions are assigned to devices on each
> > device structure initialization.
> >
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> > Acked-by: Michal Nazarewicz <mina86@mina86.com>
> > Acked-by: Tomasz Figa <t.figa@samsung.com>
> > Acked-by: Stephen Warren <swarren@nvidia.com>
> > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
>
> Hi Marek,
>
> This patch is in good shape, but I have some comments below and a few
> concerns about the binding....
>
> g.
>
> > ---
> > Documentation/devicetree/bindings/memory.txt | 168 +++++++++++++++++++++++++
> > drivers/of/Kconfig | 6 +
> > drivers/of/Makefile | 1 +
> > drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++
> > drivers/of/platform.c | 4 +
> > include/linux/of_reserved_mem.h | 14 +++
> > 6 files changed, 368 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/memory.txt
> > create mode 100644 drivers/of/of_reserved_mem.c
> > create mode 100644 include/linux/of_reserved_mem.h
> >
> > diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
> > new file mode 100644
> > index 0000000..eb24693
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/memory.txt
> > @@ -0,0 +1,168 @@
> > +*** Memory binding ***
> > +
> > +The /memory node provides basic information about the address and size
> > +of the physical memory. This node is usually filled or updated by the
> > +bootloader, depending on the actual memory configuration of the given
> > +hardware.
> > +
> > +The memory layout is described by the following node:
> > +
> > +/ {
> > + #address-cells = <(n)>;
> > + #size-cells = <(m)>;
> > + memory {
> > + device_type = "memory";
> > + reg = <(baseaddr1) (size1)
> > + (baseaddr2) (size2)
> > + ...
> > + (baseaddrN) (sizeN)>;
> > + };
> > + ...
> > +};
> > +
> > +A memory node follows the typical device tree rules for "reg" property:
> > +n: number of cells used to store base address value
> > +m: number of cells used to store size value
> > +baseaddrX: defines a base address of the defined memory bank
> > +sizeX: the size of the defined memory bank
> > +
> > +
> > +More than one memory bank can be defined.
> > +
> > +
> > +*** Reserved memory regions ***
> > +
> > +In /memory/reserved-memory node one can create child nodes describing
> > +particular reserved (excluded from normal use) memory regions. Such
> > +memory regions are usually designed for the special usage by various
> > +device drivers. A good example are contiguous memory allocations or
> > +memory sharing with other operating system on the same hardware board.
> > +Those special memory regions might depend on the board configuration and
> > +devices used on the target system.
> > +
> > +Parameters for each memory region can be encoded into the device tree
> > +with the following convention:
> > +
> > +[(label):] (name) {
> > + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
> > + reg = <(address) (size)>;
> > + (linux,default-contiguous-region);
> > +};
> > +
> > +compatible: one or more of:
>
> It's unclear what the meaning of having both values means for the
> kernel. Does it mean the regions is sharable with the kernel or not? I
> would think they are mutually exclusive.
I consider CMA ("linux,contiguous-memory-region") as a special case of the
reserved memory driver. The main advantage is the ability of sharing the
memory
with the system instead of just allocating it from the carved out memory
region. From the device and hardware perspective there is no difference
if the buffer comes from CMA or reserved memory. However if you insist, I
can change it to something different, like "shareable-memory-region".
Specifying both compatible values would let kernel to bind the more specific
driver (cma, if available) over the generic one (simple reserved memory
carve-out allocator based on dma_coherent).
> > + - "linux,contiguous-memory-region" - enables binding of this
> > + region to Contiguous Memory Allocator (special region for
> > + contiguous memory allocations, shared with movable system
> > + memory, Linux kernel-specific).
>
> As mentioned in the older thread, you can drop the 'linux,' prefix here.
> Perhaps something like "shareable-memory-region" or merely
> "memory-region". It is reasonable for any kernel (not just Linux) to use
> marked regions for movable pages until it gets requested by a driver, in
> which case a rather generic "memory-region" makes a lot of sense as a
> name.
>
> > + - "reserved-memory-region" - compatibility is defined, given
> > + region is assigned for exclusive usage for by the respective
> > + devices.
>
> BTW, just so you're aware there is already a binding for marking regions
> as reserved. It was recently added to arch/powerpc/kernel/prom.c.
> Unfortunately it doesn't look like it got documented. Search for
> "reserved-ranges". However, I don't think it blocks your work here. That
> binding doesn't provide any way for matching devices to reserved ranges.
> It is only for telling the kernel "hands of that memory".
ok, good to know.
> > +
> > +reg: standard property defining the base address and size of
> > + the memory region
> > +
> > +linux,default-contiguous-region: property indicating that the region
> > + is the default region for all contiguous memory
> > + allocations, Linux specific (optional)
> > +
> > +It is optional to specify the base address, so if one wants to use
> > +autoconfiguration of the base address, '0' can be specified as a base
> > +address in the 'reg' property.
>
> I don't understand this. What does autoconfiguration of the base address
> actually do? If this is intended to dynamically allocate a region of RAM
> for contiguous allocations, then don't use 'reg'. Use a different
> property that only specifies the size.
Ok, I will try to make a patch which removes special 'zero' base address
handling and adds separate 'size' property for automatically configured
regions.
> > +The /memory/reserved-memory node must contain the same #address-cells
> > +and #size-cells value as the root node.
>
> That seems to be an arbitrary restriction. Why does the reserved-memory
> node need to have exactly the same #address/size values? The 'reg'
> property binding quite easily handles different values at different
> levels of the tree. More below....
Does it really makes sense to have such configuration with different
#address-cells/#size-cells than the root memory node?
> > +/ {
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > +
> > + /* ... */
> > +
> > + memory {
> > + reg = <0x40000000 0x10000000
> > + 0x50000000 0x10000000
> > + 0x60000000 0x10000000
> > + 0x70000000 0x10000000>;
> > +
> > + reserved-memory {
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > +
> > + /*
> > + * global autoconfigured region for contiguous allocations
> > + * (used only with Contiguous Memory Allocator)
> > + */
> > + contig_region@0 {
>
> I would expect this to be "region@0", not "contig_region". Also, the '_'
> character is strongly discouraged in node names.
>
> > + compatible = "linux,contiguous-memory-region";
> > + reg = <0x0 0x4000000>;
>
> As written, this example tree is abusing the 'reg' binding. Whenever a
> node has a mappable 'reg' propertie, then all of the parent nodes above
> it need to have 'ranges' properties. In this case it is pretty easy to
> fix by simply adding "ranges;" to the reserved-memory and memory nodes.
> An empty ranges property simply means that all addresses are 1:1 mapped
> if #address/size are the same between each parent/child.
>
> The documentation above should specify that both memory and
> reserved-memory need to have 'ranges', but can suggest that the best
> use-case is for ranges to be empty.
>
> I mentioned above that #address/#size can actually be different. If
> someone wants to do that, then they need to have a fully specified
> ranges property that declares the mapping from one address space to
> another.
>
> I'm okay with the implementation as it currently stands, but only if you
> make it test for the presence of an empty ranges property. If ranges is
> missing, or if it has data in it then it should throw an error that it
> cannot be parsed.
Ok, now I see the problem. Too bad that the ranges and #address/#size
cells need to be parsed from FDT, what makes the code much more complicated,
especially because there is almost no infrastructure for parsing it. I can
resurrect the simple code for parsing FDT from V5 of the patches (see
http://thread.gmane.org/gmane.linux.ports.arm.kernel/259278/focus=259281 ),
but Rob already pointed that such code is quite hard to understand.
> > + linux,default-contiguous-region;
> > + };
> > +
> > + /*
> > + * special region for framebuffer
> > + */
> > + display_region: region@78000000 {
> > + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
> > + reg = <0x78000000 0x800000>;
> > + };
> > +
> > + /*
> > + * special region for multimedia processing devices
> > + */
> > + multimedia_region: region@77000000 {
> > + compatible = "linux,contiguous-memory-region";
> > + reg = <0x77000000 0x4000000>;
> > + };
> > + };
> > + };
> > +
> > + /* ... */
> > +
> > + fb0: fb@12300000 {
> > + status = "okay";
> > + memory-region = <&display_region>;
> > + };
> > +
> > + scaler: scaler@12500000 {
> > + status = "okay";
> > + memory-region = <&multimedia_region>;
> > + };
> > +
> > + codec: codec@12600000 {
> > + status = "okay";
> > + memory-region = <&multimedia_region>;
> > + };
> > +};
> > diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> > index 80e5c13..f7107fa 100644
> > --- a/drivers/of/Kconfig
> > +++ b/drivers/of/Kconfig
> > @@ -80,4 +80,10 @@ config OF_MTD
> > depends on MTD
> > def_bool y
> >
> > +config OF_RESERVED_MEM
> > + depends on DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK)
> > + def_bool y
> > + help
> > + Initialization code for DMA reserved memory
> > +
> > endmenu # OF
> > diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> > index 1f9c0c4..e7e3322 100644
> > --- a/drivers/of/Makefile
> > +++ b/drivers/of/Makefile
> > @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
> > obj-$(CONFIG_OF_PCI) += of_pci.o
> > obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> > obj-$(CONFIG_OF_MTD) += of_mtd.o
> > +obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
> > diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
> > new file mode 100644
> > index 0000000..a754b84
> > --- /dev/null
> > +++ b/drivers/of/of_reserved_mem.c
> > @@ -0,0 +1,175 @@
> > +/*
> > + * Device tree based initialization code for reserved memory.
> > + *
> > + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> > + * http://www.samsung.com
> > + * Author: Marek Szyprowski <m.szyprowski@samsung.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation; either version 2 of the
> > + * License or (at your optional) any later version of the license.
> > + */
> > +
> > +#include <asm/dma-contiguous.h>
> > +
> > +#include <linux/memblock.h>
> > +#include <linux/err.h>
> > +#include <linux/of.h>
> > +#include <linux/of_fdt.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/mm.h>
> > +#include <linux/sizes.h>
> > +#include <linux/mm_types.h>
> > +#include <linux/dma-contiguous.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/of_reserved_mem.h>
> > +
> > +#define MAX_RESERVED_REGIONS 16
>
> Nit: This seems a little arbitrary. I would expect the reserved_mem
> array to be dynamically allocated. I'm not going to force you to change
> this, but it should be revisited with a follow-on patch.
>
> > +struct reserved_mem {
> > + phys_addr_t base;
> > + unsigned long size;
> > + struct cma *cma;
> > + char name[32];
>
> Why is name a fixed size string? And why is it a magic size of 32?
>
> > +};
> > +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
> > +static int reserved_mem_count;
> > +
> > +static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
> > + int depth, void *data)
> > +{
> > + struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
> > + phys_addr_t base, size;
> > + int is_cma, is_reserved;
> > + unsigned long len;
> > + const char *status;
> > + __be32 *prop;
> > +
> > + is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
> > + of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
>
> Nit: Indentation by tabs.
>
> > + is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
> > +
> > + if (!is_reserved && !is_cma) {
> > + /* ignore node and scan next one */
> > + return 0;
> > + }
> > +
> > + status = of_get_flat_dt_prop(node, "status", &len);
> > + if (status && strcmp(status, "okay") != 0) {
> > + /* ignore disabled node nad scan next one */
> > + return 0;
> > + }
> > +
> > + prop = of_get_flat_dt_prop(node, "reg", &len);
> > + if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
> > + sizeof(__be32))) {
> > + pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
> > + uname);
> > + /* ignore node and scan next one */
> > + return 0;
> > + }
> > + base = dt_mem_next_cell(dt_root_addr_cells, &prop);
> > + size = dt_mem_next_cell(dt_root_size_cells, &prop);
> > +
> > + if (!size) {
> > + /* ignore node and scan next one */
> > + return 0;
> > + }
> > +
> > + pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
> > + uname, (unsigned long)base, (unsigned long)size / SZ_1M);
> > +
> > + if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
> > + return -ENOSPC;
> > +
> > + rmem->base = base;
> > + rmem->size = size;
> > + strlcpy(rmem->name, uname, sizeof(rmem->name));
>
> If I'm reading the code correctly, uname is directly from the flattened
> device tree and is safe to keep a pointer to. Can you make rmem->name a
> char* and merely do a rmem->name = uname;?
Ok, I didn't know it is safe to keep a pointer to FDT.
> > +
> > + if (is_cma) {
> > + struct cma *cma;
> > + if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
> > + rmem->cma = cma;
> > + reserved_mem_count++;
> > + if (of_get_flat_dt_prop(node,
> > + "linux,default-contiguous-region",
> > + NULL))
> > + dma_contiguous_set_default(cma);
> > + }
> > + } else if (is_reserved) {
> > + if (memblock_remove(base, size) == 0)
> > + reserved_mem_count++;
> > + else
> > + pr_err("Failed to reserve memory for %s\n", uname);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static struct reserved_mem *get_dma_memory_region(struct device *dev)
> > +{
> > + struct device_node *node;
> > + const char *name;
> > + int i;
> > +
> > + node = of_parse_phandle(dev->of_node, "memory-region", 0);
> > + if (!node)
> > + return NULL;
> > +
> > + name = kbasename(node->full_name);
> > + for (i = 0; i < reserved_mem_count; i++)
> > + if (strcmp(name, reserved_mem[i].name) == 0)
> > + return &reserved_mem[i];
> > + return NULL;
> > +}
> > +
> > +/**
> > + * of_reserved_mem_device_init() - assign reserved memory region to given device
> > + *
> > + * This function assign memory region pointed by "memory-region" device tree
> > + * property to the given device.
> > + */
> > +void of_reserved_mem_device_init(struct device *dev)
> > +{
> > + struct reserved_mem *region = get_dma_memory_region(dev);
> > + if (!region)
> > + return;
> > +
> > + if (region->cma) {
> > + dev_set_cma_area(dev, region->cma);
> > + pr_info("Assigned CMA %s to %s device\n", region->name,
> > + dev_name(dev));
> > + } else {
> > + if (dma_declare_coherent_memory(dev, region->base, region->base,
> > + region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
> > + pr_info("Declared reserved memory %s to %s device\n",
> > + region->name, dev_name(dev));
> > + }
> > +}
> > +
> > +/**
> > + * of_reserved_mem_device_release() - release reserved memory device structures
> > + *
> > + * This function releases structures allocated for memory region handling for
> > + * the given device.
> > + */
> > +void of_reserved_mem_device_release(struct device *dev)
> > +{
> > + struct reserved_mem *region = get_dma_memory_region(dev);
> > + if (!region && !region->cma)
> > + dma_release_declared_memory(dev);
> > +}
> > +
> > +/**
> > + * early_init_dt_scan_reserved_mem() - create reserved memory regions
> > + *
> > + * This function grabs memory from early allocator for device exclusive use
> > + * defined in device tree structures. It should be called by arch specific code
> > + * once the early allocator (memblock) has been activated and all other
> > + * subsystems have already allocated/reserved memory.
> > + */
> > +void __init early_init_dt_scan_reserved_mem(void)
> > +{
> > + of_scan_flat_dt_by_path("/memory/reserved-memory",
> > + fdt_scan_reserved_mem, NULL);
> > +}
> > diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> > index e0a6514..eeca8a5 100644
> > --- a/drivers/of/platform.c
> > +++ b/drivers/of/platform.c
> > @@ -21,6 +21,7 @@
> > #include <linux/of_device.h>
> > #include <linux/of_irq.h>
> > #include <linux/of_platform.h>
> > +#include <linux/of_reserved_mem.h>
> > #include <linux/platform_device.h>
> >
> > const struct of_device_id of_default_bus_match_table[] = {
> > @@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
> > dev->dev.bus = &platform_bus_type;
> > dev->dev.platform_data = platform_data;
> >
> > + of_reserved_mem_device_init(&dev->dev);
> > +
> > /* We do not fill the DMA ops for platform devices by default.
> > * This is currently the responsibility of the platform code
> > * to do such, possibly using a device notifier
> > @@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
> >
> > if (of_device_add(dev) != 0) {
> > platform_device_put(dev);
> > + of_reserved_mem_device_release(&dev->dev);
> > return NULL;
> > }
> >
> > diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
> > new file mode 100644
> > index 0000000..c841282
> > --- /dev/null
> > +++ b/include/linux/of_reserved_mem.h
> > @@ -0,0 +1,14 @@
> > +#ifndef __OF_RESERVED_MEM_H
> > +#define __OF_RESERVED_MEM_H
> > +
> > +#ifdef CONFIG_OF_RESERVED_MEM
> > +void of_reserved_mem_device_init(struct device *dev);
> > +void of_reserved_mem_device_release(struct device *dev);
> > +void early_init_dt_scan_reserved_mem(void);
> > +#else
> > +static inline void of_reserved_mem_device_init(struct device *dev) { }
> > +static inline void of_reserved_mem_device_release(struct device *dev) { }
> > +static inline void early_init_dt_scan_reserved_mem(void) { }
> > +#endif
> > +
> > +#endif /* __OF_RESERVED_MEM_H */
> > --
> > 1.7.9.5
Best regards
--
Marek Szyprowski
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-08-30 12:39 ` Marek Szyprowski
@ 2013-08-30 20:26 ` Kumar Gala
2013-09-09 16:01 ` Grant Likely
2013-09-09 13:05 ` Grant Likely
1 sibling, 1 reply; 27+ messages in thread
From: Kumar Gala @ 2013-08-30 20:26 UTC (permalink / raw)
To: Marek Szyprowski
Cc: Mark Rutland, linaro-mm-sig, Laura Abbott, Pawel Moll,
Arnd Bergmann, devicetree, Tomasz Figa, Stephen Warren,
Tomasz Figa, Michal Nazarewicz, Grant Likely, Marc, Kyungmin Park,
Sylwester Nawrocki, Olof Johansson, Nishanth Peethambaran,
Sascha Hauer, linux-arm-kernel, Ian Campbell
On Aug 30, 2013, at 7:39 AM, Marek Szyprowski wrote:
> Hello,
>
> On 8/30/2013 12:46 AM, Grant Likely wrote:
>> On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>> > This patch adds device tree support for contiguous and reserved memory
>> > regions defined in device tree.
>> >
>> > Large memory blocks can be reliably reserved only during early boot.
>> > This must happen before the whole memory management subsystem is
>> > initialized, because we need to ensure that the given contiguous blocks
>> > are not yet allocated by kernel. Also it must happen before kernel
>> > mappings for the whole low memory are created, to ensure that there will
>> > be no mappings (for reserved blocks) or mapping with special properties
>> > can be created (for CMA blocks). This all happens before device tree
>> > structures are unflattened, so we need to get reserved memory layout
>> > directly from fdt.
>> >
>> > Later, those reserved memory regions are assigned to devices on each
>> > device structure initialization.
>> >
>> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> > Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> > Acked-by: Michal Nazarewicz <mina86@mina86.com>
>> > Acked-by: Tomasz Figa <t.figa@samsung.com>
>> > Acked-by: Stephen Warren <swarren@nvidia.com>
>> > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
>>
>> Hi Marek,
>>
>> This patch is in good shape, but I have some comments below and a few
>> concerns about the binding....
>>
>> g.
>>
>> > ---
>> > Documentation/devicetree/bindings/memory.txt | 168 +++++++++++++++++++++++++
>> > drivers/of/Kconfig | 6 +
>> > drivers/of/Makefile | 1 +
>> > drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++
>> > drivers/of/platform.c | 4 +
>> > include/linux/of_reserved_mem.h | 14 +++
>> > 6 files changed, 368 insertions(+)
>> > create mode 100644 Documentation/devicetree/bindings/memory.txt
>> > create mode 100644 drivers/of/of_reserved_mem.c
>> > create mode 100644 include/linux/of_reserved_mem.h
>> >
>> > diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
>> > new file mode 100644
>> > index 0000000..eb24693
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/memory.txt
>> > @@ -0,0 +1,168 @@
>> > +*** Memory binding ***
>> > +
>> > +The /memory node provides basic information about the address and size
>> > +of the physical memory. This node is usually filled or updated by the
>> > +bootloader, depending on the actual memory configuration of the given
>> > +hardware.
>> > +
>> > +The memory layout is described by the following node:
>> > +
>> > +/ {
>> > + #address-cells = <(n)>;
>> > + #size-cells = <(m)>;
>> > + memory {
>> > + device_type = "memory";
>> > + reg = <(baseaddr1) (size1)
>> > + (baseaddr2) (size2)
>> > + ...
>> > + (baseaddrN) (sizeN)>;
>> > + };
>> > + ...
>> > +};
>> > +
>> > +A memory node follows the typical device tree rules for "reg" property:
>> > +n: number of cells used to store base address value
>> > +m: number of cells used to store size value
>> > +baseaddrX: defines a base address of the defined memory bank
>> > +sizeX: the size of the defined memory bank
>> > +
>> > +
>> > +More than one memory bank can be defined.
>> > +
>> > +
>> > +*** Reserved memory regions ***
>> > +
>> > +In /memory/reserved-memory node one can create child nodes describing
>> > +particular reserved (excluded from normal use) memory regions. Such
>> > +memory regions are usually designed for the special usage by various
>> > +device drivers. A good example are contiguous memory allocations or
>> > +memory sharing with other operating system on the same hardware board.
>> > +Those special memory regions might depend on the board configuration and
>> > +devices used on the target system.
>> > +
>> > +Parameters for each memory region can be encoded into the device tree
>> > +with the following convention:
>> > +
>> > +[(label):] (name) {
>> > + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
>> > + reg = <(address) (size)>;
>> > + (linux,default-contiguous-region);
>> > +};
>> > +
>> > +compatible: one or more of:
>>
>> It's unclear what the meaning of having both values means for the
>> kernel. Does it mean the regions is sharable with the kernel or not? I
>> would think they are mutually exclusive.
>
> I consider CMA ("linux,contiguous-memory-region") as a special case of the
> reserved memory driver. The main advantage is the ability of sharing the memory
> with the system instead of just allocating it from the carved out memory
> region. From the device and hardware perspective there is no difference
> if the buffer comes from CMA or reserved memory. However if you insist, I
> can change it to something different, like "shareable-memory-region".
>
> Specifying both compatible values would let kernel to bind the more specific
> driver (cma, if available) over the generic one (simple reserved memory
> carve-out allocator based on dma_coherent).
>
>> > + - "linux,contiguous-memory-region" - enables binding of this
>> > + region to Contiguous Memory Allocator (special region for
>> > + contiguous memory allocations, shared with movable system
>> > + memory, Linux kernel-specific).
>>
>> As mentioned in the older thread, you can drop the 'linux,' prefix here.
>> Perhaps something like "shareable-memory-region" or merely
>> "memory-region". It is reasonable for any kernel (not just Linux) to use
>> marked regions for movable pages until it gets requested by a driver, in
>> which case a rather generic "memory-region" makes a lot of sense as a
>> name.
>>
>> > + - "reserved-memory-region" - compatibility is defined, given
>> > + region is assigned for exclusive usage for by the respective
>> > + devices.
>>
>> BTW, just so you're aware there is already a binding for marking regions
>> as reserved. It was recently added to arch/powerpc/kernel/prom.c.
>> Unfortunately it doesn't look like it got documented. Search for
>> "reserved-ranges". However, I don't think it blocks your work here. That
>> binding doesn't provide any way for matching devices to reserved ranges.
>> It is only for telling the kernel "hands of that memory".
>
> ok, good to know.
So I think the most generic compatible should effectively be the same as 'reserved-ranges', ie this region shouldn't be touched by the kernel.
Than we can build on top of that with more specific compatibles.
I have examples from FSL networking SoCs where we would carve out memory for backing storage managed completely by the HW and Linux wouldn't need to touch it, however we might have a "fsl,qman-backing-store" compat encase we might want some debug code in linux to look at the region of memory.
I've got examples at qualcomm where we have shared data structures in specific memory regions between different processors that aren't cache coherent, so want the memory not to be marked as cacheable by Linux when it accesses it. Again we'd have a "qcom,smem" prop on top of the "reserved-memory-region".
So I'd like what we come up with to handle these use cases in addition to CMA.
Maybe, "reserved-memory-region" should be "carved-out-memory-region". To say this region isn't for general OS usage, than compat's on top of that might imply more meaning.
>> > +
>> > +reg: standard property defining the base address and size of
>> > + the memory region
>> > +
>> > +linux,default-contiguous-region: property indicating that the region
>> > + is the default region for all contiguous memory
>> > + allocations, Linux specific (optional)
>> > +
>> > +It is optional to specify the base address, so if one wants to use
>> > +autoconfiguration of the base address, '0' can be specified as a base
>> > +address in the 'reg' property.
>>
>> I don't understand this. What does autoconfiguration of the base address
>> actually do? If this is intended to dynamically allocate a region of RAM
>> for contiguous allocations, then don't use 'reg'. Use a different
>> property that only specifies the size.
>
> Ok, I will try to make a patch which removes special 'zero' base address
> handling and adds separate 'size' property for automatically configured
> regions.
>
>> > +The /memory/reserved-memory node must contain the same #address-cells
>> > +and #size-cells value as the root node.
>>
>> That seems to be an arbitrary restriction. Why does the reserved-memory
>> node need to have exactly the same #address/size values? The 'reg'
>> property binding quite easily handles different values at different
>> levels of the tree. More below....
>
> Does it really makes sense to have such configuration with different
> #address-cells/#size-cells than the root memory node?
>
>> > +/ {
>> > + #address-cells = <1>;
>> > + #size-cells = <1>;
>> > +
>> > + /* ... */
>> > +
>> > + memory {
>> > + reg = <0x40000000 0x10000000
>> > + 0x50000000 0x10000000
>> > + 0x60000000 0x10000000
>> > + 0x70000000 0x10000000>;
>> > +
>> > + reserved-memory {
>> > + #address-cells = <1>;
>> > + #size-cells = <1>;
>> > +
>> > + /*
>> > + * global autoconfigured region for contiguous allocations
>> > + * (used only with Contiguous Memory Allocator)
>> > + */
>> > + contig_region@0 {
>>
>> I would expect this to be "region@0", not "contig_region". Also, the '_'
>> character is strongly discouraged in node names.
>>
>> > + compatible = "linux,contiguous-memory-region";
>> > + reg = <0x0 0x4000000>;
>>
>> As written, this example tree is abusing the 'reg' binding. Whenever a
>> node has a mappable 'reg' propertie, then all of the parent nodes above
>> it need to have 'ranges' properties. In this case it is pretty easy to
>> fix by simply adding "ranges;" to the reserved-memory and memory nodes.
>> An empty ranges property simply means that all addresses are 1:1 mapped
>> if #address/size are the same between each parent/child.
>>
>> The documentation above should specify that both memory and
>> reserved-memory need to have 'ranges', but can suggest that the best
>> use-case is for ranges to be empty.
>>
>> I mentioned above that #address/#size can actually be different. If
>> someone wants to do that, then they need to have a fully specified
>> ranges property that declares the mapping from one address space to
>> another.
>>
>> I'm okay with the implementation as it currently stands, but only if you
>> make it test for the presence of an empty ranges property. If ranges is
>> missing, or if it has data in it then it should throw an error that it
>> cannot be parsed.
>
> Ok, now I see the problem. Too bad that the ranges and #address/#size
> cells need to be parsed from FDT, what makes the code much more complicated,
> especially because there is almost no infrastructure for parsing it. I can
> resurrect the simple code for parsing FDT from V5 of the patches (see
> http://thread.gmane.org/gmane.linux.ports.arm.kernel/259278/focus=259281 ),
> but Rob already pointed that such code is quite hard to understand.
>
>> > + linux,default-contiguous-region;
>> > + };
>> > +
>> > + /*
>> > + * special region for framebuffer
>> > + */
>> > + display_region: region@78000000 {
>> > + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
>> > + reg = <0x78000000 0x800000>;
>> > + };
>> > +
>> > + /*
>> > + * special region for multimedia processing devices
>> > + */
>> > + multimedia_region: region@77000000 {
>> > + compatible = "linux,contiguous-memory-region";
>> > + reg = <0x77000000 0x4000000>;
>> > + };
>> > + };
>> > + };
>> > +
>> > + /* ... */
>> > +
>> > + fb0: fb@12300000 {
>> > + status = "okay";
>> > + memory-region = <&display_region>;
>> > + };
>> > +
>> > + scaler: scaler@12500000 {
>> > + status = "okay";
>> > + memory-region = <&multimedia_region>;
>> > + };
>> > +
>> > + codec: codec@12600000 {
>> > + status = "okay";
>> > + memory-region = <&multimedia_region>;
>> > + };
>> > +};
>> > diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
>> > index 80e5c13..f7107fa 100644
>> > --- a/drivers/of/Kconfig
>> > +++ b/drivers/of/Kconfig
>> > @@ -80,4 +80,10 @@ config OF_MTD
>> > depends on MTD
>> > def_bool y
>> >
>> > +config OF_RESERVED_MEM
>> > + depends on DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK)
>> > + def_bool y
>> > + help
>> > + Initialization code for DMA reserved memory
>> > +
>> > endmenu # OF
>> > diff --git a/drivers/of/Makefile b/drivers/of/Makefile
>> > index 1f9c0c4..e7e3322 100644
>> > --- a/drivers/of/Makefile
>> > +++ b/drivers/of/Makefile
>> > @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
>> > obj-$(CONFIG_OF_PCI) += of_pci.o
>> > obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
>> > obj-$(CONFIG_OF_MTD) += of_mtd.o
>> > +obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
>> > diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
>> > new file mode 100644
>> > index 0000000..a754b84
>> > --- /dev/null
>> > +++ b/drivers/of/of_reserved_mem.c
>> > @@ -0,0 +1,175 @@
>> > +/*
>> > + * Device tree based initialization code for reserved memory.
>> > + *
>> > + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
>> > + * http://www.samsung.com
>> > + * Author: Marek Szyprowski <m.szyprowski@samsung.com>
>> > + *
>> > + * This program is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU General Public License as
>> > + * published by the Free Software Foundation; either version 2 of the
>> > + * License or (at your optional) any later version of the license.
>> > + */
>> > +
>> > +#include <asm/dma-contiguous.h>
>> > +
>> > +#include <linux/memblock.h>
>> > +#include <linux/err.h>
>> > +#include <linux/of.h>
>> > +#include <linux/of_fdt.h>
>> > +#include <linux/of_platform.h>
>> > +#include <linux/mm.h>
>> > +#include <linux/sizes.h>
>> > +#include <linux/mm_types.h>
>> > +#include <linux/dma-contiguous.h>
>> > +#include <linux/dma-mapping.h>
>> > +#include <linux/of_reserved_mem.h>
>> > +
>> > +#define MAX_RESERVED_REGIONS 16
>>
>> Nit: This seems a little arbitrary. I would expect the reserved_mem
>> array to be dynamically allocated. I'm not going to force you to change
>> this, but it should be revisited with a follow-on patch.
>>
>> > +struct reserved_mem {
>> > + phys_addr_t base;
>> > + unsigned long size;
>> > + struct cma *cma;
>> > + char name[32];
>>
>> Why is name a fixed size string? And why is it a magic size of 32?
>>
>> > +};
>> > +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
>> > +static int reserved_mem_count;
>> > +
>> > +static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
>> > + int depth, void *data)
>> > +{
>> > + struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
>> > + phys_addr_t base, size;
>> > + int is_cma, is_reserved;
>> > + unsigned long len;
>> > + const char *status;
>> > + __be32 *prop;
>> > +
>> > + is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
>> > + of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
>>
>> Nit: Indentation by tabs.
>>
>> > + is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
>> > +
>> > + if (!is_reserved && !is_cma) {
>> > + /* ignore node and scan next one */
>> > + return 0;
>> > + }
>> > +
>> > + status = of_get_flat_dt_prop(node, "status", &len);
>> > + if (status && strcmp(status, "okay") != 0) {
>> > + /* ignore disabled node nad scan next one */
>> > + return 0;
>> > + }
>> > +
>> > + prop = of_get_flat_dt_prop(node, "reg", &len);
>> > + if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
>> > + sizeof(__be32))) {
>> > + pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
>> > + uname);
>> > + /* ignore node and scan next one */
>> > + return 0;
>> > + }
>> > + base = dt_mem_next_cell(dt_root_addr_cells, &prop);
>> > + size = dt_mem_next_cell(dt_root_size_cells, &prop);
>> > +
>> > + if (!size) {
>> > + /* ignore node and scan next one */
>> > + return 0;
>> > + }
>> > +
>> > + pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
>> > + uname, (unsigned long)base, (unsigned long)size / SZ_1M);
>> > +
>> > + if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
>> > + return -ENOSPC;
>> > +
>> > + rmem->base = base;
>> > + rmem->size = size;
>> > + strlcpy(rmem->name, uname, sizeof(rmem->name));
>>
>> If I'm reading the code correctly, uname is directly from the flattened
>> device tree and is safe to keep a pointer to. Can you make rmem->name a
>> char* and merely do a rmem->name = uname;?
>
> Ok, I didn't know it is safe to keep a pointer to FDT.
>
>> > +
>> > + if (is_cma) {
>> > + struct cma *cma;
>> > + if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
>> > + rmem->cma = cma;
>> > + reserved_mem_count++;
>> > + if (of_get_flat_dt_prop(node,
>> > + "linux,default-contiguous-region",
>> > + NULL))
>> > + dma_contiguous_set_default(cma);
>> > + }
>> > + } else if (is_reserved) {
>> > + if (memblock_remove(base, size) == 0)
>> > + reserved_mem_count++;
>> > + else
>> > + pr_err("Failed to reserve memory for %s\n", uname);
>> > + }
>> > +
>> > + return 0;
>> > +}
>> > +
>> > +static struct reserved_mem *get_dma_memory_region(struct device *dev)
>> > +{
>> > + struct device_node *node;
>> > + const char *name;
>> > + int i;
>> > +
>> > + node = of_parse_phandle(dev->of_node, "memory-region", 0);
>> > + if (!node)
>> > + return NULL;
>> > +
>> > + name = kbasename(node->full_name);
>> > + for (i = 0; i < reserved_mem_count; i++)
>> > + if (strcmp(name, reserved_mem[i].name) == 0)
>> > + return &reserved_mem[i];
>> > + return NULL;
>> > +}
>> > +
>> > +/**
>> > + * of_reserved_mem_device_init() - assign reserved memory region to given device
>> > + *
>> > + * This function assign memory region pointed by "memory-region" device tree
>> > + * property to the given device.
>> > + */
>> > +void of_reserved_mem_device_init(struct device *dev)
>> > +{
>> > + struct reserved_mem *region = get_dma_memory_region(dev);
>> > + if (!region)
>> > + return;
>> > +
>> > + if (region->cma) {
>> > + dev_set_cma_area(dev, region->cma);
>> > + pr_info("Assigned CMA %s to %s device\n", region->name,
>> > + dev_name(dev));
>> > + } else {
>> > + if (dma_declare_coherent_memory(dev, region->base, region->base,
>> > + region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
>> > + pr_info("Declared reserved memory %s to %s device\n",
>> > + region->name, dev_name(dev));
>> > + }
>> > +}
>> > +
>> > +/**
>> > + * of_reserved_mem_device_release() - release reserved memory device structures
>> > + *
>> > + * This function releases structures allocated for memory region handling for
>> > + * the given device.
>> > + */
>> > +void of_reserved_mem_device_release(struct device *dev)
>> > +{
>> > + struct reserved_mem *region = get_dma_memory_region(dev);
>> > + if (!region && !region->cma)
>> > + dma_release_declared_memory(dev);
>> > +}
>> > +
>> > +/**
>> > + * early_init_dt_scan_reserved_mem() - create reserved memory regions
>> > + *
>> > + * This function grabs memory from early allocator for device exclusive use
>> > + * defined in device tree structures. It should be called by arch specific code
>> > + * once the early allocator (memblock) has been activated and all other
>> > + * subsystems have already allocated/reserved memory.
>> > + */
>> > +void __init early_init_dt_scan_reserved_mem(void)
>> > +{
>> > + of_scan_flat_dt_by_path("/memory/reserved-memory",
>> > + fdt_scan_reserved_mem, NULL);
>> > +}
>> > diff --git a/drivers/of/platform.c b/drivers/of/platform.c
>> > index e0a6514..eeca8a5 100644
>> > --- a/drivers/of/platform.c
>> > +++ b/drivers/of/platform.c
>> > @@ -21,6 +21,7 @@
>> > #include <linux/of_device.h>
>> > #include <linux/of_irq.h>
>> > #include <linux/of_platform.h>
>> > +#include <linux/of_reserved_mem.h>
>> > #include <linux/platform_device.h>
>> >
>> > const struct of_device_id of_default_bus_match_table[] = {
>> > @@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
>> > dev->dev.bus = &platform_bus_type;
>> > dev->dev.platform_data = platform_data;
>> >
>> > + of_reserved_mem_device_init(&dev->dev);
>> > +
>> > /* We do not fill the DMA ops for platform devices by default.
>> > * This is currently the responsibility of the platform code
>> > * to do such, possibly using a device notifier
>> > @@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
>> >
>> > if (of_device_add(dev) != 0) {
>> > platform_device_put(dev);
>> > + of_reserved_mem_device_release(&dev->dev);
>> > return NULL;
>> > }
>> >
>> > diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
>> > new file mode 100644
>> > index 0000000..c841282
>> > --- /dev/null
>> > +++ b/include/linux/of_reserved_mem.h
>> > @@ -0,0 +1,14 @@
>> > +#ifndef __OF_RESERVED_MEM_H
>> > +#define __OF_RESERVED_MEM_H
>> > +
>> > +#ifdef CONFIG_OF_RESERVED_MEM
>> > +void of_reserved_mem_device_init(struct device *dev);
>> > +void of_reserved_mem_device_release(struct device *dev);
>> > +void early_init_dt_scan_reserved_mem(void);
>> > +#else
>> > +static inline void of_reserved_mem_device_init(struct device *dev) { }
>> > +static inline void of_reserved_mem_device_release(struct device *dev) { }
>> > +static inline void early_init_dt_scan_reserved_mem(void) { }
>> > +#endif
>> > +
>> > +#endif /* __OF_RESERVED_MEM_H */
>> > --
>> > 1.7.9.5
>
> Best regards
> --
> Marek Szyprowski
> Samsung R&D Institute Poland
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-08-30 20:26 ` Kumar Gala
@ 2013-09-09 16:01 ` Grant Likely
2013-09-10 19:53 ` Kumar Gala
` (2 more replies)
0 siblings, 3 replies; 27+ messages in thread
From: Grant Likely @ 2013-09-09 16:01 UTC (permalink / raw)
To: Kumar Gala, Marek Szyprowski
Cc: Mark Rutland, devicetree, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
linaro-mm-sig, Marc, Kyungmin Park, Sylwester Nawrocki,
Olof Johansson, Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel, Ian Campbell
On Fri, 30 Aug 2013 15:26:24 -0500, Kumar Gala <galak@codeaurora.org> wrote:
> On Aug 30, 2013, at 7:39 AM, Marek Szyprowski wrote:
> > On 8/30/2013 12:46 AM, Grant Likely wrote:
> >> On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> >> > + - "reserved-memory-region" - compatibility is defined, given
> >> > + region is assigned for exclusive usage for by the respective
> >> > + devices.
> >>
> >> BTW, just so you're aware there is already a binding for marking regions
> >> as reserved. It was recently added to arch/powerpc/kernel/prom.c.
> >> Unfortunately it doesn't look like it got documented. Search for
> >> "reserved-ranges". However, I don't think it blocks your work here. That
> >> binding doesn't provide any way for matching devices to reserved ranges.
> >> It is only for telling the kernel "hands of that memory".
> >
> > ok, good to know.
>
> So I think the most generic compatible should effectively be the same
> as 'reserved-ranges', ie this region shouldn't be touched by the
> kernel.
>
> Than we can build on top of that with more specific compatibles.
>
> I have examples from FSL networking SoCs where we would carve out
> memory for backing storage managed completely by the HW and Linux
> wouldn't need to touch it, however we might have a
> "fsl,qman-backing-store" compat encase we might want some debug code
> in linux to look at the region of memory.
>
> I've got examples at qualcomm where we have shared data structures in
> specific memory regions between different processors that aren't cache
> coherent, so want the memory not to be marked as cacheable by Linux
> when it accesses it. Again we'd have a "qcom,smem" prop on top of the
> "reserved-memory-region".
I think that is a reasonable approach, and works really well for regions
associated with specific hardware because the hardware driver can be
responsible for wiring it up to CMA or manage the region directly.
Whatever the driver desires to do.
It still remains what to do for generic regions that any device can use.
As I've previously said, I don't like calling out "CMA" specifically in
the compatible property because that happens to be a Linux
implementation specific details. Two years from now someone may propose
a new allocator that should take over what used to be handled by CMA
(kind of like how CMA may end up taking over from ION)....
Alright, I've thought about it some more and it probably does make sense
to use an additional compatible string. Marek originally suggested
"linux,contiguous-memory-region". I later suggested "shareable-memory-region",
but that's actually a worse name because it doesn't have any reference
to what the region is for (I was fixating on the kernel being able to
use unallocated pages; but that is also an implementation detail). I
exercise my right to change my mind and agree that contiguous is
appropriate here. But instead of calling out the contiguous allocator,
the binding should specifically lay out the usage model for these
regions. I would change the contiguous-memory binding to state the
following:
Contiguous-memory is a region of general purpose memory from
which large buffers of contiguous memory can be allocated.
Contiguous buffers are often used for DMA buffers. The operating
system may use the memory for any purpose, but must immediately
release the pages if a contiguous buffer is required.
So the way I read things, the current proposal would be:
The generic form for do-not-touch memory:
compatible = "reserved-memory";
- I've dropped '-region' because I think it is redundant
- The kernel will not make use of this memory except for when a driver picks it up
For contiguous memory:
compatible = "contiguous-memory", "reserved-memory"
For contiguous memory that Linux will use by default if a specific
region isn't specified.
compatible = "contiguous-memory", "reserved-memory"
linux,default-contiguous-region;
- I stuck with a linux, prefix here because I haven't come up with a
non-linux way to describe this.
Memory that specific hardware can pick up:
compatible = "qcom,smem", "reserved-memory"
Nodes with a 'size' property and without a 'reg' property need to have a
region allocated and reserved. The allocated region needs to be cached
somewhere. We could create a data structure for tracking the reserved
regions, or could write it in directly. While I shudder at the thought of
modifying the device tree at runtime by the kernel, it might just be the
sanest implementation at this time. I'd like to see what the
implementation looks like. (Since this is potentially controversial, I
would recommend implementing the exact regions in on patch, and add
dynamically allocated regions as a follow-up patch)
As far as proper implementation is concerned, I think it should be
explicit in the binding that the kernel should automatically exclude
anything under the reserved-memory node, regardless of the compatible
value. Merely being a child of the reserved-memory node immediately
means that it is a reserved memory region.
g.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-09-09 16:01 ` Grant Likely
@ 2013-09-10 19:53 ` Kumar Gala
[not found] ` <BA65D7E3-8C15-4B44-95E2-E5DC862DDDE0-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2013-09-12 18:22 ` Kumar Gala
2013-09-16 7:12 ` Marek Szyprowski
2 siblings, 1 reply; 27+ messages in thread
From: Kumar Gala @ 2013-09-10 19:53 UTC (permalink / raw)
To: Grant Likely
Cc: Mark Rutland, devicetree, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
linaro-mm-sig, Marc, Kyungmin Park, Sylwester Nawrocki,
Olof Johansson, Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel, Marek Szyprowski
On Sep 9, 2013, at 11:01 AM, Grant Likely wrote:
> On Fri, 30 Aug 2013 15:26:24 -0500, Kumar Gala <galak@codeaurora.org> wrote:
>> On Aug 30, 2013, at 7:39 AM, Marek Szyprowski wrote:
>>> On 8/30/2013 12:46 AM, Grant Likely wrote:
>>>> On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>>>>> + - "reserved-memory-region" - compatibility is defined, given
>>>>> + region is assigned for exclusive usage for by the respective
>>>>> + devices.
>>>>
>>>> BTW, just so you're aware there is already a binding for marking regions
>>>> as reserved. It was recently added to arch/powerpc/kernel/prom.c.
>>>> Unfortunately it doesn't look like it got documented. Search for
>>>> "reserved-ranges". However, I don't think it blocks your work here. That
>>>> binding doesn't provide any way for matching devices to reserved ranges.
>>>> It is only for telling the kernel "hands of that memory".
>>>
>>> ok, good to know.
>>
>> So I think the most generic compatible should effectively be the same
>> as 'reserved-ranges', ie this region shouldn't be touched by the
>> kernel.
>>
>> Than we can build on top of that with more specific compatibles.
>>
>> I have examples from FSL networking SoCs where we would carve out
>> memory for backing storage managed completely by the HW and Linux
>> wouldn't need to touch it, however we might have a
>> "fsl,qman-backing-store" compat encase we might want some debug code
>> in linux to look at the region of memory.
>>
>> I've got examples at qualcomm where we have shared data structures in
>> specific memory regions between different processors that aren't cache
>> coherent, so want the memory not to be marked as cacheable by Linux
>> when it accesses it. Again we'd have a "qcom,smem" prop on top of the
>> "reserved-memory-region".
>
> I think that is a reasonable approach, and works really well for regions
> associated with specific hardware because the hardware driver can be
> responsible for wiring it up to CMA or manage the region directly.
> Whatever the driver desires to do.
>
> It still remains what to do for generic regions that any device can use.
> As I've previously said, I don't like calling out "CMA" specifically in
> the compatible property because that happens to be a Linux
> implementation specific details. Two years from now someone may propose
> a new allocator that should take over what used to be handled by CMA
> (kind of like how CMA may end up taking over from ION)....
>
> Alright, I've thought about it some more and it probably does make sense
> to use an additional compatible string. Marek originally suggested
> "linux,contiguous-memory-region". I later suggested "shareable-memory-region",
> but that's actually a worse name because it doesn't have any reference
> to what the region is for (I was fixating on the kernel being able to
> use unallocated pages; but that is also an implementation detail). I
> exercise my right to change my mind and agree that contiguous is
> appropriate here. But instead of calling out the contiguous allocator,
> the binding should specifically lay out the usage model for these
> regions. I would change the contiguous-memory binding to state the
> following:
> Contiguous-memory is a region of general purpose memory from
> which large buffers of contiguous memory can be allocated.
> Contiguous buffers are often used for DMA buffers. The operating
> system may use the memory for any purpose, but must immediately
> release the pages if a contiguous buffer is required.
>
> So the way I read things, the current proposal would be:
>
> The generic form for do-not-touch memory:
> compatible = "reserved-memory";
> - I've dropped '-region' because I think it is redundant
> - The kernel will not make use of this memory except for when a driver picks it up
>
> For contiguous memory:
> compatible = "contiguous-memory", "reserved-memory"
Hmm.., what's an example of a generic use of this compatible set that isn't linux/CMA specific?
> For contiguous memory that Linux will use by default if a specific
> region isn't specified.
> compatible = "contiguous-memory", "reserved-memory"
> linux,default-contiguous-region;
> - I stuck with a linux, prefix here because I haven't come up with a
> non-linux way to describe this.
>
> Memory that specific hardware can pick up:
> compatible = "qcom,smem", "reserved-memory"
>
> Nodes with a 'size' property and without a 'reg' property need to have a
> region allocated and reserved. The allocated region needs to be cached
> somewhere. We could create a data structure for tracking the reserved
> regions, or could write it in directly. While I shudder at the thought of
> modifying the device tree at runtime by the kernel, it might just be the
> sanest implementation at this time. I'd like to see what the
> implementation looks like. (Since this is potentially controversial, I
> would recommend implementing the exact regions in on patch, and add
> dynamically allocated regions as a follow-up patch)
curious, what's the example for this situation of not having a 'reg' but having a size?
>
> As far as proper implementation is concerned, I think it should be
> explicit in the binding that the kernel should automatically exclude
> anything under the reserved-memory node, regardless of the compatible
> value. Merely being a child of the reserved-memory node immediately
> means that it is a reserved memory region.
>
> g.
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-09-09 16:01 ` Grant Likely
2013-09-10 19:53 ` Kumar Gala
@ 2013-09-12 18:22 ` Kumar Gala
[not found] ` <13185491-534E-4547-8412-5704346EA2DC-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2013-09-16 7:12 ` Marek Szyprowski
2 siblings, 1 reply; 27+ messages in thread
From: Kumar Gala @ 2013-09-12 18:22 UTC (permalink / raw)
To: Grant Likely
Cc: Mark Rutland, devicetree, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
linaro-mm-sig, Marc, Kyungmin Park, Sylwester Nawrocki,
Olof Johansson, Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel, Marek Szyprowski
On Sep 9, 2013, at 11:01 AM, Grant Likely wrote:
>
> The generic form for do-not-touch memory:
> compatible = "reserved-memory";
> - I've dropped '-region' because I think it is redundant
> - The kernel will not make use of this memory except for when a driver picks it up
>
> For contiguous memory:
> compatible = "contiguous-memory", "reserved-memory"
Should the phandle references still be 'memory-region' ?
- k
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-09-09 16:01 ` Grant Likely
2013-09-10 19:53 ` Kumar Gala
2013-09-12 18:22 ` Kumar Gala
@ 2013-09-16 7:12 ` Marek Szyprowski
2013-09-16 7:25 ` Benjamin Herrenschmidt
[not found] ` <5236AF64.80607-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2 siblings, 2 replies; 27+ messages in thread
From: Marek Szyprowski @ 2013-09-16 7:12 UTC (permalink / raw)
To: Grant Likely
Cc: Kumar Gala, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linaro-mm-sig-cunTk1MwBs8s++Sfvej+rw,
devicetree-u79uwXL29TY76Z2rM5mHXA, Kyungmin Park, Arnd Bergmann,
Michal Nazarewicz, Tomasz Figa, Sylwester Nawrocki, Sascha Hauer,
Laura Abbott, Rob Herring, Olof Johansson, Pawel Moll,
Mark Rutland, Stephen Warren, Ian Campbell, Tomasz Figa,
Nishanth Peethambaran, Marc, Benjamin Herrenschmidt
Hello,
On 9/9/2013 6:01 PM, Grant Likely wrote:
> On Fri, 30 Aug 2013 15:26:24 -0500, Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org> wrote:
> > On Aug 30, 2013, at 7:39 AM, Marek Szyprowski wrote:
> > > On 8/30/2013 12:46 AM, Grant Likely wrote:
> > >> On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
> > >> > + - "reserved-memory-region" - compatibility is defined, given
> > >> > + region is assigned for exclusive usage for by the respective
> > >> > + devices.
> > >>
> > >> BTW, just so you're aware there is already a binding for marking regions
> > >> as reserved. It was recently added to arch/powerpc/kernel/prom.c.
> > >> Unfortunately it doesn't look like it got documented. Search for
> > >> "reserved-ranges". However, I don't think it blocks your work here. That
> > >> binding doesn't provide any way for matching devices to reserved ranges.
> > >> It is only for telling the kernel "hands of that memory".
> > >
> > > ok, good to know.
> >
> > So I think the most generic compatible should effectively be the same
> > as 'reserved-ranges', ie this region shouldn't be touched by the
> > kernel.
> >
> > Than we can build on top of that with more specific compatibles.
> >
> > I have examples from FSL networking SoCs where we would carve out
> > memory for backing storage managed completely by the HW and Linux
> > wouldn't need to touch it, however we might have a
> > "fsl,qman-backing-store" compat encase we might want some debug code
> > in linux to look at the region of memory.
> >
> > I've got examples at qualcomm where we have shared data structures in
> > specific memory regions between different processors that aren't cache
> > coherent, so want the memory not to be marked as cacheable by Linux
> > when it accesses it. Again we'd have a "qcom,smem" prop on top of the
> > "reserved-memory-region".
>
> I think that is a reasonable approach, and works really well for regions
> associated with specific hardware because the hardware driver can be
> responsible for wiring it up to CMA or manage the region directly.
> Whatever the driver desires to do.
>
> It still remains what to do for generic regions that any device can use.
> As I've previously said, I don't like calling out "CMA" specifically in
> the compatible property because that happens to be a Linux
> implementation specific details. Two years from now someone may propose
> a new allocator that should take over what used to be handled by CMA
> (kind of like how CMA may end up taking over from ION)....
>
> Alright, I've thought about it some more and it probably does make sense
> to use an additional compatible string. Marek originally suggested
> "linux,contiguous-memory-region". I later suggested "shareable-memory-region",
> but that's actually a worse name because it doesn't have any reference
> to what the region is for (I was fixating on the kernel being able to
> use unallocated pages; but that is also an implementation detail). I
> exercise my right to change my mind and agree that contiguous is
> appropriate here. But instead of calling out the contiguous allocator,
> the binding should specifically lay out the usage model for these
> regions. I would change the contiguous-memory binding to state the
> following:
> Contiguous-memory is a region of general purpose memory from
> which large buffers of contiguous memory can be allocated.
> Contiguous buffers are often used for DMA buffers. The operating
> system may use the memory for any purpose, but must immediately
> release the pages if a contiguous buffer is required.
>
> So the way I read things, the current proposal would be:
>
> The generic form for do-not-touch memory:
> compatible = "reserved-memory";
> - I've dropped '-region' because I think it is redundant
> - The kernel will not make use of this memory except for when a driver picks it up
>
> For contiguous memory:
> compatible = "contiguous-memory", "reserved-memory"
>
> For contiguous memory that Linux will use by default if a specific
> region isn't specified.
> compatible = "contiguous-memory", "reserved-memory"
> linux,default-contiguous-region;
> - I stuck with a linux, prefix here because I haven't come up with a
> non-linux way to describe this.
>
> Memory that specific hardware can pick up:
> compatible = "qcom,smem", "reserved-memory"
>
> Nodes with a 'size' property and without a 'reg' property need to have a
> region allocated and reserved. The allocated region needs to be cached
> somewhere. We could create a data structure for tracking the reserved
> regions, or could write it in directly. While I shudder at the thought of
> modifying the device tree at runtime by the kernel, it might just be the
> sanest implementation at this time. I'd like to see what the
> implementation looks like. (Since this is potentially controversial, I
> would recommend implementing the exact regions in on patch, and add
> dynamically allocated regions as a follow-up patch)
>
> As far as proper implementation is concerned, I think it should be
> explicit in the binding that the kernel should automatically exclude
> anything under the reserved-memory node, regardless of the compatible
> value. Merely being a child of the reserved-memory node immediately
> means that it is a reserved memory region.
It looks that my proposal for the reserved memory nodes causes much more
controversy than I expected when I've sent a pull request to Linus:
https://lkml.org/lkml/2013/9/15/151
http://www.spinics.net/lists/arm-kernel/msg273548.html
Fixing those issues requires further discussion. Frankly, right now I
really have no idea which way should I go. The /reserved-ranges node seems
to be easy to match particular reserved memory region with a given device.
I'm also not really convinced if it makes sense to add a code for finding
and matching a reserved memory region to every device driver, which might
need it. I would really like to get some more feedback on the Ben's
comment.
In any case, the code will also change significantly, so I assume that the
best, what can be done now is to revert the current version and start from
the scratch with a new, complete proposal.
Best regards
--
Marek Szyprowski
Samsung R&D Institute Poland
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-09-16 7:12 ` Marek Szyprowski
@ 2013-09-16 7:25 ` Benjamin Herrenschmidt
2013-09-16 13:43 ` Grant Likely
[not found] ` <5236AF64.80607-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
1 sibling, 1 reply; 27+ messages in thread
From: Benjamin Herrenschmidt @ 2013-09-16 7:25 UTC (permalink / raw)
To: Marek Szyprowski
Cc: Mark Rutland, linaro-mm-sig, Laura Abbott, Pawel Moll,
Arnd Bergmann, devicetree, Tomasz Figa, Stephen Warren,
Tomasz Figa, Michal Nazarewicz, Grant Likely, Marc, Kyungmin Park,
Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Nishanth Peethambaran, Sascha Hauer, linux-arm-kernel,
Ian Campbell
On Mon, 2013-09-16 at 09:12 +0200, Marek Szyprowski wrote:
>
> Fixing those issues requires further discussion. Frankly, right now I
> really have no idea which way should I go. The /reserved-ranges node seems
> to be easy to match particular reserved memory region with a given device.
> I'm also not really convinced if it makes sense to add a code for finding
> and matching a reserved memory region to every device driver, which might
> need it. I would really like to get some more feedback on the Ben's
> comment.
>
> In any case, the code will also change significantly, so I assume that the
> best, what can be done now is to revert the current version and start from
> the scratch with a new, complete proposal.
Yes, let's do that. I will try to help. It shouldn't be that a big deal.
Worst case, how many of us will meet physically next month in Edinburgh ?
Cheers,
Ben.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-09-16 7:25 ` Benjamin Herrenschmidt
@ 2013-09-16 13:43 ` Grant Likely
[not found] ` <CACxGe6s_JY7GpjXN7gwADV0oE+BnQfJX4AaXTZURumfepa3NiA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 27+ messages in thread
From: Grant Likely @ 2013-09-16 13:43 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Marek Szyprowski, Mark Rutland,
linaro-mm-sig-cunTk1MwBs8s++Sfvej+rw, Laura Abbott, Pawel Moll,
Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Tomasz Figa, Stephen Warren, Tomasz Figa, Michal Nazarewicz, Marc,
Kyungmin Park, Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Ian Campbell
On Mon, Sep 16, 2013 at 12:25 AM, Benjamin Herrenschmidt
<benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org> wrote:
> On Mon, 2013-09-16 at 09:12 +0200, Marek Szyprowski wrote:
>>
>> Fixing those issues requires further discussion. Frankly, right now I
>> really have no idea which way should I go. The /reserved-ranges node seems
>> to be easy to match particular reserved memory region with a given device.
>> I'm also not really convinced if it makes sense to add a code for finding
>> and matching a reserved memory region to every device driver, which might
>> need it. I would really like to get some more feedback on the Ben's
>> comment.
>>
>> In any case, the code will also change significantly, so I assume that the
>> best, what can be done now is to revert the current version and start from
>> the scratch with a new, complete proposal.
>
> Yes, let's do that. I will try to help. It shouldn't be that a big deal.
I think we can get the concerns sorted quickly. I'm at meetings all
day today in SJC, but I'll take a look at it this evening. I'll be in
Edinburgh. We're holding an ARM summit at the same time so a bunch of
affected ARM folks will be there.
g.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 27+ messages in thread
[parent not found: <5236AF64.80607-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>]
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
[not found] ` <5236AF64.80607-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2013-09-16 8:17 ` Marek Szyprowski
0 siblings, 0 replies; 27+ messages in thread
From: Marek Szyprowski @ 2013-09-16 8:17 UTC (permalink / raw)
To: Grant Likely
Cc: Kumar Gala, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linaro-mm-sig-cunTk1MwBs8s++Sfvej+rw,
devicetree-u79uwXL29TY76Z2rM5mHXA, Kyungmin Park, Arnd Bergmann,
Michal Nazarewicz, Tomasz Figa, Sylwester Nawrocki, Sascha Hauer,
Laura Abbott, Rob Herring, Olof Johansson, Pawel Moll,
Mark Rutland, Stephen Warren, Ian Campbell, Tomasz Figa,
Nishanth Peethambaran, Marc, Benjamin Herrenschmidt
On 9/16/2013 9:12 AM, Marek Szyprowski wrote:
> Hello,
>
> On 9/9/2013 6:01 PM, Grant Likely wrote:
>> On Fri, 30 Aug 2013 15:26:24 -0500, Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> wrote:
>> > On Aug 30, 2013, at 7:39 AM, Marek Szyprowski wrote:
>> > > On 8/30/2013 12:46 AM, Grant Likely wrote:
>> > >> On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski
>> <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>> > >> > + - "reserved-memory-region" - compatibility is defined, given
>> > >> > + region is assigned for exclusive usage for by the
>> respective
>> > >> > + devices.
>> > >>
>> > >> BTW, just so you're aware there is already a binding for marking
>> regions
>> > >> as reserved. It was recently added to arch/powerpc/kernel/prom.c.
>> > >> Unfortunately it doesn't look like it got documented. Search for
>> > >> "reserved-ranges". However, I don't think it blocks your work
>> here. That
>> > >> binding doesn't provide any way for matching devices to reserved
>> ranges.
>> > >> It is only for telling the kernel "hands of that memory".
>> > >
>> > > ok, good to know.
>> >
>> > So I think the most generic compatible should effectively be the same
>> > as 'reserved-ranges', ie this region shouldn't be touched by the
>> > kernel.
>> >
>> > Than we can build on top of that with more specific compatibles.
>> >
>> > I have examples from FSL networking SoCs where we would carve out
>> > memory for backing storage managed completely by the HW and Linux
>> > wouldn't need to touch it, however we might have a
>> > "fsl,qman-backing-store" compat encase we might want some debug code
>> > in linux to look at the region of memory.
>> >
>> > I've got examples at qualcomm where we have shared data structures in
>> > specific memory regions between different processors that aren't cache
>> > coherent, so want the memory not to be marked as cacheable by Linux
>> > when it accesses it. Again we'd have a "qcom,smem" prop on top of the
>> > "reserved-memory-region".
>>
>> I think that is a reasonable approach, and works really well for regions
>> associated with specific hardware because the hardware driver can be
>> responsible for wiring it up to CMA or manage the region directly.
>> Whatever the driver desires to do.
>>
>> It still remains what to do for generic regions that any device can use.
>> As I've previously said, I don't like calling out "CMA" specifically in
>> the compatible property because that happens to be a Linux
>> implementation specific details. Two years from now someone may propose
>> a new allocator that should take over what used to be handled by CMA
>> (kind of like how CMA may end up taking over from ION)....
>>
>> Alright, I've thought about it some more and it probably does make sense
>> to use an additional compatible string. Marek originally suggested
>> "linux,contiguous-memory-region". I later suggested
>> "shareable-memory-region",
>> but that's actually a worse name because it doesn't have any reference
>> to what the region is for (I was fixating on the kernel being able to
>> use unallocated pages; but that is also an implementation detail). I
>> exercise my right to change my mind and agree that contiguous is
>> appropriate here. But instead of calling out the contiguous allocator,
>> the binding should specifically lay out the usage model for these
>> regions. I would change the contiguous-memory binding to state the
>> following:
>> Contiguous-memory is a region of general purpose memory from
>> which large buffers of contiguous memory can be allocated.
>> Contiguous buffers are often used for DMA buffers. The operating
>> system may use the memory for any purpose, but must immediately
>> release the pages if a contiguous buffer is required.
>>
>> So the way I read things, the current proposal would be:
>>
>> The generic form for do-not-touch memory:
>> compatible = "reserved-memory";
>> - I've dropped '-region' because I think it is redundant
>> - The kernel will not make use of this memory except for when a
>> driver picks it up
>>
>> For contiguous memory:
>> compatible = "contiguous-memory", "reserved-memory"
>>
>> For contiguous memory that Linux will use by default if a specific
>> region isn't specified.
>> compatible = "contiguous-memory", "reserved-memory"
>> linux,default-contiguous-region;
>> - I stuck with a linux, prefix here because I haven't come up with a
>> non-linux way to describe this.
>>
>> Memory that specific hardware can pick up:
>> compatible = "qcom,smem", "reserved-memory"
>>
>> Nodes with a 'size' property and without a 'reg' property need to have a
>> region allocated and reserved. The allocated region needs to be cached
>> somewhere. We could create a data structure for tracking the reserved
>> regions, or could write it in directly. While I shudder at the
>> thought of
>> modifying the device tree at runtime by the kernel, it might just be the
>> sanest implementation at this time. I'd like to see what the
>> implementation looks like. (Since this is potentially controversial, I
>> would recommend implementing the exact regions in on patch, and add
>> dynamically allocated regions as a follow-up patch)
>>
>> As far as proper implementation is concerned, I think it should be
>> explicit in the binding that the kernel should automatically exclude
>> anything under the reserved-memory node, regardless of the compatible
>> value. Merely being a child of the reserved-memory node immediately
>> means that it is a reserved memory region.
>
> It looks that my proposal for the reserved memory nodes causes much more
> controversy than I expected when I've sent a pull request to Linus:
> https://lkml.org/lkml/2013/9/15/151
> http://www.spinics.net/lists/arm-kernel/msg273548.html
>
> Fixing those issues requires further discussion. Frankly, right now I
> really have no idea which way should I go. The /reserved-ranges node
> seems
> to be easy to match particular reserved memory region with a given
> device.
Huh, I've hurried to much. It should be:
The /reserved-ranges node approach seems to be easy to implement, but it
makes much harder to to match particular reserved memory region with a given
device.
> I'm also not really convinced if it makes sense to add a code for finding
> and matching a reserved memory region to every device driver, which might
> need it. I would really like to get some more feedback on the Ben's
> comment.
>
> In any case, the code will also change significantly, so I assume that
> the
> best, what can be done now is to revert the current version and start
> from
> the scratch with a new, complete proposal.
Best regards
--
Marek Szyprowski
Samsung R&D Institute Poland
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-08-30 12:39 ` Marek Szyprowski
2013-08-30 20:26 ` Kumar Gala
@ 2013-09-09 13:05 ` Grant Likely
1 sibling, 0 replies; 27+ messages in thread
From: Grant Likely @ 2013-09-09 13:05 UTC (permalink / raw)
To: Marek Szyprowski
Cc: Mark Rutland, devicetree, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
linaro-mm-sig, Marc, Kyungmin Park, Sylwester Nawrocki,
Kumar Gala, Olof Johansson, Nishanth Peethambaran, Sascha Hauer,
linux-arm-kernel, Ian Campbell
On Fri, 30 Aug 2013 14:39:20 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Hello,
>
> On 8/30/2013 12:46 AM, Grant Likely wrote:
> > On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> > > This patch adds device tree support for contiguous and reserved memory
> > > regions defined in device tree.
> > >
> > > Large memory blocks can be reliably reserved only during early boot.
> > > This must happen before the whole memory management subsystem is
> > > initialized, because we need to ensure that the given contiguous blocks
> > > are not yet allocated by kernel. Also it must happen before kernel
> > > mappings for the whole low memory are created, to ensure that there will
> > > be no mappings (for reserved blocks) or mapping with special properties
> > > can be created (for CMA blocks). This all happens before device tree
> > > structures are unflattened, so we need to get reserved memory layout
> > > directly from fdt.
> > >
> > > Later, those reserved memory regions are assigned to devices on each
> > > device structure initialization.
> > >
> > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > > Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> > > Acked-by: Michal Nazarewicz <mina86@mina86.com>
> > > Acked-by: Tomasz Figa <t.figa@samsung.com>
> > > Acked-by: Stephen Warren <swarren@nvidia.com>
> > > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> >
> > Hi Marek,
> >
> > This patch is in good shape, but I have some comments below and a few
> > concerns about the binding....
> >
> > g.
> >
> > > ---
> > > Documentation/devicetree/bindings/memory.txt | 168 +++++++++++++++++++++++++
> > > drivers/of/Kconfig | 6 +
> > > drivers/of/Makefile | 1 +
> > > drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++
> > > drivers/of/platform.c | 4 +
> > > include/linux/of_reserved_mem.h | 14 +++
> > > 6 files changed, 368 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/memory.txt
> > > create mode 100644 drivers/of/of_reserved_mem.c
> > > create mode 100644 include/linux/of_reserved_mem.h
> > >
> > > diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
> > > new file mode 100644
> > > index 0000000..eb24693
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/memory.txt
> > > @@ -0,0 +1,168 @@
> > > +*** Memory binding ***
> > > +
> > > +The /memory node provides basic information about the address and size
> > > +of the physical memory. This node is usually filled or updated by the
> > > +bootloader, depending on the actual memory configuration of the given
> > > +hardware.
> > > +
> > > +The memory layout is described by the following node:
> > > +
> > > +/ {
> > > + #address-cells = <(n)>;
> > > + #size-cells = <(m)>;
> > > + memory {
> > > + device_type = "memory";
> > > + reg = <(baseaddr1) (size1)
> > > + (baseaddr2) (size2)
> > > + ...
> > > + (baseaddrN) (sizeN)>;
> > > + };
> > > + ...
> > > +};
> > > +
> > > +A memory node follows the typical device tree rules for "reg" property:
> > > +n: number of cells used to store base address value
> > > +m: number of cells used to store size value
> > > +baseaddrX: defines a base address of the defined memory bank
> > > +sizeX: the size of the defined memory bank
> > > +
> > > +
> > > +More than one memory bank can be defined.
> > > +
> > > +
> > > +*** Reserved memory regions ***
> > > +
> > > +In /memory/reserved-memory node one can create child nodes describing
> > > +particular reserved (excluded from normal use) memory regions. Such
> > > +memory regions are usually designed for the special usage by various
> > > +device drivers. A good example are contiguous memory allocations or
> > > +memory sharing with other operating system on the same hardware board.
> > > +Those special memory regions might depend on the board configuration and
> > > +devices used on the target system.
> > > +
> > > +Parameters for each memory region can be encoded into the device tree
> > > +with the following convention:
> > > +
> > > +[(label):] (name) {
> > > + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
> > > + reg = <(address) (size)>;
> > > + (linux,default-contiguous-region);
> > > +};
> > > +
> > > +compatible: one or more of:
> >
> > It's unclear what the meaning of having both values means for the
> > kernel. Does it mean the regions is sharable with the kernel or not? I
> > would think they are mutually exclusive.
>
> I consider CMA ("linux,contiguous-memory-region") as a special case of the
> reserved memory driver. The main advantage is the ability of sharing the
> memory
> with the system instead of just allocating it from the carved out memory
> region. From the device and hardware perspective there is no difference
> if the buffer comes from CMA or reserved memory. However if you insist, I
> can change it to something different, like "shareable-memory-region".
>
> Specifying both compatible values would let kernel to bind the more specific
> driver (cma, if available) over the generic one (simple reserved memory
> carve-out allocator based on dma_coherent).
I guess the question is that if they are effectively identical, then why
would they have separate compatible values? CMA is a particular user,
but there are other potential users (out of tree ION for example). The
other difference would be reserved regions that are in-use at boot time
(ie. framebuffer) and others that are completely free, but need to be
made available later. Are there any other conditions that could be
applicable here?
Compatible happens to be a convenient property to use for identifying
the usage model, but I wonder if it is the best. Another option would be
to add flag properties to indicate usage.... However, I am thinking out
loud at the moment and not telling you that you must change the model.
However, the document needs to be very explicit about the precedence and
how compatible or extra properties affect the behaviour.
As a thought experiment, how would you differentiate between regions
intended for different allocators? Say you had an imaginary system that
needs to support both GEM and CMA regions?
>
> > > + - "linux,contiguous-memory-region" - enables binding of this
> > > + region to Contiguous Memory Allocator (special region for
> > > + contiguous memory allocations, shared with movable system
> > > + memory, Linux kernel-specific).
> >
> > As mentioned in the older thread, you can drop the 'linux,' prefix here.
> > Perhaps something like "shareable-memory-region" or merely
> > "memory-region". It is reasonable for any kernel (not just Linux) to use
> > marked regions for movable pages until it gets requested by a driver, in
> > which case a rather generic "memory-region" makes a lot of sense as a
> > name.
Actually, I got this backwards; I think it is /NOT/ reasonable for Linux
to use a reserved region unless explicitly told that it can do so.
Otherwise it goes and overwrites framebuffers and stuff.
> >
> > > + - "reserved-memory-region" - compatibility is defined, given
> > > + region is assigned for exclusive usage for by the respective
> > > + devices.
> >
> > BTW, just so you're aware there is already a binding for marking regions
> > as reserved. It was recently added to arch/powerpc/kernel/prom.c.
> > Unfortunately it doesn't look like it got documented. Search for
> > "reserved-ranges". However, I don't think it blocks your work here. That
> > binding doesn't provide any way for matching devices to reserved ranges.
> > It is only for telling the kernel "hands of that memory".
>
> ok, good to know.
>
> > > +
> > > +reg: standard property defining the base address and size of
> > > + the memory region
> > > +
> > > +linux,default-contiguous-region: property indicating that the region
> > > + is the default region for all contiguous memory
> > > + allocations, Linux specific (optional)
> > > +
> > > +It is optional to specify the base address, so if one wants to use
> > > +autoconfiguration of the base address, '0' can be specified as a base
> > > +address in the 'reg' property.
> >
> > I don't understand this. What does autoconfiguration of the base address
> > actually do? If this is intended to dynamically allocate a region of RAM
> > for contiguous allocations, then don't use 'reg'. Use a different
> > property that only specifies the size.
>
> Ok, I will try to make a patch which removes special 'zero' base address
> handling and adds separate 'size' property for automatically configured
> regions.
>
> > > +The /memory/reserved-memory node must contain the same #address-cells
> > > +and #size-cells value as the root node.
> >
> > That seems to be an arbitrary restriction. Why does the reserved-memory
> > node need to have exactly the same #address/size values? The 'reg'
> > property binding quite easily handles different values at different
> > levels of the tree. More below....
>
> Does it really makes sense to have such configuration with different
> #address-cells/#size-cells than the root memory node?
Possibly not, but I've learned the hard way not to gratuitously deviate
from established convention.
g.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
2013-08-26 14:39 ` [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory Marek Szyprowski
2013-08-29 22:46 ` Grant Likely
@ 2013-08-29 22:48 ` Grant Likely
[not found] ` <1377527959-5080-4-git-send-email-m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2 siblings, 0 replies; 27+ messages in thread
From: Grant Likely @ 2013-08-29 22:48 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz, Marc,
Kyungmin Park, Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
On Mon, 26 Aug 2013 16:39:18 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index e0a6514..eeca8a5 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -21,6 +21,7 @@
> #include <linux/of_device.h>
> #include <linux/of_irq.h>
> #include <linux/of_platform.h>
> +#include <linux/of_reserved_mem.h>
> #include <linux/platform_device.h>
>
> const struct of_device_id of_default_bus_match_table[] = {
> @@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
> dev->dev.bus = &platform_bus_type;
> dev->dev.platform_data = platform_data;
>
> + of_reserved_mem_device_init(&dev->dev);
> +
One more comment. This only covers platform devices. What about AMBA
devices?
> /* We do not fill the DMA ops for platform devices by default.
> * This is currently the responsibility of the platform code
> * to do such, possibly using a device notifier
> @@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
>
> if (of_device_add(dev) != 0) {
> platform_device_put(dev);
> + of_reserved_mem_device_release(&dev->dev);
> return NULL;
> }
>
> diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
> new file mode 100644
> index 0000000..c841282
> --- /dev/null
> +++ b/include/linux/of_reserved_mem.h
> @@ -0,0 +1,14 @@
> +#ifndef __OF_RESERVED_MEM_H
> +#define __OF_RESERVED_MEM_H
> +
> +#ifdef CONFIG_OF_RESERVED_MEM
> +void of_reserved_mem_device_init(struct device *dev);
> +void of_reserved_mem_device_release(struct device *dev);
> +void early_init_dt_scan_reserved_mem(void);
> +#else
> +static inline void of_reserved_mem_device_init(struct device *dev) { }
> +static inline void of_reserved_mem_device_release(struct device *dev) { }
> +static inline void early_init_dt_scan_reserved_mem(void) { }
> +#endif
> +
> +#endif /* __OF_RESERVED_MEM_H */
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 27+ messages in thread
[parent not found: <1377527959-5080-4-git-send-email-m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>]
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
[not found] ` <1377527959-5080-4-git-send-email-m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2013-09-27 15:47 ` Kumar Gala
2013-09-27 17:06 ` Matt Sealey
1 sibling, 0 replies; 27+ messages in thread
From: Kumar Gala @ 2013-09-27 15:47 UTC (permalink / raw)
To: Marek Szyprowski
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linaro-mm-sig-cunTk1MwBs8s++Sfvej+rw,
devicetree-u79uwXL29TY76Z2rM5mHXA, Kyungmin Park, Arnd Bergmann,
Michal Nazarewicz, Grant Likely, Tomasz Figa, Sylwester Nawrocki,
Sascha Hauer, Laura Abbott, Rob Herring, Olof Johansson,
Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell,
Tomasz Figa, Nishanth Peethambaran, Marc
On Aug 26, 2013, at 9:39 AM, Marek Szyprowski wrote:
> +/**
> + * of_reserved_mem_device_init() - assign reserved memory region to given device
> + *
> + * This function assign memory region pointed by "memory-region" device tree
> + * property to the given device.
> + */
> +void of_reserved_mem_device_init(struct device *dev)
> +{
> + struct reserved_mem *region = get_dma_memory_region(dev);
> + if (!region)
> + return;
> +
> + if (region->cma) {
> + dev_set_cma_area(dev, region->cma);
> + pr_info("Assigned CMA %s to %s device\n", region->name,
> + dev_name(dev));
> + } else {
I don't think its a reasonable assumption that a 'reserved-memory-region' is necessary dma coherent if its not cma.
> + if (dma_declare_coherent_memory(dev, region->base, region->base,
> + region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
> + pr_info("Declared reserved memory %s to %s device\n",
> + region->name, dev_name(dev));
> + }
> +}
> +
- k
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory
[not found] ` <1377527959-5080-4-git-send-email-m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-09-27 15:47 ` Kumar Gala
@ 2013-09-27 17:06 ` Matt Sealey
1 sibling, 0 replies; 27+ messages in thread
From: Matt Sealey @ 2013-09-27 17:06 UTC (permalink / raw)
To: Marek Szyprowski
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linaro-mm-sig-cunTk1MwBs8s++Sfvej+rw,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Mark Rutland,
Laura Abbott, Pawel Moll, Arnd Bergmann, Stephen Warren,
Tomasz Figa, Tomasz Figa, Michal Nazarewicz, Grant Likely, Marc,
Kyungmin Park, Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Ian Campbell, Nishanth Peethambaran, Sascha Hauer
No comment on advocating re-use of the device_type = "reserved" from
CHRP that I posted a good while ago?
There is a large amount of extra code going in here. Normalizing the
/memory node to the spec ('available' property...) and re-using an
existing specification for reserved regions means less documentation,
less extra code and more expected behavior.. the memory setup parser
should be able to find 'reserved' memory from those nodes the same way
it finds 'memory' and put it in a special place, without screwing up
the memory node and adding all kinds of new children. At least for
Snowball PDK BSP kernels, there are a ton of memory reservation kernel
args required.
Setting up regions in the DT per these docs and isn't making this
easier, but more complicated and wordy... defining new properties when
the definition of the standard node (and the 'reserved' node) would
work so well.
Do I have to go dig out the CHRP spec?
On Mon, Aug 26, 2013 at 9:39 AM, Marek Szyprowski
<m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
> This patch adds device tree support for contiguous and reserved memory
> regions defined in device tree.
>
> Large memory blocks can be reliably reserved only during early boot.
> This must happen before the whole memory management subsystem is
> initialized, because we need to ensure that the given contiguous blocks
> are not yet allocated by kernel. Also it must happen before kernel
> mappings for the whole low memory are created, to ensure that there will
> be no mappings (for reserved blocks) or mapping with special properties
> can be created (for CMA blocks). This all happens before device tree
> structures are unflattened, so we need to get reserved memory layout
> directly from fdt.
>
> Later, those reserved memory regions are assigned to devices on each
> device structure initialization.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Michal Nazarewicz <mina86-deATy8a+UHjQT0dZR+AlfA@public.gmane.org>
> Acked-by: Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> Reviewed-by: Rob Herring <rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
> ---
> Documentation/devicetree/bindings/memory.txt | 168 +++++++++++++++++++++++++
> drivers/of/Kconfig | 6 +
> drivers/of/Makefile | 1 +
> drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++
> drivers/of/platform.c | 4 +
> include/linux/of_reserved_mem.h | 14 +++
> 6 files changed, 368 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/memory.txt
> create mode 100644 drivers/of/of_reserved_mem.c
> create mode 100644 include/linux/of_reserved_mem.h
>
> diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
> new file mode 100644
> index 0000000..eb24693
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/memory.txt
> @@ -0,0 +1,168 @@
> +*** Memory binding ***
> +
> +The /memory node provides basic information about the address and size
> +of the physical memory. This node is usually filled or updated by the
> +bootloader, depending on the actual memory configuration of the given
> +hardware.
> +
> +The memory layout is described by the following node:
> +
> +/ {
> + #address-cells = <(n)>;
> + #size-cells = <(m)>;
> + memory {
> + device_type = "memory";
> + reg = <(baseaddr1) (size1)
> + (baseaddr2) (size2)
> + ...
> + (baseaddrN) (sizeN)>;
> + };
> + ...
> +};
> +
> +A memory node follows the typical device tree rules for "reg" property:
> +n: number of cells used to store base address value
> +m: number of cells used to store size value
> +baseaddrX: defines a base address of the defined memory bank
> +sizeX: the size of the defined memory bank
> +
> +
> +More than one memory bank can be defined.
> +
> +
> +*** Reserved memory regions ***
> +
> +In /memory/reserved-memory node one can create child nodes describing
> +particular reserved (excluded from normal use) memory regions. Such
> +memory regions are usually designed for the special usage by various
> +device drivers. A good example are contiguous memory allocations or
> +memory sharing with other operating system on the same hardware board.
> +Those special memory regions might depend on the board configuration and
> +devices used on the target system.
> +
> +Parameters for each memory region can be encoded into the device tree
> +with the following convention:
> +
> +[(label):] (name) {
> + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
> + reg = <(address) (size)>;
> + (linux,default-contiguous-region);
> +};
> +
> +compatible: one or more of:
> + - "linux,contiguous-memory-region" - enables binding of this
> + region to Contiguous Memory Allocator (special region for
> + contiguous memory allocations, shared with movable system
> + memory, Linux kernel-specific).
> + - "reserved-memory-region" - compatibility is defined, given
> + region is assigned for exclusive usage for by the respective
> + devices.
> +
> +reg: standard property defining the base address and size of
> + the memory region
> +
> +linux,default-contiguous-region: property indicating that the region
> + is the default region for all contiguous memory
> + allocations, Linux specific (optional)
> +
> +It is optional to specify the base address, so if one wants to use
> +autoconfiguration of the base address, '0' can be specified as a base
> +address in the 'reg' property.
> +
> +The /memory/reserved-memory node must contain the same #address-cells
> +and #size-cells value as the root node.
> +
> +
> +*** Device node's properties ***
> +
> +Once regions in the /memory/reserved-memory node have been defined, they
> +may be referenced by other device nodes. Bindings that wish to reference
> +memory regions should explicitly document their use of the following
> +property:
> +
> +memory-region = <&phandle_to_defined_region>;
> +
> +This property indicates that the device driver should use the memory
> +region pointed by the given phandle.
> +
> +
> +*** Example ***
> +
> +This example defines a memory consisting of 4 memory banks. 3 contiguous
> +regions are defined for Linux kernel, one default of all device drivers
> +(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the
> +framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB)
> +and one for multimedia processing (labelled multimedia_mem, placed at
> +0x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000
> +device for DMA memory allocations (Linux kernel drivers will use CMA is
> +available or dma-exclusive usage otherwise). 'multimedia_mem' is
> +assigned to scaler@12500000 and codec@12600000 devices for contiguous
> +memory allocations when CMA driver is enabled.
> +
> +The reason for creating a separate region for framebuffer device is to
> +match the framebuffer base address to the one configured by bootloader,
> +so once Linux kernel drivers starts no glitches on the displayed boot
> +logo appears. Scaller and codec drivers should share the memory
> +allocations.
> +
> +/ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + /* ... */
> +
> + memory {
> + reg = <0x40000000 0x10000000
> + 0x50000000 0x10000000
> + 0x60000000 0x10000000
> + 0x70000000 0x10000000>;
> +
> + reserved-memory {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + /*
> + * global autoconfigured region for contiguous allocations
> + * (used only with Contiguous Memory Allocator)
> + */
> + contig_region@0 {
> + compatible = "linux,contiguous-memory-region";
> + reg = <0x0 0x4000000>;
> + linux,default-contiguous-region;
> + };
> +
> + /*
> + * special region for framebuffer
> + */
> + display_region: region@78000000 {
> + compatible = "linux,contiguous-memory-region", "reserved-memory-region";
> + reg = <0x78000000 0x800000>;
> + };
> +
> + /*
> + * special region for multimedia processing devices
> + */
> + multimedia_region: region@77000000 {
> + compatible = "linux,contiguous-memory-region";
> + reg = <0x77000000 0x4000000>;
> + };
> + };
> + };
> +
> + /* ... */
> +
> + fb0: fb@12300000 {
> + status = "okay";
> + memory-region = <&display_region>;
> + };
> +
> + scaler: scaler@12500000 {
> + status = "okay";
> + memory-region = <&multimedia_region>;
> + };
> +
> + codec: codec@12600000 {
> + status = "okay";
> + memory-region = <&multimedia_region>;
> + };
> +};
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index 80e5c13..f7107fa 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -80,4 +80,10 @@ config OF_MTD
> depends on MTD
> def_bool y
>
> +config OF_RESERVED_MEM
> + depends on DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK)
> + def_bool y
> + help
> + Initialization code for DMA reserved memory
> +
> endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index 1f9c0c4..e7e3322 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
> obj-$(CONFIG_OF_PCI) += of_pci.o
> obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> obj-$(CONFIG_OF_MTD) += of_mtd.o
> +obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
> new file mode 100644
> index 0000000..a754b84
> --- /dev/null
> +++ b/drivers/of/of_reserved_mem.c
> @@ -0,0 +1,175 @@
> +/*
> + * Device tree based initialization code for reserved memory.
> + *
> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> + * http://www.samsung.com
> + * Author: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License or (at your optional) any later version of the license.
> + */
> +
> +#include <asm/dma-contiguous.h>
> +
> +#include <linux/memblock.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
> +#include <linux/mm.h>
> +#include <linux/sizes.h>
> +#include <linux/mm_types.h>
> +#include <linux/dma-contiguous.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/of_reserved_mem.h>
> +
> +#define MAX_RESERVED_REGIONS 16
> +struct reserved_mem {
> + phys_addr_t base;
> + unsigned long size;
> + struct cma *cma;
> + char name[32];
> +};
> +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
> +static int reserved_mem_count;
> +
> +static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
> + int depth, void *data)
> +{
> + struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
> + phys_addr_t base, size;
> + int is_cma, is_reserved;
> + unsigned long len;
> + const char *status;
> + __be32 *prop;
> +
> + is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
> + of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
> + is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
> +
> + if (!is_reserved && !is_cma) {
> + /* ignore node and scan next one */
> + return 0;
> + }
> +
> + status = of_get_flat_dt_prop(node, "status", &len);
> + if (status && strcmp(status, "okay") != 0) {
> + /* ignore disabled node nad scan next one */
> + return 0;
> + }
> +
> + prop = of_get_flat_dt_prop(node, "reg", &len);
> + if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
> + sizeof(__be32))) {
> + pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
> + uname);
> + /* ignore node and scan next one */
> + return 0;
> + }
> + base = dt_mem_next_cell(dt_root_addr_cells, &prop);
> + size = dt_mem_next_cell(dt_root_size_cells, &prop);
> +
> + if (!size) {
> + /* ignore node and scan next one */
> + return 0;
> + }
> +
> + pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
> + uname, (unsigned long)base, (unsigned long)size / SZ_1M);
> +
> + if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
> + return -ENOSPC;
> +
> + rmem->base = base;
> + rmem->size = size;
> + strlcpy(rmem->name, uname, sizeof(rmem->name));
> +
> + if (is_cma) {
> + struct cma *cma;
> + if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
> + rmem->cma = cma;
> + reserved_mem_count++;
> + if (of_get_flat_dt_prop(node,
> + "linux,default-contiguous-region",
> + NULL))
> + dma_contiguous_set_default(cma);
> + }
> + } else if (is_reserved) {
> + if (memblock_remove(base, size) == 0)
> + reserved_mem_count++;
> + else
> + pr_err("Failed to reserve memory for %s\n", uname);
> + }
> +
> + return 0;
> +}
> +
> +static struct reserved_mem *get_dma_memory_region(struct device *dev)
> +{
> + struct device_node *node;
> + const char *name;
> + int i;
> +
> + node = of_parse_phandle(dev->of_node, "memory-region", 0);
> + if (!node)
> + return NULL;
> +
> + name = kbasename(node->full_name);
> + for (i = 0; i < reserved_mem_count; i++)
> + if (strcmp(name, reserved_mem[i].name) == 0)
> + return &reserved_mem[i];
> + return NULL;
> +}
> +
> +/**
> + * of_reserved_mem_device_init() - assign reserved memory region to given device
> + *
> + * This function assign memory region pointed by "memory-region" device tree
> + * property to the given device.
> + */
> +void of_reserved_mem_device_init(struct device *dev)
> +{
> + struct reserved_mem *region = get_dma_memory_region(dev);
> + if (!region)
> + return;
> +
> + if (region->cma) {
> + dev_set_cma_area(dev, region->cma);
> + pr_info("Assigned CMA %s to %s device\n", region->name,
> + dev_name(dev));
> + } else {
> + if (dma_declare_coherent_memory(dev, region->base, region->base,
> + region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
> + pr_info("Declared reserved memory %s to %s device\n",
> + region->name, dev_name(dev));
> + }
> +}
> +
> +/**
> + * of_reserved_mem_device_release() - release reserved memory device structures
> + *
> + * This function releases structures allocated for memory region handling for
> + * the given device.
> + */
> +void of_reserved_mem_device_release(struct device *dev)
> +{
> + struct reserved_mem *region = get_dma_memory_region(dev);
> + if (!region && !region->cma)
> + dma_release_declared_memory(dev);
> +}
> +
> +/**
> + * early_init_dt_scan_reserved_mem() - create reserved memory regions
> + *
> + * This function grabs memory from early allocator for device exclusive use
> + * defined in device tree structures. It should be called by arch specific code
> + * once the early allocator (memblock) has been activated and all other
> + * subsystems have already allocated/reserved memory.
> + */
> +void __init early_init_dt_scan_reserved_mem(void)
> +{
> + of_scan_flat_dt_by_path("/memory/reserved-memory",
> + fdt_scan_reserved_mem, NULL);
> +}
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index e0a6514..eeca8a5 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -21,6 +21,7 @@
> #include <linux/of_device.h>
> #include <linux/of_irq.h>
> #include <linux/of_platform.h>
> +#include <linux/of_reserved_mem.h>
> #include <linux/platform_device.h>
>
> const struct of_device_id of_default_bus_match_table[] = {
> @@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
> dev->dev.bus = &platform_bus_type;
> dev->dev.platform_data = platform_data;
>
> + of_reserved_mem_device_init(&dev->dev);
> +
> /* We do not fill the DMA ops for platform devices by default.
> * This is currently the responsibility of the platform code
> * to do such, possibly using a device notifier
> @@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
>
> if (of_device_add(dev) != 0) {
> platform_device_put(dev);
> + of_reserved_mem_device_release(&dev->dev);
> return NULL;
> }
>
> diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
> new file mode 100644
> index 0000000..c841282
> --- /dev/null
> +++ b/include/linux/of_reserved_mem.h
> @@ -0,0 +1,14 @@
> +#ifndef __OF_RESERVED_MEM_H
> +#define __OF_RESERVED_MEM_H
> +
> +#ifdef CONFIG_OF_RESERVED_MEM
> +void of_reserved_mem_device_init(struct device *dev);
> +void of_reserved_mem_device_release(struct device *dev);
> +void early_init_dt_scan_reserved_mem(void);
> +#else
> +static inline void of_reserved_mem_device_init(struct device *dev) { }
> +static inline void of_reserved_mem_device_release(struct device *dev) { }
> +static inline void early_init_dt_scan_reserved_mem(void) { }
> +#endif
> +
> +#endif /* __OF_RESERVED_MEM_H */
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v7 4/4] ARM: init: add support for reserved memory defined by device tree
2013-08-26 14:39 [PATCH v7 0/4] Device Tree support for CMA (Contiguous Memory Allocator) Marek Szyprowski
` (2 preceding siblings ...)
2013-08-26 14:39 ` [PATCH v7 3/4] drivers: of: add initialization code for dma reserved memory Marek Szyprowski
@ 2013-08-26 14:39 ` Marek Szyprowski
2013-08-29 22:49 ` Grant Likely
3 siblings, 1 reply; 27+ messages in thread
From: Marek Szyprowski @ 2013-08-26 14:39 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz,
Grant Likely, Marc, Kyungmin Park, Sylwester Nawrocki, Kumar Gala,
Olof Johansson, Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
Enable reserved memory initialization from device tree.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Tomasz Figa <t.figa@samsung.com>
---
arch/arm/mm/init.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 15225d8..6a2fe44 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -17,6 +17,7 @@
#include <linux/nodemask.h>
#include <linux/initrd.h>
#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
#include <linux/highmem.h>
#include <linux/gfp.h>
#include <linux/memblock.h>
@@ -377,6 +378,8 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
if (mdesc->reserve)
mdesc->reserve();
+ early_init_dt_scan_reserved_mem();
+
/*
* reserve memory for DMA contigouos allocations,
* must come from DMA area inside low memory
--
1.7.9.5
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v7 4/4] ARM: init: add support for reserved memory defined by device tree
2013-08-26 14:39 ` [PATCH v7 4/4] ARM: init: add support for reserved memory defined by device tree Marek Szyprowski
@ 2013-08-29 22:49 ` Grant Likely
0 siblings, 0 replies; 27+ messages in thread
From: Grant Likely @ 2013-08-29 22:49 UTC (permalink / raw)
To: linux-arm-kernel, linaro-mm-sig, devicetree
Cc: Mark Rutland, Laura Abbott, Pawel Moll, Arnd Bergmann,
Stephen Warren, Tomasz Figa, Tomasz Figa, Michal Nazarewicz, Marc,
Kyungmin Park, Sylwester Nawrocki, Kumar Gala, Olof Johansson,
Ian Campbell, Nishanth Peethambaran, Sascha Hauer,
Marek Szyprowski
On Mon, 26 Aug 2013 16:39:19 +0200, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Enable reserved memory initialization from device tree.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Acked-by: Michal Nazarewicz <mina86@mina86.com>
> Acked-by: Tomasz Figa <t.figa@samsung.com>
> ---
> arch/arm/mm/init.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index 15225d8..6a2fe44 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -17,6 +17,7 @@
> #include <linux/nodemask.h>
> #include <linux/initrd.h>
> #include <linux/of_fdt.h>
> +#include <linux/of_reserved_mem.h>
> #include <linux/highmem.h>
> #include <linux/gfp.h>
> #include <linux/memblock.h>
> @@ -377,6 +378,8 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
> if (mdesc->reserve)
> mdesc->reserve();
>
> + early_init_dt_scan_reserved_mem();
> +
Don't forget ARM64.
g.
^ permalink raw reply [flat|nested] 27+ messages in thread