Re: [PATCH v3 3/7] of: reserved_mem: add support for named reserved mem nodes
Hi Rob, On 2015-12-31 00:25, Rob Herring wrote: On Wed, Dec 16, 2015 at 9:37 AM, Marek Szyprowski <m.szyprow...@samsung.com> wrote: This patch allows device drivers to initialize more than one reserved memory region assigned to given device. When driver needs to use more than one reserved memory region, it should allocate child devices and initialize regions by index or name for each of its child devices. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- .../bindings/reserved-memory/reserved-memory.txt | 2 + .../devicetree/bindings/resource-names.txt | 1 + drivers/of/of_reserved_mem.c | 104 + include/linux/of_reserved_mem.h| 31 +- 4 files changed, 115 insertions(+), 23 deletions(-) diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt index 3da0ebdba8d9..43a14957fd64 100644 --- a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -74,6 +74,8 @@ Regions in the /reserved-memory node may be referenced by other device nodes by adding a memory-region property to the device node. memory-region (optional) - phandle, specifier pairs to children of /reserved-memory +memory-region-names (optional) - supplemental names property, provide array of +names to identify memory regions Example --- diff --git a/Documentation/devicetree/bindings/resource-names.txt b/Documentation/devicetree/bindings/resource-names.txt index e280fef6f265..51823e99b983 100644 --- a/Documentation/devicetree/bindings/resource-names.txt +++ b/Documentation/devicetree/bindings/resource-names.txt @@ -12,6 +12,7 @@ Resource Property Supplemental Names Property regreg-names clocks clock-names interrupts interrupt-names +memory-region memory-region-names The other cases of *-names should correspond to actual h/w names for a h/w block. memory-regions are not really h/w. So I'd prefer to not add memory-region-names. If you want a name for the region, put it in the region node. The name for each client node is not going to be different. There is a difference between a name in the region node and a name assigned in client node. Reserved memory region bindings already allows assigning given region to more than one device. In such case the name put in the region itself is not really useful. In my case (Exynos MFC device) the names are related to HW names. The memory regions are named in the hw documentation (referred as 'left memory bank' and 'right memory bank'). Using those names in the binding is also simply convenient (no need to remember which regions is at which index number). Those names might be also convenient for describing Android's ION related regions, although I didn't look deep into details of such use case. Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 5/7] media: set proper max seg size for devices on Exynos SoCs
All multimedia devices found on Exynos SoCs support only contiguous buffers, so set DMA max segment size to DMA_BIT_MASK(32) to let memory allocator to correctly create contiguous memory mappings. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/exynos-gsc/gsc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-is.c | 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 1 + drivers/media/platform/s5p-g2d/g2d.c | 1 + drivers/media/platform/s5p-jpeg/jpeg-core.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 ++ drivers/media/platform/s5p-tv/mixer_video.c | 1 + 8 files changed, 9 insertions(+) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 9b9e423e4fc4..4f90be43b5a9 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1140,6 +1140,7 @@ static int gsc_probe(struct platform_device *pdev) goto err_m2m; /* Initialize continious memory allocator */ + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(gsc->alloc_ctx)) { ret = PTR_ERR(gsc->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index cef2a7f07cdb..368e19b50498 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -1019,6 +1019,7 @@ static int fimc_probe(struct platform_device *pdev) } /* Initialize contiguous memory allocator */ + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 49658ca39e51..123772fa0241 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -841,6 +841,7 @@ static int fimc_is_probe(struct platform_device *pdev) if (ret < 0) goto err_pm; + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); is->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(is->alloc_ctx)) { ret = PTR_ERR(is->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 6f76afd909c4..9cfd2221f53d 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1564,6 +1564,7 @@ static int fimc_lite_probe(struct platform_device *pdev) goto err_sd; } + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index e1936d9d27da..31f6c233b146 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -681,6 +681,7 @@ static int g2d_probe(struct platform_device *pdev) goto put_clk_gate; } + vb2_dma_contig_set_max_seg_size(>dev, DMA_BIT_MASK(32)); dev->alloc_ctx = vb2_dma_contig_init_ctx(>dev); if (IS_ERR(dev->alloc_ctx)) { ret = PTR_ERR(dev->alloc_ctx); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 4a608cbe0fdb..6bd92f014a23 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2839,6 +2839,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) goto device_register_rollback; } + vb2_dma_contig_set_max_seg_size(>dev, DMA_BIT_MASK(32)); jpeg->alloc_ctx = vb2_dma_contig_init_ctx(>dev); if (IS_ERR(jpeg->alloc_ctx)) { v4l2_err(>v4l2_dev, "Failed to init memory allocator\n"); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 3ffe2ecfd5ef..3e9cdafe2168 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1143,11 +1143,13 @@ static int s5p_mfc_probe(struct platform_device *pdev) } } + vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32)); dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); if (IS_ERR(dev->alloc_ctx[0])) { ret = PTR_ERR(dev->alloc_ctx[0]); goto err_res; } + vb2_dma_contig_set_max
[PATCH v3 0/7] Exynos: MFC driver: reserved memory cleanup and IOMMU support
Hello, This patchset finally perform cleanup of custom code in s5p-mfc codec driver. The first part is removal of custom, driver specific code for intializing and handling of reserved memory. Instead, a generic code for reserved memory regions is used. Then, once it is done, the proper setup of DMA parameters (max segment size) is applied for all multimedia devices found on Exynos SoCs to let them properly handle shared buffers mapped into contiguous DMA address space. The last patch adds support for IOMMU to MFC driver. Some additional code is needed because of specific requirements of MFC device firmware (see patch 7 for more details). When no IOMMU is available, the code fallbacks to generic reserved memory regions. After applying this patchset, MFC device works correctly when IOMMU is either enabled or disabled. Patches have been tested on top of linux-next from 20151207. I would prefer to merge patches 1-2 via Samsung tree and patches 3-7 via media tree (there are no compile-time dependencies between patches 1-2 and 3-7). Patches have been tested on Odroid U3 (Exynos 4412 based) and Odroid XU3 (Exynos 5422 based) boards. Best regards Marek Szyprowski Samsung R Institute Poland Changelog: v3: - fixed issues pointed by Laurent Pinchart: - added documentation to memory-region-names property, - changed devm_kzalloc to kzalloc in vb2_dma_contig_set_max_seg_size() to avoid access to freed memory after reloading driver module - unified odroid mfc reserved memory configuration with other Exynos4 boards v2: http://thread.gmane.org/gmane.linux.drivers.video-input-infrastructure/97025 - reworked of_reserved_mem_init* functions on request from Rob Herring, added separate index and name based selection of reserved region - adapted for of_reserved_mem_init* related changes v1: https://www.mail-archive.com/linux-media@vger.kernel.org/msg94100.html - initial version of another approach for this problem, rewrote driver code for new reserved memory bindings, which finally have been merged some time ago v0: http://lists.infradead.org/pipermail/linux-arm-kernel/2013-August/189259.html - old patchset solving the same problem, abandoned due to other tasks and long time of merging reserved memory bindings and support code for it Patch summary: Marek Szyprowski (7): ARM: Exynos: convert MFC device to generic reserved memory bindings ARM: dts: exynos4412-odroid*: enable MFC device of: reserved_mem: add support for named reserved mem nodes media: vb2-dma-contig: add helper for setting dma max seg size media: set proper max seg size for devices on Exynos SoCs media: s5p-mfc: replace custom reserved memory init code with generic one media: s5p-mfc: add iommu support .../devicetree/bindings/media/s5p-mfc.txt | 16 +-- .../bindings/reserved-memory/reserved-memory.txt | 2 + .../devicetree/bindings/resource-names.txt | 1 + arch/arm/boot/dts/exynos4210-origen.dts| 22 ++- arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 ++- arch/arm/boot/dts/exynos4412-odroid-common.dtsi| 24 arch/arm/boot/dts/exynos4412-origen.dts| 22 ++- arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 ++- arch/arm/boot/dts/exynos5250-arndale.dts | 22 ++- arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 ++- arch/arm/boot/dts/exynos5250-spring.dts| 22 ++- arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 ++- arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 ++- arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 22 ++- arch/arm/mach-exynos/Makefile | 2 - arch/arm/mach-exynos/exynos.c | 19 --- arch/arm/mach-exynos/mfc.h | 16 --- arch/arm/mach-exynos/s5p-dev-mfc.c | 94 - drivers/media/platform/exynos-gsc/gsc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-is.c| 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 1 + drivers/media/platform/s5p-g2d/g2d.c | 1 + drivers/media/platform/s5p-jpeg/jpeg-core.c| 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 153 - drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 79 +++ drivers/media/platform/s5p-tv/mixer_video.c| 1 + drivers/media/v4l2-core/videobuf2-dma-contig.c | 14 ++ drivers/of/of_reserved_mem.c | 104 +++--- include/linux/of_reserved_mem.h| 31 - include/media/videobuf2-dma-contig.h | 1 + 31 files changed, 535 insertions(+), 248 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/mach-exynos/s5p-dev-mfc.c create mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devic
[PATCH v3 4/7] media: vb2-dma-contig: add helper for setting dma max seg size
Add a helper function for device drivers to set DMA's max_seg_size. Setting it to largest possible value lets DMA-mapping API always create contiguous mappings in DMA address space. This is essential for all devices, which use dma-contig videobuf2 memory allocator and shared buffers. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 14 ++ include/media/videobuf2-dma-contig.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index c33127284cfe..bd893788d1ae 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -742,6 +742,20 @@ void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) } EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size) +{ + if (!dev->dma_parms) { + dev->dma_parms = kzalloc(sizeof(dev->dma_parms), GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + if (dma_get_max_seg_size(dev) < size) + return dma_set_max_seg_size(dev, size); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); + MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak <pa...@osciak.com>"); MODULE_LICENSE("GPL"); diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index c33dfa69d7ab..0e6ba644939e 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -26,6 +26,7 @@ vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) void *vb2_dma_contig_init_ctx(struct device *dev); void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); extern const struct vb2_mem_ops vb2_dma_contig_memops; -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 6/7] media: s5p-mfc: replace custom reserved memory init code with generic one
This patch removes custom code for initialization and handling of reserved memory regions in s5p-mfc driver and replaces it with generic named reserved memory regions specified in device tree. s5p-mfc driver now handles two reserved memory regions: "left" and "right", defined by generic reserved memory bindings. Support for non-dt platform has been removed, because all supported platforms have been converted to device tree. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 129 +++ 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 3e9cdafe2168..306344994c8e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "s5p_mfc_common.h" #include "s5p_mfc_ctrl.h" @@ -1022,55 +1023,67 @@ static const struct v4l2_file_operations s5p_mfc_fops = { .mmap = s5p_mfc_mmap, }; -static int match_child(struct device *dev, void *data) +/* DMA memory related helper functions */ +static void s5p_mfc_memdev_release(struct device *dev) { - if (!dev_name(dev)) - return 0; - return !strcmp(dev_name(dev), (char *)data); + of_reserved_mem_device_release(dev); } -static void *mfc_get_drv_data(struct platform_device *pdev); - -static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) +static struct device *s5p_mfc_alloc_memdev(struct device *dev, const char *name) { - unsigned int mem_info[2] = { }; + struct device *child; + int ret; - dev->mem_dev_l = devm_kzalloc(>plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_l) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_l); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-l", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_l, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - mfc_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; + child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL); + if (!child) + return NULL; + + device_initialize(child); + dev_set_name(child, "%s:%s", dev_name(dev), name); + child->parent = dev; + child->bus = dev->bus; + child->coherent_dma_mask = dev->coherent_dma_mask; + child->dma_mask = dev->dma_mask; + child->release = s5p_mfc_memdev_release; + + if (device_add(child) == 0) { + ret = of_reserved_mem_init_by_name(child, dev->of_node, name); + if (ret == 0) + return child; } - dev->mem_dev_r = devm_kzalloc(>plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_r) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_r); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-r", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_r, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - pr_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; + put_device(child); + return NULL; +} + +static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = _dev->plat_dev->dev; + + /* +* Create and initialize virtual devices for accessing +* reserved memory regions. +*/ + mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left"); + if (!mfc_dev->mem_dev_l) + return -ENODEV; + mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right"); + if (!mfc_dev->mem_dev_r) { + device_unregister(mfc_dev->mem_dev_l); + return -ENODEV; } + return 0; } +static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + device_unregister(mfc_dev->mem_dev_l); + device_unregister(mfc_dev->mem_dev_r); +} + +static void *mfc_get_drv_data(struct platform_device *pdev); + /* MFC probe function */ static int s5p_m
[PATCH v3 3/7] of: reserved_mem: add support for named reserved mem nodes
This patch allows device drivers to initialize more than one reserved memory region assigned to given device. When driver needs to use more than one reserved memory region, it should allocate child devices and initialize regions by index or name for each of its child devices. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- .../bindings/reserved-memory/reserved-memory.txt | 2 + .../devicetree/bindings/resource-names.txt | 1 + drivers/of/of_reserved_mem.c | 104 + include/linux/of_reserved_mem.h| 31 +- 4 files changed, 115 insertions(+), 23 deletions(-) diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt index 3da0ebdba8d9..43a14957fd64 100644 --- a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -74,6 +74,8 @@ Regions in the /reserved-memory node may be referenced by other device nodes by adding a memory-region property to the device node. memory-region (optional) - phandle, specifier pairs to children of /reserved-memory +memory-region-names (optional) - supplemental names property, provide array of +names to identify memory regions Example --- diff --git a/Documentation/devicetree/bindings/resource-names.txt b/Documentation/devicetree/bindings/resource-names.txt index e280fef6f265..51823e99b983 100644 --- a/Documentation/devicetree/bindings/resource-names.txt +++ b/Documentation/devicetree/bindings/resource-names.txt @@ -12,6 +12,7 @@ Resource Property Supplemental Names Property regreg-names clocks clock-names interrupts interrupt-names +memory-region memory-region-names Usage: diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 1a3556a9e9ea..c58b362aaa63 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MAX_RESERVED_REGIONS 16 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; @@ -287,53 +288,116 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) return NULL; } +struct rmem_assigned_device { + struct device *dev; + struct reserved_mem *rmem; + struct list_head list; +}; + +static LIST_HEAD(of_rmem_assigned_device_list); +static DEFINE_MUTEX(of_rmem_assigned_device_mutex); + /** * of_reserved_mem_device_init() - assign reserved memory region to given device + * @dev: Pointer to the device to configure + * @np:Pointer to the device_node with 'reserved-memory' property + * @idx: Index of selected region + * + * This function assigns respective DMA-mapping operations based on reserved + * memory region specified by 'memory-region' property in @np node to the @dev + * device. When driver needs to use more than one reserved memory region, it + * should allocate child devices and initialize regions by name for each of + * child device. * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. + * Returns error code or zero on success. */ -int of_reserved_mem_device_init(struct device *dev) +int of_reserved_mem_init(struct device *dev, struct device_node *np, int idx) { + struct rmem_assigned_device *rd; + struct device_node *target; struct reserved_mem *rmem; - struct device_node *np; int ret; - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return -ENODEV; + if (!np || !dev) + return -EINVAL; + + target = of_parse_phandle(np, "memory-region", idx); + if (!target) + return -EINVAL; - rmem = __find_rmem(np); - of_node_put(np); + rmem = __find_rmem(target); + of_node_put(target); if (!rmem || !rmem->ops || !rmem->ops->device_init) return -EINVAL; + rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); + if (!rd) + return -ENOMEM; + ret = rmem->ops->device_init(rmem, dev); - if (ret == 0) + if (ret == 0) { + rd->dev = dev; + rd->rmem = rmem; + + mutex_lock(_rmem_assigned_device_mutex); + list_add(>list, _rmem_assigned_device_list); + mutex_unlock(_rmem_assigned_device_mutex); + dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + } else { + kfree(rd); + } return ret; } -EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); +EXPORT_SYMBOL_GPL(of_reserved_mem_init); + +/*
[PATCH v3 7/7] media: s5p-mfc: add iommu support
This patch adds support for IOMMU to s5p-mfc device driver. MFC firmware is limited and it cannot use the default configuration. If IOMMU is available, the patch disables the default DMA address space configuration and creates a new address space of size limited to 256M and base address set to 0x2000. For now the same address space is shared by both 'left' and 'right' memory channels, because the DMA/IOMMU frameworks do not support configuring them separately. This is not optimal, but besides limiting total address space available has no other drawbacks (MFC firmware supports 256M of address space per each channel). Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 24 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 79 ++ 2 files changed, 103 insertions(+) create mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 306344994c8e..bae7c0f7bfd4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -30,6 +30,7 @@ #include "s5p_mfc_dec.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" +#include "s5p_mfc_iommu.h" #include "s5p_mfc_opr.h" #include "s5p_mfc_cmd.h" #include "s5p_mfc_pm.h" @@ -1061,6 +1062,22 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = _dev->plat_dev->dev; /* +* When IOMMU is available, we cannot use the default configuration, +* because of MFC firmware requirements: address space limited to +* 256M and non-zero default start address. +* This is still simplified, not optimal configuration, but for now +* IOMMU core doesn't allow to configure device's IOMMUs channel +* separately. +*/ + if (exynos_is_iommu_available(dev)) { + int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, +S5P_MFC_IOMMU_DMA_SIZE); + if (ret == 0) + mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev; + return ret; + } + + /* * Create and initialize virtual devices for accessing * reserved memory regions. */ @@ -1078,6 +1095,13 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) { + struct device *dev = _dev->plat_dev->dev; + + if (exynos_is_iommu_available(dev)) { + exynos_unconfigure_iommu(dev); + return; + } + device_unregister(mfc_dev->mem_dev_l); device_unregister(mfc_dev->mem_dev_r); } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h new file mode 100644 index ..5d1d1c2922e8 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co.Ltd + * Authors: Marek Szyprowski <m.szyprow...@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 + * option) any later version. + */ + +#ifndef S5P_MFC_IOMMU_H_ +#define S5P_MFC_IOMMU_H_ + +#define S5P_MFC_IOMMU_DMA_BASE 0x2000lu +#define S5P_MFC_IOMMU_DMA_SIZE SZ_256M + +#ifdef CONFIG_EXYNOS_IOMMU + +#include + +static inline bool exynos_is_iommu_available(struct device *dev) +{ + return dev->archdata.iommu != NULL; +} + +static inline void exynos_unconfigure_iommu(struct device *dev) +{ + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); +} + +static inline int exynos_configure_iommu(struct device *dev, +unsigned int base, unsigned int size) +{ + struct dma_iommu_mapping *mapping = NULL; + int ret; + + /* Disable the default mapping created by device core */ + if (to_dma_iommu_mapping(dev)) + exynos_unconfigure_iommu(dev); + + mapping = arm_iommu_create_mapping(dev->bus, base, size); + if (IS_ERR(mapping)) { + pr_warn("Failed to create IOMMU mapping for device %s\n", + dev_name(dev)); + return PTR_ERR(mapping); + } + + ret = arm_iommu_attach_device(dev, mapping); + if (ret) { + pr_warn("Failed to attached device %s to IOMMU_mapping\n", + dev_name(dev)); + arm_iommu_release_mapping(mapping);
[PATCH v3 2/7] ARM: dts: exynos4412-odroid*: enable MFC device
Enable support for Multimedia Codec (MFC) device for all Exynos4412-based Odroid boards. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 24 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 395c3ca9601e..349e6cc51283 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -18,6 +18,24 @@ stdout-path = _1; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@5100 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x5100 0x80>; + }; + + mfc_right: region@4300 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x4300 0x80>; + }; + }; + firmware@0204F000 { compatible = "samsung,secure-firmware"; reg = <0x0204F000 0x1000>; @@ -447,6 +465,12 @@ clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; }; + { + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; + status = "okay"; +}; + { status = "okay"; }; -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 1/7] ARM: Exynos: convert MFC device to generic reserved memory bindings
This patch replaces custom properties for definining reserved memory regions with generic reserved memory bindings. All custom code for handling MFC-specific reserved memory can be now removed from Exynos-DT generic board code. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- .../devicetree/bindings/media/s5p-mfc.txt | 16 ++-- arch/arm/boot/dts/exynos4210-origen.dts| 22 - arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 - arch/arm/boot/dts/exynos4412-origen.dts| 22 - arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 - arch/arm/boot/dts/exynos5250-arndale.dts | 22 - arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 - arch/arm/boot/dts/exynos5250-spring.dts| 22 - arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 - arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 - arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 22 - arch/arm/mach-exynos/Makefile | 2 - arch/arm/mach-exynos/exynos.c | 19 - arch/arm/mach-exynos/mfc.h | 16 arch/arm/mach-exynos/s5p-dev-mfc.c | 94 -- 15 files changed, 208 insertions(+), 159 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/mach-exynos/s5p-dev-mfc.c diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 2d5787eac91a..4603673c593b 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -21,16 +21,16 @@ Required properties: - clock-names : from common clock binding: must contain "mfc", corresponding to entry in the clocks property. - - samsung,mfc-r : Base address of the first memory bank used by MFC - for DMA contiguous memory allocation and its size. - - - samsung,mfc-l : Base address of the second memory bank used by MFC - for DMA contiguous memory allocation and its size. - Optional properties: - power-domains : power-domain property defined with a phandle to respective power domain. + - memory-region : from reserved memory binding: phandles to two reserved + memory regions: accessed by "left" and "right" mfc memory bus + interfaces, used when no SYSMMU support is available + - memory-region-names : from reserved memory binding: must be "left" + and "right" + Example: SoC specific DT entry: @@ -46,6 +46,6 @@ mfc: codec@1340 { Board specific DT entry: codec@1340 { - samsung,mfc-r = <0x4300 0x80>; - samsung,mfc-l = <0x5100 0x80>; + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; }; diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index 5821ad87e32c..4b7637dfa392 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -30,6 +30,24 @@ 0x7000 0x1000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@5100 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x5100 0x80>; + }; + + mfc_right: region@4300 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x4300 0x80>; + }; + }; + chosen { bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x4100,8M console=ttySAC2,115200 init=/linuxrc"; stdout-path = _2; @@ -288,8 +306,8 @@ }; { - samsung,mfc-r = <0x4300 0x80>; - samsung,mfc-l = <0x5100 0x80>; + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; status = "okay"; }; diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts index 104cbb33d2bb..efafc5721817 100644 --- a/arch/arm/boot/dts/exynos4210-smdkv310.dts +++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts @@ -26,6 +26,24 @@ reg = <0x4000 0x8000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@5100 { + compatible = "shared-dma-pool"; + no-map; +
Re: [PATCH v2 4/7] media: vb2-dma-contig: add helper for setting dma max seg size
Hi Laurent, On 2015-12-14 16:50, Laurent Pinchart wrote: Hi Marek, On Monday 14 December 2015 10:20:22 Marek Szyprowski wrote: On 2015-12-13 20:57, Laurent Pinchart wrote: On Wednesday 09 December 2015 14:58:19 Marek Szyprowski wrote: Add a helper function for device drivers to set DMA's max_seg_size. Setting it to largest possible value lets DMA-mapping API always create contiguous mappings in DMA address space. This is essential for all devices, which use dma-contig videobuf2 memory allocator and shared buffers. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 15 +++ include/media/videobuf2-dma-contig.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index c331272..628518d 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -742,6 +742,21 @@ void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) } EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size) +{ + if (!dev->dma_parms) { When can this function be called with dev->dma_parms not NULL ? When one loads a module with multimedia driver (which calls this function), then unloads and loads it again. It is rather safe to have this check. Don't you have a much bigger problem in that case ? When you unload the module the device will be unbound from the driver, causing the memory allocated by devm_kzalloc to be freed. dev->dma_parms will then point to freed memory, which will get reused by all subsequent calls to dma_get_max_seg_size(), dma_get_max_seg_size() & co (including the ones in this function). You are right. I've thought that devm resources are freed on device release not driver remove. Then probably the safest fix is to change devm_kzalloc back to kzalloc. + dev->dma_parms = devm_kzalloc(dev, sizeof(dev->dma_parms), + GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + if (dma_get_max_seg_size(dev) < size) + return dma_set_max_seg_size(dev, size); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); + MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak <pa...@osciak.com>"); MODULE_LICENSE("GPL"); diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index c33dfa6..0e6ba64 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -26,6 +26,7 @@ vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) void *vb2_dma_contig_init_ctx(struct device *dev); void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); extern const struct vb2_mem_ops vb2_dma_contig_memops; Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 0/7] Exynos: MFC driver: reserved memory cleanup and IOMMU support
Hello, On 2015-12-13 20:52, Laurent Pinchart wrote: Hi Marek, Thank you for the patches. On Wednesday 09 December 2015 14:58:15 Marek Szyprowski wrote: Hello, This patchset finally perform cleanup of custom code in s5p-mfc codec driver. The first part is removal of custom, driver specific code for intializing and handling of reserved memory. Instead, a generic code for reserved memory regions is used. Should you update the reserved memory bindings documentation (Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) to document usage of the memory-region-names property ? Okay, I will update documentation as well. Then, once it is done, the proper setup of DMA parameters (max segment size) is applied for all multimedia devices found on Exynos SoCs to let them properly handle shared buffers mapped into contiguous DMA address space. The last patch adds support for IOMMU to MFC driver. Some additional code is needed because of specific requirements of MFC device firmware (see patch 7 for more details). When no IOMMU is available, the code fallbacks to generic reserved memory regions. After applying this patchset, MFC device works correctly when IOMMU is either enabled or disabled. Patches have been tested on top of linux-next from 20151207. I would prefer to merge patches 1-2 via Samsung tree and patches 3-7 via media tree (there are no compile-time dependencies between patches 1-2 and 3-7). Patches have been tested on Odroid U3 (Exynos 4412 based) and Odroid XU3 (Exynos 5422 based) boards. Best regards Marek Szyprowski Samsung R Institute Poland Changelog: v2: - reworked of_reserved_mem_init* functions on request from Rob Herring, added separate index and name based selection of reserved region - adapted for of_reserved_mem_init* related changes v1: https://www.mail-archive.com/linux-media@vger.kernel.org/msg94100.html - initial version of another approach for this problem, rewrote driver code for new reserved memory bindings, which finally have been merged some time ago v0: http://lists.infradead.org/pipermail/linux-arm-kernel/2013-August/189259.ht ml - old patchset solving the same problem, abandoned due to other tasks and long time of merging reserved memory bindings and support code for it Patch summary: Marek Szyprowski (7): ARM: Exynos: convert MFC device to generic reserved memory bindings ARM: dts: exynos4412-odroid*: enable MFC device of: reserved_mem: add support for named reserved mem nodes media: vb2-dma-contig: add helper for setting dma max seg size media: set proper max seg size for devices on Exynos SoCs media: s5p-mfc: replace custom reserved memory init code with generic one media: s5p-mfc: add iommu support .../devicetree/bindings/media/s5p-mfc.txt | 16 +-- arch/arm/boot/dts/exynos4210-origen.dts| 22 ++- arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 ++- arch/arm/boot/dts/exynos4412-odroid-common.dtsi| 24 arch/arm/boot/dts/exynos4412-origen.dts| 22 ++- arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 ++- arch/arm/boot/dts/exynos5250-arndale.dts | 22 ++- arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 ++- arch/arm/boot/dts/exynos5250-spring.dts| 22 ++- arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 ++- arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 ++- arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 22 ++- arch/arm/mach-exynos/Makefile | 2 - arch/arm/mach-exynos/exynos.c | 19 --- arch/arm/mach-exynos/mfc.h | 16 --- arch/arm/mach-exynos/s5p-dev-mfc.c | 94 - drivers/media/platform/exynos-gsc/gsc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-is.c| 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 1 + drivers/media/platform/s5p-g2d/g2d.c | 1 + drivers/media/platform/s5p-jpeg/jpeg-core.c| 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 153 ++ drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 79 +++ drivers/media/platform/s5p-tv/mixer_video.c| 1 + drivers/media/v4l2-core/videobuf2-dma-contig.c | 15 ++ drivers/of/of_reserved_mem.c | 104 +++--- include/linux/of_reserved_mem.h| 31 - include/media/videobuf2-dma-contig.h | 1 + 29 files changed, 533 insertions(+), 248 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/mach-exynos/s5p-dev-mfc.c create mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of
Re: [PATCH v2 4/7] media: vb2-dma-contig: add helper for setting dma max seg size
Hello, On 2015-12-13 20:57, Laurent Pinchart wrote: Hi Marek, Thank you for the patch. On Wednesday 09 December 2015 14:58:19 Marek Szyprowski wrote: Add a helper function for device drivers to set DMA's max_seg_size. Setting it to largest possible value lets DMA-mapping API always create contiguous mappings in DMA address space. This is essential for all devices, which use dma-contig videobuf2 memory allocator and shared buffers. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 15 +++ include/media/videobuf2-dma-contig.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index c331272..628518d 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -742,6 +742,21 @@ void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) } EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size) +{ + if (!dev->dma_parms) { When can this function be called with dev->dma_parms not NULL ? When one loads a module with multimedia driver (which calls this function), then unloads and loads it again. It is rather safe to have this check. + dev->dma_parms = devm_kzalloc(dev, sizeof(dev->dma_parms), + GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + if (dma_get_max_seg_size(dev) < size) + return dma_set_max_seg_size(dev, size); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); + MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak <pa...@osciak.com>"); MODULE_LICENSE("GPL"); diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index c33dfa6..0e6ba64 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -26,6 +26,7 @@ vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) void *vb2_dma_contig_init_ctx(struct device *dev); void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); extern const struct vb2_mem_ops vb2_dma_contig_memops; Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/7] of: reserved_mem: add support for named reserved mem nodes
Hello, On 2015-12-08 15:58, Rob Herring wrote: On Mon, Dec 7, 2015 at 6:08 AM, Marek Szyprowski <m.szyprow...@samsung.com> wrote: This patch allows device drivers to use more than one reserved memory region assigned to given device. When NULL name is passed to of_reserved_mem_device_init(), the default (first) region is used. Every property that's an array does not need a name property. Just use indexes please. Okay, I will update the patch and add support for indices in the main implementation as well as a wrapper, which accepts "name" parameter. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/of/of_reserved_mem.c| 101 +++- include/linux/of_reserved_mem.h | 6 ++- 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 1a3556a9e9ea..0a0b23b73004 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MAX_RESERVED_REGIONS 16 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; @@ -287,31 +288,84 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) return NULL; } +static struct reserved_mem *__node_to_rmem(struct device_node *node, + const char *name) +{ + struct reserved_mem *rmem; + struct device_node *target; + int idx = 0; + + if (!node) + return NULL; + + if (name) { + idx = of_property_match_string(node, + "memory-region-names", name); + if (idx < 0) + return NULL; + } + + target = of_parse_phandle(node, "memory-region", idx); + if (!target) + return NULL; + rmem = __find_rmem(target); + of_node_put(target); + + return rmem; +} + +struct rmem_assigned_device { + struct device *dev; + struct reserved_mem *rmem; + struct list_head list; +}; + +static LIST_HEAD(of_rmem_assigned_device_list); +static DEFINE_MUTEX(of_rmem_assigned_device_mutex); Not that this is a fast or contended path, but I think a spinlock would be more appropriate here. This is not meant to be called really often and for all kinds on initialization lists and structures I saw that mutexes are used instead of spinlocks. There is no intention to let this function to be called from atomic context. + /** * of_reserved_mem_device_init() - assign reserved memory region to given device + * @dev: Pointer to the device to configure + * @np:Pointer to the device_node with 'reserved-memory' property + * @name: Optional name of the selected region (can be NULL) + * + * This function assigns respective DMA-mapping operations based on reserved + * memory regionspecified by 'memory-region' property in @np node, named @name + * to the @dev device. When NULL name is provided, the default (first) memory + * region is used. When driver needs to use more than one reserved memory + * region, it should allocate child devices and initialize regions by name for + * each of child device. * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. + * Returns error code or zero on success. */ -int of_reserved_mem_device_init(struct device *dev) +int of_reserved_mem_device_init(struct device *dev, struct device_node *np, + const char *name) { + struct rmem_assigned_device *rd; struct reserved_mem *rmem; - struct device_node *np; int ret; - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return -ENODEV; - - rmem = __find_rmem(np); - of_node_put(np); - + rmem = __node_to_rmem(np, name); if (!rmem || !rmem->ops || !rmem->ops->device_init) return -EINVAL; + rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); + if (!rd) + return -ENOMEM; + ret = rmem->ops->device_init(rmem, dev); - if (ret == 0) + if (ret == 0) { + rd->dev = dev; + rd->rmem = rmem; + + mutex_lock(_rmem_assigned_device_mutex); + list_add(>list, _rmem_assigned_device_list); + mutex_unlock(_rmem_assigned_device_mutex); + dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + } else { + kfree(rd); + } return ret; } @@ -319,21 +373,26 @@ EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); /** * of_reserved_mem_device_release() - release reserved memory device structures + * @dev: Pointer to t
[PATCH v2 0/7] Exynos: MFC driver: reserved memory cleanup and IOMMU support
Hello, This patchset finally perform cleanup of custom code in s5p-mfc codec driver. The first part is removal of custom, driver specific code for intializing and handling of reserved memory. Instead, a generic code for reserved memory regions is used. Then, once it is done, the proper setup of DMA parameters (max segment size) is applied for all multimedia devices found on Exynos SoCs to let them properly handle shared buffers mapped into contiguous DMA address space. The last patch adds support for IOMMU to MFC driver. Some additional code is needed because of specific requirements of MFC device firmware (see patch 7 for more details). When no IOMMU is available, the code fallbacks to generic reserved memory regions. After applying this patchset, MFC device works correctly when IOMMU is either enabled or disabled. Patches have been tested on top of linux-next from 20151207. I would prefer to merge patches 1-2 via Samsung tree and patches 3-7 via media tree (there are no compile-time dependencies between patches 1-2 and 3-7). Patches have been tested on Odroid U3 (Exynos 4412 based) and Odroid XU3 (Exynos 5422 based) boards. Best regards Marek Szyprowski Samsung R Institute Poland Changelog: v2: - reworked of_reserved_mem_init* functions on request from Rob Herring, added separate index and name based selection of reserved region - adapted for of_reserved_mem_init* related changes v1: https://www.mail-archive.com/linux-media@vger.kernel.org/msg94100.html - initial version of another approach for this problem, rewrote driver code for new reserved memory bindings, which finally have been merged some time ago v0: http://lists.infradead.org/pipermail/linux-arm-kernel/2013-August/189259.html - old patchset solving the same problem, abandoned due to other tasks and long time of merging reserved memory bindings and support code for it Patch summary: Marek Szyprowski (7): ARM: Exynos: convert MFC device to generic reserved memory bindings ARM: dts: exynos4412-odroid*: enable MFC device of: reserved_mem: add support for named reserved mem nodes media: vb2-dma-contig: add helper for setting dma max seg size media: set proper max seg size for devices on Exynos SoCs media: s5p-mfc: replace custom reserved memory init code with generic one media: s5p-mfc: add iommu support .../devicetree/bindings/media/s5p-mfc.txt | 16 +-- arch/arm/boot/dts/exynos4210-origen.dts| 22 ++- arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 ++- arch/arm/boot/dts/exynos4412-odroid-common.dtsi| 24 arch/arm/boot/dts/exynos4412-origen.dts| 22 ++- arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 ++- arch/arm/boot/dts/exynos5250-arndale.dts | 22 ++- arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 ++- arch/arm/boot/dts/exynos5250-spring.dts| 22 ++- arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 ++- arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 ++- arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 22 ++- arch/arm/mach-exynos/Makefile | 2 - arch/arm/mach-exynos/exynos.c | 19 --- arch/arm/mach-exynos/mfc.h | 16 --- arch/arm/mach-exynos/s5p-dev-mfc.c | 94 - drivers/media/platform/exynos-gsc/gsc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-is.c| 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 1 + drivers/media/platform/s5p-g2d/g2d.c | 1 + drivers/media/platform/s5p-jpeg/jpeg-core.c| 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 153 - drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 79 +++ drivers/media/platform/s5p-tv/mixer_video.c| 1 + drivers/media/v4l2-core/videobuf2-dma-contig.c | 15 ++ drivers/of/of_reserved_mem.c | 104 +++--- include/linux/of_reserved_mem.h| 31 - include/media/videobuf2-dma-contig.h | 1 + 29 files changed, 533 insertions(+), 248 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/mach-exynos/s5p-dev-mfc.c create mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/7] ARM: Exynos: convert MFC device to generic reserved memory bindings
This patch replaces custom properties for definining reserved memory regions with generic reserved memory bindings. All custom code for handling MFC-specific reserved memory can be now removed from Exynos-DT generic board code. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- .../devicetree/bindings/media/s5p-mfc.txt | 16 ++-- arch/arm/boot/dts/exynos4210-origen.dts| 22 - arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 - arch/arm/boot/dts/exynos4412-origen.dts| 22 - arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 - arch/arm/boot/dts/exynos5250-arndale.dts | 22 - arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 - arch/arm/boot/dts/exynos5250-spring.dts| 22 - arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 - arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 - arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 22 - arch/arm/mach-exynos/Makefile | 2 - arch/arm/mach-exynos/exynos.c | 19 - arch/arm/mach-exynos/mfc.h | 16 arch/arm/mach-exynos/s5p-dev-mfc.c | 94 -- 15 files changed, 208 insertions(+), 159 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/mach-exynos/s5p-dev-mfc.c diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 2d5787e..4603673 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -21,16 +21,16 @@ Required properties: - clock-names : from common clock binding: must contain "mfc", corresponding to entry in the clocks property. - - samsung,mfc-r : Base address of the first memory bank used by MFC - for DMA contiguous memory allocation and its size. - - - samsung,mfc-l : Base address of the second memory bank used by MFC - for DMA contiguous memory allocation and its size. - Optional properties: - power-domains : power-domain property defined with a phandle to respective power domain. + - memory-region : from reserved memory binding: phandles to two reserved + memory regions: accessed by "left" and "right" mfc memory bus + interfaces, used when no SYSMMU support is available + - memory-region-names : from reserved memory binding: must be "left" + and "right" + Example: SoC specific DT entry: @@ -46,6 +46,6 @@ mfc: codec@1340 { Board specific DT entry: codec@1340 { - samsung,mfc-r = <0x4300 0x80>; - samsung,mfc-l = <0x5100 0x80>; + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; }; diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index b8f8669..5a5ec93 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -30,6 +30,24 @@ 0x7000 0x1000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@5100 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x5100 0x80>; + }; + + mfc_right: region@4300 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x4300 0x80>; + }; + }; + chosen { bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x4100,8M console=ttySAC2,115200 init=/linuxrc"; stdout-path = _2; @@ -292,8 +310,8 @@ }; { - samsung,mfc-r = <0x4300 0x80>; - samsung,mfc-l = <0x5100 0x80>; + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; status = "okay"; }; diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts index bc1448b..0d204b7 100644 --- a/arch/arm/boot/dts/exynos4210-smdkv310.dts +++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts @@ -26,6 +26,24 @@ reg = <0x4000 0x8000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@5100 { + compatible = "shared-dma-pool"; + no-map; +
[PATCH v2 7/7] media: s5p-mfc: add iommu support
This patch adds support for IOMMU to s5p-mfc device driver. MFC firmware is limited and it cannot use the default configuration. If IOMMU is available, the patch disables the default DMA address space configuration and creates a new address space of size limited to 256M and base address set to 0x2000. For now the same address space is shared by both 'left' and 'right' memory channels, because the DMA/IOMMU frameworks do not support configuring them separately. This is not optimal, but besides limiting total address space available has no other drawbacks (MFC firmware supports 256M of address space per each channel). Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 24 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 79 ++ 2 files changed, 103 insertions(+) create mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 3063449..bae7c0f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -30,6 +30,7 @@ #include "s5p_mfc_dec.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" +#include "s5p_mfc_iommu.h" #include "s5p_mfc_opr.h" #include "s5p_mfc_cmd.h" #include "s5p_mfc_pm.h" @@ -1061,6 +1062,22 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = _dev->plat_dev->dev; /* +* When IOMMU is available, we cannot use the default configuration, +* because of MFC firmware requirements: address space limited to +* 256M and non-zero default start address. +* This is still simplified, not optimal configuration, but for now +* IOMMU core doesn't allow to configure device's IOMMUs channel +* separately. +*/ + if (exynos_is_iommu_available(dev)) { + int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, +S5P_MFC_IOMMU_DMA_SIZE); + if (ret == 0) + mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev; + return ret; + } + + /* * Create and initialize virtual devices for accessing * reserved memory regions. */ @@ -1078,6 +1095,13 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) { + struct device *dev = _dev->plat_dev->dev; + + if (exynos_is_iommu_available(dev)) { + exynos_unconfigure_iommu(dev); + return; + } + device_unregister(mfc_dev->mem_dev_l); device_unregister(mfc_dev->mem_dev_r); } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h new file mode 100644 index 000..5d1d1c2 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co.Ltd + * Authors: Marek Szyprowski <m.szyprow...@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 + * option) any later version. + */ + +#ifndef S5P_MFC_IOMMU_H_ +#define S5P_MFC_IOMMU_H_ + +#define S5P_MFC_IOMMU_DMA_BASE 0x2000lu +#define S5P_MFC_IOMMU_DMA_SIZE SZ_256M + +#ifdef CONFIG_EXYNOS_IOMMU + +#include + +static inline bool exynos_is_iommu_available(struct device *dev) +{ + return dev->archdata.iommu != NULL; +} + +static inline void exynos_unconfigure_iommu(struct device *dev) +{ + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); +} + +static inline int exynos_configure_iommu(struct device *dev, +unsigned int base, unsigned int size) +{ + struct dma_iommu_mapping *mapping = NULL; + int ret; + + /* Disable the default mapping created by device core */ + if (to_dma_iommu_mapping(dev)) + exynos_unconfigure_iommu(dev); + + mapping = arm_iommu_create_mapping(dev->bus, base, size); + if (IS_ERR(mapping)) { + pr_warn("Failed to create IOMMU mapping for device %s\n", + dev_name(dev)); + return PTR_ERR(mapping); + } + + ret = arm_iommu_attach_device(dev, mapping); + if (ret) { + pr_warn("Failed to attached device %s to IOMMU_mapping\n", + dev_name(dev)); + arm_iommu_release_mapping(mapping); +
[PATCH v2 3/7] of: reserved_mem: add support for named reserved mem nodes
This patch allows device drivers to initialize more than one reserved memory region assigned to given device. When driver needs to use more than one reserved memory region, it should allocate child devices and initialize regions by index or name for each of its child devices. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/of/of_reserved_mem.c| 104 include/linux/of_reserved_mem.h | 31 ++-- 2 files changed, 112 insertions(+), 23 deletions(-) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index be77e75..a583480 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MAX_RESERVED_REGIONS 16 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; @@ -281,53 +282,116 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) return NULL; } +struct rmem_assigned_device { + struct device *dev; + struct reserved_mem *rmem; + struct list_head list; +}; + +static LIST_HEAD(of_rmem_assigned_device_list); +static DEFINE_MUTEX(of_rmem_assigned_device_mutex); + /** * of_reserved_mem_device_init() - assign reserved memory region to given device + * @dev: Pointer to the device to configure + * @np:Pointer to the device_node with 'reserved-memory' property + * @idx: Index of selected region + * + * This function assigns respective DMA-mapping operations based on reserved + * memory region specified by 'memory-region' property in @np node to the @dev + * device. When driver needs to use more than one reserved memory region, it + * should allocate child devices and initialize regions by name for each of + * child device. * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. + * Returns error code or zero on success. */ -int of_reserved_mem_device_init(struct device *dev) +int of_reserved_mem_init(struct device *dev, struct device_node *np, int idx) { + struct rmem_assigned_device *rd; + struct device_node *target; struct reserved_mem *rmem; - struct device_node *np; int ret; - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return -ENODEV; + if (!np || !dev) + return -EINVAL; + + target = of_parse_phandle(np, "memory-region", idx); + if (!target) + return -EINVAL; - rmem = __find_rmem(np); - of_node_put(np); + rmem = __find_rmem(target); + of_node_put(target); if (!rmem || !rmem->ops || !rmem->ops->device_init) return -EINVAL; + rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); + if (!rd) + return -ENOMEM; + ret = rmem->ops->device_init(rmem, dev); - if (ret == 0) + if (ret == 0) { + rd->dev = dev; + rd->rmem = rmem; + + mutex_lock(_rmem_assigned_device_mutex); + list_add(>list, _rmem_assigned_device_list); + mutex_unlock(_rmem_assigned_device_mutex); + dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + } else { + kfree(rd); + } return ret; } -EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); +EXPORT_SYMBOL_GPL(of_reserved_mem_init); + +/** + * of_reserved_mem_device_init() - assign reserved memory region to given device + * @dev: Pointer to the device to configure + * @np:Pointer to the device_node with 'reserved-memory' property + * @name: Name of the selected region + * + * This function assigns respective DMA-mapping operations based on reserved + * memory region specified by 'memory-region' property in @np node, named @name + * to the @dev device. + * + * Returns error code or zero on success. + */ +int of_reserved_mem_init_by_name(struct device *dev, struct device_node *np, + const char *name) +{ + int idx = of_property_match_string(np, "memory-region-names", name); + + if (idx < 0) + return -EINVAL; + return of_reserved_mem_init(dev, np, idx); +} +EXPORT_SYMBOL_GPL(of_reserved_mem_init_by_name); /** * of_reserved_mem_device_release() - release reserved memory device structures + * @dev: Pointer to the device to deconfigure * * 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 *rmem; - struct device_node *np; - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return; - - rm
[PATCH v2 5/7] media: set proper max seg size for devices on Exynos SoCs
All multimedia devices found on Exynos SoCs support only contiguous buffers, so set DMA max segment size to DMA_BIT_MASK(32) to let memory allocator to correctly create contiguous memory mappings. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/exynos-gsc/gsc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-is.c | 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 1 + drivers/media/platform/s5p-g2d/g2d.c | 1 + drivers/media/platform/s5p-jpeg/jpeg-core.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 ++ drivers/media/platform/s5p-tv/mixer_video.c | 1 + 8 files changed, 9 insertions(+) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 9b9e423..4f90be4 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1140,6 +1140,7 @@ static int gsc_probe(struct platform_device *pdev) goto err_m2m; /* Initialize continious memory allocator */ + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(gsc->alloc_ctx)) { ret = PTR_ERR(gsc->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index cef2a7f..368e19b 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -1019,6 +1019,7 @@ static int fimc_probe(struct platform_device *pdev) } /* Initialize contiguous memory allocator */ + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 49658ca..123772f 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -841,6 +841,7 @@ static int fimc_is_probe(struct platform_device *pdev) if (ret < 0) goto err_pm; + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); is->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(is->alloc_ctx)) { ret = PTR_ERR(is->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 60660c3..a7e47c7 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1564,6 +1564,7 @@ static int fimc_lite_probe(struct platform_device *pdev) goto err_sd; } + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index e1936d9..31f6c23 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -681,6 +681,7 @@ static int g2d_probe(struct platform_device *pdev) goto put_clk_gate; } + vb2_dma_contig_set_max_seg_size(>dev, DMA_BIT_MASK(32)); dev->alloc_ctx = vb2_dma_contig_init_ctx(>dev); if (IS_ERR(dev->alloc_ctx)) { ret = PTR_ERR(dev->alloc_ctx); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 4a608cb..6bd92f0 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2839,6 +2839,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) goto device_register_rollback; } + vb2_dma_contig_set_max_seg_size(>dev, DMA_BIT_MASK(32)); jpeg->alloc_ctx = vb2_dma_contig_init_ctx(>dev); if (IS_ERR(jpeg->alloc_ctx)) { v4l2_err(>v4l2_dev, "Failed to init memory allocator\n"); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 3ffe2ec..3e9cdaf 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1143,11 +1143,13 @@ static int s5p_mfc_probe(struct platform_device *pdev) } } + vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32)); dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); if (IS_ERR(dev->alloc_ctx[0])) { ret = PTR_ERR(dev->alloc_ctx[0]); goto err_res; } + vb2_dma_contig_set_max_seg_size(dev->mem_dev_r, DMA_BIT_MASK(32)); dev->alloc_ctx[
[PATCH v2 4/7] media: vb2-dma-contig: add helper for setting dma max seg size
Add a helper function for device drivers to set DMA's max_seg_size. Setting it to largest possible value lets DMA-mapping API always create contiguous mappings in DMA address space. This is essential for all devices, which use dma-contig videobuf2 memory allocator and shared buffers. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 15 +++ include/media/videobuf2-dma-contig.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index c331272..628518d 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -742,6 +742,21 @@ void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) } EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size) +{ + if (!dev->dma_parms) { + dev->dma_parms = devm_kzalloc(dev, sizeof(dev->dma_parms), + GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + if (dma_get_max_seg_size(dev) < size) + return dma_set_max_seg_size(dev, size); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); + MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak <pa...@osciak.com>"); MODULE_LICENSE("GPL"); diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index c33dfa6..0e6ba64 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -26,6 +26,7 @@ vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) void *vb2_dma_contig_init_ctx(struct device *dev); void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); extern const struct vb2_mem_ops vb2_dma_contig_memops; -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 6/7] media: s5p-mfc: replace custom reserved memory init code with generic one
This patch removes custom code for initialization and handling of reserved memory regions in s5p-mfc driver and replaces it with generic named reserved memory regions specified in device tree. s5p-mfc driver now handles two reserved memory regions: "left" and "right", defined by generic reserved memory bindings. Support for non-dt platform has been removed, because all supported platforms have been converted to device tree. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 129 +++ 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 3e9cdaf..3063449 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "s5p_mfc_common.h" #include "s5p_mfc_ctrl.h" @@ -1022,55 +1023,67 @@ static const struct v4l2_file_operations s5p_mfc_fops = { .mmap = s5p_mfc_mmap, }; -static int match_child(struct device *dev, void *data) +/* DMA memory related helper functions */ +static void s5p_mfc_memdev_release(struct device *dev) { - if (!dev_name(dev)) - return 0; - return !strcmp(dev_name(dev), (char *)data); + of_reserved_mem_device_release(dev); } -static void *mfc_get_drv_data(struct platform_device *pdev); - -static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) +static struct device *s5p_mfc_alloc_memdev(struct device *dev, const char *name) { - unsigned int mem_info[2] = { }; + struct device *child; + int ret; - dev->mem_dev_l = devm_kzalloc(>plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_l) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_l); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-l", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_l, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - mfc_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; + child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL); + if (!child) + return NULL; + + device_initialize(child); + dev_set_name(child, "%s:%s", dev_name(dev), name); + child->parent = dev; + child->bus = dev->bus; + child->coherent_dma_mask = dev->coherent_dma_mask; + child->dma_mask = dev->dma_mask; + child->release = s5p_mfc_memdev_release; + + if (device_add(child) == 0) { + ret = of_reserved_mem_init_by_name(child, dev->of_node, name); + if (ret == 0) + return child; } - dev->mem_dev_r = devm_kzalloc(>plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_r) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_r); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-r", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_r, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - pr_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; + put_device(child); + return NULL; +} + +static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = _dev->plat_dev->dev; + + /* +* Create and initialize virtual devices for accessing +* reserved memory regions. +*/ + mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left"); + if (!mfc_dev->mem_dev_l) + return -ENODEV; + mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right"); + if (!mfc_dev->mem_dev_r) { + device_unregister(mfc_dev->mem_dev_l); + return -ENODEV; } + return 0; } +static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + device_unregister(mfc_dev->mem_dev_l); + device_unregister(mfc_dev->mem_dev_r); +} + +static void *mfc_get_drv_data(struct platform_device *pdev); + /* MFC probe function */ static int s5p_mfc_probe(
[PATCH v2 2/7] ARM: dts: exynos4412-odroid*: enable MFC device
Enable support for Multimedia Codec (MFC) device for all Exynos4412-based Odroid boards. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 24 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index edf0fc8..5825abf 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -18,6 +18,24 @@ stdout-path = _1; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@7700 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x7700 0x100>; + }; + + mfc_right: region@7800 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x7800 0x100>; + }; + }; + firmware@0204F000 { compatible = "samsung,secure-firmware"; reg = <0x0204F000 0x1000>; @@ -451,6 +469,12 @@ clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; }; + { + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; + status = "okay"; +}; + { status = "okay"; }; -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/7] Exynos: MFC driver: reserved memory cleanup and IOMMU support
Hello, On 2015-12-07 13:08, Marek Szyprowski wrote: This patchset finally perform cleanup of custom code in s5p-mfc codec driver. The first part is removal of custom, driver specific code for intializing and handling of reserved memory. Instead, a generic code for reserved memory regions is used. Then, once it is done, the proper setup of DMA parameters (max segment size) is applied for all multimedia devices found on Exynos SoCs to let them properly handle shared buffers mapped into contiguous DMA address space. The last patch adds support for IOMMU to MFC driver. Some additional code is needed because of specific requirements of MFC device firmware (see patch 7 for more details). When no IOMMU is available, the code fallbacks to generic reserved memory regions. After applying this patchset, MFC device works correctly when IOMMU is either enabled or disabled. Patches have been tested on top of linux-next from 20151207. I would prefer to merge patches 1-2 via Samsung tree and patches 3-7 via media tree (there are no compile-time dependencies between patches 1-2 and 3-7). Patches have been tested on Odroid U3 (Exynos 4412 based) and Odroid XU3 (Exynos 5422 based) boards. One more notice: this is an updated version of the old patch initially posted here: http://lists.infradead.org/pipermail/linux-arm-kernel/2013-August/189259.html The main change since that is adaptation for generic reserved memory bindings, which have been merged a while ago and added support for IOMMU. Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/7] of: reserved_mem: add support for named reserved mem nodes
This patch allows device drivers to use more than one reserved memory region assigned to given device. When NULL name is passed to of_reserved_mem_device_init(), the default (first) region is used. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/of/of_reserved_mem.c| 101 +++- include/linux/of_reserved_mem.h | 6 ++- 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 1a3556a9e9ea..0a0b23b73004 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MAX_RESERVED_REGIONS 16 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; @@ -287,31 +288,84 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) return NULL; } +static struct reserved_mem *__node_to_rmem(struct device_node *node, + const char *name) +{ + struct reserved_mem *rmem; + struct device_node *target; + int idx = 0; + + if (!node) + return NULL; + + if (name) { + idx = of_property_match_string(node, + "memory-region-names", name); + if (idx < 0) + return NULL; + } + + target = of_parse_phandle(node, "memory-region", idx); + if (!target) + return NULL; + rmem = __find_rmem(target); + of_node_put(target); + + return rmem; +} + +struct rmem_assigned_device { + struct device *dev; + struct reserved_mem *rmem; + struct list_head list; +}; + +static LIST_HEAD(of_rmem_assigned_device_list); +static DEFINE_MUTEX(of_rmem_assigned_device_mutex); + /** * of_reserved_mem_device_init() - assign reserved memory region to given device + * @dev: Pointer to the device to configure + * @np:Pointer to the device_node with 'reserved-memory' property + * @name: Optional name of the selected region (can be NULL) + * + * This function assigns respective DMA-mapping operations based on reserved + * memory regionspecified by 'memory-region' property in @np node, named @name + * to the @dev device. When NULL name is provided, the default (first) memory + * region is used. When driver needs to use more than one reserved memory + * region, it should allocate child devices and initialize regions by name for + * each of child device. * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. + * Returns error code or zero on success. */ -int of_reserved_mem_device_init(struct device *dev) +int of_reserved_mem_device_init(struct device *dev, struct device_node *np, + const char *name) { + struct rmem_assigned_device *rd; struct reserved_mem *rmem; - struct device_node *np; int ret; - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return -ENODEV; - - rmem = __find_rmem(np); - of_node_put(np); - + rmem = __node_to_rmem(np, name); if (!rmem || !rmem->ops || !rmem->ops->device_init) return -EINVAL; + rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); + if (!rd) + return -ENOMEM; + ret = rmem->ops->device_init(rmem, dev); - if (ret == 0) + if (ret == 0) { + rd->dev = dev; + rd->rmem = rmem; + + mutex_lock(_rmem_assigned_device_mutex); + list_add(>list, _rmem_assigned_device_list); + mutex_unlock(_rmem_assigned_device_mutex); + dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + } else { + kfree(rd); + } return ret; } @@ -319,21 +373,26 @@ EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); /** * of_reserved_mem_device_release() - release reserved memory device structures + * @dev: Pointer to the device to deconfigure * * 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 *rmem; - struct device_node *np; - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return; - - rmem = __find_rmem(np); - of_node_put(np); + struct rmem_assigned_device *rd; + struct reserved_mem *rmem = NULL; + + mutex_lock(_rmem_assigned_device_mutex); + list_for_each_entry(rd, _rmem_assigned_device_list, list) { + if (rd->dev == dev) { + rmem = rd->rme
[PATCH 5/7] media: set proper max seg size for devices on Exynos SoCs
All multimedia devices found on Exynos SoCs support only contiguous buffers, so set DMA max segment size to DMA_BIT_MASK(32) to let memory allocator to correctly create contiguous memory mappings. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/exynos-gsc/gsc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-is.c | 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 1 + drivers/media/platform/s5p-g2d/g2d.c | 1 + drivers/media/platform/s5p-jpeg/jpeg-core.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 ++ drivers/media/platform/s5p-tv/mixer_video.c | 1 + 8 files changed, 9 insertions(+) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 9b9e423e4fc4..4f90be43b5a9 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1140,6 +1140,7 @@ static int gsc_probe(struct platform_device *pdev) goto err_m2m; /* Initialize continious memory allocator */ + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(gsc->alloc_ctx)) { ret = PTR_ERR(gsc->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index cef2a7f07cdb..368e19b50498 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -1019,6 +1019,7 @@ static int fimc_probe(struct platform_device *pdev) } /* Initialize contiguous memory allocator */ + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 49658ca39e51..123772fa0241 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -841,6 +841,7 @@ static int fimc_is_probe(struct platform_device *pdev) if (ret < 0) goto err_pm; + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); is->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(is->alloc_ctx)) { ret = PTR_ERR(is->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 6f76afd909c4..9cfd2221f53d 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1564,6 +1564,7 @@ static int fimc_lite_probe(struct platform_device *pdev) goto err_sd; } + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index e1936d9d27da..31f6c233b146 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -681,6 +681,7 @@ static int g2d_probe(struct platform_device *pdev) goto put_clk_gate; } + vb2_dma_contig_set_max_seg_size(>dev, DMA_BIT_MASK(32)); dev->alloc_ctx = vb2_dma_contig_init_ctx(>dev); if (IS_ERR(dev->alloc_ctx)) { ret = PTR_ERR(dev->alloc_ctx); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 4a608cbe0fdb..6bd92f014a23 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2839,6 +2839,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) goto device_register_rollback; } + vb2_dma_contig_set_max_seg_size(>dev, DMA_BIT_MASK(32)); jpeg->alloc_ctx = vb2_dma_contig_init_ctx(>dev); if (IS_ERR(jpeg->alloc_ctx)) { v4l2_err(>v4l2_dev, "Failed to init memory allocator\n"); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 81ffb67e6d66..8fcecf8a9a17 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1164,11 +1164,13 @@ static int s5p_mfc_probe(struct platform_device *pdev) } } + vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32)); dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); if (IS_ERR(dev->alloc_ctx[0])) { ret = PTR_ERR(dev->alloc_ctx[0]); goto err_res; } + vb2_dma_contig_set_max
[PATCH 6/7] media: s5p-mfc: replace custom reserved memory init code with generic one
This patch removes custom code for initialization and handling of reserved memory regions in s5p-mfc driver and replaces it with generic named reserved memory regions specified in device tree. s5p-mfc driver now handles two reserved memory regions: "left" and "right", defined by generic reserved memory bindings. Support for non-dt platform has been removed, because all supported platforms have been converted to device tree. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 129 +++ 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 8fcecf8a9a17..55c557f835f2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "s5p_mfc_common.h" #include "s5p_mfc_ctrl.h" @@ -1043,55 +1044,67 @@ static const struct v4l2_file_operations s5p_mfc_fops = { .mmap = s5p_mfc_mmap, }; -static int match_child(struct device *dev, void *data) +/* DMA memory related helper functions */ +static void s5p_mfc_memdev_release(struct device *dev) { - if (!dev_name(dev)) - return 0; - return !strcmp(dev_name(dev), (char *)data); + of_reserved_mem_device_release(dev); } -static void *mfc_get_drv_data(struct platform_device *pdev); - -static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) +static struct device *s5p_mfc_alloc_memdev(struct device *dev, const char *name) { - unsigned int mem_info[2] = { }; + struct device *child; + int ret; - dev->mem_dev_l = devm_kzalloc(>plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_l) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_l); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-l", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_l, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - mfc_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; + child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL); + if (!child) + return NULL; + + device_initialize(child); + dev_set_name(child, "%s:%s", dev_name(dev), name); + child->parent = dev; + child->bus = dev->bus; + child->coherent_dma_mask = dev->coherent_dma_mask; + child->dma_mask = dev->dma_mask; + child->release = s5p_mfc_memdev_release; + + if (device_add(child) == 0) { + ret = of_reserved_mem_device_init(child, dev->of_node, name); + if (ret == 0) + return child; } - dev->mem_dev_r = devm_kzalloc(>plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_r) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_r); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-r", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_r, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - pr_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; + put_device(child); + return NULL; +} + +static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = _dev->plat_dev->dev; + + /* +* Create and initialize virtual devices for accessing +* reserved memory regions. +*/ + mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left"); + if (!mfc_dev->mem_dev_l) + return -ENODEV; + mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right"); + if (!mfc_dev->mem_dev_r) { + device_unregister(mfc_dev->mem_dev_l); + return -ENODEV; } + return 0; } +static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + device_unregister(mfc_dev->mem_dev_l); + device_unregister(mfc_dev->mem_dev_r); +} + +static void *mfc_get_drv_data(struct platform_device *pdev); + /* MFC probe function */ static int s5p_m
[PATCH 1/7] ARM: Exynos: convert MFC device to generic reserved memory bindings
This patch replaces custom properties for definining reserved memory regions with generic reserved memory bindings. All custom code for handling MFC-specific reserved memory can be now removed from Exynos-DT generic board code. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- .../devicetree/bindings/media/s5p-mfc.txt | 16 ++-- arch/arm/boot/dts/exynos4210-origen.dts| 22 - arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 - arch/arm/boot/dts/exynos4412-origen.dts| 22 - arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 - arch/arm/boot/dts/exynos5250-arndale.dts | 22 - arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 - arch/arm/boot/dts/exynos5250-spring.dts| 22 - arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 - arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 - arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 22 - arch/arm/mach-exynos/Makefile | 2 - arch/arm/mach-exynos/exynos.c | 19 - arch/arm/mach-exynos/mfc.h | 16 arch/arm/mach-exynos/s5p-dev-mfc.c | 94 -- 15 files changed, 208 insertions(+), 159 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/mach-exynos/s5p-dev-mfc.c diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 2d5787eac91a..4603673c593b 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -21,16 +21,16 @@ Required properties: - clock-names : from common clock binding: must contain "mfc", corresponding to entry in the clocks property. - - samsung,mfc-r : Base address of the first memory bank used by MFC - for DMA contiguous memory allocation and its size. - - - samsung,mfc-l : Base address of the second memory bank used by MFC - for DMA contiguous memory allocation and its size. - Optional properties: - power-domains : power-domain property defined with a phandle to respective power domain. + - memory-region : from reserved memory binding: phandles to two reserved + memory regions: accessed by "left" and "right" mfc memory bus + interfaces, used when no SYSMMU support is available + - memory-region-names : from reserved memory binding: must be "left" + and "right" + Example: SoC specific DT entry: @@ -46,6 +46,6 @@ mfc: codec@1340 { Board specific DT entry: codec@1340 { - samsung,mfc-r = <0x4300 0x80>; - samsung,mfc-l = <0x5100 0x80>; + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; }; diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index 5821ad87e32c..4b7637dfa392 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -30,6 +30,24 @@ 0x7000 0x1000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@5100 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x5100 0x80>; + }; + + mfc_right: region@4300 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x4300 0x80>; + }; + }; + chosen { bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x4100,8M console=ttySAC2,115200 init=/linuxrc"; stdout-path = _2; @@ -288,8 +306,8 @@ }; { - samsung,mfc-r = <0x4300 0x80>; - samsung,mfc-l = <0x5100 0x80>; + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; status = "okay"; }; diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts index 104cbb33d2bb..efafc5721817 100644 --- a/arch/arm/boot/dts/exynos4210-smdkv310.dts +++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts @@ -26,6 +26,24 @@ reg = <0x4000 0x8000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@5100 { + compatible = "shared-dma-pool"; + no-map; +
[PATCH 4/7] media: vb2-dma-contig: add helper for setting dma max seg size
Add a helper function for device drivers to set DMA's max_seg_size. Setting it to largest possible value lets DMA-mapping API always create contiguous mappings in DMA address space. This is essential for all devices, which use dma-contig videobuf2 memory allocator and shared buffers. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- Changelog: v3: - make this code a helper function instead of chaning max_seg_size unconditionally on vb2_dma_contig_init_ctx v2: - set max segment size only if a new dma params structure has been allocated, as suggested by Laurent Pinchart --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 15 +++ include/media/videobuf2-dma-contig.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index c33127284cfe..628518dc3aad 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -742,6 +742,21 @@ void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) } EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size) +{ + if (!dev->dma_parms) { + dev->dma_parms = devm_kzalloc(dev, sizeof(dev->dma_parms), + GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + if (dma_get_max_seg_size(dev) < size) + return dma_set_max_seg_size(dev, size); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); + MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak <pa...@osciak.com>"); MODULE_LICENSE("GPL"); diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index c33dfa69d7ab..0e6ba644939e 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -26,6 +26,7 @@ vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) void *vb2_dma_contig_init_ctx(struct device *dev); void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); extern const struct vb2_mem_ops vb2_dma_contig_memops; -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/7] Exynos: MFC driver: reserved memory cleanup and IOMMU support
Hello, This patchset finally perform cleanup of custom code in s5p-mfc codec driver. The first part is removal of custom, driver specific code for intializing and handling of reserved memory. Instead, a generic code for reserved memory regions is used. Then, once it is done, the proper setup of DMA parameters (max segment size) is applied for all multimedia devices found on Exynos SoCs to let them properly handle shared buffers mapped into contiguous DMA address space. The last patch adds support for IOMMU to MFC driver. Some additional code is needed because of specific requirements of MFC device firmware (see patch 7 for more details). When no IOMMU is available, the code fallbacks to generic reserved memory regions. After applying this patchset, MFC device works correctly when IOMMU is either enabled or disabled. Patches have been tested on top of linux-next from 20151207. I would prefer to merge patches 1-2 via Samsung tree and patches 3-7 via media tree (there are no compile-time dependencies between patches 1-2 and 3-7). Patches have been tested on Odroid U3 (Exynos 4412 based) and Odroid XU3 (Exynos 5422 based) boards. Best regards Marek Szyprowski Samsung R Institute Poland Patch summary: Marek Szyprowski (7): ARM: Exynos: convert MFC device to generic reserved memory bindings ARM: dts: exynos4412-odroid*: enable MFC device of: reserved_mem: add support for named reserved mem nodes media: vb2-dma-contig: add helper for setting dma max seg size media: set proper max seg size for devices on Exynos SoCs media: s5p-mfc: replace custom reserved memory init code with generic one media: s5p-mfc: add iommu support .../devicetree/bindings/media/s5p-mfc.txt | 16 +-- arch/arm/boot/dts/exynos4210-origen.dts| 22 ++- arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 ++- arch/arm/boot/dts/exynos4412-odroid-common.dtsi| 24 arch/arm/boot/dts/exynos4412-origen.dts| 22 ++- arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 ++- arch/arm/boot/dts/exynos5250-arndale.dts | 22 ++- arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 ++- arch/arm/boot/dts/exynos5250-spring.dts| 22 ++- arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 ++- arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 ++- arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi | 22 ++- arch/arm/mach-exynos/Makefile | 2 - arch/arm/mach-exynos/exynos.c | 19 --- arch/arm/mach-exynos/mfc.h | 16 --- arch/arm/mach-exynos/s5p-dev-mfc.c | 94 - drivers/media/platform/exynos-gsc/gsc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-core.c | 1 + drivers/media/platform/exynos4-is/fimc-is.c| 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 1 + drivers/media/platform/s5p-g2d/g2d.c | 1 + drivers/media/platform/s5p-jpeg/jpeg-core.c| 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 153 - drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 79 +++ drivers/media/platform/s5p-tv/mixer_video.c| 1 + drivers/media/v4l2-core/videobuf2-dma-contig.c | 15 ++ drivers/of/of_reserved_mem.c | 101 +++--- include/linux/of_reserved_mem.h| 6 +- include/media/videobuf2-dma-contig.h | 1 + 29 files changed, 505 insertions(+), 248 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/mach-exynos/s5p-dev-mfc.c create mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 7/7] media: s5p-mfc: add iommu support
This patch adds support for IOMMU to s5p-mfc device driver. MFC firmware is limited and it cannot use the default configuration. If IOMMU is available, the patch disables the default DMA address space configuration and creates a new address space of size limited to 256M and base address set to 0x2000. For now the same address space is shared by both 'left' and 'right' memory channels, because the DMA/IOMMU frameworks do not support configuring them separately. This is not optimal, but besides limiting total address space available has no other drawbacks (MFC firmware supports 256M of address space per each channel). Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 24 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 79 ++ 2 files changed, 103 insertions(+) create mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 55c557f835f2..dfbaadd22a3d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -30,6 +30,7 @@ #include "s5p_mfc_dec.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" +#include "s5p_mfc_iommu.h" #include "s5p_mfc_opr.h" #include "s5p_mfc_cmd.h" #include "s5p_mfc_pm.h" @@ -1082,6 +1083,22 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) struct device *dev = _dev->plat_dev->dev; /* +* When IOMMU is available, we cannot use the default configuration, +* because of MFC firmware requirements: address space limited to +* 256M and non-zero default start address. +* This is still simplified, not optimal configuration, but for now +* IOMMU core doesn't allow to configure device's IOMMUs channel +* separately. +*/ + if (exynos_is_iommu_available(dev)) { + int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, +S5P_MFC_IOMMU_DMA_SIZE); + if (ret == 0) + mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev; + return ret; + } + + /* * Create and initialize virtual devices for accessing * reserved memory regions. */ @@ -1099,6 +1116,13 @@ static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) { + struct device *dev = _dev->plat_dev->dev; + + if (exynos_is_iommu_available(dev)) { + exynos_unconfigure_iommu(dev); + return; + } + device_unregister(mfc_dev->mem_dev_l); device_unregister(mfc_dev->mem_dev_r); } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h new file mode 100644 index ..5d1d1c2922e8 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co.Ltd + * Authors: Marek Szyprowski <m.szyprow...@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 + * option) any later version. + */ + +#ifndef S5P_MFC_IOMMU_H_ +#define S5P_MFC_IOMMU_H_ + +#define S5P_MFC_IOMMU_DMA_BASE 0x2000lu +#define S5P_MFC_IOMMU_DMA_SIZE SZ_256M + +#ifdef CONFIG_EXYNOS_IOMMU + +#include + +static inline bool exynos_is_iommu_available(struct device *dev) +{ + return dev->archdata.iommu != NULL; +} + +static inline void exynos_unconfigure_iommu(struct device *dev) +{ + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); +} + +static inline int exynos_configure_iommu(struct device *dev, +unsigned int base, unsigned int size) +{ + struct dma_iommu_mapping *mapping = NULL; + int ret; + + /* Disable the default mapping created by device core */ + if (to_dma_iommu_mapping(dev)) + exynos_unconfigure_iommu(dev); + + mapping = arm_iommu_create_mapping(dev->bus, base, size); + if (IS_ERR(mapping)) { + pr_warn("Failed to create IOMMU mapping for device %s\n", + dev_name(dev)); + return PTR_ERR(mapping); + } + + ret = arm_iommu_attach_device(dev, mapping); + if (ret) { + pr_warn("Failed to attached device %s to IOMMU_mapping\n", + dev_name(dev)); + arm_iommu_release_mapping(mapping);
[PATCH 2/7] ARM: dts: exynos4412-odroid*: enable MFC device
Enable support for Multimedia Codec (MFC) device for all Exynos4412-based Odroid boards. Signed-off-by: Marek Szyprowski <m.szyprow...@samsung.com> --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 24 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 395c3ca9601e..90b952e29ebf 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -18,6 +18,24 @@ stdout-path = _1; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@7700 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x7700 0x100>; + }; + + mfc_right: region@7800 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x7800 0x100>; + }; + }; + firmware@0204F000 { compatible = "samsung,secure-firmware"; reg = <0x0204F000 0x1000>; @@ -447,6 +465,12 @@ clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; }; + { + memory-region = <_left>, <_right>; + memory-region-names = "left", "right"; + status = "okay"; +}; + { status = "okay"; }; -- 1.9.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH v3 0/2] Expose DMA_MEMORY_EXCLUSIVE through shared-dma-pool
Hello, On 2015-11-10 17:18, Neil Armstrong wrote: The shared-dma-pool dt node only exposes exclusive memory, but in order to export non-exclusive coherent memory, add the no-exclusive property and document it. v3: use correct of_get_flat_dt_prop helper v2: simplify patch by looking for DT attribute in callback Neil Armstrong (2): base: dma-coherent: Add DT property for non exclusive shared-dma-pool devicetree: reserved-memory: document the optional no-exclusive parameter .../devicetree/bindings/reserved-memory/reserved-memory.txt | 3 +++ drivers/base/dma-coherent.c | 6 +- 2 files changed, 8 insertions(+), 1 deletion(-) Acked-by: Marek Szyprowski <m.szyprow...@samsung.com> Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] drivers: of: of_reserved_mem: fixup the alignment with CMA setup
Hello, On 2015-11-10 13:30, Jason Liu wrote: There is an alignment mismatch issue between the of_reserved_mem and the CMA setup requirement. The of_reserved_mem will try to get the alignment value from the DTS and pass it to __memblock_alloc_base to do the memory block base allocation, but the alignment value specified in the DTS may not satisfy the CAM setup requirement since CMA setup required the alignment as the following in the code: align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); The sanity check in the function of rmem_cma_setup will fail if the alignment does not setup correctly and thus CMA will fail to setup. This patch is to fixup the alignment to meet the CMA setup required. Mailing-list-thread: https://lkml.org/lkml/2015/11/9/138 Signed-off-by: Jason Liu <r64...@freescale.com> Cc: Marek Szyprowski <m.szyprow...@samsung.com> Cc: Grant Likely <grant.lik...@linaro.org> Cc: Rob Herring <robh...@kernel.org> Acked-by: Marek Szyprowski <m.szyprow...@samsung.com> --- drivers/of/of_reserved_mem.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 62f467b..9394311 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -124,6 +124,10 @@ static int __init __reserved_mem_alloc_size(unsigned long node, align = dt_mem_next_cell(dt_root_addr_cells, ); } + /* Need adjust the alignment to satisfy the CMA requirement */ + if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool")) + align = max(align, (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order)); + prop = of_get_flat_dt_prop(node, "alloc-ranges", ); if (prop) { Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 01/10] clk/samsung: exynos5433: add definitions of HDMI-PHY output clocks
Hello, On 2015-10-20 12:34, Michael Turquette wrote: Quoting Andrzej Hajda (2015-10-20 02:22:32) HDMI driver must re-parent respective muxes during HDMI-PHY on/off to HDMI-PHY output clocks. To reference those clocks their definitions should be added. Signed-off-by: Andrzej Hajda <a.ha...@samsung.com> --- drivers/clk/samsung/clk-exynos5433.c | 6 -- include/dt-bindings/clock/exynos5433.h | 5 - 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 650ec13..e037406 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -2614,8 +2614,10 @@ static struct samsung_fixed_rate_clock disp_fixed_clks[] __initdata = { FRATE(0, "phyclk_mipidphy0_rxclkesc0_phy", NULL, CLK_IS_ROOT, 1), /* PHY clocks from HDMI_PHY */ - FRATE(0, "phyclk_hdmiphy_tmds_clko_phy", NULL, CLK_IS_ROOT, 3), - FRATE(0, "phyclk_hdmiphy_pixel_clko_phy", NULL, CLK_IS_ROOT, 16600), + FRATE(CLK_PHYCLK_HDMIPHY_TMDS_CLKO_PHY, "phyclk_hdmiphy_tmds_clko_phy", + NULL, CLK_IS_ROOT, 3), + FRATE(CLK_PHYCLK_HDMIPHY_PIXEL_CLKO_PHY, "phyclk_hdmiphy_pixel_clko_phy", + NULL, CLK_IS_ROOT, 16600), }; static struct samsung_mux_clock disp_mux_clks[] __initdata = { diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 5bd80d5..4f0d566 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -765,7 +765,10 @@ #define CLK_SCLK_RGB_VCLK 109 #define CLK_SCLK_RGB_TV_VCLK 110 -#define DISP_NR_CLK111 +#define CLK_PHYCLK_HDMIPHY_PIXEL_CLKO_PHY 111 +#define CLK_PHYCLK_HDMIPHY_TMDS_CLKO_PHY 112 + +#define DISP_NR_CLK113 Why break compatibility with older DTBs? This patch just adds support for 2 more clocks to exynos 5433 clk driver, which were previously undefined. How this break compatibility with older DTBs? Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFT 0/3] usb: usb3503: Fix probing on Arndale board (missing phy)
Hello, On 2015-10-08 11:35, Javier Martinez Canillas wrote: Hello, On 10/08/2015 08:23 AM, Marek Szyprowski wrote: Hello, On 2015-10-08 08:02, Krzysztof Kozlowski wrote: On 07.10.2015 23:26, Marek Szyprowski wrote: Hello, On 2015-10-07 02:30, Krzysztof Kozlowski wrote: Introduction This patchset tries to fix probing of usb3503 on Arndale board if the Samsung PHY driver is probed later (or built as a module). *The patchset was not tested on Arndale board.* I don't have that board. Please test it and say if the usb3503 deferred probe works fine and the issue is solved. The patchset was tested on Odroid U3 board (which is different!) in a simulated environment. It is not sufficient testing. Difference == The usb3503 device driver can be used as a I2C device (on Odroid U3) or as a platform device connected through phy (on Arndale). In the second case the necessary phy reference has to be obtained and enabled. For some details please look also at thread [0][1]. [0] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348524.html [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348875.html I'm not sure that this is the correct approach. usb3503 chip is simply connected to Exynos USB2 phy, so it visible on the USB bus. The real driver that controls USB2 PHY is Exynos EHCI driver and USB3503 should not mess around it. The ehci node (usb@1211) has one port configured and it takes one PHY reference (phy of id 1 - USB host). I can't see driver taking reference to HSIC0 or HSIC1 phys... Since I cannot diagnose the error I don't know what is really expected here. It looks that EHCI in Exynos 5250 and 5420 still use old phy bindings. For the reference, see Exynos4 dts and exynos4412-odroidu3.dts to check how to enable more than one USB port (Odroid U3 has both HSIC ports enabled). In my opinion all that is needed in case of Arndale board is forcing reset of usb3503 chip after successful EHCI and USB2 PHY initialization (for some reason initialization of usb3503 chip must be done after usb host initialization). However I have no idea which driver should trigger this reset. Right now I didn't find any good solution for additional control for devices which are on autoprobed bus like usb. The reset is done at the end of usb3503's probe. The question "why usb3503 has to be initialized after EHCI and USB PHY" is still valid... I remember that I saw some code to reset HSIC device after phy power on in case of HSIC-connected modem chip, so maybe this is somehow common for HSIC chips (which are some special case of 'embedded usb'). I also don't have an Arndale board and haven't followed the thread to closely but I just wanted to mention that the ChromiumOS 3.8 tree has a workaround to reset the HSIC phys: https://chromium.googlesource.com/chromiumos/third_party/kernel/+/81685c447954a29d1098268776582457258dd98f%5E%21/ and later a "supports-hsicphy-reset" DT property was added to force the reset per board instead of unconditionally: https://chromium.googlesource.com/chromiumos/third_party/kernel/+/a4d1c1a223ffa1ed38a4257d0378ca70c6667be0%5E%21/ I didn't check this approach, but for me it looks that the problem is caused by the lack of resetting the chip connected to hsic phy not the lack of resetting the phy itself. However this is pure speculation and one should check it with the real hardware. Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFT 0/3] usb: usb3503: Fix probing on Arndale board (missing phy)
Hello, On 2015-10-07 02:30, Krzysztof Kozlowski wrote: Introduction This patchset tries to fix probing of usb3503 on Arndale board if the Samsung PHY driver is probed later (or built as a module). *The patchset was not tested on Arndale board.* I don't have that board. Please test it and say if the usb3503 deferred probe works fine and the issue is solved. The patchset was tested on Odroid U3 board (which is different!) in a simulated environment. It is not sufficient testing. Difference == The usb3503 device driver can be used as a I2C device (on Odroid U3) or as a platform device connected through phy (on Arndale). In the second case the necessary phy reference has to be obtained and enabled. For some details please look also at thread [0][1]. [0] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348524.html [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348875.html I'm not sure that this is the correct approach. usb3503 chip is simply connected to Exynos USB2 phy, so it visible on the USB bus. The real driver that controls USB2 PHY is Exynos EHCI driver and USB3503 should not mess around it. In my opinion all that is needed in case of Arndale board is forcing reset of usb3503 chip after successful EHCI and USB2 PHY initialization (for some reason initialization of usb3503 chip must be done after usb host initialization). However I have no idea which driver should trigger this reset. Right now I didn't find any good solution for additional control for devices which are on autoprobed bus like usb. Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] ARM: dts: exynos5420: fix wrong clock binding for sysmmu_fimd1_1
Hello, On 2015-09-23 09:41, Joonyoung Shim wrote: The sysmmu_fimd1_1 should bind the clock CLK_SMMU_FIMD1M1, not the clock CLK_SMMU_FIMD1M0. CLK_SMMU_FIMD1M0 is a clock for the sysmmu_fimd1_0. This wrong clock binding causes the problem that is blocked in iommu_map function when IOMMU is enabled and exynos-drm driver tries to allocate buffer via DMA mapping API on Odroid-XU3 board. Fixes: b70045167815 ("ARM: dts: add sysmmu nodes for exynos5420") Signed-off-by: Joonyoung Shim <jy0922.s...@samsung.com> Cc: <sta...@vger.kernel.org> # v4.2 Reviewed-by: Javier Martinez Canillas <jav...@osg.samsung.com> Acked-by: Marek Szyprowski <m.szyprow...@samsung.com> --- Changes for v2: - Update the commit message - Add Fixes: and Reviewed-by: tags arch/arm/boot/dts/exynos5420.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index df9aee9..1b3d6c7 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -1117,7 +1117,7 @@ interrupt-parent = <>; interrupts = <3 0>; clock-names = "sysmmu", "master"; - clocks = < CLK_SMMU_FIMD1M0>, < CLK_FIMD1>; + clocks = < CLK_SMMU_FIMD1M1>, < CLK_FIMD1>; power-domains = <_pd>; #iommu-cells = <0>; }; Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH/RFC 0/4] Probe deferral for IOMMU DT integration
as 3.b, leading to infinite probe deferral of bus master devices. For those reasons we have concluded that IOMMU probe deferral needs to be implemented with a combination of several mechanisms. The following steps should happen at bus master device probe time. 1. The IOMMU device referenced by the firmware with the bus master device is looked up. On DT-based systems, this will be the IOMMU DT node referenced by the iommus property. If no IOMMU device is associated, dma_map_ops will be set to linear mapping or SWIOTLB and device probe will continue. 2. An IOMMU device is referenced for the bus master device. The corresponding IOMMU instance is looked up. This requires a new IOMMU registration system. IOMMU drivers will create IOMMU instances at probe time and register them with the IOMMU core. If an IOMMU instance is found for the referenced IOMMU device, the IOMMU instance's of_xlate function will be called to setup the IOMMU. If the of_xlate call succeeds dma_map_ops will be set to IOMMU ops and device probe will continue. If the call fails we can either fail the bus master device probe, or fall back to non-IOMMU dma_map_ops (to be discussed). 3. The IOMMU device referenced for the bus master device isn't present, due to the IOMMU device probe not having been performed yet, having been deferred, or having failed. The IOMMU driver associated with the IOMMU device is looked up. This was initially thought to require an early registration mechanism for IOMMU drivers (using an OF_DECLARE mechanism for DT-based systems for instance), but on second thought it might be possible to implement this based on normal driver registration (to be researched). If an IOMMU driver is found for the referenced IOMMU device, a callback function of the IOMMU driver is called to check whether an IOMMU instance is expected to be registered later (most IOMMU drivers will just return true, so we could skip this callback function until an IOMMU driver requires it). If an IOMMU instance is expected to be registered later the bus master device probe is deferred. Otherwise dma_map_ops will be set to linear mapping/SWIOTLB and device probe will continue. The initial DMA mask and the DMA offset can still be configured at device instantiation time if desired. I'm sorry for not participating in the discussions, I was terribly busy with our internal stuff. The approach you have described looks fine although I would like also to know a bit more about the roadmap of development. The IOMMU integration is being discussed for over 2 years and right now we are STILL discussing. Do you plan to post any patches implementing this approach? I would really like to merge something simple, maybe not fully optimized and then resolve all the corner cases and possible integration details. - Currently tested where we knew the driver was going to be deferring. Probably need some logic for calling of_dma_configure again. This is based on Robin Murphy's work for dma mapping[4] and a few patches from Murali Kaicheri[5] for of_dma_configure. [1] http://lists.linuxfoundation.org/pipermail/iommu/2015-January/011764.html [2] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/279036.ht ml [3] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-December/311579. html [4] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-January/315459.h tml [5] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-January/319390.h tml Laura Abbott (3): dma-mapping: Make arch_setup_dma_ops return an error code of: Return error codes from of_dma_configure iommu/arm-smmu: Support deferred probing Mitchel Humpherys (1): iommu/arm-smmu: add support for specifying clocks arch/arm/include/asm/dma-mapping.h | 2 +- arch/arm/mm/dma-mapping.c| 4 +- arch/arm64/include/asm/dma-mapping.h | 2 +- arch/arm64/mm/dma-mapping.c | 16 +-- drivers/iommu/arm-smmu.c | 186 ++-- drivers/iommu/iommu.c| 49 - drivers/iommu/of_iommu.c | 14 ++- drivers/of/device.c | 9 +- include/linux/dma-mapping.h | 7 +- include/linux/iommu.h| 2 + include/linux/of_device.h| 4 +- 11 files changed, 268 insertions(+), 27 deletions(-) Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH/RFC 0/4] Probe deferral for IOMMU DT integration
Hello, On 2015-02-07 23:41, a...@arndb.de wrote: Laura Abbott lau...@codeaurora.org hat am 6. Februar 2015 um 01:31 geschrieben: The requirement for this is based on a previous patch to add clock support to the ARM SMMU driver[2]. Once we have clock support, it's possible that the driver itself may need to be defered which breaks a bunch of assumptions about how SMMU probing is supposed to work. Hi Laura, I was hoping that we would not need this, and instead treat the iommu in the same way as timers and SMP initialization, both of which need to be run early at boot time but may rely on clock controllers to be initialized first. Is there a specific requirement that makes this impossible here, or is your intention to solve the problem more nicely by allowing deferred probing over forcing the input clocks of the iommu to be early? I case of Exynos SoCs there is also a dependency on power domains (some might be disabled by the bootloader). It is convenient to use the whole device infrastructure for this although it still doesn't provide any methods of modelling the real power management dependencies. Right now I simply ignored this problem and left it for the future. I will check if this patchset helps in our case. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/4] mmc: core: add support for hardware reset gpio line
Hello, On 2015-01-29 11:56, Javier Martinez Canillas wrote: On Thu, Jan 29, 2015 at 10:15 AM, Marek Szyprowski m.szyprow...@samsung.com wrote: Also, I wonder whether we could extend the mmc-pwrseq to cover your case? Did you consider that as an option? I didn't consider mmc-pwrseq yet. For me it looked straightforward to I agree with Ulf that using mmc-pwrseq would be a good solution and in fact I think the pwrseq_simple [0] driver will fit your use case since it supports a reset GPIO pin which is what many WLAN chips attached to a SDIO interface use. Ok, I've checked mmc-prwseq and mmc-pwrseq-simple. I also checked the hardware and it mmc-pwrseq-simple cannot be used directly. Although the signal is called RSTN (on Odroid U3 schema), the eMMC card gets resetted not on low line level, but during the rising edge. This RSTN line is also pulled up by the external resistor. However, the strangest thing is the fact that the default SoC configuration (which is applied during hw reset) for this GPIO line is input, pulled-down. The SoC internal pull-down is stronger than the external pull up, so in the end, during the SoC reboot the RSTN signal is set to zero. Later bootloader disables the internal pull-down. To sum up - to perform proper reboot on Odroid U3/XU3, one need to set RSTN to zero, wait a while and the set it back to 1. To achieve this with mmc-pwrseq-simple, I would need to modify the power_off callback to toggle reset line to zero and back to one. This however might not be desired to other sd/mmc cards used with mmc-pwrseq-simple. I can also provide separate mmc-pwrsrq-odroid driver, which will be very similar to mmc-pwrseq-simple. Ulf - which approach would you prefer? implement it just like card detect or write-protection gpio pins. I already noticed that there is code for some mmc host driver, which perform mmc hardware reset. If you think that extending pwrseq is the better approach, I will try to update my patches. This will add reboot handler to mmc-pwrseq then. The only question is I don't think that adding a reboot handler to mmc-pwrseq is needed. AFAICT the call chain is: sys_reboot() - kernel_restart() - device_shutdown() - mmc_bus_shutdown() - _mmc_suspend() - mmc_power_off() - mmc_pwrseq_power_off() - struct mmc_pwrseq_ops .power_off So since the pwrseq_simple already asserts the reset GPIO in .power_off, it should be enough to ensure the eMMC will be reset to its default configuration for the iROM to work properly. It also asserts the GPIO pin in .pre_power_on and de-asserts in .post_power_on which should be needed as well for the other case you mentioned when a broken bootloader left the emmc card in some unknown state. emergency_restart() doesn't call device_shutdown(), so I think it still makes sense to add real reset handler to mmc-pwrseq to ensure that power_off will be called even during emergency_restart(). Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/4] mmc: core: add support for hardware reset gpio line
Hello, On 2015-01-28 15:24, Ulf Hansson wrote: On 28 January 2015 at 14:59, Marek Szyprowski m.szyprow...@samsung.com wrote: There are boards (like Hardkernel's Odroid boards) on which eMMC card's reset line is connected to GPIO line instead of the hardware reset logic. In case of such boards, if first stage of bootloader is loaded from such eMMC card, before performing system reboot, additional reset of eMMC card is required to properly boot the whole system again. This patch adds code for handling reset gpio lines defined in device tree. I don't follow the above sequence. Can you try to elaborate and describe for what exact scenario we require the hardware reset to be done? Odroid boards uses multi stage bootloaders. The very first stage is in SoC ROM. That code loads next stages (called bl1, bl2, tz) from either eMMC or SD card (depending on jumper configuration or some card detect pins). This ROM code is very simple and assumes that the mmc card has been reset to the default configuration. However, eMMC card is not being reset by the board 'reboot' logic. Instead the nreset line from emmc card is connected to gpio line of SoC. Thus to perform full system reboot procedure, before triggering reboot inside the SoC, one need to manually toggle nreset line of this emmc card to 'zero' for a while. Only then the card is put back to the default state, so ROM code is able to read bootloaders from it. My patch adds code for managing gpio line connected to nreset signal of emmc card. It registers reset handler, which is being triggered from Linux reboot code. This handler toggles such gpio line before the final reboot is triggered. My patch also provides a function for registering as a mmc host hw_reset callback, so it can be used to reset mmc card before initializing it with kernel driver (this is already implemented), which also might help to get it working if broken bootloader left the emmc card in some unknown/broken state (already observed such issue, but it has been fixed finally by patching bootloader). Also, I wonder whether we could extend the mmc-pwrseq to cover your case? Did you consider that as an option? I didn't consider mmc-pwrseq yet. For me it looked straightforward to implement it just like card detect or write-protection gpio pins. I already noticed that there is code for some mmc host driver, which perform mmc hardware reset. If you think that extending pwrseq is the better approach, I will try to update my patches. This will add reboot handler to mmc-pwrseq then. The only question is weather to use it always when mmc-pwrseq has been enabled or only if some additional property like 'reset-on-reboot' has been provided. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/4] mmc: core: add support for hardware reset gpio line
Hello, On 2015-01-29 11:56, Javier Martinez Canillas wrote: On Thu, Jan 29, 2015 at 10:15 AM, Marek Szyprowski m.szyprow...@samsung.com wrote: Also, I wonder whether we could extend the mmc-pwrseq to cover your case? Did you consider that as an option? I didn't consider mmc-pwrseq yet. For me it looked straightforward to I agree with Ulf that using mmc-pwrseq would be a good solution and in fact I think the pwrseq_simple [0] driver will fit your use case since it supports a reset GPIO pin which is what many WLAN chips attached to a SDIO interface use. implement it just like card detect or write-protection gpio pins. I already noticed that there is code for some mmc host driver, which perform mmc hardware reset. If you think that extending pwrseq is the better approach, I will try to update my patches. This will add reboot handler to mmc-pwrseq then. The only question is I don't think that adding a reboot handler to mmc-pwrseq is needed. AFAICT the call chain is: sys_reboot() - kernel_restart() - device_shutdown() - mmc_bus_shutdown() - _mmc_suspend() - mmc_power_off() - mmc_pwrseq_power_off() - struct mmc_pwrseq_ops .power_off So since the pwrseq_simple already asserts the reset GPIO in .power_off, it should be enough to ensure the eMMC will be reset to its default configuration for the iROM to work properly. I think that I had to add reset handler, because device_shutdown() was not called if reset was triggered from magic sysrq, but I will check it again. It also asserts the GPIO pin in .pre_power_on and de-asserts in .post_power_on which should be needed as well for the other case you mentioned when a broken bootloader left the emmc card in some unknown state. weather to use it always when mmc-pwrseq has been enabled or only if some additional property like 'reset-on-reboot' has been provided. Having a reset GPIO is optional AFAIK so I don't think there is a need for an additional reset-on-reboot propery. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland Best regards, Javier [0]: FYI, these are the relevant commits in linux-next: fe1922d5d4d0 mmc: pwrseq_simple: Add support for a reset GPIO pin ec2017f2491f mmc: pwrseq: Initial support for the simple MMC power sequence provider fe1686658f9c mmc: pwrseq: Document DT bindings for the simple MMC power sequence 1b745e8a4627 mmc: core: Initial support for MMC power sequences Ok, I will check it. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/4] ARM: dts: exynos5422-odroidxu3: add eMMC reset line
This patch adds reset-gpios property to the eMMC slot, so the MMC driver is able to properly reset eMMC card on system restart and thus fixes system hang on software reboot. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm/boot/dts/exynos5422-odroidxu3.dts | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3.dts b/arch/arm/boot/dts/exynos5422-odroidxu3.dts index a519c863248d..bafbc4e19adc 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/boot/dts/exynos5422-odroidxu3.dts @@ -298,13 +298,15 @@ mmc_0 { status = okay; + reset-gpios = gpd1 0 0; + reset-invered; broken-cd; card-detect-delay = 200; samsung,dw-mshc-ciu-div = 3; samsung,dw-mshc-sdr-timing = 0 4; samsung,dw-mshc-ddr-timing = 0 2; pinctrl-names = default; - pinctrl-0 = sd0_clk sd0_cmd sd0_bus4 sd0_bus8; + pinctrl-0 = sd0_clk sd0_cmd sd0_bus4 sd0_bus8 emmc_nrst; bus-width = 8; cap-mmc-highspeed; }; @@ -330,6 +332,15 @@ }; }; +pinctrl_1 { + emmc_nrst: emmc-nrst { + samsung,pins = gpd1-0; + samsung,pin-function = 0; + samsung,pin-pud = 0; + samsung,pin-drv = 0; + }; +}; + usbdrd_dwc3_0 { dr_mode = host; }; -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] mmc: dw_mmc-exynos: add support for controlling emmc reset pin
There are boards (like Hardkernel's Odroid boards) on which eMMC card's reset line is connected to SoC GPIO line instead of the hardware reset logic. In case of such boards, before performing system reboot, additional reset of eMMC card is required to boot again properly. This patch adds code for handling such cases. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +++ drivers/mmc/host/dw_mmc-exynos.c | 43 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt index ee4fc0576c7d..fc53d335e7db 100644 --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt @@ -50,6 +50,12 @@ Required Properties: - if CIU clock divider value is 0 (that is divide by 1), both tx and rx phase shift clocks should be 0. +Optional properties: + +* dw-mshc-reset-gpios: optional property specifying gpio for the eMMC nreset + line, it will be triggered on system reboot to properly reset eMMC card for + next system boot. + Required properties for a slot (Deprecated - Recommend to use one slot per host): * gpios: specifies a list of gpios used for command, clock and data bus. The diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 509365cb22c6..2add5a93859d 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -12,12 +12,14 @@ #include linux/module.h #include linux/platform_device.h #include linux/clk.h +#include linux/delay.h #include linux/mmc/host.h #include linux/mmc/dw_mmc.h #include linux/mmc/mmc.h #include linux/of.h #include linux/of_gpio.h #include linux/slab.h +#include linux/reboot.h #include dw_mmc.h #include dw_mmc-pltfm.h @@ -77,8 +79,23 @@ struct dw_mci_exynos_priv_data { u32 sdr_timing; u32 ddr_timing; u32 cur_speed; + struct gpio_desc*reset_gpio; + struct notifier_block reset_nb; }; +static int dw_mci_restart_handler(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct dw_mci_exynos_priv_data *data; + data = container_of(this, struct dw_mci_exynos_priv_data, reset_nb); + + gpiod_direction_output(data-reset_gpio, 0); + mdelay(150); + gpiod_direction_output(data-reset_gpio, 1); + + return NOTIFY_DONE; +} + static struct dw_mci_exynos_compatible { char*compatible; enum dw_mci_exynos_type ctrl_type; @@ -295,7 +312,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) return ret; priv-ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); + + priv-reset_gpio = devm_gpiod_get_optional(host-dev, + samsung,dw-mshc-reset, + GPIOD_OUT_HIGH); + if (!IS_ERR_OR_NULL(priv-reset_gpio)) { + priv-reset_nb.notifier_call = dw_mci_restart_handler; + priv-reset_nb.priority = 255; + ret = register_restart_handler(priv-reset_nb); + if (ret) + dev_err(host-dev, cannot register restart handler\n); + } + host-priv = priv; + return 0; } @@ -490,6 +520,17 @@ static int dw_mci_exynos_probe(struct platform_device *pdev) return dw_mci_pltfm_register(pdev, drv_data); } +static int dw_mci_exynos_remove(struct platform_device *pdev) +{ + struct dw_mci *host = platform_get_drvdata(pdev); + struct dw_mci_exynos_priv_data *priv = host-priv; + + if (priv-reset_gpio) + unregister_restart_handler(priv-reset_nb); + + return dw_mci_pltfm_remove(pdev); +} + static const struct dev_pm_ops dw_mci_exynos_pmops = { SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume) .resume_noirq = dw_mci_exynos_resume_noirq, @@ -499,7 +540,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = { static struct platform_driver dw_mci_exynos_pltfm_driver = { .probe = dw_mci_exynos_probe, - .remove = __exit_p(dw_mci_pltfm_remove), + .remove = dw_mci_exynos_remove, .driver = { .name = dwmmc_exynos, .of_match_table = dw_mci_exynos_match, -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/2] Fix reboot issue on Odroid boards with eMMC card
Hello, This patchset fixes reboot hang issue on Hardkernel's Odroid boards with eMMC card. Those boards are designed in such a way, that the eMMC nreset signal is routed to SoC GPIO line instead of the board reset logic. To properly restard system, one need to set this line to zero before performing reboot. The initial patches consisted of a complete reset/power off driver, but after further analysis, it turned out that only eMMC nreset line control logic is specific for those boards. Everything else can be done by generic Exynos code, so the code has been moved to Exynos DW MMC driver. Best regards Marek Szyprowski Samsung RD Institute Poland Changelog: initial version: http://thread.gmane.org/gmane.linux.power-management.general/51855/ Path summary: Marek Szyprowski (2): mmc: dw_mmc-exynos: add support for controlling emmc reset pin ARM: dts: exynos*-odroid*: add eMMC reset line .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +++ arch/arm/boot/dts/exynos4412-odroid-common.dtsi| 1 + arch/arm/boot/dts/exynos5422-odroidxu3.dts | 1 + drivers/mmc/host/dw_mmc-exynos.c | 43 +- 4 files changed, 50 insertions(+), 1 deletion(-) -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] ARM: dts: exynos*-odroid*: add eMMC reset line
This patch add samsung,dw-mshc-reset-gpios property to the eMMC slot, so Exynos DW MMC driver is able to properly reset eMMC card on system restart and thus fixes hang on software reboot. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 1 + arch/arm/boot/dts/exynos5422-odroidxu3.dts | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 74e89cbfb00c..97df0ef81d1a 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -69,6 +69,7 @@ samsung,dw-mshc-ciu-div = 3; samsung,dw-mshc-sdr-timing = 2 3; samsung,dw-mshc-ddr-timing = 1 2; + samsung,dw-mshc-reset-gpios = gpk1 2 1; bus-width = 8; cap-mmc-highspeed; }; diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3.dts b/arch/arm/boot/dts/exynos5422-odroidxu3.dts index d829e220eedb..20064e36a5be 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/boot/dts/exynos5422-odroidxu3.dts @@ -336,6 +336,7 @@ samsung,dw-mshc-ciu-div = 3; samsung,dw-mshc-sdr-timing = 0 4; samsung,dw-mshc-ddr-timing = 0 2; + samsung,dw-mshc-reset-gpios = gpd1 0 0; pinctrl-names = default; pinctrl-0 = sd0_clk sd0_cmd sd0_bus4 sd0_bus8; bus-width = 8; -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] power: reset: add driver for Hardkernel's Odroid boards
Hello, On 2015-01-25 15:32, Sebastian Reichel wrote: On Fri, Jan 23, 2015 at 12:11:22PM +0100, Marek Szyprowski wrote: Frankly, I analyzed this case once again and I came to conclusion that there is no need to make a separate reset driver for Odroid boards. There is nothing special, specific to whole board about this gpio. It is rather a property of MMC host controller and eMMC card that is connected to it. When only gpio toggling code is moved to reset handler registered from mmc controller, the board properly performs reboot with a generic exynos4 code. OK, so I guess this will be fixed independently via mmc subsystem. I've posted an updated patch. The poweroff code in above driver is just a generic Exynos4 code, so again there is no need to duplicate it. OK. It seems there is a driver for that in arch/arm/mach-exynos. Otherwise I would have suggest to create something like syscon-reboot for shutdown. By moving the code to mmc driver, the same approach can be used for other Odroid boards (XU/XU3) and maybe even other boards which need manual resetting of eMMC cards to properly perform reboot procedure. I suggest to start a new thread for discussing this, which includes linux-mmc. It might be interesting to provide some more details about eMMC_nDET, since MMC already contain a reset signal (which seems to be used according to the odroid schematics I found). My fault. The documentation for this initial driver was incorrect. The reboot fix has noting to eMMC_nDET signal. It should be eMMC nreset, which is routed directly to SoC GPIO line with external pull-up resistor. I really have no idea why I wrote eMMC_nDET instead of nreset. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/2] Fix reboot issue on Odroid boards with eMMC card
Hello, On 2015-01-27 09:56, Sjoerd Simons wrote: On Tue, 2015-01-27 at 09:11 +0100, Marek Szyprowski wrote: This patchset fixes reboot hang issue on Hardkernel's Odroid boards with eMMC card. Those boards are designed in such a way, that the eMMC nreset signal is routed to SoC GPIO line instead of the board reset logic. To properly restard system, one need to set this line to zero before performing reboot. The initial patches consisted of a complete reset/power off driver, but after further analysis, it turned out that only eMMC nreset line control logic is specific for those boards. Everything else can be done by generic Exynos code, so the code has been moved to Exynos DW MMC driver. This seems a general board design quirk, rather then an exynos specific one. Potentially better to have this in the mmc core so it can be re-used by non-exynos boards? A very quick peek at the schematic for the hardkernel C1 (amlogic based), shows that for that board the eMMC reset line is hooked up to an SoC gpio line as well. (Although ofcourse, it may not need to be reset before a warm restart depending on what the amlogic rom code does). Random side-note, at least the samsung peach chromebooks are also hooked up this way. But don't run into this issue as they load their initial stages from flash rather then the eMMC. Okay, I will try to move all the code to mmc core. I've also noticed that sdhci-pci driver already implements hw_reset feature with gpio line, although I cannot find any user of it (I cannot find any platform data provider for sdhci-pci driver). Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] power: reset: add driver for Hardkernel's Odroid boards
Hello, On 2015-01-22 02:33, Joonyoung Shim wrote: On 01/22/2015 10:06 AM, Sebastian Reichel wrote: On Wed, Oct 29, 2014 at 02:13:28PM +0100, Marek Szyprowski wrote: This patch adds a driver implementing correct reboot and poweroff procedures for Exynos4412-based Hardkernel's Odroid X/X2/U2/U3/U3+ boards. Sorry it took so long. I have a couple of small requests before applying this (comments inline). Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- .../bindings/power/reset/odroid-reset.txt | 18 drivers/power/reset/Kconfig| 6 ++ drivers/power/reset/Makefile | 1 + drivers/power/reset/odroid-reboot.c| 119 + 4 files changed, 144 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/odroid-reset.txt create mode 100644 drivers/power/reset/odroid-reboot.c diff --git a/Documentation/devicetree/bindings/power/reset/odroid-reset.txt b/Documentation/devicetree/bindings/power/reset/odroid-reset.txt new file mode 100644 index ..86471a463518 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/odroid-reset.txt @@ -0,0 +1,18 @@ +* Device tree bindings for Hardkernel's Exynos4412 based Odroid boards + +This node is intended to allow proper system reboot and power off of +Odroid X/X2/U2/U3/U3+ boards with eMMC storage. Without this node, board +hangs during standard reset procedure. + +Required properties: +- compatible: hardkernel,odroid-reboot +- samsung,pmureg-phandle: phandle to Exynos PMU node +- reset-gpios: phandle and gpio-specifier to the GPIO pin + connected to the eMMC_nDET + +Example: +odroid_reboot { + compatible = hardkernel,odroid-reboot; + samsung,pmureg-phandle = pmu_system_controller; + reset-gpio = gpk1 2 0; +}; diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index f65ff49bb275..f02b13d5344f 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -84,6 +84,12 @@ config POWER_RESET_LTC2952 This driver supports an external powerdown trigger and board power down via the LTC2952. Bindings are made in the device tree. +config POWER_RESET_ODROID + bool Hardkernel's Exynos4412 based Odroid reboot driver + depends on POWER_RESET ARCH_EXYNOS once the arm specific restart handler is gone you can add || COMPILE_TEST + help + Power off and restart support for Odroid boards. + config POWER_RESET_QNAP bool QNAP power-off driver depends on OF_GPIO PLAT_ORION diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 76ce1c59469b..178ee86eb813 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o +obj-$(CONFIG_POWER_RESET_ODROID) += odroid-reboot.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o diff --git a/drivers/power/reset/odroid-reboot.c b/drivers/power/reset/odroid-reboot.c new file mode 100644 index ..823e93539220 --- /dev/null +++ b/drivers/power/reset/odroid-reboot.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.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 option) any later version. + */ + +#include linux/delay.h +#include linux/gpio.h +#include linux/io.h +#include linux/mfd/syscon.h +#include linux/module.h +#include linux/of_platform.h +#include linux/of_gpio.h +#include linux/reboot.h +#include linux/regmap.h + +#include asm/system_misc.h + +#define PS_HOLD_CONTROL0x330C + +struct odroid_reboot_data { + struct device *dev; + int power_gpio; + struct regmap *reg_pmu; + void (*reboot_func)(enum reboot_mode mode, const char *cmd); +}; + +static struct odroid_reboot_data *reboot_data; + +static void odroid_reboot(enum reboot_mode mode, const char *cmd) +{ + local_irq_disable(); + + gpio_set_value(reboot_data-power_gpio, 0); + mdelay(150); + gpio_set_value(reboot_data-power_gpio, 1); + + reboot_data-reboot_func(mode, cmd); + It is called do_kernel_restart() if arm_pm_restart is NULL from machine_restart of arch/arm/kernel/process.c How about this? if (reboot_data-reboot_func) reboot_data-reboot_func(mode, cmd); else do_kernel_restart(cmd); Frankly, I analyzed this case once again and I came
[PATCH v3 1/7 RESEND] PM / Domains: Add a note about power domain subdomains
This patch adds a note on defining subdomains to generic PM domain binding documentation to let power domain providers use common approach for defining power domain hierarchy. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- RESEND version: - fixed spelling mistakes, thanks go to Geert! --- .../devicetree/bindings/power/power_domain.txt | 29 ++ 1 file changed, 29 insertions(+) diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 98c1667..eeea45b 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -19,6 +19,16 @@ Required properties: providing multiple PM domains (e.g. power controllers), but can be any value as specified by device tree binding documentation of particular provider. +Optional properties: + - power-domains : A phandle and PM domain specifier as defined by bindings of + the power controller specified by phandle. + Some power domains might be powered from another power domain (or have + other hardware specific dependencies). For representing such dependency + a standard PM domain consumer binding is used. When provided, all domains + created by the given provider should be subdomains of the domain + specified by this binding. More details about power domain specifier are + available in the next section. + Example: power: power-controller@1234 { @@ -30,6 +40,25 @@ Example: The node above defines a power controller that is a PM domain provider and expects one cell as its phandle argument. +Example 2: + + parent: power-controller@1234 { + compatible = foo,power-controller; + reg = 0x1234 0x1000; + #power-domain-cells = 1; + }; + + child: power-controller@1234 { + compatible = foo,power-controller; + reg = 0x12341000 0x1000; + power-domains = parent 0; + #power-domain-cells = 1; + }; + +The nodes above define two power controllers: 'parent' and 'child'. +Domains created by the 'child' power controller are subdomains of '0' power +domain provided by the 'parent' power controller. + ==PM domain consumers== Required properties: -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v2 08/12] soc: samsung: pm_domain: Add support for parent power domain
Hello, On 2014-11-25 10:19, Geert Uytterhoeven wrote: On Tue, Nov 25, 2014 at 9:57 AM, amit daniel kachhap amit.dan...@samsung.com wrote: diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt index 00ebda1..0160bdc 100644 --- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt +++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt @@ -24,6 +24,7 @@ Optional Properties: - pclkN, clkN: Pairs of parent of input clock and input clock to the devices in this power domain. Maximum of 4 pairs (N = 0 to 3) are supported currently. +- parents: phandle of parent power domains. Why not using just power-domains = pd_top? This is consistent with how clocks refer to their parent clocks. I agree. The only question is weather exynos dts should keep using samsung,power-domain property, or switch to generic 'power-domains' approach. I assume that exynos-pm driver should support both. Node of a device using power domains must have a samsung,power-domain property defined with a phandle to respective power domain. @@ -48,6 +49,7 @@ Example: mfc_pd: power-domain@10044060 { compatible = samsung,exynos4210-pd, samsung,exynos7-pd-mfc; reg = 0x10044060 0x20; + parents = pd_top; #power-domain-cells = 0; }; This seems like a good and generic approach to describe that a PM domain could have a parent. I would suggest to rename it, such it reflects its a PM domain binding though. I am not sure if this is generic. I guess PD's represented like below are more generic. PD1 { PD2 { PD3 { }; }; }; Such a representation is not always possible. If you have one power-controller for a hierarchy of PM domains, you can use it. If you have multiple power-controllers, the power controller nodes are at the same level in DT, so you'll have to use power-domains properties to link them together. I agree. I will send updated patch for this purpose for existing exynos4 power domain driver. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] ARM: dts: exynos4412-odroid-common: add reboot handler
This patch adds node which enables board-specific reboot/poweroff code. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 4ebb5572d8d0..3544bb255e58 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -32,6 +32,12 @@ }; }; + odroid_reboot { + compatible = hardkernel,odroid-reboot; + samsung,pmureg-phandle = pmu_system_controller; + reset-gpios = gpk1 2 0; + }; + i2s0: i2s@0383 { pinctrl-0 = i2s0_bus; pinctrl-names = default; -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] power: reset: add driver for Hardkernel's Odroid boards
This patch adds a driver implementing correct reboot and poweroff procedures for Exynos4412-based Hardkernel's Odroid X/X2/U2/U3/U3+ boards. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- .../bindings/power/reset/odroid-reset.txt | 18 drivers/power/reset/Kconfig| 6 ++ drivers/power/reset/Makefile | 1 + drivers/power/reset/odroid-reboot.c| 119 + 4 files changed, 144 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/odroid-reset.txt create mode 100644 drivers/power/reset/odroid-reboot.c diff --git a/Documentation/devicetree/bindings/power/reset/odroid-reset.txt b/Documentation/devicetree/bindings/power/reset/odroid-reset.txt new file mode 100644 index ..86471a463518 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/odroid-reset.txt @@ -0,0 +1,18 @@ +* Device tree bindings for Hardkernel's Exynos4412 based Odroid boards + +This node is intended to allow proper system reboot and power off of +Odroid X/X2/U2/U3/U3+ boards with eMMC storage. Without this node, board +hangs during standard reset procedure. + +Required properties: +- compatible: hardkernel,odroid-reboot +- samsung,pmureg-phandle: phandle to Exynos PMU node +- reset-gpios: phandle and gpio-specifier to the GPIO pin + connected to the eMMC_nDET + +Example: +odroid_reboot { + compatible = hardkernel,odroid-reboot; + samsung,pmureg-phandle = pmu_system_controller; + reset-gpio = gpk1 2 0; +}; diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index f65ff49bb275..f02b13d5344f 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -84,6 +84,12 @@ config POWER_RESET_LTC2952 This driver supports an external powerdown trigger and board power down via the LTC2952. Bindings are made in the device tree. +config POWER_RESET_ODROID + bool Hardkernel's Exynos4412 based Odroid reboot driver + depends on POWER_RESET ARCH_EXYNOS + help + Power off and restart support for Odroid boards. + config POWER_RESET_QNAP bool QNAP power-off driver depends on OF_GPIO PLAT_ORION diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 76ce1c59469b..178ee86eb813 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o +obj-$(CONFIG_POWER_RESET_ODROID) += odroid-reboot.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o diff --git a/drivers/power/reset/odroid-reboot.c b/drivers/power/reset/odroid-reboot.c new file mode 100644 index ..823e93539220 --- /dev/null +++ b/drivers/power/reset/odroid-reboot.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.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 option) any later version. + */ + +#include linux/delay.h +#include linux/gpio.h +#include linux/io.h +#include linux/mfd/syscon.h +#include linux/module.h +#include linux/of_platform.h +#include linux/of_gpio.h +#include linux/reboot.h +#include linux/regmap.h + +#include asm/system_misc.h + +#define PS_HOLD_CONTROL0x330C + +struct odroid_reboot_data { + struct device *dev; + int power_gpio; + struct regmap *reg_pmu; + void (*reboot_func)(enum reboot_mode mode, const char *cmd); +}; + +static struct odroid_reboot_data *reboot_data; + +static void odroid_reboot(enum reboot_mode mode, const char *cmd) +{ + local_irq_disable(); + + gpio_set_value(reboot_data-power_gpio, 0); + mdelay(150); + gpio_set_value(reboot_data-power_gpio, 1); + + reboot_data-reboot_func(mode, cmd); + + pr_emerg(%s: waiting for reboot\n, __func__); + while (1) + ; +} + +static void odroid_power_off(void) +{ + regmap_update_bits(reboot_data-reg_pmu, PS_HOLD_CONTROL, 0x, 0x5200); + while (1) { + pr_emerg(%s: should not reach here!\n, __func__); + msleep(1000); + } +} + +static struct odroid_reboot_data *odroid_reboot_parse_dt(struct device *dev) +{ + struct device_node *np = dev-of_node; + struct odroid_reboot_data *data; + + data = devm_kzalloc(dev, sizeof(struct odroid_reboot_data), GFP_KERNEL); + if (!data) + return NULL
Re: [PATCH v2 0/4] CMA device tree, once again
Hello, On 2014-08-09 02:28, Laura Abbott wrote: On 7/14/2014 12:12 AM, Marek Szyprowski wrote: Hello, This is one more respin of the patches which add support for creating reserved memory regions defined in device tree. The last attempt (http://lists.linaro.org/pipermail/linaro-mm-sig/2014-February/003738.html) ended in merging only half of the code, so right now we have complete documentation merged and only basic code, which implements a half of it is written in the documentation. Although the merged patches allow to reserve memory, there is no way of using it for devices and drivers. This situation makes CMA rather useless, as the main architecture (ARM), which used it, has been converted from board-file based system initialization to device tree. Thus there is no place to use direct calls to dma_declare_contiguous() and some new solution, which bases on device tree, is urgently needed. This patch series fixes this issue. It provides two, already widely discussed and already present in the kernel, drivers for reserved memory: first based on DMA-coherent allocator, second using Contiguous Memory Allocator. The first one nicely implements typical 'carved out' reserved memory way of allocating contiguous buffers in a kernel-style way. The memory is used exclusively by devices assigned to the given memory region. The second one allows to reuse reserved memory for movable kernel pages (like disk buffers, anonymous memory) and migrates it out when device to allocates contiguous memory buffer. Both driver provides memory buffers via standard dma-mapping API. The patches have been rebased on top of latest CMA and mm changes merged to akmp kernel tree. To define a 64MiB CMA region following node is needed: multimedia_reserved: multimedia_mem_region { compatible = shared-dma-pool; reusable; size = 0x400; alignment = 0x40; }; Similarly, one can define 64MiB region with DMA coherent memory: multimedia_reserved: multimedia_mem_region { compatible = shared-dma-pool; no-map; size = 0x400; alignment = 0x40; }; Longer term, I think it would be good if we didn't have to use no-map with the coherent memory. With no-map and dma-coherent.c right now, not only do you lose out on the physical memory space, you also have to give up the same amount of vmalloc space for mapping. On arm32, if you have the default 240MB vmalloc space, 64M is ~25% of the vmalloc space. At least on arm you can make this up by remapping the memory as coherent. I haven't seen this picked up anywhere yet so you are welcome to add Tested-by: Laura Abbott lau...@codeaurora.org Right, when the code reaches mainline I will add code which will remove no-map requirement. Changing memory attributes can be handled in this case the same way as for CMA. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 RESEND 3/4] drivers: dma-coherent: add initialization from device tree
Hello, On 2014-07-31 01:49, Grant Likely wrote: On Tue, Jul 29, 2014 at 11:33 PM, Marek Szyprowski m.szyprow...@samsung.com wrote: Hello, On 2014-07-29 23:54, Grant Likely wrote: On Mon, 14 Jul 2014 10:28:06 +0200, Marek Szyprowski m.szyprow...@samsung.com wrote: Initialization procedure of dma coherent pool has been split into two parts, so memory pool can now be initialized without assigning to particular struct device. Then initialized region can be assigned to more than one struct device. To protect from concurent allocations from different devices, a spinlock has been added to dma_coherent_mem structure. The last part of this patch adds support for handling 'shared-dma-pool' reserved-memory device tree nodes. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com I think this looks okay. It isn't in my area of expertise though. Comments below. --- drivers/base/dma-coherent.c | 137 ++-- 1 file changed, 118 insertions(+), 19 deletions(-) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 7d6e84a51424..7185a4f247e1 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -14,11 +14,14 @@ struct dma_coherent_mem { int size; int flags; unsigned long *bitmap; + spinlock_t spinlock; }; -int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags) +static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr, +size_t size, int flags, +struct dma_coherent_mem **mem) This is a bit odd. Why wouldn't you return the dma_mem pointer directly instead of passing in a **mem argument? Because this function (as a direct successor of dma_declare_coherent_memory) doesn't return typical error codes, but some custom values like DMA_MEMORY_MAP, DMA_MEMORY_IO or zero (which means failure). I wanted to avoid confusion with typical error handling path and IS_ERR/ERR_PTR usage used widely in other functions. This probably should be unified with the rest of kernel some day, but right now I wanted to keep the patch simple and easy to review. { + struct dma_coherent_mem *dma_mem = NULL; void __iomem *mem_base = NULL; int pages = size PAGE_SHIFT; int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); @@ -27,27 +30,26 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, goto out; if (!size) goto out; - if (dev-dma_mem) - goto out; - - /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ mem_base = ioremap(phys_addr, size); if (!mem_base) goto out; - dev-dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); - if (!dev-dma_mem) + dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); + if (!dma_mem) goto out; - dev-dma_mem-bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!dev-dma_mem-bitmap) + dma_mem-bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dma_mem-bitmap) goto free1_out; - dev-dma_mem-virt_base = mem_base; - dev-dma_mem-device_base = device_addr; - dev-dma_mem-pfn_base = PFN_DOWN(phys_addr); - dev-dma_mem-size = pages; - dev-dma_mem-flags = flags; + dma_mem-virt_base = mem_base; + dma_mem-device_base = device_addr; + dma_mem-pfn_base = PFN_DOWN(phys_addr); + dma_mem-size = pages; + dma_mem-flags = flags; + spin_lock_init(dma_mem-spinlock); + + *mem = dma_mem; if (flags DMA_MEMORY_MAP) return DMA_MEMORY_MAP; @@ -55,12 +57,51 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, return DMA_MEMORY_IO; free1_out: - kfree(dev-dma_mem); + kfree(dma_mem); out: if (mem_base) iounmap(mem_base); return 0; } + +static void dma_release_coherent_memory(struct dma_coherent_mem *mem) +{ + if (!mem) + return; + iounmap(mem-virt_base); + kfree(mem-bitmap); + kfree(mem); +} + +static int dma_assign_coherent_memory(struct device *dev, + struct dma_coherent_mem *mem) +{ + if (dev-dma_mem) + return -EBUSY; + + dev-dma_mem = mem; + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + return 0; +} + +int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + struct dma_coherent_mem *mem; + int ret; + + ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags
Re: [PATCH v2 RESEND 2/4] drivers: of: initialize and assign reserved memory to newly created devices
Hello, On 2014-07-28 16:17, Grant Likely wrote: On Mon, 14 Jul 2014 10:28:05 +0200, Marek Szyprowski m.szyprow...@samsung.com wrote: Use recently introduced of_reserved_mem_device_init() function to automatically assign respective reserved memory region to the newly created platform and amba device. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com I'm still not okay with this patch. I don't think it is appropriate to add the hook into the generic path that gets used for every platform device. The devices that need reserved memory should explicitly request it, and any setup be done at that time. Okay... I thought that it will be easier to have it done in generic code, if You don't think so, then I give up and we will add it in all drivers requiring such memory regions. What about patch 3/4 and 4/4? Would it be possible to have your ack to get them merged? Right now patch 4/4 depends on changes from akpm tree, so it will be best to merge them to akpm tree. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 RESEND 3/4] drivers: dma-coherent: add initialization from device tree
Hello, On 2014-07-29 23:54, Grant Likely wrote: On Mon, 14 Jul 2014 10:28:06 +0200, Marek Szyprowski m.szyprow...@samsung.com wrote: Initialization procedure of dma coherent pool has been split into two parts, so memory pool can now be initialized without assigning to particular struct device. Then initialized region can be assigned to more than one struct device. To protect from concurent allocations from different devices, a spinlock has been added to dma_coherent_mem structure. The last part of this patch adds support for handling 'shared-dma-pool' reserved-memory device tree nodes. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com I think this looks okay. It isn't in my area of expertise though. Comments below. --- drivers/base/dma-coherent.c | 137 ++-- 1 file changed, 118 insertions(+), 19 deletions(-) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 7d6e84a51424..7185a4f247e1 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -14,11 +14,14 @@ struct dma_coherent_mem { int size; int flags; unsigned long *bitmap; + spinlock_t spinlock; }; -int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags) +static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr, +size_t size, int flags, +struct dma_coherent_mem **mem) This is a bit odd. Why wouldn't you return the dma_mem pointer directly instead of passing in a **mem argument? Because this function (as a direct successor of dma_declare_coherent_memory) doesn't return typical error codes, but some custom values like DMA_MEMORY_MAP, DMA_MEMORY_IO or zero (which means failure). I wanted to avoid confusion with typical error handling path and IS_ERR/ERR_PTR usage used widely in other functions. This probably should be unified with the rest of kernel some day, but right now I wanted to keep the patch simple and easy to review. { + struct dma_coherent_mem *dma_mem = NULL; void __iomem *mem_base = NULL; int pages = size PAGE_SHIFT; int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); @@ -27,27 +30,26 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, goto out; if (!size) goto out; - if (dev-dma_mem) - goto out; - - /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ mem_base = ioremap(phys_addr, size); if (!mem_base) goto out; - dev-dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); - if (!dev-dma_mem) + dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); + if (!dma_mem) goto out; - dev-dma_mem-bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!dev-dma_mem-bitmap) + dma_mem-bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dma_mem-bitmap) goto free1_out; - dev-dma_mem-virt_base = mem_base; - dev-dma_mem-device_base = device_addr; - dev-dma_mem-pfn_base = PFN_DOWN(phys_addr); - dev-dma_mem-size = pages; - dev-dma_mem-flags = flags; + dma_mem-virt_base = mem_base; + dma_mem-device_base = device_addr; + dma_mem-pfn_base = PFN_DOWN(phys_addr); + dma_mem-size = pages; + dma_mem-flags = flags; + spin_lock_init(dma_mem-spinlock); + + *mem = dma_mem; if (flags DMA_MEMORY_MAP) return DMA_MEMORY_MAP; @@ -55,12 +57,51 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, return DMA_MEMORY_IO; free1_out: - kfree(dev-dma_mem); + kfree(dma_mem); out: if (mem_base) iounmap(mem_base); return 0; } + +static void dma_release_coherent_memory(struct dma_coherent_mem *mem) +{ + if (!mem) + return; + iounmap(mem-virt_base); + kfree(mem-bitmap); + kfree(mem); +} + +static int dma_assign_coherent_memory(struct device *dev, + struct dma_coherent_mem *mem) +{ + if (dev-dma_mem) + return -EBUSY; + + dev-dma_mem = mem; + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + return 0; +} + +int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + struct dma_coherent_mem *mem; + int ret; + + ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags, + mem); + if (ret == 0) + return 0; + + if (dma_assign_coherent_memory(dev, mem) == 0) + return
[PATCH v2 2/4] drivers: of: initialize and assign reserved memory to newly created devices
Use recently introduced of_reserved_mem_device_init() function to automatically assign respective reserved memory region to the newly created platform and amba device. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/platform.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 6c48d73a7fd7..a7f967866f13 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[] = { @@ -237,12 +238,15 @@ static 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 */ if (of_device_add(dev) != 0) { + of_reserved_mem_device_release(dev-dev); platform_device_put(dev); goto err_clear_flag; } @@ -304,6 +308,8 @@ static struct amba_device *of_amba_device_create(struct device_node *node, else of_device_make_bus_id(dev-dev); + of_reserved_mem_device_init(dev-dev); + /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, arm,primecell-periphid, NULL); if (prop) @@ -330,6 +336,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node, return dev; err_free: + of_reserved_mem_device_release(dev-dev); amba_device_put(dev); err_clear_flag: of_node_clear_flag(node, OF_POPULATED); -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/4] CMA device tree, once again
Hello, This is one more respin of the patches which add support for creating reserved memory regions defined in device tree. The last attempt (http://lists.linaro.org/pipermail/linaro-mm-sig/2014-February/003738.html) ended in merging only half of the code, so right now we have complete documentation merged and only basic code, which implements a half of it is written in the documentation. Although the merged patches allow to reserve memory, there is no way of using it for devices and drivers. This situation makes CMA rather useless, as the main architecture (ARM), which used it, has been converted from board-file based system initialization to device tree. Thus there is no place to use direct calls to dma_declare_contiguous() and some new solution, which bases on device tree, is urgently needed. This patch series fixes this issue. It provides two, already widely discussed and already present in the kernel, drivers for reserved memory: first based on DMA-coherent allocator, second using Contiguous Memory Allocator. The first one nicely implements typical 'carved out' reserved memory way of allocating contiguous buffers in a kernel-style way. The memory is used exclusively by devices assigned to the given memory region. The second one allows to reuse reserved memory for movable kernel pages (like disk buffers, anonymous memory) and migrates it out when device to allocates contiguous memory buffer. Both driver provides memory buffers via standard dma-mapping API. The patches have been rebased on top of latest CMA and mm changes merged to akmp kernel tree. To define a 64MiB CMA region following node is needed: multimedia_reserved: multimedia_mem_region { compatible = shared-dma-pool; reusable; size = 0x400; alignment = 0x40; }; Similarly, one can define 64MiB region with DMA coherent memory: multimedia_reserved: multimedia_mem_region { compatible = shared-dma-pool; no-map; size = 0x400; alignment = 0x40; }; Then the defined region can be assigned to devices: scaler: scaler@1250 { memory-region = multimedia_reserved; /* ... */ }; codec: codec@1260 { memory-region = multimedia_reserved; /* ... */ }; Best regards Marek Szyprowski Samsung RD Institute Poland Changes since v1: (http://www.spinics.net/lists/arm-kernel/msg343702.html) - fixed possible memory leak in case of reserved memory allocation failure (thanks to Joonsoo Kim) Changes since the version posted in '[PATCH v6 00/11] reserved-memory regions/CMA in devicetree, again' thread http://lists.linaro.org/pipermail/linaro-mm-sig/2014-February/003738.html: - rebased on top of '[PATCH v3 -next 0/9] CMA: generalize CMA reserved area management code' patch series on v3.16-rc3 - improved dma-coherent driver, now it correctly handles assigning more than one device to the given memory region Patch summary: Marek Szyprowski (4): drivers: of: add automated assignment of reserved regions to client devices drivers: of: initialize and assign reserved memory to newly created devices drivers: dma-coherent: add initialization from device tree drivers: dma-contiguous: add initialization from device tree drivers/base/dma-coherent.c | 40 +++ drivers/base/dma-contiguous.c | 60 +++ drivers/of/of_reserved_mem.c| 70 + drivers/of/platform.c | 7 + include/linux/cma.h | 3 ++ include/linux/of_reserved_mem.h | 7 + mm/cma.c| 62 +--- 7 files changed, 238 insertions(+), 11 deletions(-) -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 4/4] drivers: dma-contiguous: add initialization from device tree
Add a function to create CMA region from previously reserved memory and add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-contiguous.c | 60 + include/linux/cma.h | 3 +++ mm/cma.c | 62 +++ 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 6606abdf880c..0e480146fe05 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -211,3 +211,63 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages, { return cma_release(dev_get_cma_area(dev), pages, count); } + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +#undef pr_fmt +#define pr_fmt(fmt) fmt + +static void rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev) +{ + struct cma *cma = rmem-priv; + dev_set_cma_area(dev, cma); +} + +static const struct reserved_mem_ops rmem_cma_ops = { + .device_init= rmem_cma_device_init, +}; + +static int __init rmem_cma_setup(struct reserved_mem *rmem) +{ + phys_addr_t align = PAGE_SIZE max(MAX_ORDER - 1, pageblock_order); + phys_addr_t mask = align - 1; + unsigned long node = rmem-fdt_node; + struct cma *cma; + int err; + + if (!of_get_flat_dt_prop(node, reusable, NULL) || + of_get_flat_dt_prop(node, no-map, NULL)) + return -EINVAL; + + if ((rmem-base mask) || (rmem-size mask)) { + pr_err(Reserved memory: incorrect alignment of CMA region\n); + return -EINVAL; + } + + err = cma_init_reserved_mem(rmem-base, rmem-size, 0, cma); + if (err) { + pr_err(Reserved memory: unable to setup CMA region\n); + return err; + } + /* Architecture specific contiguous memory fixup. */ + dma_contiguous_early_fixup(rmem-base, rmem-size); + + if (of_get_flat_dt_prop(node, linux,cma-default, NULL)) + dma_contiguous_set_default(cma); + + rmem-ops = rmem_cma_ops; + rmem-priv = cma; + + pr_info(Reserved memory: created CMA memory pool at %pa, size %ld MiB\n, + rmem-base, (unsigned long)rmem-size / SZ_1M); + + return 0; +} +RESERVEDMEM_OF_DECLARE(cma, shared-dma-pool, rmem_cma_setup); +#endif diff --git a/include/linux/cma.h b/include/linux/cma.h index 32cab7a425f9..9a18a2b1934c 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -16,6 +16,9 @@ extern int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base, phys_addr_t limit, phys_addr_t alignment, unsigned int order_per_bit, bool fixed, struct cma **res_cma); +extern int cma_init_reserved_mem(phys_addr_t size, + phys_addr_t base, int order_per_bit, + struct cma **res_cma); extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align); extern bool cma_release(struct cma *cma, struct page *pages, int count); #endif diff --git a/mm/cma.c b/mm/cma.c index 4b251b037e1b..b3d8b925ad34 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -140,6 +140,54 @@ static int __init cma_init_reserved_areas(void) core_initcall(cma_init_reserved_areas); /** + * cma_init_reserved_mem() - create custom contiguous area from reserved memory + * @base: Base address of the reserved area + * @size: Size of the reserved area (in bytes), + * @order_per_bit: Order of pages represented by one bit on bitmap. + * @res_cma: Pointer to store the created cma region. + * + * This function creates custom contiguous area from already reserved memory. + */ +int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, +int order_per_bit, struct cma **res_cma) +{ + struct cma *cma; + phys_addr_t alignment; + + /* Sanity checks */ + if (cma_area_count == ARRAY_SIZE(cma_areas)) { + pr_err(Not enough slots for CMA reserved regions!\n); + return -ENOSPC; + } + + if (!size || !memblock_is_region_reserved(base, size)) + return -EINVAL; + + /* ensure minimal alignment requied by mm core */ + alignment = PAGE_SIZE max(MAX_ORDER - 1, pageblock_order); + + /* alignment should be aligned with order_per_bit */ + if (!IS_ALIGNED(alignment PAGE_SHIFT, 1 order_per_bit)) + return -EINVAL; + + if (ALIGN(base, alignment) != base || ALIGN(size, alignment) != size) + return -EINVAL
[PATCH v2 1/4] drivers: of: add automated assignment of reserved regions to client devices
This patch adds code for automated assignment of reserved memory regions to struct device. reserved_mem-ops-device_init()/device_cleanup() callbacks are called to perform reserved memory driver specific initialization and cleanup Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/of_reserved_mem.c| 70 + include/linux/of_reserved_mem.h | 7 + 2 files changed, 77 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 632aae861375..59fb12e84e6b 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -206,8 +206,16 @@ void __init fdt_init_reserved_mem(void) for (i = 0; i reserved_mem_count; i++) { struct reserved_mem *rmem = reserved_mem[i]; unsigned long node = rmem-fdt_node; + int len; + const __be32 *prop; int err = 0; + prop = of_get_flat_dt_prop(node, phandle, len); + if (!prop) + prop = of_get_flat_dt_prop(node, linux,phandle, len); + if (prop) + rmem-phandle = of_read_number(prop, len/4); + if (rmem-size == 0) err = __reserved_mem_alloc_size(node, rmem-name, rmem-base, rmem-size); @@ -215,3 +223,65 @@ void __init fdt_init_reserved_mem(void) __reserved_mem_init_node(rmem); } } + +static inline struct reserved_mem *__find_rmem(struct device_node *node) +{ + unsigned int i; + + if (!node-phandle) + return NULL; + + for (i = 0; i reserved_mem_count; i++) + if (reserved_mem[i].phandle == node-phandle) + 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 *rmem; + struct device_node *np; + + np = of_parse_phandle(dev-of_node, memory-region, 0); + if (!np) + return; + + rmem = __find_rmem(np); + of_node_put(np); + + if (!rmem || !rmem-ops || !rmem-ops-device_init) + return; + + rmem-ops-device_init(rmem, dev); + dev_info(dev, assigned reserved memory node %s\n, rmem-name); +} + +/** + * 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 *rmem; + struct device_node *np; + + np = of_parse_phandle(dev-of_node, memory-region, 0); + if (!np) + return; + + rmem = __find_rmem(np); + of_node_put(np); + + if (!rmem || !rmem-ops || !rmem-ops-device_release) + return; + + rmem-ops-device_release(rmem, dev); +} diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 4669ddfdd5af..5b5efae09135 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -8,6 +8,7 @@ struct reserved_mem_ops; struct reserved_mem { const char *name; unsigned long fdt_node; + unsigned long phandle; const struct reserved_mem_ops *ops; phys_addr_t base; phys_addr_t size; @@ -27,10 +28,16 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn) #ifdef CONFIG_OF_RESERVED_MEM +void of_reserved_mem_device_init(struct device *dev); +void of_reserved_mem_device_release(struct device *dev); + void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); #else +static inline void of_reserved_mem_device_init(struct device *dev) { } +static inline void of_reserved_mem_device_release(struct device *pdev) { } + static inline void fdt_init_reserved_mem(void) { } static inline void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size) { } -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 RESEND 0/4] CMA device tree, once again
Hello, (please ignore previous patchset, I've attached wrong version of patches) This is one more respin of the patches which add support for creating reserved memory regions defined in device tree. The last attempt (http://lists.linaro.org/pipermail/linaro-mm-sig/2014-February/003738.html) ended in merging only half of the code, so right now we have complete documentation merged and only basic code, which implements a half of it is written in the documentation. Although the merged patches allow to reserve memory, there is no way of using it for devices and drivers. This situation makes CMA rather useless, as the main architecture (ARM), which used it, has been converted from board-file based system initialization to device tree. Thus there is no place to use direct calls to dma_declare_contiguous() and some new solution, which bases on device tree, is urgently needed. This patch series fixes this issue. It provides two, already widely discussed and already present in the kernel, drivers for reserved memory: first based on DMA-coherent allocator, second using Contiguous Memory Allocator. The first one nicely implements typical 'carved out' reserved memory way of allocating contiguous buffers in a kernel-style way. The memory is used exclusively by devices assigned to the given memory region. The second one allows to reuse reserved memory for movable kernel pages (like disk buffers, anonymous memory) and migrates it out when device to allocates contiguous memory buffer. Both driver provides memory buffers via standard dma-mapping API. The patches have been rebased on top of latest CMA and mm changes merged to akmp kernel tree. To define a 64MiB CMA region following node is needed: multimedia_reserved: multimedia_mem_region { compatible = shared-dma-pool; reusable; size = 0x400; alignment = 0x40; }; Similarly, one can define 64MiB region with DMA coherent memory: multimedia_reserved: multimedia_mem_region { compatible = shared-dma-pool; no-map; size = 0x400; alignment = 0x40; }; Then the defined region can be assigned to devices: scaler: scaler@1250 { memory-region = multimedia_reserved; /* ... */ }; codec: codec@1260 { memory-region = multimedia_reserved; /* ... */ }; Best regards Marek Szyprowski Samsung RD Institute Poland Changes since v1: (http://www.spinics.net/lists/arm-kernel/msg343702.html) - fixed possible memory leak in case of reserved memory allocation failure (thanks to Joonsoo Kim) Changes since the version posted in '[PATCH v6 00/11] reserved-memory regions/CMA in devicetree, again' thread http://lists.linaro.org/pipermail/linaro-mm-sig/2014-February/003738.html: - rebased on top of '[PATCH v3 -next 0/9] CMA: generalize CMA reserved area management code' patch series on v3.16-rc3 - improved dma-coherent driver, now it correctly handles assigning more than one device to the given memory region Patch summary: Marek Szyprowski (4): drivers: of: add automated assignment of reserved regions to client devices drivers: of: initialize and assign reserved memory to newly created devices drivers: dma-coherent: add initialization from device tree drivers: dma-contiguous: add initialization from device tree drivers/base/dma-coherent.c | 137 ++-- drivers/base/dma-contiguous.c | 67 drivers/of/of_reserved_mem.c| 70 drivers/of/platform.c | 7 ++ include/linux/cma.h | 3 + include/linux/of_reserved_mem.h | 7 ++ mm/cma.c| 62 ++ 7 files changed, 323 insertions(+), 30 deletions(-) -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 RESEND 1/4] drivers: of: add automated assignment of reserved regions to client devices
This patch adds code for automated assignment of reserved memory regions to struct device. reserved_mem-ops-device_init()/device_cleanup() callbacks are called to perform reserved memory driver specific initialization and cleanup Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/of_reserved_mem.c| 70 + include/linux/of_reserved_mem.h | 7 + 2 files changed, 77 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 632aae861375..59fb12e84e6b 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -206,8 +206,16 @@ void __init fdt_init_reserved_mem(void) for (i = 0; i reserved_mem_count; i++) { struct reserved_mem *rmem = reserved_mem[i]; unsigned long node = rmem-fdt_node; + int len; + const __be32 *prop; int err = 0; + prop = of_get_flat_dt_prop(node, phandle, len); + if (!prop) + prop = of_get_flat_dt_prop(node, linux,phandle, len); + if (prop) + rmem-phandle = of_read_number(prop, len/4); + if (rmem-size == 0) err = __reserved_mem_alloc_size(node, rmem-name, rmem-base, rmem-size); @@ -215,3 +223,65 @@ void __init fdt_init_reserved_mem(void) __reserved_mem_init_node(rmem); } } + +static inline struct reserved_mem *__find_rmem(struct device_node *node) +{ + unsigned int i; + + if (!node-phandle) + return NULL; + + for (i = 0; i reserved_mem_count; i++) + if (reserved_mem[i].phandle == node-phandle) + 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 *rmem; + struct device_node *np; + + np = of_parse_phandle(dev-of_node, memory-region, 0); + if (!np) + return; + + rmem = __find_rmem(np); + of_node_put(np); + + if (!rmem || !rmem-ops || !rmem-ops-device_init) + return; + + rmem-ops-device_init(rmem, dev); + dev_info(dev, assigned reserved memory node %s\n, rmem-name); +} + +/** + * 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 *rmem; + struct device_node *np; + + np = of_parse_phandle(dev-of_node, memory-region, 0); + if (!np) + return; + + rmem = __find_rmem(np); + of_node_put(np); + + if (!rmem || !rmem-ops || !rmem-ops-device_release) + return; + + rmem-ops-device_release(rmem, dev); +} diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 4669ddfdd5af..5b5efae09135 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -8,6 +8,7 @@ struct reserved_mem_ops; struct reserved_mem { const char *name; unsigned long fdt_node; + unsigned long phandle; const struct reserved_mem_ops *ops; phys_addr_t base; phys_addr_t size; @@ -27,10 +28,16 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn) #ifdef CONFIG_OF_RESERVED_MEM +void of_reserved_mem_device_init(struct device *dev); +void of_reserved_mem_device_release(struct device *dev); + void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); #else +static inline void of_reserved_mem_device_init(struct device *dev) { } +static inline void of_reserved_mem_device_release(struct device *pdev) { } + static inline void fdt_init_reserved_mem(void) { } static inline void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size) { } -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 RESEND 4/4] drivers: dma-contiguous: add initialization from device tree
Add a function to create CMA region from previously reserved memory and add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-contiguous.c | 67 +++ include/linux/cma.h | 3 ++ mm/cma.c | 62 --- 3 files changed, 121 insertions(+), 11 deletions(-) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 6606abdf880c..b77ea8bac176 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -211,3 +211,70 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages, { return cma_release(dev_get_cma_area(dev), pages, count); } + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +#undef pr_fmt +#define pr_fmt(fmt) fmt + +static void rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev) +{ + struct cma *cma = rmem-priv; + dev_set_cma_area(dev, cma); +} + +static void rmem_cma_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dev_set_cma_area(dev, NULL); +} + +static const struct reserved_mem_ops rmem_cma_ops = { + .device_init= rmem_cma_device_init, + .device_release = rmem_cma_device_release, +}; + +static int __init rmem_cma_setup(struct reserved_mem *rmem) +{ + phys_addr_t align = PAGE_SIZE max(MAX_ORDER - 1, pageblock_order); + phys_addr_t mask = align - 1; + unsigned long node = rmem-fdt_node; + struct cma *cma; + int err; + + if (!of_get_flat_dt_prop(node, reusable, NULL) || + of_get_flat_dt_prop(node, no-map, NULL)) + return -EINVAL; + + if ((rmem-base mask) || (rmem-size mask)) { + pr_err(Reserved memory: incorrect alignment of CMA region\n); + return -EINVAL; + } + + err = cma_init_reserved_mem(rmem-base, rmem-size, 0, cma); + if (err) { + pr_err(Reserved memory: unable to setup CMA region\n); + return err; + } + /* Architecture specific contiguous memory fixup. */ + dma_contiguous_early_fixup(rmem-base, rmem-size); + + if (of_get_flat_dt_prop(node, linux,cma-default, NULL)) + dma_contiguous_set_default(cma); + + rmem-ops = rmem_cma_ops; + rmem-priv = cma; + + pr_info(Reserved memory: created CMA memory pool at %pa, size %ld MiB\n, + rmem-base, (unsigned long)rmem-size / SZ_1M); + + return 0; +} +RESERVEDMEM_OF_DECLARE(cma, shared-dma-pool, rmem_cma_setup); +#endif diff --git a/include/linux/cma.h b/include/linux/cma.h index 32cab7a425f9..9a18a2b1934c 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -16,6 +16,9 @@ extern int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base, phys_addr_t limit, phys_addr_t alignment, unsigned int order_per_bit, bool fixed, struct cma **res_cma); +extern int cma_init_reserved_mem(phys_addr_t size, + phys_addr_t base, int order_per_bit, + struct cma **res_cma); extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align); extern bool cma_release(struct cma *cma, struct page *pages, int count); #endif diff --git a/mm/cma.c b/mm/cma.c index 4b251b037e1b..b3d8b925ad34 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -140,6 +140,54 @@ static int __init cma_init_reserved_areas(void) core_initcall(cma_init_reserved_areas); /** + * cma_init_reserved_mem() - create custom contiguous area from reserved memory + * @base: Base address of the reserved area + * @size: Size of the reserved area (in bytes), + * @order_per_bit: Order of pages represented by one bit on bitmap. + * @res_cma: Pointer to store the created cma region. + * + * This function creates custom contiguous area from already reserved memory. + */ +int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, +int order_per_bit, struct cma **res_cma) +{ + struct cma *cma; + phys_addr_t alignment; + + /* Sanity checks */ + if (cma_area_count == ARRAY_SIZE(cma_areas)) { + pr_err(Not enough slots for CMA reserved regions!\n); + return -ENOSPC; + } + + if (!size || !memblock_is_region_reserved(base, size)) + return -EINVAL; + + /* ensure minimal alignment requied by mm core */ + alignment = PAGE_SIZE max(MAX_ORDER - 1, pageblock_order); + + /* alignment should be aligned with order_per_bit
[PATCH v2 RESEND 2/4] drivers: of: initialize and assign reserved memory to newly created devices
Use recently introduced of_reserved_mem_device_init() function to automatically assign respective reserved memory region to the newly created platform and amba device. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/platform.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 500436f9be7f..a9055d3da5c2 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[] = { @@ -233,12 +234,15 @@ static 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 */ if (of_device_add(dev) != 0) { + of_reserved_mem_device_release(dev-dev); platform_device_put(dev); goto err_clear_flag; } @@ -300,6 +304,8 @@ static struct amba_device *of_amba_device_create(struct device_node *node, else of_device_make_bus_id(dev-dev); + of_reserved_mem_device_init(dev-dev); + /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, arm,primecell-periphid, NULL); if (prop) @@ -326,6 +332,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node, return dev; err_free: + of_reserved_mem_device_release(dev-dev); amba_device_put(dev); err_clear_flag: of_node_clear_flag(node, OF_POPULATED); -- 1.9.2 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 RESEND 3/4] drivers: dma-coherent: add initialization from device tree
Initialization procedure of dma coherent pool has been split into two parts, so memory pool can now be initialized without assigning to particular struct device. Then initialized region can be assigned to more than one struct device. To protect from concurent allocations from different devices, a spinlock has been added to dma_coherent_mem structure. The last part of this patch adds support for handling 'shared-dma-pool' reserved-memory device tree nodes. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-coherent.c | 137 ++-- 1 file changed, 118 insertions(+), 19 deletions(-) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 7d6e84a51424..7185a4f247e1 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -14,11 +14,14 @@ struct dma_coherent_mem { int size; int flags; unsigned long *bitmap; + spinlock_t spinlock; }; -int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags) +static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr, +size_t size, int flags, +struct dma_coherent_mem **mem) { + struct dma_coherent_mem *dma_mem = NULL; void __iomem *mem_base = NULL; int pages = size PAGE_SHIFT; int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); @@ -27,27 +30,26 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, goto out; if (!size) goto out; - if (dev-dma_mem) - goto out; - - /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ mem_base = ioremap(phys_addr, size); if (!mem_base) goto out; - dev-dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); - if (!dev-dma_mem) + dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); + if (!dma_mem) goto out; - dev-dma_mem-bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!dev-dma_mem-bitmap) + dma_mem-bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dma_mem-bitmap) goto free1_out; - dev-dma_mem-virt_base = mem_base; - dev-dma_mem-device_base = device_addr; - dev-dma_mem-pfn_base = PFN_DOWN(phys_addr); - dev-dma_mem-size = pages; - dev-dma_mem-flags = flags; + dma_mem-virt_base = mem_base; + dma_mem-device_base = device_addr; + dma_mem-pfn_base = PFN_DOWN(phys_addr); + dma_mem-size = pages; + dma_mem-flags = flags; + spin_lock_init(dma_mem-spinlock); + + *mem = dma_mem; if (flags DMA_MEMORY_MAP) return DMA_MEMORY_MAP; @@ -55,12 +57,51 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, return DMA_MEMORY_IO; free1_out: - kfree(dev-dma_mem); + kfree(dma_mem); out: if (mem_base) iounmap(mem_base); return 0; } + +static void dma_release_coherent_memory(struct dma_coherent_mem *mem) +{ + if (!mem) + return; + iounmap(mem-virt_base); + kfree(mem-bitmap); + kfree(mem); +} + +static int dma_assign_coherent_memory(struct device *dev, + struct dma_coherent_mem *mem) +{ + if (dev-dma_mem) + return -EBUSY; + + dev-dma_mem = mem; + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + return 0; +} + +int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + struct dma_coherent_mem *mem; + int ret; + + ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags, + mem); + if (ret == 0) + return 0; + + if (dma_assign_coherent_memory(dev, mem) == 0) + return ret; + + dma_release_coherent_memory(mem); + return 0; +} EXPORT_SYMBOL(dma_declare_coherent_memory); void dma_release_declared_memory(struct device *dev) @@ -69,10 +110,8 @@ void dma_release_declared_memory(struct device *dev) if (!mem) return; + dma_release_coherent_memory(mem); dev-dma_mem = NULL; - iounmap(mem-virt_base); - kfree(mem-bitmap); - kfree(mem); } EXPORT_SYMBOL(dma_release_declared_memory); @@ -80,6 +119,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev, dma_addr_t device_addr, size_t size) { struct dma_coherent_mem *mem = dev-dma_mem; + unsigned long flags; int pos, err; size += device_addr ~PAGE_MASK
Re: [PATCH 4/4] drivers: dma-contiguous: add initialization from device tree
Hello, On 2014-07-04 07:52, Joonsoo Kim wrote: -Original Message- From: Marek Szyprowski [mailto:m.szyprow...@samsung.com] Sent: Wednesday, July 02, 2014 7:49 PM Subject: [PATCH 4/4] drivers: dma-contiguous: add initialization from device tree Add a code to create CMA region from reserved memory and add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-contiguous.c | 67 + include/linux/cma.h | 3 ++ mm/cma.c | 69 --- 3 files changed, 122 insertions(+), 17 deletions(-) ... +/** * cma_declare_contiguous() - reserve custom contiguous area * @base: Base address of the reserved area optional, use 0 for any * @size: Size of the reserved area (in bytes), @@ -162,18 +210,12 @@ int __init cma_declare_contiguous(phys_addr_t base, phys_addr_t alignment, unsigned int order_per_bit, bool fixed, struct cma **res_cma) { - struct cma *cma; - int ret = 0; + int ret; pr_debug(%s(size %lx, base %08lx, limit %08lx alignment %08lx)\n, __func__, (unsigned long)size, (unsigned long)base, (unsigned long)limit, (unsigned long)alignment); - if (cma_area_count == ARRAY_SIZE(cma_areas)) { - pr_err(Not enough slots for CMA reserved regions!\n); - return -ENOSPC; - } - Hello, Marek. After this change, if we have not enough cma_areas, memory will leak. I think that we need separate function to check constraint and this function should be called before reserving memory in cma_declare_contiguous(). Well, I will leave this check to avoid memory leak then. BTW, this mail doesn't appear in LKML. What happens? :) I have no idea, I will send second version then. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH V2 0/2] Sound support for Exynos4412 Odroid X2, U3 board
Hello, On 2014-06-24 10:35, Daniel Drake wrote: On Mon, Jun 23, 2014 at 5:32 PM, Sylwester Nawrocki s.nawro...@samsung.com wrote: I could reproduce such behaviour on the U3 board, but only with u-boot which sets the MPLL clock frequency (fout_mpll) to 880 MHz, rather than 800 MHz, which was the case in my original environment. All fout_mpll child clocks have then different frequency values in both cases. It's a bit strange though, because frequencies of all the audio subsystem clocks seem to be same anyway: I'm using the standard uboot from hardkernel. # cat /sys/kernel/debug/clk/clk_summary This command makes the kernel totally hang, weird. This is known issue with clocks vs. ISP power domain. We should really fix this in exynos4 clock driver. # speaker-test -c 2 -t wav -l 2 -p 1024 This plays back fine. Could it be a problem with the samsung-i2s driver, not correctly flushing at the right times? Or do you think the problem is more likely to be clock-related? Hard to say right now, but at least we need to test a bit more our solutions with different initial clocks configuration. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/6] of: align RESERVEDMEM_OF_DECLARE function callbacks to other callbacks
Hello, On 2014-05-09 00:23, Rob Herring wrote: From: Rob Herring r...@kernel.org All the parameters for RESERVEDMEM_OF_DECLARE function callbacks are members of struct reserved_mem, so just pass the struct ptr to callback functions so the function callback is more in line with other OF match table callbacks. Cc: Marek Szyprowski m.szyprow...@samsung.com Cc: Grant Likely grant.lik...@linaro.org Signed-off-by: Rob Herring r...@kernel.org Acked-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/of_reserved_mem.c| 2 +- include/linux/of_reserved_mem.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index e420eb5..632aae8 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -188,7 +188,7 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem) if (!of_flat_dt_is_compatible(rmem-fdt_node, compat)) continue; - if (initfn(rmem, rmem-fdt_node, rmem-name) == 0) { + if (initfn(rmem) == 0) { pr_info(Reserved memory: initialized node %s, compatible id %s\n, rmem-name, compat); return 0; diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 9b1fbb7..4c81b84 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -21,8 +21,8 @@ struct reserved_mem_ops { struct device *dev); }; -typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem, - unsigned long node, const char *uname); +typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); + #ifdef CONFIG_OF_RESERVED_MEM void fdt_init_reserved_mem(void); Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 01/11] of: document bindings for reserved-memory nodes
Hello, On 2014-02-26 12:51, Grant Likely wrote: On Fri, 21 Feb 2014 13:25:17 +0100, Marek Szyprowski m.szyprow...@samsung.com wrote: From: Grant Likely grant.lik...@linaro.org Reserved memory nodes allow for the reservation of static (fixed address) regions, or dynamically allocated regions for a specific purpose. Signed-off-by: Grant Likely grant.lik...@linaro.org [joshc: Based on binding document proposed (in non-patch form) here: http://lkml.kernel.org/g/20131030134702.19b57c40...@trevor.secretlab.ca adapted to support #memory-region-cells] Signed-off-by: Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- .../bindings/reserved-memory/reserved-memory.txt | 138 1 file changed, 138 insertions(+) create mode 100644 Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt new file mode 100644 index ..a606ce90c9c4 --- /dev/null +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -0,0 +1,138 @@ +*** Reserved memory regions *** + +Reserved memory is specified as a node under the /reserved-memory node. +The operating system shall exclude reserved memory from normal usage +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. + +Parameters for each memory region can be encoded into the device tree +with the following nodes: + +/reserved-memory node +- +#address-cells, #size-cells (required) - standard definition +- Should use the same values as the root node +#memory-region-cells (required) - dictates number of cells used in the child + nodes memory-region specifier I still don't like this portion of the binding. I'm not convinced that it is necessary in the majority of cases and it is going to be very driver specific. I would rather drop it entirely from the common binding. If a specific driver needs to do something like the above then it can have a driver specific binding. Otherwise I think the default should be a simple phandle with no arguments to a single reserved memory node. Ben, can you weigh in on the current state of this document. I'm mostly happy with it aside from my comment above. Do you think this is ready to be merged? +ranges (required) - standard definition +- Should be empty + +/reserved-memory/ child nodes +- +Each child of the reserved-memory node specifies one or more regions of +reserved memory. Each child node may either use a 'reg' property to +specify a specific range of reserved memory, or a 'size' property with +optional constraints to request a dynamically allocated block of memory. + +Following the generic-names recommended practice, node names should +reflect the purpose of the node (ie. framebuffer or dma-pool). Unit +address (@address) should be appended to the name if the node is a +static allocation. + +Properties: +Requires either a) or b) below. +a) static allocation + reg (required) - standard definition +b) dynamic allocation + size (required) - length based on parent's #size-cells + - Size in bytes of memory to reserve. + alignment (optional) - length based on parent's #size-cells +- Address boundary for alignment of allocation. + alloc-ranges (optional) - prop-encoded-array (address, length pairs). + - Specifies regions of memory that are + acceptable to allocate from. + +If both reg and size are present, then the reg property takes precedence +and size is ignored. + +Additional properties: +compatible (optional) - standard definition +- may contain the following strings: +- shared-dma-pool: This indicates a region of memory meant to be + used as a shared pool of DMA buffers for a set of devices. It can + be used by an operating system to instanciate the necessary pool + management subsystem if necessary. +- vendor specific string in the form vendor,[device-]usage Add Use vendor strings to identify regions dedicates for a specific vendor device. For example: 'acme,framebuffer'. Platform code can use vendor strings to identify device specific regions So do you want to completely drop phandle based links between device nodes and memory regions? +no-map (optional) - empty property +- Indicates the operating system must not create a virtual mapping + of the region as part of its standard mapping of system memory, + nor permit speculative access to it under any circumstances other + than under the control
[PATCH v6 00/11] reserved-memory regions/CMA in devicetree, again
Hello again! Here is another update of the support for reserved memory regions in device tree. I've fixes a few more minor issues pointed by Grant. See changelog for more details. The initial code for this feature were posted here [1], merged as commit 9d8eab7af79cb4ce2de5de39f82c455b1f796963 (drivers: of: add initialization code for dma reserved memory) and later reverted by commit 1931ee143b0ab72924944bc06e363d837ba05063. For more information, see [2]. Finally a new bindings has been proposed [3] and Josh Cartwright a few days ago prepared some code which implements those bindings [4]. This finally pushed me again to find some time to finish this task and review the code. Josh agreed to give me the ownership of this series to continue preparing them for mainline inclusion. For more information please refer to the changlelog and links below. [1]: http://lkml.kernel.org/g/1377527959-5080-1-git-send-email-m.szyprow...@samsung.com [2]: http://lkml.kernel.org/g/1381476448-14548-1-git-send-email-m.szyprow...@samsung.com [3]: http://lkml.kernel.org/g/20131030134702.19b57c40...@trevor.secretlab.ca [4]: http://thread.gmane.org/gmane.linux.documentation/19579 Changelog: v6: - removed the need for #memory-region-cells property - fixed compilation issues on some systems - some other minor code cleanups v5: https://lkml.org/lkml/2014/2/21/147 - sliced main patch into several smaller patches on Grant's request - fixed coding style issues pointed by Grant - use node-phandle value directly instead of parsing properties manually v4: https://lkml.org/lkml/2014/2/20/150 - dynamic allocations are processed after all static reservations has been done - moved code for handling static reservations to drivers/of/fdt.c - removed node matching by string comparison, now phandle values are used directly - moved code for DMA and CMA handling directly to drivers/base/dma-{coherent,contiguous}.c - added checks for proper #size-cells, #address-cells, ranges properties in /reserved-memory node - even more code cleanup - added init code for ARM64 and PowerPC v3: http://article.gmane.org/gmane.linux.documentation/20169/ - refactored memory reservation code, created common code to parse reg, size, align, alloc-ranges properties - added support for multiple tuples in 'reg' property - memory is reserved regardless of presence of the driver for its compatible - prepared arch specific hooks for memory reservation (defaults use memblock calls) - removed node matching by string during device initialization - CMA init code: added checks for required region alignment - more code cleanup here and there v2: http://thread.gmane.org/gmane.linux.documentation/19870/ - removed copying of the node name - split shared-dma-pool handling into separate files (one for CMA and one for dma_declare_coherent based implementations) for making the code easier to understand - added support for AMBA devices, changed prototypes to use struct decice instead of struct platform_device - renamed some functions to better match other names used in drivers/of/ - restructured the rest of the code a bit for better readability - added 'reusable' property to exmaple linux,cma node in documentation - exclusive dma (dma_coherent) is used for only handling 'shared-dma-pool' regions without 'reusable' property and CMA is used only for handling 'shared-dma-pool' regions with 'reusable' property. v1: http://thread.gmane.org/gmane.linux.documentation/19579 - initial version prepared by Josh Cartwright Summary: Grant Likely (1): of: document bindings for reserved-memory nodes Marek Szyprowski (10): drivers: of: add initialization code for static reserved memory drivers: of: add initialization code for dynamic reserved memory drivers: of: add support for custom reserved memory drivers drivers: of: add automated assignment of reserved regions to client devices drivers: of: initialize and assign reserved memory to newly created devices drivers: dma-coherent: add initialization from device tree drivers: dma-contiguous: add initialization from device tree arm: add support for reserved memory defined by device tree arm64: add support for reserved memory defined by device tree powerpc: add support for reserved memory defined by device tree .../bindings/reserved-memory/reserved-memory.txt | 136 ++ arch/arm/Kconfig |1 + arch/arm/mm/init.c |2 + arch/arm64/Kconfig |1 + arch/arm64/mm/init.c |1 + arch/powerpc/Kconfig |1 + arch/powerpc/kernel/prom.c |3 + drivers/base/dma-coherent.c| 40 +++ drivers/base/dma-contiguous.c | 129 +++-- drivers/of/Kconfig |6 + drivers/of/Makefile|1 + drivers
[PATCH v6 01/11] of: document bindings for reserved-memory nodes
From: Grant Likely grant.lik...@linaro.org Reserved memory nodes allow for the reservation of static (fixed address) regions, or dynamically allocated regions for a specific purpose. Signed-off-by: Grant Likely grant.lik...@linaro.org [joshc: Based on binding document proposed (in non-patch form) here: http://lkml.kernel.org/g/20131030134702.19b57c40...@trevor.secretlab.ca adapted to support #memory-region-cells] Signed-off-by: Josh Cartwright jo...@codeaurora.org [mszyprow: removed #memory-region-cells property] Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- .../bindings/reserved-memory/reserved-memory.txt | 136 1 file changed, 136 insertions(+) create mode 100644 Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt new file mode 100644 index ..8b0d747a38e7 --- /dev/null +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -0,0 +1,136 @@ +*** Reserved memory regions *** + +Reserved memory is specified as a node under the /reserved-memory node. +The operating system shall exclude reserved memory from normal usage +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. + +Parameters for each memory region can be encoded into the device tree +with the following nodes: + +/reserved-memory node +- +#address-cells, #size-cells (required) - standard definition +- Should use the same values as the root node +ranges (required) - standard definition +- Should be empty + +/reserved-memory/ child nodes +- +Each child of the reserved-memory node specifies one or more regions of +reserved memory. Each child node may either use a 'reg' property to +specify a specific range of reserved memory, or a 'size' property with +optional constraints to request a dynamically allocated block of memory. + +Following the generic-names recommended practice, node names should +reflect the purpose of the node (ie. framebuffer or dma-pool). Unit +address (@address) should be appended to the name if the node is a +static allocation. + +Properties: +Requires either a) or b) below. +a) static allocation + reg (required) - standard definition +b) dynamic allocation + size (required) - length based on parent's #size-cells + - Size in bytes of memory to reserve. + alignment (optional) - length based on parent's #size-cells +- Address boundary for alignment of allocation. + alloc-ranges (optional) - prop-encoded-array (address, length pairs). + - Specifies regions of memory that are + acceptable to allocate from. + +If both reg and size are present, then the reg property takes precedence +and size is ignored. + +Additional properties: +compatible (optional) - standard definition +- may contain the following strings: +- shared-dma-pool: This indicates a region of memory meant to be + used as a shared pool of DMA buffers for a set of devices. It can + be used by an operating system to instanciate the necessary pool + management subsystem if necessary. +- vendor specific string in the form vendor,[device-]usage +no-map (optional) - empty property +- Indicates the operating system must not create a virtual mapping + of the region as part of its standard mapping of system memory, + nor permit speculative access to it under any circumstances other + than under the control of the device driver using the region. +reusable (optional) - empty property +- The operating system can use the memory in this region with the + limitation that the device driver(s) owning the region need to be + able to reclaim it back. Typically that means that the operating + system can use that region to store volatile or cached data that + can be otherwise regenerated or migrated elsewhere. + +Linux implementation note: +- If a linux,cma-default property is present, then Linux will use the + region for the default pool of the contiguous memory allocator. + +Device node references to reserved memory +- +Regions in the /reserved-memory node may be referenced by other device +nodes by adding a memory-region property to the device node. + +memory-region (optional) - phandle, specifier pairs to children of /reserved-memory + +Example +--- +This example defines 3 contiguous regions are defined for Linux kernel: +one default of all device drivers (named linux,cma@7200 and 64MiB in size), +one dedicated to the framebuffer device (named framebuffer@7800, 8MiB), and +one for multimedia processing
[PATCH v6 05/11] drivers: of: add automated assignment of reserved regions to client devices
This patch adds code for automated assignment of reserved memory regions to struct device. reserved_mem-ops-device_init()/device_cleanup() callbacks are called to perform reserved memory driver specific initialization and cleanup Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/of_reserved_mem.c| 70 +++ include/linux/of_reserved_mem.h |7 2 files changed, 77 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index daaaf935911d..5c45016efd31 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -206,8 +206,16 @@ void __init fdt_init_reserved_mem(void) for (i = 0; i reserved_mem_count; i++) { struct reserved_mem *rmem = reserved_mem[i]; unsigned long node = rmem-fdt_node; + unsigned long len; + __be32 *prop; int err = 0; + prop = of_get_flat_dt_prop(node, phandle, len); + if (!prop) + prop = of_get_flat_dt_prop(node, linux,phandle, len); + if (prop) + rmem-phandle = of_read_number(prop, len/4); + if (rmem-size == 0) err = __reserved_mem_alloc_size(node, rmem-name, rmem-base, rmem-size); @@ -215,3 +223,65 @@ void __init fdt_init_reserved_mem(void) __reserved_mem_init_node(rmem); } } + +static inline struct reserved_mem *__find_rmem(struct device_node *node) +{ + unsigned int i; + + if (!node-phandle) + return NULL; + + for (i = 0; i reserved_mem_count; i++) + if (reserved_mem[i].phandle == node-phandle) + 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 *rmem; + struct device_node *np; + + np = of_parse_phandle(dev-of_node, memory-region, 0); + if (!np) + return; + + rmem = __find_rmem(np); + of_node_put(np); + + if (!rmem || !rmem-ops || !rmem-ops-device_init) + return; + + rmem-ops-device_init(rmem, dev); + dev_info(dev, assigned reserved memory node %s\n, rmem-name); +} + +/** + * 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 *rmem; + struct device_node *np; + + np = of_parse_phandle(dev-of_node, memory-region, 0); + if (!np) + return; + + rmem = __find_rmem(np); + of_node_put(np); + + if (!rmem || !rmem-ops || !rmem-ops-device_release) + return; + + rmem-ops-device_release(rmem, dev); +} diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 9b1fbb7f29fc..6a54e6565b89 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -8,6 +8,7 @@ struct reserved_mem_ops; struct reserved_mem { const char *name; unsigned long fdt_node; + unsigned long phandle; const struct reserved_mem_ops *ops; phys_addr_t base; phys_addr_t size; @@ -25,6 +26,9 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem, unsigned long node, const char *uname); #ifdef CONFIG_OF_RESERVED_MEM +void of_reserved_mem_device_init(struct device *dev); +void of_reserved_mem_device_release(struct device *dev); + void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); @@ -37,6 +41,9 @@ void fdt_reserved_mem_save_node(unsigned long node, const char *uname, init : init } #else +static inline void of_reserved_mem_device_init(struct device *dev) { } +static inline void of_reserved_mem_device_release(struct device *pdev) { } + static inline void fdt_init_reserved_mem(void) { } static inline void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size) { } -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 10/11] arm64: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm64/Kconfig |1 + arch/arm64/mm/init.c |1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 27bbcfc7202a..6abf15407dca 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -43,6 +43,7 @@ config ARM64 select NO_BOOTMEM select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM select PERF_USE_VMALLOC select POWER_RESET select POWER_SUPPLY diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index d0b4c2efda90..3fb8d50dfdaa 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -160,6 +160,7 @@ void __init arm64_memblock_init(void) memblock_reserve(base, size); } + early_init_fdt_scan_reserved_mem(); dma_contiguous_reserve(0); memblock_allow_resize(); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 04/11] drivers: of: add support for custom reserved memory drivers
Add support for custom reserved memory drivers. Call their init() function for each reserved region and prepare for using operations provided by them with by the reserved_mem-ops array. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/of_reserved_mem.c | 29 + include/asm-generic/vmlinux.lds.h | 11 +++ include/linux/of_reserved_mem.h | 32 3 files changed, 72 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 69b811779585..daaaf935911d 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -170,6 +170,33 @@ static int __init __reserved_mem_alloc_size(unsigned long node, return 0; } +static const struct of_device_id __rmem_of_table_sentinel + __used __section(__reservedmem_of_table_end); + +/** + * res_mem_init_node() - call region specific reserved memory init code + */ +static int __init __reserved_mem_init_node(struct reserved_mem *rmem) +{ + extern const struct of_device_id __reservedmem_of_table[]; + const struct of_device_id *i; + + for (i = __reservedmem_of_table; i __rmem_of_table_sentinel; i++) { + reservedmem_of_init_fn initfn = i-data; + const char *compat = i-compatible; + + if (!of_flat_dt_is_compatible(rmem-fdt_node, compat)) + continue; + + if (initfn(rmem, rmem-fdt_node, rmem-name) == 0) { + pr_info(Reserved memory: initialized node %s, compatible id %s\n, + rmem-name, compat); + return 0; + } + } + return -ENOENT; +} + /** * fdt_init_reserved_mem - allocate and init all saved reserved memory regions */ @@ -184,5 +211,7 @@ void __init fdt_init_reserved_mem(void) if (rmem-size == 0) err = __reserved_mem_alloc_size(node, rmem-name, rmem-base, rmem-size); + if (err == 0) + __reserved_mem_init_node(rmem); } } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index bc2121fa9132..f10f64fcc815 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -167,6 +167,16 @@ #define CLK_OF_TABLES() #endif +#ifdef CONFIG_OF_RESERVED_MEM +#define RESERVEDMEM_OF_TABLES()\ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__reservedmem_of_table) = .; \ + *(__reservedmem_of_table) \ + *(__reservedmem_of_table_end) +#else +#define RESERVEDMEM_OF_TABLES() +#endif + #define KERNEL_DTB() \ STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__dtb_start) = .;\ @@ -490,6 +500,7 @@ TRACE_SYSCALLS()\ MEM_DISCARD(init.rodata)\ CLK_OF_TABLES() \ + RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ KERNEL_DTB()\ IRQCHIP_OF_MATCH_TABLE() diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 89226ed7d954..9b1fbb7f29fc 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -1,21 +1,53 @@ #ifndef __OF_RESERVED_MEM_H #define __OF_RESERVED_MEM_H +struct device; +struct of_phandle_args; +struct reserved_mem_ops; + struct reserved_mem { const char *name; unsigned long fdt_node; + const struct reserved_mem_ops *ops; phys_addr_t base; phys_addr_t size; + void*priv; +}; + +struct reserved_mem_ops { + void(*device_init)(struct reserved_mem *rmem, + struct device *dev); + void(*device_release)(struct reserved_mem *rmem, + struct device *dev); }; +typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem, + unsigned long node, const char *uname); + #ifdef CONFIG_OF_RESERVED_MEM void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); + +#define RESERVEDMEM_OF_DECLARE(name, compat, init) \ + static const struct of_device_id __reservedmem_of_table_
[PATCH v6 11/11] powerpc: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/powerpc/Kconfig |1 + arch/powerpc/kernel/prom.c |3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 957bf344c0f5..3b6617fed8fc 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -90,6 +90,7 @@ config PPC select BINFMT_ELF select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f58c0d3aaeb4..591986215801 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -33,6 +33,7 @@ #include linux/irq.h #include linux/memblock.h #include linux/of.h +#include linux/of_fdt.h #include asm/prom.h #include asm/rtas.h @@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void) memblock_reserve(base, size); } } + + early_init_fdt_scan_reserved_mem(); } static void __init early_reserve_mem(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 06/11] drivers: of: initialize and assign reserved memory to newly created devices
Use recently introduced of_reserved_mem_device_init() function to automatically assign respective reserved memory region to the newly created platform and amba device. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/platform.c |7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 404d1daebefa..3df0b1826e8b 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[] = { @@ -220,6 +221,8 @@ static 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 @@ -227,6 +230,7 @@ static 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; } @@ -282,6 +286,8 @@ static struct amba_device *of_amba_device_create(struct device_node *node, else of_device_make_bus_id(dev-dev); + of_reserved_mem_device_init(dev-dev); + /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, arm,primecell-periphid, NULL); if (prop) @@ -308,6 +314,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node, return dev; err_free: + of_reserved_mem_device_release(dev-dev); amba_device_put(dev); return NULL; } -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 08/11] drivers: dma-contiguous: add initialization from device tree
Refactor internal dma_contiguous_init_reserved_mem() function, which creates CMA area from previously reserved memory region and add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-contiguous.c | 129 ++--- 1 file changed, 107 insertions(+), 22 deletions(-) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 165c2c299e57..0efdf1986990 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -182,6 +182,49 @@ static int __init cma_init_reserved_areas(void) core_initcall(cma_init_reserved_areas); /** + * dma_contiguous_init_reserved_mem() - 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 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. + */ +static int __init dma_contiguous_init_reserved_mem(phys_addr_t size, + phys_addr_t base, struct cma **res_cma) +{ + struct cma *cma = cma_areas[cma_area_count]; + phys_addr_t alignment; + + /* Sanity checks */ + if (cma_area_count == ARRAY_SIZE(cma_areas)) { + pr_err(Not enough slots for CMA reserved regions!\n); + return -ENOSPC; + } + + if (!size || !memblock_is_region_reserved(base, size)) + return -EINVAL; + + /* Sanitise input arguments */ + alignment = PAGE_SIZE max(MAX_ORDER - 1, pageblock_order); + if (ALIGN(base, alignment) != base || ALIGN(size, alignment) != size) + return -EINVAL; + + cma-base_pfn = PFN_DOWN(base); + cma-count = size PAGE_SHIFT; + *res_cma = cma; + cma_area_count++; + + /* Architecture specific contiguous memory fixup. */ + dma_contiguous_early_fixup(base, size); + return 0; +} + +/** * 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 @@ -197,7 +240,6 @@ core_initcall(cma_init_reserved_areas); int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, phys_addr_t limit, struct cma **res_cma) { - struct cma *cma = cma_areas[cma_area_count]; phys_addr_t alignment; int ret = 0; @@ -205,12 +247,6 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, (unsigned long)size, (unsigned long)base, (unsigned long)limit); - /* Sanity checks */ - if (cma_area_count == ARRAY_SIZE(cma_areas)) { - pr_err(Not enough slots for CMA reserved regions!\n); - return -ENOSPC; - } - if (!size) return -EINVAL; @@ -241,21 +277,12 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, } } - /* -* Each reserved area must be initialised later, when more kernel -* subsystems (like slab allocator) are available. -*/ - 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); - - /* Architecture specific contiguous memory fixup. */ - dma_contiguous_early_fixup(base, size); - return 0; + ret = dma_contiguous_init_reserved_mem(size, base, res_cma); + if (ret == 0) { + pr_info(CMA: reserved %ld MiB at %08lx\n, + (unsigned long)size / SZ_1M, (unsigned long)base); + return 0; + } err: pr_err(CMA: failed to reserve %ld MiB\n, (unsigned long)size / SZ_1M); return ret; @@ -357,3 +384,61 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages, return true; } + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +#undef pr_fmt +#define pr_fmt(fmt) fmt + +static void rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev) +{ + struct cma *cma = rmem-priv; + dev_set_cma_area(dev, cma); +} + +static const struct reserved_mem_ops rmem_cma_ops
[PATCH v6 03/11] drivers: of: add initialization code for dynamic reserved memory
This patch adds support for dynamically allocated reserved memory regions declared in device tree. Such regions are defined by 'size', 'alignment' and 'alloc-ranges' properties. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com Acked-by: Grant Likely grant.lik...@linaro.org --- drivers/of/Kconfig |6 ++ drivers/of/Makefile |1 + drivers/of/fdt.c| 13 ++- drivers/of/of_reserved_mem.c| 188 +++ include/linux/of_reserved_mem.h | 21 + 5 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 drivers/of/of_reserved_mem.c create mode 100644 include/linux/of_reserved_mem.h diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index c6973f101a3e..30a7d87a8077 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -75,4 +75,10 @@ config OF_MTD depends on MTD def_bool y +config OF_RESERVED_MEM + depends on OF_EARLY_FLATTREE + bool + help + Helpers to allow for reservation of memory regions + endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index efd05102c405..ed9660adad77 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -9,3 +9,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/fdt.c b/drivers/of/fdt.c index 819e11209718..510c0d8de8a0 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,7 @@ #include linux/module.h #include linux/of.h #include linux/of_fdt.h +#include linux/of_reserved_mem.h #include linux/sizes.h #include linux/string.h #include linux/errno.h @@ -450,7 +451,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, phys_addr_t base, size; unsigned long len; __be32 *prop; - int nomap; + int nomap, first = 1; prop = of_get_flat_dt_prop(node, reg, len); if (!prop) @@ -477,6 +478,10 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, uname, base, (unsigned long)size / SZ_1M); len -= t_len; + if (first) { + fdt_reserved_mem_save_node(node, uname, base, size); + first = 0; + } } return 0; } @@ -512,6 +517,7 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, { static int found; const char *status; + int err; if (!found depth == 1 strcmp(uname, reserved-memory) == 0) { if (__reserved_mem_check_root(node) != 0) { @@ -534,7 +540,9 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, if (status strcmp(status, okay) != 0 strcmp(status, ok) != 0) return 0; - __reserved_mem_reserve_reg(node, uname); + err = __reserved_mem_reserve_reg(node, uname); + if (err == -ENOENT of_get_flat_dt_prop(node, size, NULL)) + fdt_reserved_mem_save_node(node, uname, 0, 0); /* scan next node */ return 0; @@ -550,6 +558,7 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, void __init early_init_fdt_scan_reserved_mem(void) { of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); + fdt_init_reserved_mem(); } /** diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c new file mode 100644 index ..69b811779585 --- /dev/null +++ b/drivers/of/of_reserved_mem.c @@ -0,0 +1,188 @@ +/* + * Device tree based initialization code for reserved memory. + * + * Copyright (c) 2013, The Linux Foundation. All Rights Reserved. + * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Author: Marek Szyprowski m.szyprow...@samsung.com + * Author: Josh Cartwright jo...@codeaurora.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License or (at your optional) any later version of the license. + */ + +#include 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/of_reserved_mem.h + +#define MAX_RESERVED_REGIONS 16 +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; +static int reserved_mem_count; + +#if defined(CONFIG_HAVE_MEMBLOCK) +#include linux/memblock.h +int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, + phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap, + phys_addr_t *res_base) +{ + /* +* We use
[PATCH v6 02/11] drivers: of: add initialization code for static reserved memory
This patch adds support for static (defined by 'reg' property) reserved memory regions declared in device tree. 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). Typically, all this happens before device tree structures are unflattened, so we need to get reserved memory layout directly from fdt. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com Acked-by: Grant Likely grant.lik...@linaro.org --- drivers/of/fdt.c | 131 include/linux/of_fdt.h |3 ++ 2 files changed, 134 insertions(+) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 758b4f8b30b7..819e11209718 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,7 @@ #include linux/module.h #include linux/of.h #include linux/of_fdt.h +#include linux/sizes.h #include linux/string.h #include linux/errno.h #include linux/slab.h @@ -440,6 +441,118 @@ struct boot_param_header *initial_boot_params; #ifdef CONFIG_OF_EARLY_FLATTREE /** + * res_mem_reserve_reg() - reserve all memory described in 'reg' property + */ +static int __init __reserved_mem_reserve_reg(unsigned long node, +const char *uname) +{ + int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); + phys_addr_t base, size; + unsigned long len; + __be32 *prop; + int nomap; + + prop = of_get_flat_dt_prop(node, reg, len); + if (!prop) + return -ENOENT; + + if (len len % t_len != 0) { + pr_err(Reserved memory: invalid reg property in '%s', skipping node.\n, + uname); + return -EINVAL; + } + + nomap = of_get_flat_dt_prop(node, no-map, NULL) != NULL; + + while (len = t_len) { + base = dt_mem_next_cell(dt_root_addr_cells, prop); + size = dt_mem_next_cell(dt_root_size_cells, prop); + + if (base size + early_init_dt_reserve_memory_arch(base, size, nomap) == 0) + pr_debug(Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n, + uname, base, (unsigned long)size / SZ_1M); + else + pr_info(Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n, + uname, base, (unsigned long)size / SZ_1M); + + len -= t_len; + } + return 0; +} + +/** + * __reserved_mem_check_root() - check if #size-cells, #address-cells provided + * in /reserved-memory matches the values supported by the current implementation, + * also check if ranges property has been provided + */ +static int __reserved_mem_check_root(unsigned long node) +{ + __be32 *prop; + + prop = of_get_flat_dt_prop(node, #size-cells, NULL); + if (!prop || be32_to_cpup(prop) != dt_root_size_cells) + return -EINVAL; + + prop = of_get_flat_dt_prop(node, #address-cells, NULL); + if (!prop || be32_to_cpup(prop) != dt_root_addr_cells) + return -EINVAL; + + prop = of_get_flat_dt_prop(node, ranges, NULL); + if (!prop) + return -EINVAL; + return 0; +} + +/** + * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory + */ +static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, + int depth, void *data) +{ + static int found; + const char *status; + + if (!found depth == 1 strcmp(uname, reserved-memory) == 0) { + if (__reserved_mem_check_root(node) != 0) { + pr_err(Reserved memory: unsupported node format, ignoring\n); + /* break scan */ + return 1; + } + found = 1; + /* scan next node */ + return 0; + } else if (!found) { + /* scan next node */ + return 0; + } else if (found depth 2) { + /* scanning of /reserved-memory has been finished */ + return 1; + } + + status = of_get_flat_dt_prop(node, status, NULL); + if (status strcmp(status, okay) != 0 strcmp(status, ok) != 0) + return 0; + + __reserved_mem_reserve_reg(node, uname); + + /* scan next node */ + return 0; +} + +/** + * early_init_fdt_scan_reserved_mem() - create reserved memory regions + * + * This function grabs memory from early allocator for device exclusive
[PATCH v6 07/11] drivers: dma-coherent: add initialization from device tree
Add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-coherent.c | 40 1 file changed, 40 insertions(+) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index bc256b641027..0a5fc7f3d03e 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -218,3 +218,43 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, return 0; } EXPORT_SYMBOL(dma_mmap_from_coherent); + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +static void rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev) +{ + dma_declare_coherent_memory(dev, rmem-base, rmem-base, + rmem-size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); +} + +static void rmem_dma_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dma_release_declared_memory(dev); +} + +static const struct reserved_mem_ops rmem_dma_ops = { + .device_init= rmem_dma_device_init, + .device_release = rmem_dma_device_release, +}; + +static int __init rmem_dma_setup(struct reserved_mem *rmem, +unsigned long node, +const char *uname) +{ + if (of_get_flat_dt_prop(node, reusable, NULL)) + return -EINVAL; + + rmem-ops = rmem_dma_ops; + pr_info(Reserved memory: created DMA memory pool at %pa, size %ld MiB\n, + rmem-base, (unsigned long)rmem-size / SZ_1M); + return 0; +} +RESERVEDMEM_OF_DECLARE(dma, shared-dma-pool, rmem_dma_setup); +#endif -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 06/11] drivers: of: initialize and assign reserved memory to newly created devices
Hello, On 2014-02-26 13:14, Grant Likely wrote: On Fri, 21 Feb 2014 13:25:22 +0100, Marek Szyprowski m.szyprow...@samsung.com wrote: Use recently introduced of_reserved_mem_device_init() function to automatically assign respective reserved memory region to the newly created platform and amba device. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com I'm wary on this patch. It hides the assignment of regions into the core code and I worry that it is the wrong level of abstraction. I would think that drivers should know that they need a reserved memory region and should be calling the API to obtain the region directly rather than doing it for them. The reason being is that there may be some situations where the common code isn't quite right and the driver needs to override the behaviour. If it is called automatically then the driver cannot do that. Is it really a big burden to have the driver call the reserved memory init function? If a device requires very special handling of the reserved memory region, it may simply provide its own reserved memory region driver which will do the required early initialization. If we assume that driver needs to initialize reserved region manually, then why do we ever bother with adding support for custom reserved memory drivers and assigning regions to a device node? We can simply stick with just a set of reserved regions and tell drivers to use them. In my opinion for most typical use cases a board designer will assign 'dma-shared-pool' driver to the given set of devices, which in turn ensures that all memory allocations for dma purposes for those device will be served from that region. It is really not a driver role to initialize it in such case. Driver should focus on controlling hw operations, regardless the way the hardware module has been integrated to the system. I can perfectly imagine a generic driver which operates the same way in any of the following cases (depends mainly on the hw version): 1) restricted dma window, 2) iommu for all dma for the given device, 3) fully featured memory master for dma for the given device (no restrictions), if the respective kernel subsystems did the correct initialization and provide their own methods for managing DMA operation. I already have a working platform glue code for the above cases tested with Samsung multimedia drivers. No changes to the drivers were required. Best regards -- Marek Szyprowski, PhD Samsung RD Institute Poland -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 1/7] drivers: of: add initialization code for reserved memory
Hello, On 2014-02-20 15:01, Grant Likely wrote: On Thu, 20 Feb 2014 11:52:41 +0100, Marek Szyprowski m.szyprow...@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.szyprow...@samsung.com [joshc: rework to implement new DT binding, provide mechanism for plugging in new reserved-memory node handlers via RESERVEDMEM_OF_DECLARE] Signed-off-by: Josh Cartwright jo...@codeaurora.org [mszyprow: added generic memory reservation code, refactored code to put it directly into fdt.c] Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/Kconfig|6 + drivers/of/Makefile |1 + drivers/of/fdt.c | 145 ++ drivers/of/of_reserved_mem.c | 296 + drivers/of/platform.c |7 + include/asm-generic/vmlinux.lds.h | 11 ++ include/linux/of_reserved_mem.h | 65 7 files changed, 531 insertions(+) create mode 100644 drivers/of/of_reserved_mem.c create mode 100644 include/linux/of_reserved_mem.h Hi Marek, There's a lot of moving parts in this patch. Can you split the patch up a bit please. There are parts that I'm not entierly comfortable with yet and it will help reviewing them if they are added separately. For instance, the attaching regions to devices is something that I want to have some discussion about, but the core reserving static ranges I think is pretty much ready to be merged. I can merge the later while still debating the former if they are split. I would recommend splitting into four: 1) reservation of static regions without the support code for referencing them later 2) code to also do dynamic allocations of reserved regions - again without any driver references 3) add hooks to reference specific regions. 4) hooks into drivers/of/platform.c for wiring into the driver model. Can you also make the binding doc the first patch? Ok, I will slice the patch into 4 pieces. (snipped) +/** + * res_mem_alloc_size() - allocate reserved memory described by 'size', 'align' + * and 'alloc-ranges' properties + */ +static int __init +__reserved_mem_alloc_size(unsigned long node, const char *uname, +phys_addr_t *res_base, phys_addr_t *res_size) +{ + int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); + phys_addr_t start = 0, end = 0; + phys_addr_t base = 0, align = 0, size; + unsigned long len; + __be32 *prop; + int nomap; + int ret; + + prop = of_get_flat_dt_prop(node, size, len); + if (!prop) + return -EINVAL; + + if (len != dt_root_size_cells * sizeof(__be32)) { + pr_err(Reserved memory: invalid size property in '%s' node.\n, + uname); + return -EINVAL; + } + size = dt_mem_next_cell(dt_root_size_cells, prop); + + nomap = of_get_flat_dt_prop(node, no-map, NULL) != NULL; + + prop = of_get_flat_dt_prop(node, align, len); + if (prop) { + if (len != dt_root_addr_cells * sizeof(__be32)) { + pr_err(Reserved memory: invalid align property in '%s' node.\n, + uname); + return -EINVAL; + } + align = dt_mem_next_cell(dt_root_addr_cells, prop); + } + + prop = of_get_flat_dt_prop(node, alloc-ranges, len); + if (prop) { + + if (len % t_len != 0) { + pr_err(Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n, + uname); + return -EINVAL; + } + + base = 0; + + while (len 0) { + start = dt_mem_next_cell(dt_root_addr_cells, prop); + end = start + dt_mem_next_cell(dt_root_size_cells, + prop); + + ret = early_init_dt_alloc_reserved_memory_arch(size, + align, start, end, nomap, base); + if (ret == 0) { + pr_debug(Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n
[PATCH v5 08/11] drivers: dma-contiguous: add initialization from device tree
Refactor internal dma_contiguous_init_reserved_mem() function, which creates CMA area from previously reserved memory region and add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-contiguous.c | 130 ++--- 1 file changed, 108 insertions(+), 22 deletions(-) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 165c2c299e57..5dfcc3743d9b 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -182,6 +182,49 @@ static int __init cma_init_reserved_areas(void) core_initcall(cma_init_reserved_areas); /** + * dma_contiguous_init_reserved_mem() - 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 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. + */ +static int __init dma_contiguous_init_reserved_mem(phys_addr_t size, + phys_addr_t base, struct cma **res_cma) +{ + struct cma *cma = cma_areas[cma_area_count]; + phys_addr_t alignment; + + /* Sanity checks */ + if (cma_area_count == ARRAY_SIZE(cma_areas)) { + pr_err(Not enough slots for CMA reserved regions!\n); + return -ENOSPC; + } + + if (!size || !memblock_is_region_reserved(base, size)) + return -EINVAL; + + /* Sanitise input arguments */ + alignment = PAGE_SIZE max(MAX_ORDER - 1, pageblock_order); + if (ALIGN(base, alignment) != base || ALIGN(size, alignment) != size) + return -EINVAL; + + cma-base_pfn = PFN_DOWN(base); + cma-count = size PAGE_SHIFT; + *res_cma = cma; + cma_area_count++; + + /* Architecture specific contiguous memory fixup. */ + dma_contiguous_early_fixup(base, size); + return 0; +} + +/** * 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 @@ -197,7 +240,6 @@ core_initcall(cma_init_reserved_areas); int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, phys_addr_t limit, struct cma **res_cma) { - struct cma *cma = cma_areas[cma_area_count]; phys_addr_t alignment; int ret = 0; @@ -205,12 +247,6 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, (unsigned long)size, (unsigned long)base, (unsigned long)limit); - /* Sanity checks */ - if (cma_area_count == ARRAY_SIZE(cma_areas)) { - pr_err(Not enough slots for CMA reserved regions!\n); - return -ENOSPC; - } - if (!size) return -EINVAL; @@ -241,21 +277,12 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, } } - /* -* Each reserved area must be initialised later, when more kernel -* subsystems (like slab allocator) are available. -*/ - 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); - - /* Architecture specific contiguous memory fixup. */ - dma_contiguous_early_fixup(base, size); - return 0; + ret = dma_contiguous_init_reserved_mem(size, base, res_cma); + if (ret == 0) { + pr_info(CMA: reserved %ld MiB at %08lx\n, + (unsigned long)size / SZ_1M, (unsigned long)base); + return 0; + } err: pr_err(CMA: failed to reserve %ld MiB\n, (unsigned long)size / SZ_1M); return ret; @@ -357,3 +384,62 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages, return true; } + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +#undef pr_fmt +#define pr_fmt(fmt) fmt + +static void rmem_cma_device_init(struct reserved_mem *rmem, +struct device *dev, struct of_phandle_args *args) +{ + struct cma *cma = rmem-priv; + dev_set_cma_area(dev, cma
[PATCH v5 11/11] powerpc: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/powerpc/Kconfig |1 + arch/powerpc/kernel/prom.c |3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 957bf344c0f5..3b6617fed8fc 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -90,6 +90,7 @@ config PPC select BINFMT_ELF select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f58c0d3aaeb4..591986215801 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -33,6 +33,7 @@ #include linux/irq.h #include linux/memblock.h #include linux/of.h +#include linux/of_fdt.h #include asm/prom.h #include asm/rtas.h @@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void) memblock_reserve(base, size); } } + + early_init_fdt_scan_reserved_mem(); } static void __init early_reserve_mem(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 09/11] arm: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm/Kconfig |1 + arch/arm/mm/init.c |2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..d0262bea8020 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1918,6 +1918,7 @@ config USE_OF select IRQ_DOMAIN select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM help Include support for flattened device tree machine descriptions. diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 804d61566a53..2a77ba8796ae 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -323,6 +323,8 @@ void __init arm_memblock_init(struct meminfo *mi, if (mdesc-reserve) mdesc-reserve(); + early_init_fdt_scan_reserved_mem(); + /* * reserve memory for DMA contigouos allocations, * must come from DMA area inside low memory -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 10/11] arm64: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm64/Kconfig |1 + arch/arm64/mm/init.c |1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 27bbcfc7202a..6abf15407dca 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -43,6 +43,7 @@ config ARM64 select NO_BOOTMEM select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM select PERF_USE_VMALLOC select POWER_RESET select POWER_SUPPLY diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index d0b4c2efda90..3fb8d50dfdaa 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -160,6 +160,7 @@ void __init arm64_memblock_init(void) memblock_reserve(base, size); } + early_init_fdt_scan_reserved_mem(); dma_contiguous_reserve(0); memblock_allow_resize(); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 05/11] drivers: of: add automated assignment of reserved regions to client devices
This patch adds code for automated assignment of reserved memory regions to struct device. reserved_mem-ops-device_init()/device_cleanup() callbacks are called to perform reserved memory driver specific initialization and cleanup. The code looks for 'memory-region' property in the client device node and assigns region pointed by the found phandle. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/of_reserved_mem.c| 74 +++ include/linux/of_reserved_mem.h |7 2 files changed, 81 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 97de6f882f85..b02a7f0a54c8 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -206,8 +206,16 @@ void __init fdt_init_reserved_mem(void) for (i = 0; i reserved_mem_count; i++) { struct reserved_mem *rmem = reserved_mem[i]; unsigned long node = rmem-fdt_node; + unsigned long len; + __be32 *prop; int err = 0; + prop = of_get_flat_dt_prop(node, phandle, len); + if (!prop) + prop = of_get_flat_dt_prop(node, linux,phandle, len); + if (prop) + rmem-phandle = of_read_number(prop, len/4); + if (rmem-size == 0) err = __reserved_mem_alloc_size(node, rmem-name, rmem-base, rmem-size); @@ -215,3 +223,69 @@ void __init fdt_init_reserved_mem(void) __reserved_mem_init_node(rmem); } } + +static inline struct reserved_mem *__find_rmem(struct device_node *node) +{ + unsigned int i; + + if (!node-phandle) + return NULL; + + for (i = 0; i reserved_mem_count; i++) + if (reserved_mem[i].phandle == node-phandle) + 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 device_node *np = dev-of_node; + struct reserved_mem *rmem; + struct of_phandle_args s; + unsigned int i; + + for (i = 0; of_parse_phandle_with_args(np, memory-region, + #memory-region-cells, i, s) == 0; i++) { + + rmem = __find_rmem(s.np); + if (!rmem || !rmem-ops || !rmem-ops-device_init) { + of_node_put(s.np); + continue; + } + + rmem-ops-device_init(rmem, dev, s); + dev_info(dev, assigned reserved memory node %s\n, rmem-name); + of_node_put(s.np); + break; + } +} + +/** + * 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 device_node *np = dev-of_node; + struct reserved_mem *rmem; + struct of_phandle_args s; + unsigned int i; + + for (i = 0; of_parse_phandle_with_args(np, memory-region, + #memory-region-cells, i, s) == 0; i++) { + + rmem = __find_rmem(s.np); + if (rmem rmem-ops rmem-ops-device_release) + rmem-ops-device_release(rmem, dev); + + of_node_put(s.np); + } +} diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index f707176619a3..a2a25de297de 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -8,6 +8,7 @@ struct reserved_mem_ops; struct reserved_mem { const char *name; unsigned long fdt_node; + unsigned long phandle; const struct reserved_mem_ops *ops; phys_addr_t base; phys_addr_t size; @@ -26,6 +27,9 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem, unsigned long node, const char *uname); #ifdef CONFIG_OF_RESERVED_MEM +void of_reserved_mem_device_init(struct device *dev); +void of_reserved_mem_device_release(struct device *dev); + void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); @@ -38,6 +42,9 @@ void fdt_reserved_mem_save_node(unsigned long node, const char *uname, init : init } #else +static inline void of_reserved_mem_device_init
[PATCH v5 06/11] drivers: of: initialize and assign reserved memory to newly created devices
Use recently introduced of_reserved_mem_device_init() function to automatically assign respective reserved memory region to the newly created platform and amba device. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/platform.c |7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 404d1daebefa..3df0b1826e8b 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[] = { @@ -220,6 +221,8 @@ static 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 @@ -227,6 +230,7 @@ static 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; } @@ -282,6 +286,8 @@ static struct amba_device *of_amba_device_create(struct device_node *node, else of_device_make_bus_id(dev-dev); + of_reserved_mem_device_init(dev-dev); + /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, arm,primecell-periphid, NULL); if (prop) @@ -308,6 +314,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node, return dev; err_free: + of_reserved_mem_device_release(dev-dev); amba_device_put(dev); return NULL; } -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 01/11] of: document bindings for reserved-memory nodes
From: Grant Likely grant.lik...@linaro.org Reserved memory nodes allow for the reservation of static (fixed address) regions, or dynamically allocated regions for a specific purpose. Signed-off-by: Grant Likely grant.lik...@linaro.org [joshc: Based on binding document proposed (in non-patch form) here: http://lkml.kernel.org/g/20131030134702.19b57c40...@trevor.secretlab.ca adapted to support #memory-region-cells] Signed-off-by: Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- .../bindings/reserved-memory/reserved-memory.txt | 138 1 file changed, 138 insertions(+) create mode 100644 Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt new file mode 100644 index ..a606ce90c9c4 --- /dev/null +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -0,0 +1,138 @@ +*** Reserved memory regions *** + +Reserved memory is specified as a node under the /reserved-memory node. +The operating system shall exclude reserved memory from normal usage +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. + +Parameters for each memory region can be encoded into the device tree +with the following nodes: + +/reserved-memory node +- +#address-cells, #size-cells (required) - standard definition +- Should use the same values as the root node +#memory-region-cells (required) - dictates number of cells used in the child + nodes memory-region specifier +ranges (required) - standard definition +- Should be empty + +/reserved-memory/ child nodes +- +Each child of the reserved-memory node specifies one or more regions of +reserved memory. Each child node may either use a 'reg' property to +specify a specific range of reserved memory, or a 'size' property with +optional constraints to request a dynamically allocated block of memory. + +Following the generic-names recommended practice, node names should +reflect the purpose of the node (ie. framebuffer or dma-pool). Unit +address (@address) should be appended to the name if the node is a +static allocation. + +Properties: +Requires either a) or b) below. +a) static allocation + reg (required) - standard definition +b) dynamic allocation + size (required) - length based on parent's #size-cells + - Size in bytes of memory to reserve. + alignment (optional) - length based on parent's #size-cells +- Address boundary for alignment of allocation. + alloc-ranges (optional) - prop-encoded-array (address, length pairs). + - Specifies regions of memory that are + acceptable to allocate from. + +If both reg and size are present, then the reg property takes precedence +and size is ignored. + +Additional properties: +compatible (optional) - standard definition +- may contain the following strings: +- shared-dma-pool: This indicates a region of memory meant to be + used as a shared pool of DMA buffers for a set of devices. It can + be used by an operating system to instanciate the necessary pool + management subsystem if necessary. +- vendor specific string in the form vendor,[device-]usage +no-map (optional) - empty property +- Indicates the operating system must not create a virtual mapping + of the region as part of its standard mapping of system memory, + nor permit speculative access to it under any circumstances other + than under the control of the device driver using the region. +reusable (optional) - empty property +- The operating system can use the memory in this region with the + limitation that the device driver(s) owning the region need to be + able to reclaim it back. Typically that means that the operating + system can use that region to store volatile or cached data that + can be otherwise regenerated or migrated elsewhere. + +Linux implementation note: +- If a linux,cma-default property is present, then Linux will use the + region for the default pool of the contiguous memory allocator. + +Device node references to reserved memory +- +Regions in the /reserved-memory node may be referenced by other device +nodes by adding a memory-region property to the device node. + +memory-region (optional) - phandle, specifier pairs to children of /reserved-memory + +Example +--- +This example defines 3 contiguous regions are defined for Linux kernel: +one default of all device drivers (named linux,cma@7200 and 64MiB in size), +one dedicated
[PATCH v5 07/11] drivers: dma-coherent: add initialization from device tree
Add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-coherent.c | 41 + 1 file changed, 41 insertions(+) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index bc256b641027..2343ba5d6d43 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -218,3 +218,44 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, return 0; } EXPORT_SYMBOL(dma_mmap_from_coherent); + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +static void rmem_dma_device_init(struct reserved_mem *rmem, + struct device *dev, struct of_phandle_args *args) +{ + dma_declare_coherent_memory(dev, rmem-base, rmem-base, + rmem-size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); +} + +static void rmem_dma_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dma_release_declared_memory(dev); +} + +static const struct reserved_mem_ops rmem_dma_ops = { + .device_init= rmem_dma_device_init, + .device_release = rmem_dma_device_release, +}; + +static int __init rmem_dma_setup(struct reserved_mem *rmem, +unsigned long node, +const char *uname) +{ + if (of_get_flat_dt_prop(node, reusable, NULL)) + return -EINVAL; + + rmem-ops = rmem_dma_ops; + pr_info(Reserved memory: created DMA memory pool at %pa, size %ld MiB\n, + rmem-base, (unsigned long)rmem-size / SZ_1M); + return 0; +} +RESERVEDMEM_OF_DECLARE(dma, shared-dma-pool, rmem_dma_setup); +#endif -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 03/11] drivers: of: add initialization code for dynamic reserved memory
This patch adds support for dynamically allocated reserved memory regions declared in device tree. Such regions are defined by 'size', 'alignment' and 'alloc-ranges' properties. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/Kconfig |6 ++ drivers/of/Makefile |1 + drivers/of/fdt.c| 13 ++- drivers/of/of_reserved_mem.c| 188 +++ include/linux/of_reserved_mem.h | 21 + 5 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 drivers/of/of_reserved_mem.c create mode 100644 include/linux/of_reserved_mem.h diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index c6973f101a3e..30a7d87a8077 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -75,4 +75,10 @@ config OF_MTD depends on MTD def_bool y +config OF_RESERVED_MEM + depends on OF_EARLY_FLATTREE + bool + help + Helpers to allow for reservation of memory regions + endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index efd05102c405..ed9660adad77 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -9,3 +9,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/fdt.c b/drivers/of/fdt.c index 12809e20ef71..eafe5805257a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,7 @@ #include linux/module.h #include linux/of.h #include linux/of_fdt.h +#include linux/of_reserved_mem.h #include linux/string.h #include linux/errno.h #include linux/slab.h @@ -449,7 +450,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, phys_addr_t base, size; unsigned long len; __be32 *prop; - int nomap; + int nomap, first = 1; prop = of_get_flat_dt_prop(node, reg, len); if (!prop) @@ -476,6 +477,10 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, uname, base, (unsigned long)size / SZ_1M); len -= t_len; + if (first) { + fdt_reserved_mem_save_node(node, uname, base, size); + first = 0; + } } return 0; } @@ -506,6 +511,7 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, { static int found; const char *status; + int err; if (!found depth == 1 strcmp(uname, reserved-memory) == 0) { if (__reserved_mem_check_root(node) != 0) { @@ -528,7 +534,9 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, if (status strcmp(status, okay) != 0 strcmp(status, ok) != 0) return 0; - __reserved_mem_reserve_reg(node, uname); + err = __reserved_mem_reserve_reg(node, uname); + if (err == -ENOENT of_get_flat_dt_prop(node, size, NULL)) + fdt_reserved_mem_save_node(node, uname, 0, 0); /* scan next node */ return 0; @@ -544,6 +552,7 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, void __init early_init_fdt_scan_reserved_mem(void) { of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); + fdt_init_reserved_mem(); } /** diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c new file mode 100644 index ..c7ca6a4a42d1 --- /dev/null +++ b/drivers/of/of_reserved_mem.c @@ -0,0 +1,188 @@ +/* + * Device tree based initialization code for reserved memory. + * + * Copyright (c) 2013, The Linux Foundation. All Rights Reserved. + * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Author: Marek Szyprowski m.szyprow...@samsung.com + * Author: Josh Cartwright jo...@codeaurora.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License or (at your optional) any later version of the license. + */ + +#include 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/of_reserved_mem.h + +#define MAX_RESERVED_REGIONS 16 +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; +static int reserved_mem_count; + +#if defined(CONFIG_HAVE_MEMBLOCK) +#include linux/memblock.h +int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, + phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap, + phys_addr_t *res_base) +{ + /* +* We use __memblock_alloc_base() because memblock_alloc_base
[PATCH v5 04/11] drivers: of: add support for custom reserved memory drivers
Add support for custom reserved memory drivers. Call their init() function for each reserved region and prepare for using operations provided by them with by the reserved_mem-ops array. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/of_reserved_mem.c | 29 + include/asm-generic/vmlinux.lds.h | 11 +++ include/linux/of_reserved_mem.h | 33 + 3 files changed, 73 insertions(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index c7ca6a4a42d1..97de6f882f85 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -170,6 +170,33 @@ static int __init __reserved_mem_alloc_size(unsigned long node, return 0; } +static const struct of_device_id __rmem_of_table_sentinel + __used __section(__reservedmem_of_table_end); + +/** + * res_mem_init_node() - call region specific reserved memory init code + */ +static int __init __reserved_mem_init_node(struct reserved_mem *rmem) +{ + extern const struct of_device_id __reservedmem_of_table[]; + const struct of_device_id *i; + + for (i = __reservedmem_of_table; i __rmem_of_table_sentinel; i++) { + reservedmem_of_init_fn initfn = i-data; + const char *compat = i-compatible; + + if (!of_flat_dt_is_compatible(rmem-fdt_node, compat)) + continue; + + if (initfn(rmem, rmem-fdt_node, rmem-name) == 0) { + pr_info(Reserved memory: initialized node %s, compatible id %s\n, + rmem-name, compat); + return 0; + } + } + return -ENOENT; +} + /** * fdt_init_reserved_mem - allocate and init all saved reserved memory regions */ @@ -184,5 +211,7 @@ void __init fdt_init_reserved_mem(void) if (rmem-size == 0) err = __reserved_mem_alloc_size(node, rmem-name, rmem-base, rmem-size); + if (err == 0) + __reserved_mem_init_node(rmem); } } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index bc2121fa9132..f10f64fcc815 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -167,6 +167,16 @@ #define CLK_OF_TABLES() #endif +#ifdef CONFIG_OF_RESERVED_MEM +#define RESERVEDMEM_OF_TABLES()\ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__reservedmem_of_table) = .; \ + *(__reservedmem_of_table) \ + *(__reservedmem_of_table_end) +#else +#define RESERVEDMEM_OF_TABLES() +#endif + #define KERNEL_DTB() \ STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__dtb_start) = .;\ @@ -490,6 +500,7 @@ TRACE_SYSCALLS()\ MEM_DISCARD(init.rodata)\ CLK_OF_TABLES() \ + RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ KERNEL_DTB()\ IRQCHIP_OF_MATCH_TABLE() diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 89226ed7d954..f707176619a3 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -1,21 +1,54 @@ #ifndef __OF_RESERVED_MEM_H #define __OF_RESERVED_MEM_H +struct device; +struct of_phandle_args; +struct reserved_mem_ops; + struct reserved_mem { const char *name; unsigned long fdt_node; + const struct reserved_mem_ops *ops; phys_addr_t base; phys_addr_t size; + void*priv; +}; + +struct reserved_mem_ops { + void(*device_init)(struct reserved_mem *rmem, + struct device *dev, + struct of_phandle_args *args); + void(*device_release)(struct reserved_mem *rmem, + struct device *dev); }; +typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem, + unsigned long node, const char *uname); + #ifdef CONFIG_OF_RESERVED_MEM void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); + +#define RESERVEDMEM_OF_DECLARE(name, compat, init
[PATCH v5 02/11] drivers: of: add initialization code for static reserved memory
This patch adds support for static (defined by 'reg' property) reserved memory regions declared in device tree. 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). Typically, all this happens before device tree structures are unflattened, so we need to get reserved memory layout directly from fdt. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/of/fdt.c | 125 include/linux/of_fdt.h |3 ++ 2 files changed, 128 insertions(+) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 758b4f8b30b7..12809e20ef71 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -440,6 +440,113 @@ struct boot_param_header *initial_boot_params; #ifdef CONFIG_OF_EARLY_FLATTREE /** + * res_mem_reserve_reg() - reserve all memory described in 'reg' property + */ +static int __init __reserved_mem_reserve_reg(unsigned long node, +const char *uname) +{ + int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); + phys_addr_t base, size; + unsigned long len; + __be32 *prop; + int nomap; + + prop = of_get_flat_dt_prop(node, reg, len); + if (!prop) + return -ENOENT; + + if (len len % t_len != 0) { + pr_err(Reserved memory: invalid reg property in '%s', skipping node.\n, + uname); + return -EINVAL; + } + + nomap = of_get_flat_dt_prop(node, no-map, NULL) != NULL; + + while (len 0) { + base = dt_mem_next_cell(dt_root_addr_cells, prop); + size = dt_mem_next_cell(dt_root_size_cells, prop); + + if (base size + early_init_dt_reserve_memory_arch(base, size, nomap) == 0) + pr_debug(Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n, + uname, base, (unsigned long)size / SZ_1M); + else + pr_info(Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n, + uname, base, (unsigned long)size / SZ_1M); + + len -= t_len; + } + return 0; +} + +static int __reserved_mem_check_root(unsigned long node) +{ + __be32 *prop; + + prop = of_get_flat_dt_prop(node, #size-cells, NULL); + if (prop be32_to_cpup(prop) != dt_root_size_cells) + return -EINVAL; + + prop = of_get_flat_dt_prop(node, #address-cells, NULL); + if (prop be32_to_cpup(prop) != dt_root_addr_cells) + return -EINVAL; + + prop = of_get_flat_dt_prop(node, ranges, NULL); + if (!prop) + return -EINVAL; + return 0; +} + +/** + * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory + */ +static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, + int depth, void *data) +{ + static int found; + const char *status; + + if (!found depth == 1 strcmp(uname, reserved-memory) == 0) { + if (__reserved_mem_check_root(node) != 0) { + pr_err(Reserved memory: unsupported node format, ignoring\n); + /* break scan */ + return 1; + } + found = 1; + /* scan next node */ + return 0; + } else if (!found) { + /* scan next node */ + return 0; + } else if (found depth 2) { + /* scanning of /reserved-memory has been finished */ + return 1; + } + + status = of_get_flat_dt_prop(node, status, NULL); + if (status strcmp(status, okay) != 0 strcmp(status, ok) != 0) + return 0; + + __reserved_mem_reserve_reg(node, uname); + + /* scan next node */ + return 0; +} + +/** + * early_init_fdt_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 (i.e. memblock) has been fully activated. + */ +void __init early_init_fdt_scan_reserved_mem(void) +{ + of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); +} + +/** * of_scan_flat_dt - scan flattened tree blob and call callback on each. * @it: callback function * @data: context data pointer @@ -856,6 +963,16 @@ void __init __weak
[PATCH v4 0/7] reserved-memory regions/CMA in devicetree, again
Hi all! This is another quick update of the patches which add basic support for dynamic allocation of memory reserved regions defined in device tree. This time I hope I've really managed to address all the issues reported by Grant Likely, see the change log for more details. As a bonus, I've added support for ARM64 and PowerPC, as those architectures had quite well defined place where early memory reservation can be done. The initial code for this feature were posted here [1], merged as commit 9d8eab7af79cb4ce2de5de39f82c455b1f796963 (drivers: of: add initialization code for dma reserved memory) and later reverted by commit 1931ee143b0ab72924944bc06e363d837ba05063. For more information, see [2]. Finally a new bindings has been proposed [3] and Josh Cartwright a few days ago prepared some code which implements those bindings [4]. This finally pushed me again to find some time to finish this task and review the code. Josh agreed to give me the ownership of this series to continue preparing them for mainline inclusion. For more information please refer to the changlelog below. [1]: http://lkml.kernel.org/g/1377527959-5080-1-git-send-email-m.szyprow...@samsung.com [2]: http://lkml.kernel.org/g/1381476448-14548-1-git-send-email-m.szyprow...@samsung.com [3]: http://lkml.kernel.org/g/20131030134702.19b57c40...@trevor.secretlab.ca [4]: http://thread.gmane.org/gmane.linux.documentation/19579 Changelog: v4: - dynamic allocations are processed after all static reservations has been done - moved code for handling static reservations to drivers/of/fdt.c - removed node matching by string comparison, now phandle values are used directly - moved code for DMA and CMA handling directly to drivers/base/dma-{coherent,contiguous}.c - added checks for proper #size-cells, #address-cells, ranges properties in /reserved-memory node - even more code cleanup - added init code for ARM64 and PowerPC v3: http://article.gmane.org/gmane.linux.documentation/20169/ - refactored memory reservation code, created common code to parse reg, size, align, alloc-ranges properties - added support for multiple tuples in 'reg' property - memory is reserved regardless of presence of the driver for its compatible - prepared arch specific hooks for memory reservation (defaults use memblock calls) - removed node matching by string during device initialization - CMA init code: added checks for required region alignment - more code cleanup here and there v2: http://thread.gmane.org/gmane.linux.documentation/19870/ - removed copying of the node name - split shared-dma-pool handling into separate files (one for CMA and one for dma_declare_coherent based implementations) for making the code easier to understand - added support for AMBA devices, changed prototypes to use struct decice instead of struct platform_device - renamed some functions to better match other names used in drivers/of/ - restructured the rest of the code a bit for better readability - added 'reusable' property to exmaple linux,cma node in documentation - exclusive dma (dma_coherent) is used for only handling 'shared-dma-pool' regions without 'reusable' property and CMA is used only for handling 'shared-dma-pool' regions with 'reusable' property. v1: http://thread.gmane.org/gmane.linux.documentation/19579 - initial version prepared by Josh Cartwright Summary: Grant Likely (1): of: document bindings for reserved-memory nodes Marek Szyprowski (6): drivers: of: add initialization code for reserved memory drivers: dma-coherent: add initialization from device tree drivers: dma-contiguous: add initialization from device tree arm: add support for reserved memory defined by device tree arm64: add support for reserved memory defined by device tree powerpc: add support for reserved memory defined by device tree .../bindings/reserved-memory/reserved-memory.txt | 138 + arch/arm/Kconfig |1 + arch/arm/mm/init.c |3 + arch/arm64/Kconfig |1 + arch/arm64/mm/init.c |2 + arch/powerpc/Kconfig |1 + arch/powerpc/kernel/prom.c |3 + drivers/base/dma-coherent.c| 41 +++ drivers/base/dma-contiguous.c | 130 +++-- drivers/of/Kconfig |6 + drivers/of/Makefile|1 + drivers/of/fdt.c | 145 ++ drivers/of/of_reserved_mem.c | 296 drivers/of/platform.c |7 + include/asm-generic/vmlinux.lds.h | 11 + include/linux/of_reserved_mem.h| 65 + 16 files changed, 829 insertions(+), 22 deletions(-) create mode 100644 Documentation/devicetree/bindings/reserved-memory/reserved
[PATCH v4 7/7] powerpc: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/powerpc/Kconfig |1 + arch/powerpc/kernel/prom.c |3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 957bf344c0f5..3b6617fed8fc 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -90,6 +90,7 @@ config PPC select BINFMT_ELF select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f58c0d3aaeb4..b814262a2048 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -33,6 +33,7 @@ #include linux/irq.h #include linux/memblock.h #include linux/of.h +#include linux/of_reserved_mem.h #include asm/prom.h #include asm/rtas.h @@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void) memblock_reserve(base, size); } } + + early_init_fdt_scan_reserved_mem(); } static void __init early_reserve_mem(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 6/7] arm64: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm64/Kconfig |1 + arch/arm64/mm/init.c |2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 27bbcfc7202a..6abf15407dca 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -43,6 +43,7 @@ config ARM64 select NO_BOOTMEM select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM select PERF_USE_VMALLOC select POWER_RESET select POWER_SUPPLY diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index d0b4c2efda90..447550d6bd9b 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -30,6 +30,7 @@ #include linux/memblock.h #include linux/sort.h #include linux/of_fdt.h +#include linux/of_reserved_mem.h #include linux/dma-contiguous.h #include asm/sections.h @@ -160,6 +161,7 @@ void __init arm64_memblock_init(void) memblock_reserve(base, size); } + early_init_fdt_scan_reserved_mem(); dma_contiguous_reserve(0); memblock_allow_resize(); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 3/7] drivers: dma-contiguous: add initialization from device tree
Refactor internal dma_contiguous_init_reserved_mem() function, which creates CMA area from previously reserved memory region and add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-contiguous.c | 130 ++--- 1 file changed, 108 insertions(+), 22 deletions(-) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 165c2c299e57..5dfcc3743d9b 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -182,6 +182,49 @@ static int __init cma_init_reserved_areas(void) core_initcall(cma_init_reserved_areas); /** + * dma_contiguous_init_reserved_mem() - 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 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. + */ +static int __init dma_contiguous_init_reserved_mem(phys_addr_t size, + phys_addr_t base, struct cma **res_cma) +{ + struct cma *cma = cma_areas[cma_area_count]; + phys_addr_t alignment; + + /* Sanity checks */ + if (cma_area_count == ARRAY_SIZE(cma_areas)) { + pr_err(Not enough slots for CMA reserved regions!\n); + return -ENOSPC; + } + + if (!size || !memblock_is_region_reserved(base, size)) + return -EINVAL; + + /* Sanitise input arguments */ + alignment = PAGE_SIZE max(MAX_ORDER - 1, pageblock_order); + if (ALIGN(base, alignment) != base || ALIGN(size, alignment) != size) + return -EINVAL; + + cma-base_pfn = PFN_DOWN(base); + cma-count = size PAGE_SHIFT; + *res_cma = cma; + cma_area_count++; + + /* Architecture specific contiguous memory fixup. */ + dma_contiguous_early_fixup(base, size); + return 0; +} + +/** * 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 @@ -197,7 +240,6 @@ core_initcall(cma_init_reserved_areas); int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, phys_addr_t limit, struct cma **res_cma) { - struct cma *cma = cma_areas[cma_area_count]; phys_addr_t alignment; int ret = 0; @@ -205,12 +247,6 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, (unsigned long)size, (unsigned long)base, (unsigned long)limit); - /* Sanity checks */ - if (cma_area_count == ARRAY_SIZE(cma_areas)) { - pr_err(Not enough slots for CMA reserved regions!\n); - return -ENOSPC; - } - if (!size) return -EINVAL; @@ -241,21 +277,12 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, } } - /* -* Each reserved area must be initialised later, when more kernel -* subsystems (like slab allocator) are available. -*/ - 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); - - /* Architecture specific contiguous memory fixup. */ - dma_contiguous_early_fixup(base, size); - return 0; + ret = dma_contiguous_init_reserved_mem(size, base, res_cma); + if (ret == 0) { + pr_info(CMA: reserved %ld MiB at %08lx\n, + (unsigned long)size / SZ_1M, (unsigned long)base); + return 0; + } err: pr_err(CMA: failed to reserve %ld MiB\n, (unsigned long)size / SZ_1M); return ret; @@ -357,3 +384,62 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages, return true; } + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +#undef pr_fmt +#define pr_fmt(fmt) fmt + +static void rmem_cma_device_init(struct reserved_mem *rmem, +struct device *dev, struct of_phandle_args *args) +{ + struct cma *cma = rmem-priv; + dev_set_cma_area(dev, cma
[PATCH v4 2/7] drivers: dma-coherent: add initialization from device tree
Add support for handling 'shared-dma-pool' reserved-memory device tree nodes. Based on previous code provided by Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- drivers/base/dma-coherent.c | 41 + 1 file changed, 41 insertions(+) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index bc256b641027..2343ba5d6d43 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -218,3 +218,44 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, return 0; } EXPORT_SYMBOL(dma_mmap_from_coherent); + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include linux/of.h +#include linux/of_fdt.h +#include linux/of_reserved_mem.h + +static void rmem_dma_device_init(struct reserved_mem *rmem, + struct device *dev, struct of_phandle_args *args) +{ + dma_declare_coherent_memory(dev, rmem-base, rmem-base, + rmem-size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); +} + +static void rmem_dma_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dma_release_declared_memory(dev); +} + +static const struct reserved_mem_ops rmem_dma_ops = { + .device_init= rmem_dma_device_init, + .device_release = rmem_dma_device_release, +}; + +static int __init rmem_dma_setup(struct reserved_mem *rmem, +unsigned long node, +const char *uname) +{ + if (of_get_flat_dt_prop(node, reusable, NULL)) + return -EINVAL; + + rmem-ops = rmem_dma_ops; + pr_info(Reserved memory: created DMA memory pool at %pa, size %ld MiB\n, + rmem-base, (unsigned long)rmem-size / SZ_1M); + return 0; +} +RESERVEDMEM_OF_DECLARE(dma, shared-dma-pool, rmem_dma_setup); +#endif -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 5/7] arm: add support for reserved memory defined by device tree
Enable reserved memory initialization from device tree. Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- arch/arm/Kconfig |1 + arch/arm/mm/init.c |3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..d0262bea8020 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1918,6 +1918,7 @@ config USE_OF select IRQ_DOMAIN select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM help Include support for flattened device tree machine descriptions. diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 804d61566a53..eee55d75bbfa 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 @@ -323,6 +324,8 @@ void __init arm_memblock_init(struct meminfo *mi, if (mdesc-reserve) mdesc-reserve(); + early_init_fdt_scan_reserved_mem(); + /* * reserve memory for DMA contigouos allocations, * must come from DMA area inside low memory -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe devicetree in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 4/7] of: document bindings for reserved-memory nodes
From: Grant Likely grant.lik...@linaro.org Reserved memory nodes allow for the reservation of static (fixed address) regions, or dynamically allocated regions for a specific purpose. Signed-off-by: Grant Likely grant.lik...@linaro.org [joshc: Based on binding document proposed (in non-patch form) here: http://lkml.kernel.org/g/20131030134702.19b57c40...@trevor.secretlab.ca adapted to support #memory-region-cells] Signed-off-by: Josh Cartwright jo...@codeaurora.org Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com --- .../bindings/reserved-memory/reserved-memory.txt | 138 1 file changed, 138 insertions(+) create mode 100644 Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt new file mode 100644 index ..a606ce90c9c4 --- /dev/null +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -0,0 +1,138 @@ +*** Reserved memory regions *** + +Reserved memory is specified as a node under the /reserved-memory node. +The operating system shall exclude reserved memory from normal usage +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. + +Parameters for each memory region can be encoded into the device tree +with the following nodes: + +/reserved-memory node +- +#address-cells, #size-cells (required) - standard definition +- Should use the same values as the root node +#memory-region-cells (required) - dictates number of cells used in the child + nodes memory-region specifier +ranges (required) - standard definition +- Should be empty + +/reserved-memory/ child nodes +- +Each child of the reserved-memory node specifies one or more regions of +reserved memory. Each child node may either use a 'reg' property to +specify a specific range of reserved memory, or a 'size' property with +optional constraints to request a dynamically allocated block of memory. + +Following the generic-names recommended practice, node names should +reflect the purpose of the node (ie. framebuffer or dma-pool). Unit +address (@address) should be appended to the name if the node is a +static allocation. + +Properties: +Requires either a) or b) below. +a) static allocation + reg (required) - standard definition +b) dynamic allocation + size (required) - length based on parent's #size-cells + - Size in bytes of memory to reserve. + alignment (optional) - length based on parent's #size-cells +- Address boundary for alignment of allocation. + alloc-ranges (optional) - prop-encoded-array (address, length pairs). + - Specifies regions of memory that are + acceptable to allocate from. + +If both reg and size are present, then the reg property takes precedence +and size is ignored. + +Additional properties: +compatible (optional) - standard definition +- may contain the following strings: +- shared-dma-pool: This indicates a region of memory meant to be + used as a shared pool of DMA buffers for a set of devices. It can + be used by an operating system to instanciate the necessary pool + management subsystem if necessary. +- vendor specific string in the form vendor,[device-]usage +no-map (optional) - empty property +- Indicates the operating system must not create a virtual mapping + of the region as part of its standard mapping of system memory, + nor permit speculative access to it under any circumstances other + than under the control of the device driver using the region. +reusable (optional) - empty property +- The operating system can use the memory in this region with the + limitation that the device driver(s) owning the region need to be + able to reclaim it back. Typically that means that the operating + system can use that region to store volatile or cached data that + can be otherwise regenerated or migrated elsewhere. + +Linux implementation note: +- If a linux,cma-default property is present, then Linux will use the + region for the default pool of the contiguous memory allocator. + +Device node references to reserved memory +- +Regions in the /reserved-memory node may be referenced by other device +nodes by adding a memory-region property to the device node. + +memory-region (optional) - phandle, specifier pairs to children of /reserved-memory + +Example +--- +This example defines 3 contiguous regions are defined for Linux kernel: +one default of all device drivers (named linux,cma@7200 and 64MiB in size), +one dedicated