From patchwork Mon Aug 19 15:04:28 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 19325 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qe0-f72.google.com (mail-qe0-f72.google.com [209.85.128.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 0879E246F8 for ; Mon, 19 Aug 2013 15:05:25 +0000 (UTC) Received: by mail-qe0-f72.google.com with SMTP id b10sf5558109qen.11 for ; Mon, 19 Aug 2013 08:05:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:cc:subject:precedence:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:mime-version :errors-to:sender:x-original-sender :x-original-authentication-results:mailing-list:content-type :content-transfer-encoding; bh=3HBlx7UCeq6qyArthGLK4rj/OostNnXZj1jPxNDyXkY=; b=EwGxEVc8XCYq6RLo3Q89AaN/GidoJjsU4xK8DhC73ufSCUHapML+Q5TGHI6XO/BOKs xfDLtIZjJhrBPsleK8E0BnaAU3bZ4+JJ0cHeCwWMTyFoWqSsZUw7lWEgHmbU07eLB5Ti 1Q3gc7h2O0TB4gpIu2CX4BRdPB0dY48zbWOwpbmdp9b5wtOujw6FaexTJLr59nrGHi8m 33SFIBmbIIoUs1JoZRqxa/04rzwBF/awvjepwBExJavkeUbGsY5N3xLxAAjSghCsl67l ZyWIGQVAGi+nDxMJArI4ZUpFL0smAKJDnwDlXXFkD6idBRQqk2b9xunLF8wm/edoJR4r bHeQ== X-Received: by 10.58.173.40 with SMTP id bh8mr642512vec.32.1376924724880; Mon, 19 Aug 2013 08:05:24 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.59.132 with SMTP id z4ls747110qeq.69.gmail; Mon, 19 Aug 2013 08:05:24 -0700 (PDT) X-Received: by 10.52.94.78 with SMTP id da14mr2118618vdb.28.1376924724740; Mon, 19 Aug 2013 08:05:24 -0700 (PDT) Received: from mail-vc0-f171.google.com (mail-vc0-f171.google.com [209.85.220.171]) by mx.google.com with ESMTPS id ed9si2444744vcb.81.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 19 Aug 2013 08:05:24 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.171; Received: by mail-vc0-f171.google.com with SMTP id ij15so3230360vcb.30 for ; Mon, 19 Aug 2013 08:05:24 -0700 (PDT) X-Gm-Message-State: ALoCoQlwRiTlIUWwXp87e/qN1bIWxHI6NQbF7ZJbv1yR6P2PV9XNloPdOrtyV6oCY0rzjf/QkYWH X-Received: by 10.220.237.208 with SMTP id kp16mr13780733vcb.4.1376924724609; Mon, 19 Aug 2013 08:05:24 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp101197vcz; Mon, 19 Aug 2013 08:05:23 -0700 (PDT) X-Received: by 10.194.176.163 with SMTP id cj3mr9040638wjc.8.1376924722839; Mon, 19 Aug 2013 08:05:22 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id j16si4495321wic.85.1969.12.31.16.00.00 (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 19 Aug 2013 08:05:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linaro-mm-sig-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1VBR0h-0002PK-Hs; Mon, 19 Aug 2013 15:04:47 +0000 Received: from mailout3.samsung.com ([203.254.224.33]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1VBR0f-0002Op-7b for linaro-mm-sig@lists.linaro.org; Mon, 19 Aug 2013 15:04:45 +0000 Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MRS00J409WONIL0@mailout3.samsung.com> for linaro-mm-sig@lists.linaro.org; Tue, 20 Aug 2013 00:05:12 +0900 (KST) X-AuditID: cbfee61a-b7f196d000007dfa-bc-5212342790c7 Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 39.B2.32250.72432125; Tue, 20 Aug 2013 00:05:12 +0900 (KST) Received: from localhost.localdomain ([106.116.147.30]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MRS004QS9VPKP20@mmp2.samsung.com>; Tue, 20 Aug 2013 00:05:11 +0900 (KST) From: Marek Szyprowski To: linux-arm-kernel@lists.infradead.org, linaro-mm-sig@lists.linaro.org, devicetree@vger.kernel.org Date: Mon, 19 Aug 2013 17:04:28 +0200 Message-id: <1376924669-28873-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1376924669-28873-1-git-send-email-m.szyprowski@samsung.com> References: <1376924669-28873-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpjkeLIzCtJLcpLzFFi42I5/e+xoK6GiVCQwbV+Jou/k46xW8w/co7V ov/NQlaLV2c2slm86e1gsTjb9IbdYnvnDHaLL1ceMllsenyN1WLtkbvsFhteHmSyWHr9IpPF guMtrBZ/pstZnLr+mc1iwvS1LBbfv31js/i7fROLxeE37UDjDraxWKyf8ZrFYtWuP4wOYh5r 5q1h9Pj9axKjx+vJExg9Lvf1MnnsnHWX3WPzknqP2/8eM3tcOdHE6rHuzysmj/6/Bh59W1Yx evx8qePxeZOcx8a5oQF8UVw2Kak5mWWpRfp2CVwZnTNaWAq+V1T8XNLE0sB4JKmLkZNDQsBE Yt3nVlYIW0ziwr31bF2MXBxCAtMZJX7d7WKHcNqZJE4+OQxWxSZgKNH1tosNxBYRSJOYsWoD C0gRs8AbVokVl3rYQRLCAmESnbu/MIPYLAKqEldvbgGyOTh4BTwkVn8qAjElBBQk5kyyAang FPCU2NZ5lAnEFgKq2Pf0K+MERt4FjAyrGEVTC5ILipPScw31ihNzi0vz0vWS83M3MYJj55nU DsaVDRaHGAU4GJV4eDuVhIKEWBPLiitzDzFKcDArifB+ZQcK8aYkVlalFuXHF5XmpBYfYpTm YFES5z3Qah0oJJCeWJKanZpakFoEk2Xi4JRqYBQM6mQ3OHJq+o5n86INsjJuB2tpLKhYpvDp xlw/xu7uQJ/AuJ5Nl7d7cLzWuTQt1Vdf4dqiHS+evvhz7NLi7393zLtQ0NpwT+pvZJKt4mL5 ebFWKnHphcrVUaJ/2V+9blGOa/V7pfLl7/+XxyYf1Jq2r3z/z5V6yRENGxrLs3m6uud5365T 1FJiKc5INNRiLipOBABwgRK7mQIAAA== Cc: Mark Rutland , Pawel Moll , Arnd Bergmann , Stephen Warren , Tomasz Figa , Tomasz Figa , Michal Nazarewicz , Grant Likely , Kyungmin Park , Rob Herring , Sylwester Nawrocki , Kumar Gala , Olof Johansson , Ian Campbell , Sascha Hauer Subject: [Linaro-mm-sig] [PATCH v6 3/4] drivers: of: add initialization code for dma reserved memory X-BeenThere: linaro-mm-sig@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: linaro-mm-sig-bounces@lists.linaro.org Sender: linaro-mm-sig-bounces@lists.linaro.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: m.szyprowski@samsung.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 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 Acked-by: Kyungmin Park Acked-by: Michal Nazarewicz Acked-by: Tomasz Figa --- Documentation/devicetree/bindings/memory.txt | 166 ++++++++++++++++++++++++ drivers/of/Kconfig | 6 + drivers/of/Makefile | 1 + drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++ drivers/of/platform.c | 5 + include/linux/of_reserved_mem.h | 14 +++ 6 files changed, 367 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory.txt create mode 100644 drivers/of/of_reserved_mem.c create mode 100644 include/linux/of_reserved_mem.h diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt new file mode 100644 index 0000000..90e96278 --- /dev/null +++ b/Documentation/devicetree/bindings/memory.txt @@ -0,0 +1,166 @@ +*** Memory binding *** + +The /memory node provides basic information about the address and size +of the physical memory. This node is usually filled or updated by the +bootloader, depending on the actual memory configuration of the given +hardware. + +The memory layout is described by the following node: + +/ { + #address-cells = <(n)>; + #size-cells = <(m)>; + memory { + device_type = "memory"; + reg = <(baseaddr1) (size1) + (baseaddr2) (size2) + ... + (baseaddrN) (sizeN)>; + }; + ... +}; + +A memory node follows the typical device tree rules for "reg" property: +n: number of cells used to store base address value +m: number of cells used to store size value +baseaddrX: defines a base address of the defined memory bank +sizeX: the size of the defined memory bank + + +More than one memory bank can be defined. + + +*** Reserved memory regions *** + +In /memory/reserved-memory node one can create additional nodes +describing particular reserved (excluded from normal use) memory +regions. Such memory regions are usually designed for the special usage +by various device drivers. A good example are contiguous memory +allocations or memory sharing with other operating system on the same +hardware board. Those special memory regions might depend on the board +configuration and devices used on the target system. + +Parameters for each memory region can be encoded into the device tree +with the following convention: + +[(label):] (name) { + compatible = "linux,contiguous-memory-region", "reserved-memory-region"; + reg = <(address) (size)>; + (linux,default-contiguous-region); +}; + +compatible: "linux,contiguous-memory-region" - enables binding of this + region to Contiguous Memory Allocator (special region for + contiguous memory allocations, shared with movable system + memory, Linux kernel-specific), alternatively if + "reserved-memory-region" - compatibility is defined, given + region is assigned for exclusive usage for by the respective + devices + +reg: standard property defining the base address and size of + the memory region + +linux,default-contiguous-region: property indicating that the region + is the default region for all contiguous memory + allocations, Linux specific (optional) + +It is optional to specify the base address, so if one wants to use +autoconfiguration of the base address, '0' can be specified as a base +address in the 'reg' property. + +The /memory/reserved-memory node must contain the same #address-cells +and #size-cells value as the root node. + + +*** Device node's properties *** + +Once regions in the /memory/reserved-memory node have been defined, they +can be assigned to device nodes to enable respective device drivers to +access them. The following properties are defined: + +memory-region = <&phandle_to_defined_region>; + +This property indicates that the device driver should use the memory +region pointed by the given phandle. + + +*** Example *** + +This example defines a memory consisting of 4 memory banks. 3 contiguous +regions are defined for Linux kernel, one default of all device drivers +(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the +framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB) +and one for multimedia processing (labelled multimedia_mem, placed at +0x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000 +device for DMA memory allocations (Linux kernel drivers will use CMA is +available or dma-exclusive usage otherwise). 'multimedia_mem' is +assigned to scaler@12500000 and codec@12600000 devices for contiguous +memory allocations when CMA driver is enabled. + +The reason for creating a separate region for framebuffer device is to +match the framebuffer base address to the one configured by bootloader, +so once Linux kernel drivers starts no glitches on the displayed boot +logo appears. Scaller and codec drivers should share the memory +allocations. + +/ { + #address-cells = <1>; + #size-cells = <1>; + + /* ... */ + + memory { + reg = <0x40000000 0x10000000 + 0x50000000 0x10000000 + 0x60000000 0x10000000 + 0x70000000 0x10000000>; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + /* + * global autoconfigured region for contiguous allocations + * (used only with Contiguous Memory Allocator) + */ + contig_region@0 { + compatible = "linux,contiguous-memory-region"; + reg = <0x0 0x4000000>; + linux,default-contiguous-region; + }; + + /* + * special region for framebuffer + */ + display_mem: region@78000000 { + compatible = "linux,contiguous-memory-region", "reserved-memory-region"; + reg = <0x78000000 0x800000>; + }; + + /* + * special region for multimedia processing devices + */ + multimedia_mem: region@77000000 { + compatible = "linux,contiguous-memory-region"; + reg = <0x77000000 0x4000000>; + }; + }; + }; + + /* ... */ + + fb0: fb@12300000 { + status = "okay"; + memory-region = <&display_mem>; + }; + + scaler: scaler@12500000 { + status = "okay"; + memory-region = <&multimedia_mem>; + }; + + codec: codec@12600000 { + status = "okay"; + memory-region = <&multimedia_mem>; + }; +}; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 80e5c13..a83ab43 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -80,4 +80,10 @@ config OF_MTD depends on MTD def_bool y +config OF_RESERVED_MEM + depends on CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK) + def_bool y + help + Initialization code for DMA reserved memory + endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 1f9c0c4..e7e3322 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o obj-$(CONFIG_OF_PCI) += of_pci.o obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o obj-$(CONFIG_OF_MTD) += of_mtd.o +obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c new file mode 100644 index 0000000..95563d33 --- /dev/null +++ b/drivers/of/of_reserved_mem.c @@ -0,0 +1,175 @@ +/* + * Device tree based initialization code for reserved memory. + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Author: Marek Szyprowski + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_RESERVED_REGIONS 16 +struct reserved_mem { + phys_addr_t base; + unsigned long size; + struct cma *cma; + char name[32]; +}; +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; +static int reserved_mem_count; + +static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname, + int depth, void *data) +{ + struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; + phys_addr_t base, size; + int is_cma, is_reserved; + unsigned long len; + const char *status; + __be32 *prop; + + is_cma = IS_ENABLED(CONFIG_CMA) && + of_flat_dt_is_compatible(node, "linux,contiguous-memory-region"); + is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region"); + + if (!is_reserved && !is_cma) { + /* ignore node and scan next one */ + return 0; + } + + status = of_get_flat_dt_prop(node, "status", &len); + if (status && strcmp(status, "okay") != 0) { + /* ignore disabled node nad scan next one */ + return 0; + } + + prop = of_get_flat_dt_prop(node, "reg", &len); + if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) * + sizeof(__be32))) { + pr_err("Reserved mem: node %s, incorrect \"reg\" property\n", + uname); + /* ignore node and scan next one */ + return 0; + } + base = dt_mem_next_cell(dt_root_addr_cells, &prop); + size = dt_mem_next_cell(dt_root_size_cells, &prop); + + if (!size) { + /* ignore node and scan next one */ + return 0; + } + + pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n", + uname, (unsigned long)base, (unsigned long)size / SZ_1M); + + if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) + return -ENOSPC; + + rmem->base = base; + rmem->size = size; + strlcpy(rmem->name, uname, sizeof(rmem->name)); + + if (is_cma) { + struct cma *cma; + if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) { + rmem->cma = cma; + reserved_mem_count++; + if (of_get_flat_dt_prop(node, + "linux,default-contiguous-region", + NULL)) + dma_contiguous_default_area = cma; + } + } else if (is_reserved) { + if (memblock_remove(base, size) == 0) + reserved_mem_count++; + else + pr_err("Failed to reserve memory for %s\n", uname); + } + + return 0; +} + +static struct reserved_mem *get_dma_memory_region(struct device *dev) +{ + struct device_node *node; + const char *name; + int i; + + node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!node) + return NULL; + + name = kbasename(node->full_name); + for (i = 0; i < reserved_mem_count; i++) + if (strcmp(name, reserved_mem[i].name) == 0) + return &reserved_mem[i]; + return NULL; +} + +/** + * of_reserved_mem_device_init() - assign reserved memory region to given device + * + * This function assign memory region pointed by "memory-region" device tree + * property to the given device. + */ +void of_reserved_mem_device_init(struct device *dev) +{ + struct reserved_mem *region = get_dma_memory_region(dev); + if (!region) + return; + + if (region->cma) { + dev_set_cma_area(dev, region->cma); + pr_info("Assigned CMA %s to %s device\n", region->name, + dev_name(dev)); + } else { + if (dma_declare_coherent_memory(dev, region->base, region->base, + region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0) + pr_info("Declared reserved memory %s to %s device\n", + region->name, dev_name(dev)); + } +} + +/** + * of_reserved_mem_device_release() - release reserved memory device structures + * + * This function releases structures allocated for memory region handling for + * the given device. + */ +void of_reserved_mem_device_release(struct device *dev) +{ + struct reserved_mem *region = get_dma_memory_region(dev); + if (!region && !region->cma) + dma_release_declared_memory(dev); +} + +/** + * early_init_dt_scan_reserved_mem() - create reserved memory regions + * + * This function grabs memory from early allocator for device exclusive use + * defined in device tree structures. It should be called by arch specific code + * once the early allocator (memblock) has been activated and all other + * subsystems have already allocated/reserved memory. + */ +void __init early_init_dt_scan_reserved_mem(void) +{ + of_scan_flat_dt_by_path("/memory/reserved-memory", + fdt_scan_reserved_mem, NULL); +} diff --git a/drivers/of/platform.c b/drivers/of/platform.c index e0a6514..1e4e91d 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -21,6 +21,7 @@ #include #include #include +#include #include const struct of_device_id of_default_bus_match_table[] = { @@ -196,6 +197,7 @@ EXPORT_SYMBOL(of_device_alloc); * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ + struct platform_device *of_platform_device_create_pdata( struct device_node *np, const char *bus_id, @@ -218,6 +220,8 @@ struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; + of_reserved_mem_device_init(&dev->dev); + /* We do not fill the DMA ops for platform devices by default. * This is currently the responsibility of the platform code * to do such, possibly using a device notifier @@ -225,6 +229,7 @@ struct platform_device *of_platform_device_create_pdata( if (of_device_add(dev) != 0) { platform_device_put(dev); + of_reserved_mem_device_release(&dev->dev); return NULL; } diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h new file mode 100644 index 0000000..c841282 --- /dev/null +++ b/include/linux/of_reserved_mem.h @@ -0,0 +1,14 @@ +#ifndef __OF_RESERVED_MEM_H +#define __OF_RESERVED_MEM_H + +#ifdef CONFIG_OF_RESERVED_MEM +void of_reserved_mem_device_init(struct device *dev); +void of_reserved_mem_device_release(struct device *dev); +void early_init_dt_scan_reserved_mem(void); +#else +static inline void of_reserved_mem_device_init(struct device *dev) { } +static inline void of_reserved_mem_device_release(struct device *dev) { } +static inline void early_init_dt_scan_reserved_mem(void) { } +#endif + +#endif /* __OF_RESERVED_MEM_H */