Hello,
This is a sixth version of my proposal for device tree integration for reserved memory and Contiguous Memory Allocator. This time I've fixes more issues pointed by Rob Herring and added support for 'status' property. For more information, please check the change log at the end of the mail.
Just a few words for those who see this code for the first time:
The proposed bindings allows to define contiguous memory regions of specified base address and size. Then, the defined regions can be assigned to the given device(s) by adding a property with a phanle to the defined contiguous memory region. From the device tree perspective that's all. Once the bindings are added, all the memory allocations from dma-mapping subsystem will be served from the defined contiguous memory regions.
Contiguous Memory Allocator is a framework, which lets to provide a large contiguous memory buffers for (usually a multimedia) devices. The contiguous memory is reserved during early boot and then shared with kernel, which is allowed to allocate it for movable pages. Then, when device driver requests a contigouous buffer, the framework migrates movable pages out of contiguous region and gives it to the driver. When device driver frees the buffer, it is added to kernel memory pool again. For more information, please refer to commit c64be2bb1c6eb43c838b2c6d57 ("drivers: add Contiguous Memory Allocator") and d484864dd96e1830e76895 (CMA merge commit).
Why we need device tree bindings for CMA at all?
Older ARM kernels used so called board-based initialization. Those board files contained a definition of all hardware blocks available on the target system and particular kernel and driver software configuration selected by the board maintainer.
In the new approach the board files will be removed completely and Device Tree approach is used to describe all hardware blocks available on the target system. By definition, the bindings should be software independent, so at least in theory it should be possible to use those bindings with other operating systems than Linux kernel.
Reserved memory configuration belongs to the grey area. It might depend on hardware restriction of the board or modules and low-level configuration done by bootloader. Putting reserved and contiguous memory regions to /memory node and having phandles to those regions in the device nodes however matches well with the device-tree typical style of linking devices with other resources like clocks, interrupts, regulators, power domains, etc. This is the main reason to use such approach instead of putting everything to /chosen node as it has been proposed in v2 and v3. However during the discussion at Linaro Connect in Dublin it has been decided that reserved memory is one of the _system_ property. Such system properties are not necessarily the hardware properties, but they are well-known and likely properties of the system that is running, so they can be encoded to device tree. This patch series tries to provide such encoding with the respect to the common device tree style of bindings and documentation.
Best regards Marek Szyprowski Samsung R&D Institute Poland
Changelog:
v6: - added support for 'status' property, so memory regions can be disabled like any other nodes - fixed issues pointed by Rob: removed annotations from function declarations and replaced macros with static inline functions. - restored of_scan_flat_dt_by_path() function to simplify reserved memory scanning function - the code now uses #size-cells/#address-cells properties from root node for interpreting 'reg' property in reserved memory regions - fixed some issues in dt binding documentation
v5: http://thread.gmane.org/gmane.linux.ports.arm.kernel/259278 - renamed "contiguous-memory-region" compatibility string to "linux,contiguous-memory-region" (this one is really specific to Linux kernel implementation) - renamed "dma-memory-region" property to "memory-region" (suggested by Kumar Gala) - added support for #address-cells, #size-cells for memory regions (thanks to Rob Herring for suggestion) - removed generic code to scan specific path in flat device tree (cannot be used to fdt one-pass scan based initialization of memory regions with #address-cells and #size-cells parsing) - replaced dma_contiguous_set_default_area() and dma_contiguous_add_device() functions with dev_set_cma_area() call
v4: http://thread.gmane.org/gmane.linux.ports.arm.kernel/256491 - corrected Devcie Tree mailing list address (resend) - moved back contiguous-memory bindings from /chosen/contiguous-memory to /memory nodes as suggested by Grant (see http://article.gmane.org/gmane.linux.drivers.devicetree/41030 for more details) - added support for DMA reserved memory with dma_declare_coherent() - moved code to drivers/of/of_reserved_mem.c - added generic code to scan specific path in flat device tree
v3: http://thread.gmane.org/gmane.linux.drivers.devicetree/40013/ - fixed issues pointed by Laura and updated documentation
v2: http://thread.gmane.org/gmane.linux.drivers.devicetree/34075 - moved contiguous-memory bindings from /memory to /chosen/contiguous-memory/ node to avoid spreading Linux specific parameters over the whole device tree definitions - added support for autoconfigured regions (use zero base) - fixes minor bugs
v1: http://thread.gmane.org/gmane.linux.drivers.devicetree/30111/ - initial proposal
Patch summary:
Marek Szyprowski (4): drivers: dma-contiguous: clean source code and prepare for device tree drivers: of: add function to scan fdt nodes given by path drivers: of: add initialization code for dma reserved memory ARM: init: add support for reserved memory defined by device tree
Documentation/devicetree/bindings/memory.txt | 166 ++++++++++++++++++++++++ arch/arm/include/asm/dma-contiguous.h | 1 - arch/arm/mm/init.c | 3 + arch/x86/include/asm/dma-contiguous.h | 1 - drivers/base/dma-contiguous.c | 119 +++++++----------- drivers/of/Kconfig | 6 + drivers/of/Makefile | 1 + drivers/of/fdt.c | 76 +++++++++++ drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++ drivers/of/platform.c | 5 + include/asm-generic/dma-contiguous.h | 28 ----- include/linux/dma-contiguous.h | 55 +++++++- include/linux/of_fdt.h | 3 + include/linux/of_reserved_mem.h | 14 +++ 14 files changed, 546 insertions(+), 107 deletions(-) create mode 100644 Documentation/devicetree/bindings/memory.txt create mode 100644 drivers/of/of_reserved_mem.c delete mode 100644 include/asm-generic/dma-contiguous.h create mode 100644 include/linux/of_reserved_mem.h
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/dma-contiguous.h | 55 ++++++++++++++- 5 files changed, 97 insertions(+), 107 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 3ed37b4..63277bc 100644 --- a/arch/arm/include/asm/dma-contiguous.h +++ b/arch/arm/include/asm/dma-contiguous.h @@ -5,7 +5,6 @@ #ifdef CONFIG_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/dma-contiguous.h b/include/linux/dma-contiguous.h index 01b5c84..9439659 100644 --- a/include/linux/dma-contiguous.h +++ b/include/linux/dma-contiguous.h @@ -67,9 +67,48 @@ 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; +} + 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 +119,20 @@ 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_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)
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 --- 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 6bb7cf2..585b1a6 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -543,6 +543,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..1151a7f 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);
On Mon, Aug 19, 2013 at 10:04 AM, 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
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 --- Documentation/devicetree/bindings/memory.txt | 166 ++++++++++++++++++++++++ drivers/of/Kconfig | 6 + drivers/of/Makefile | 1 + drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++ drivers/of/platform.c | 5 + include/linux/of_reserved_mem.h | 14 +++ 6 files changed, 367 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..90e96278 --- /dev/null +++ b/Documentation/devicetree/bindings/memory.txt @@ -0,0 +1,166 @@ +*** 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 additional 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: "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), alternatively if + "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 +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined: + +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_mem: region@78000000 { + compatible = "linux,contiguous-memory-region", "reserved-memory-region"; + reg = <0x78000000 0x800000>; + }; + + /* + * special region for multimedia processing devices + */ + multimedia_mem: region@77000000 { + compatible = "linux,contiguous-memory-region"; + reg = <0x77000000 0x4000000>; + }; + }; + }; + + /* ... */ + + fb0: fb@12300000 { + status = "okay"; + memory-region = <&display_mem>; + }; + + scaler: scaler@12500000 { + status = "okay"; + memory-region = <&multimedia_mem>; + }; + + codec: codec@12600000 { + status = "okay"; + memory-region = <&multimedia_mem>; + }; +}; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 80e5c13..a83ab43 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 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..95563d33 --- /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_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_default_area = 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..1e4e91d 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[] = { @@ -196,6 +197,7 @@ EXPORT_SYMBOL(of_device_alloc); * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ + struct platform_device *of_platform_device_create_pdata( struct device_node *np, const char *bus_id, @@ -218,6 +220,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 +229,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 */
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
---------- 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. ----------
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for "contiguous-memory- region". The concept of contiguous memory region is rather OS independent and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that there are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong opinion on this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
Best regards, Tomasz
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for "contiguous-memory- region". The concept of contiguous memory region is rather OS independent and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that there are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong opinion on this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
---------- ** 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. ----------
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
On Monday 19 of August 2013 16:17:30 Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for "contiguous-memory- region". The concept of contiguous memory region is rather OS independent and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that there are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong opinion on this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
** 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.
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Well, such setup simply cannot be handled by Linux today, as one device (aka one struct device) can only have one memory region bound to it. So this is not something we can implement today.
I agree that the device tree should be able to describe such configurations, though, but I'm not sure if this should be done from this side.
IMHO the concept of memport (or bus master) can be used to represent cases when multiple parts of an IP have different requirements for memory they work with. This is what Marek's patches adjusting MFC bindings to use memory-regions are also about.
Best regards, Tomasz
On 08/19/2013 04:24 PM, Tomasz Figa wrote:
On Monday 19 of August 2013 16:17:30 Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for "contiguous-memory- region". The concept of contiguous memory region is rather OS independent and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that there are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong opinion on this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
** 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.
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Well, such setup simply cannot be handled by Linux today, as one device (aka one struct device) can only have one memory region bound to it. So this is not something we can implement today.
Don't you just create "fake" struct devices to make this work, so that the top-level struct device is instantiated from DT, and the others created manually in the top-level device's probe routine, and the memory regions get attached to those "fake" child devices? Seems pretty conceptually easy.
I agree that the device tree should be able to describe such configurations,
good:-)
though, but I'm not sure if this should be done from this side.
I'm not sure what "from this side" means. It seems pretty simple to adjust this patch to allow such HW to be represented, so shouldn't we just do it and be done with the question?
On Monday 19 of August 2013 16:27:14 Stephen Warren wrote:
On 08/19/2013 04:24 PM, Tomasz Figa wrote:
On Monday 19 of August 2013 16:17:30 Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is
defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for "contiguous-memory- region". The concept of contiguous memory region is rather OS independent and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that there are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong opinion on this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
** 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.
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Well, such setup simply cannot be handled by Linux today, as one device (aka one struct device) can only have one memory region bound to it. So this is not something we can implement today.
Don't you just create "fake" struct devices to make this work, so that the top-level struct device is instantiated from DT, and the others created manually in the top-level device's probe routine, and the memory regions get attached to those "fake" child devices? Seems pretty conceptually easy.
Correct. However you need those fake struct devices to be attached to some memory region and often other things like IOMMU. In fact, they aren't entirely fake, as they usually represent real bus masters of the IP.
I agree that the device tree should be able to describe such configurations,
good:-)
though, but I'm not sure if this should be done from this side.
I'm not sure what "from this side" means. It seems pretty simple to adjust this patch to allow such HW to be represented, so shouldn't we just do it and be done with the question?
Well, if it's just about modifying the binding to support such cases, but without actually adding support for them in Linux, then I guess it's fine. Otherwise a lot of memory management code (mostly the DMA mapping API and a lot of its users) would have to be almost completely reworked, which wouldn't be an easy task.
Best regards, Tomasz
On 08/19/2013 04:40 PM, Tomasz Figa wrote:
On Monday 19 of August 2013 16:27:14 Stephen Warren wrote:
On 08/19/2013 04:24 PM, Tomasz Figa wrote:
On Monday 19 of August 2013 16:17:30 Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote: > This patch adds device tree support for contiguous and reserved > memory regions defined in device tree. > > diff --git a/Documentation/devicetree/bindings/memory.txt > b/Documentation/devicetree/bindings/memory.txt
...
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Well, such setup simply cannot be handled by Linux today, as one
...
I agree that the device tree should be able to describe such configurations,
...
Well, if it's just about modifying the binding to support such cases, but without actually adding support for them in Linux, then I guess it's fine.
Yes. I don't care so much if the SW won't work (yet?), but I want to make sure the binding isn't going to need semantic changes.
Hello,
On 8/20/2013 12:17 AM, Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for "contiguous-memory- region". The concept of contiguous memory region is rather OS independent and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that there are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong opinion on this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
** 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.
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Support for multiple regions is something that need to be discussed separately. In case of Exynos hardware it is also related to iommu bindings and configuration, because each busmuster on the internal memory bus has separate iommu controller. Having each busmaster defined as a separate node, enables to put there the associated memory region and/or iommu controller as well as dma window properties (in case of limited dma window).
However right now I would like to focus on the simple case (1 device, 1 memory region) and define bindings which can be extended later. I hope that my current proposal covers this (I will send updated binding documentation asap) and the initial support for reserved memory can be merged to -next soon.
Best regards
On 08/20/2013 04:57 AM, Marek Szyprowski wrote:
Hello,
On 8/20/2013 12:17 AM, Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved
memory
regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer
where the
"additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards
"linux,contiguous-memory-allocator-region", or
perhaps "linux,cma-region" since it's not really describing whether
the
memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for
"contiguous-memory-
region". The concept of contiguous memory region is rather OS
independent
and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that
there
are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong
opinion on
this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
** 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.
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Support for multiple regions is something that need to be discussed separately. In case of Exynos hardware it is also related to iommu bindings and configuration, because each busmuster on the internal memory bus has separate iommu controller. Having each busmaster defined as a separate node, enables to put there the associated memory region and/or iommu controller as well as dma window properties (in case of limited dma window).
However right now I would like to focus on the simple case (1 device, 1 memory region) and define bindings which can be extended later. I hope that my current proposal covers this (I will send updated binding documentation asap) and the initial support for reserved memory can be merged to -next soon.
I don't believe that's a good approach unless you have at least a partial idea of how the current bindings will be extended to support multiple memory regions.
Without a clear idea how that will eventually work, you run a real risk of not being able to extend the bindings in a 100% backwards-compatible way, and hence wishing to break DT ABI.
Hello,
On 8/20/2013 6:35 PM, Stephen Warren wrote:
On 08/20/2013 04:57 AM, Marek Szyprowski wrote:
Hello,
On 8/20/2013 12:17 AM, Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved
memory
regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer
where the
"additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards
"linux,contiguous-memory-allocator-region", or
perhaps "linux,cma-region" since it's not really describing whether
the
memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for
"contiguous-memory-
region". The concept of contiguous memory region is rather OS
independent
and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that
there
are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong
opinion on
this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
** 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.
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Support for multiple regions is something that need to be discussed separately. In case of Exynos hardware it is also related to iommu bindings and configuration, because each busmuster on the internal memory bus has separate iommu controller. Having each busmaster defined as a separate node, enables to put there the associated memory region and/or iommu controller as well as dma window properties (in case of limited dma window).
However right now I would like to focus on the simple case (1 device, 1 memory region) and define bindings which can be extended later. I hope that my current proposal covers this (I will send updated binding documentation asap) and the initial support for reserved memory can be merged to -next soon.
I don't believe that's a good approach unless you have at least a partial idea of how the current bindings will be extended to support multiple memory regions.
Without a clear idea how that will eventually work, you run a real risk of not being able to extend the bindings in a 100% backwards-compatible way, and hence wishing to break DT ABI.
Both already proposed approaches for extending them to support multiple memory regions are compatible with the 'single memory region' approach defined in my patches. Adding additional property with region names is probably the simplest way from binding perspective, while adding additional child nodes for each bus master or memory interface gives much more flexibility in describing hardware properties. Besides memory region, one can assign iommu controller or dma window properties to each such node.
Best regards
On 08/21/2013 08:38 AM, Marek Szyprowski wrote: ...
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case
I think if we just make that change to the binding doc, it'll be fine. It's obvious how to extend the binding then.
On Tuesday 20 of August 2013 10:35:51 Stephen Warren wrote:
On 08/20/2013 04:57 AM, Marek Szyprowski wrote:
Hello,
On 8/20/2013 12:17 AM, Stephen Warren wrote:
On 08/19/2013 04:02 PM, Tomasz Figa wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved
memory
regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer
where the
"additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined,
given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards
"linux,contiguous-memory-allocator-region", or
perhaps "linux,cma-region" since it's not really describing whether
the
memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for
"contiguous-memory-
region". The concept of contiguous memory region is rather OS
independent
and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that
there
are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong
opinion on
this.
+*** Device node's properties ***
+Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+memory-region = <&phandle_to_defined_region>;
I think the naming of that property should more obviously match this binding and/or compatible value; perhaps cma-region or contiguous-memory-region?
This property is not CMA-specific. Any memory region can be given using the memory-region property and used to allocate buffers for particular device.
OK, that makes sense.
What I'm looking for is some way to make it obvious that when you see a "memory-region" property in a node, you go look at the "memory.txt" rather than the DT binding for the node where that property appears. Right now, it doesn't seem that obvious to me.
I think the real issue here is that my brief reading of memory.txt implies that arbitrary device nodes can include the memory-region property without the node's own binding having to document it; the property name is essentially "forced into" all other bindings.
I think instead, memory.txt should say:
** 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.
Also, what if a device needs multiple separate memory regions? Perhaps a GPU is forced to allocate displayable surfaces from addresses 0..32M and textures/off-screen-render-targets from 256M..384M or something whacky like that. In that case, we could either:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
or:
b) Adjust memory.txt not to mention any specific property names, but simply mention that other DT nodes can refer to define memory regions by phandle, and leave it up to individual bindings to define which property they use to reference the memory regions, perhaps with memory.txt providing a recommendation of memory-region for the simple case, but perhaps also allowing a custom case, e.g.:
display-memory-region = <&phandl1e1>; texture-memory-region = <&phahndle2>;
Support for multiple regions is something that need to be discussed separately. In case of Exynos hardware it is also related to iommu bindings and configuration, because each busmuster on the internal memory bus has separate iommu controller. Having each busmaster defined as a separate node, enables to put there the associated memory region and/or iommu controller as well as dma window properties (in case of limited dma window).
However right now I would like to focus on the simple case (1 device, 1 memory region) and define bindings which can be extended later. I hope that my current proposal covers this (I will send updated binding documentation asap) and the initial support for reserved memory can be merged to -next soon.
I don't believe that's a good approach unless you have at least a partial idea of how the current bindings will be extended to support multiple memory regions.
I believe that at least three "at least partial" ideas have been brought in this thread. Moreover, I don't think that defining the simple binding now would stop us from extending it according to any of those ideas in any way.
Without a clear idea how that will eventually work, you run a real risk of not being able to extend the bindings in a 100% backwards-compatible way, and hence wishing to break DT ABI.
As a fallback you can always define a new binding, while keeping support for old one. Of course this is the last resort, but it is not that simple to find a case that couldn't be supported without breaking the ABI.
Best regards, Tomasz
On Wed, 21 Aug 2013 17:39:48 +0200, Tomasz Figa t.figa@samsung.com wrote:
On Tuesday 20 of August 2013 10:35:51 Stephen Warren wrote:
a) Adjust memory.txt to allow multiple entries in memory-regions, and add an associated memory-region-names property.
I don't believe that's a good approach unless you have at least a partial idea of how the current bindings will be extended to support multiple memory regions.
I believe that at least three "at least partial" ideas have been brought in this thread. Moreover, I don't think that defining the simple binding now would stop us from extending it according to any of those ideas in any way.
I would plan on extending later with suggestion 'a)' above. Making the memory-region an array of phandles is a better match with how most of the core bindings work. I actually regret the *-gpio properties that were defined earlier becasue it makes it harder for software to look at a tree and determine if there are any gpio references.
It of course doesn't need to be done immediately, only when it becomes required.
g.
On Tue, 20 Aug 2013 00:02:37 +0200, Tomasz Figa tomasz.figa@gmail.com wrote:
Hi Stephen,
On Monday 19 of August 2013 15:49:20 Stephen Warren wrote:
On 08/19/2013 09:04 AM, Marek Szyprowski wrote:
This patch adds device tree support for contiguous and reserved memory regions defined in device tree.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+In /memory/reserved-memory node one can create additional nodes
s/additional/child/ or s/additional/sub/ would make it clearer where the "additional" nodes should be placed.
+compatible: "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), alternatively if
"reserved-memory-region" - compatibility is defined, given
region is assigned for exclusive usage for by the
respective
devices
"alternatively" makes it sound like the two compatible values are mutually-exclusive. Perhaps make this a list, like:
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.
"linux,contiguous-memory-region" is already long enough, but I'd slightly bikeshed towards "linux,contiguous-memory-allocator-region", or perhaps "linux,cma-region" since it's not really describing whether the memory is contiguous (at the level of /memory, each chunk of memory is contiguous...)
I'm not really sure if we need the "linux" prefix for "contiguous-memory- region". The concept of contiguous memory region is rather OS independent and tells us that memory allocated from this region will be contiguous. IMHO any OS is free to implement its own contiguous memory allocation method, without being limited to Linux CMA.
Keep in mind that rationale behind those contiguous regions was that there are devices that require buffers contiguous in memory to operate correctly.
But this is just nitpicking and I don't really have any strong opinion on this.
Actually, I think this is important. It is something that describes the expected usage of the hardware (flicker-free framebuffer is a really good example) and isn't really linux-specific from that perspective. I think you can drop the 'linux,' prefix string.
g.
I have a suggestion here.
I recall that CHRP had a reserved node definition which essentially, since it was not a lot more than a definition of the bare minimum node that can describe a memory region, acted as a way to carve out peripheral addresses. In this case, the device_type would be "reserved" and a property to mark it as for the Linux contiguous memory allocator would be prudent here. This way nothing new is being defined except the property. In the case you want default regions and supplemental regions, give the linux,contiguous-memory-region property a value. In the case of the reserved node, the name could be "default" though and CMA could special-case this.
It doesn't even need to be called reserved-memory or be a child node of it's own, then, but I also guess this would mean duplicating #address-cells and #size-cells in every node (that said.. isn't there a case for a 32-bit system having a >32-bit memory map somewhere that the kernel somehow needs to know about? On PowerPC I've seen 8GB hooked up to it on CPUs that didn't have 36-bit addressing, and therefore could not do anything with that amount of memory. But the DMA controllers in this case were designed around 36-bit addressing and could easily access the upper 4GB.. it would have come in handy for a kind of DMA-assisted buffering whereby you wanted to put all your network or "graphics" stuff in a safe place and copy it in and out as needed, or even as 4GB of magical swap space driven by a custom DMA driver)
The naming of nodes is not really "important" in device-tree, in this case it might make sense in the same way the regulator guys specify regulators. In any case where the "default" name does not exist, then the first parsed becomes the default, but this does mean we'd be kind of restricting the namespace for everyone based on a Linux kernel behavior..
If you can search for the device_type = "memory" node you can also search for all nodes matching device_type = "reserved" under the memory node, with the appropriate property in place to bundle them up for adding to CMA, and just carve it out. In fact, this would work without needing to be in the /memory node at all. Hooray for device_type, long live device_type? :D
-- Matt
On Mon, Aug 19, 2013 at 10:04 AM, 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
Documentation/devicetree/bindings/memory.txt | 166 ++++++++++++++++++++++++ drivers/of/Kconfig | 6 + drivers/of/Makefile | 1 + drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++ drivers/of/platform.c | 5 + include/linux/of_reserved_mem.h | 14 +++ 6 files changed, 367 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..90e96278 --- /dev/null +++ b/Documentation/devicetree/bindings/memory.txt @@ -0,0 +1,166 @@ +*** 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 additional 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: "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), alternatively if
"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 +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined:
+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_mem: region@78000000 {
compatible = "linux,contiguous-memory-region", "reserved-memory-region";
reg = <0x78000000 0x800000>;
};
/*
* special region for multimedia processing devices
*/
multimedia_mem: region@77000000 {
compatible = "linux,contiguous-memory-region";
reg = <0x77000000 0x4000000>;
};
};
};
/* ... */
fb0: fb@12300000 {
status = "okay";
memory-region = <&display_mem>;
};
scaler: scaler@12500000 {
status = "okay";
memory-region = <&multimedia_mem>;
};
codec: codec@12600000 {
status = "okay";
memory-region = <&multimedia_mem>;
};
+}; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 80e5c13..a83ab43 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 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..95563d33 --- /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_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_default_area = 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..1e4e91d 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[] = { @@ -196,6 +197,7 @@ EXPORT_SYMBOL(of_device_alloc);
- Returns pointer to created platform device, or NULL if a device was not
- registered. Unavailable devices will not get registered.
*/
struct platform_device *of_platform_device_create_pdata( struct device_node *np, const char *bus_id, @@ -218,6 +220,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 +229,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@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marek Szyprowski m.szyprowski@samsung.com
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 ---
This is an updated version with some changes in the binding documentation suggested by Stephen Warren.
I decided to keep "linux,contiguous-memory-region" compatible name to emphasize, that the given region is designed for Linux specific reserved memory driver (I consider CMA just as an improved driver for the reserved memory). Using the acronym in the compatible name might be misleading, there have been already some confusion between "Contiguous Memory Allocator" and "Cross Memory Attach" (both are now available in Linux kernel).
Best regards Marek Szyprowski Samsung R&D Institute Poland --- 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 | 5 + include/linux/of_reserved_mem.h | 14 +++ 6 files changed, 369 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..67a35a3 --- /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_mem: region@78000000 { + compatible = "linux,contiguous-memory-region", "reserved-memory-region"; + reg = <0x78000000 0x800000>; + }; + + /* + * special region for multimedia processing devices + */ + multimedia_mem: region@77000000 { + compatible = "linux,contiguous-memory-region"; + reg = <0x77000000 0x4000000>; + }; + }; + }; + + /* ... */ + + fb0: fb@12300000 { + status = "okay"; + memory-region = <&display_mem>; + }; + + scaler: scaler@12500000 { + status = "okay"; + memory-region = <&multimedia_mem>; + }; + + codec: codec@12600000 { + status = "okay"; + memory-region = <&multimedia_mem>; + }; +}; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 80e5c13..a83ab43 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 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..95563d33 --- /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_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_default_area = 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..1e4e91d 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[] = { @@ -196,6 +197,7 @@ EXPORT_SYMBOL(of_device_alloc); * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ + struct platform_device *of_platform_device_create_pdata( struct device_node *np, const char *bus_id, @@ -218,6 +220,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 +229,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 */
On 08/23/2013 02:39 AM, wrote:
From: Marek Szyprowski m.szyprowski@samsung.com
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.
I think the binding looks OK now; just a couple minor comments below.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
+*** Reserved memory regions ***
+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.
I'm slightly hesitant to agree with "linux" in the name here, since it seems like the concept of a memory region where DMA buffers/... should be allocated is pretty OS-independant. Similar for:
+linux,default-contiguous-region: property indicating that the region
- is the default region for all contiguous memory
- allocations, Linux specific (optional)
But, I guess there's nothing stopping any other OS from parsing this same property, so I suppose it's OK. What do other DT maintainers think?
+*** Example ***
reserved-memory {
...
contig_region@0 {
...
display_mem: region@78000000 {
...
multimedia_mem: region@77000000 {
Nit: I think all 3 of those nodes should be called region, but it's probably fine as-is.
So, the binding, Acked-by: Stephen Warren swarren@nvidia.com
On Mon, Aug 19, 2013 at 10:04 AM, 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
Reviewed-by: Rob Herring rob.herring@calxeda.com
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
linaro-mm-sig@lists.linaro.org