diff options
Diffstat (limited to 'target/linux/ipq806x/patches/0050-drivers-of-add-initialization-code-for-dynamic-reser.patch')
-rw-r--r-- | target/linux/ipq806x/patches/0050-drivers-of-add-initialization-code-for-dynamic-reser.patch | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches/0050-drivers-of-add-initialization-code-for-dynamic-reser.patch b/target/linux/ipq806x/patches/0050-drivers-of-add-initialization-code-for-dynamic-reser.patch new file mode 100644 index 0000000000..b23867ba55 --- /dev/null +++ b/target/linux/ipq806x/patches/0050-drivers-of-add-initialization-code-for-dynamic-reser.patch @@ -0,0 +1,331 @@ +From 968b497e1027ec78e986370976c76e1652aa0459 Mon Sep 17 00:00:00 2001 +From: Marek Szyprowski <m.szyprowski@samsung.com> +Date: Fri, 28 Feb 2014 14:42:48 +0100 +Subject: [PATCH 050/182] 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 <joshc@codeaurora.org> + +Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> +Signed-off-by: Grant Likely <grant.likely@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 c6973f1..30a7d87 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 efd0510..ed9660a 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 819e112..510c0d8 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 0000000..69b8117 +--- /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.szyprowski@samsung.com> ++ * Author: Josh Cartwright <joshc@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() ++ * panic()s on allocation failure. ++ */ ++ phys_addr_t base = __memblock_alloc_base(size, align, end); ++ if (!base) ++ return -ENOMEM; ++ ++ /* ++ * Check if the allocated region fits in to start..end window ++ */ ++ if (base < start) { ++ memblock_free(base, size); ++ return -ENOMEM; ++ } ++ ++ *res_base = base; ++ if (nomap) ++ return memblock_remove(base, size); ++ return 0; ++} ++#else ++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) ++{ ++ pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n", ++ size, nomap ? " (nomap)" : ""); ++ return -ENOSYS; ++} ++#endif ++ ++/** ++ * res_mem_save_node() - save fdt node for second pass initialization ++ */ ++void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, ++ phys_addr_t base, phys_addr_t size) ++{ ++ struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; ++ ++ if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) { ++ pr_err("Reserved memory: not enough space all defined regions.\n"); ++ return; ++ } ++ ++ rmem->fdt_node = node; ++ rmem->name = uname; ++ rmem->base = base; ++ rmem->size = size; ++ ++ reserved_mem_count++; ++ return; ++} ++ ++/** ++ * 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, "alignment", &len); ++ if (prop) { ++ if (len != dt_root_addr_cells * sizeof(__be32)) { ++ pr_err("Reserved memory: invalid alignment 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", ++ uname, &base, ++ (unsigned long)size / SZ_1M); ++ break; ++ } ++ len -= t_len; ++ } ++ ++ } else { ++ ret = early_init_dt_alloc_reserved_memory_arch(size, align, ++ 0, 0, nomap, &base); ++ if (ret == 0) ++ pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n", ++ uname, &base, (unsigned long)size / SZ_1M); ++ } ++ ++ if (base == 0) { ++ pr_info("Reserved memory: failed to allocate memory for node '%s'\n", ++ uname); ++ return -ENOMEM; ++ } ++ ++ *res_base = base; ++ *res_size = size; ++ ++ return 0; ++} ++ ++/** ++ * fdt_init_reserved_mem - allocate and init all saved reserved memory regions ++ */ ++void __init fdt_init_reserved_mem(void) ++{ ++ int i; ++ for (i = 0; i < reserved_mem_count; i++) { ++ struct reserved_mem *rmem = &reserved_mem[i]; ++ unsigned long node = rmem->fdt_node; ++ int err = 0; ++ ++ if (rmem->size == 0) ++ err = __reserved_mem_alloc_size(node, rmem->name, ++ &rmem->base, &rmem->size); ++ } ++} +diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h +new file mode 100644 +index 0000000..89226ed +--- /dev/null ++++ b/include/linux/of_reserved_mem.h +@@ -0,0 +1,21 @@ ++#ifndef __OF_RESERVED_MEM_H ++#define __OF_RESERVED_MEM_H ++ ++struct reserved_mem { ++ const char *name; ++ unsigned long fdt_node; ++ phys_addr_t base; ++ phys_addr_t size; ++}; ++ ++#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); ++#else ++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) { } ++#endif ++ ++#endif /* __OF_RESERVED_MEM_H */ +-- +1.7.10.4 + |