xref: /openbmc/linux/drivers/of/of_reserved_mem.c (revision b34081f1)
1 /*
2  * Device tree based initialization code for reserved memory.
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5  *		http://www.samsung.com
6  * Author: Marek Szyprowski <m.szyprowski@samsung.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License or (at your optional) any later version of the license.
12  */
13 
14 #include <asm/dma-contiguous.h>
15 
16 #include <linux/memblock.h>
17 #include <linux/err.h>
18 #include <linux/of.h>
19 #include <linux/of_fdt.h>
20 #include <linux/of_platform.h>
21 #include <linux/mm.h>
22 #include <linux/sizes.h>
23 #include <linux/mm_types.h>
24 #include <linux/dma-contiguous.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/of_reserved_mem.h>
27 
28 #define MAX_RESERVED_REGIONS	16
29 struct reserved_mem {
30 	phys_addr_t		base;
31 	unsigned long		size;
32 	struct cma		*cma;
33 	char			name[32];
34 };
35 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
36 static int reserved_mem_count;
37 
38 static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
39 					int depth, void *data)
40 {
41 	struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
42 	phys_addr_t base, size;
43 	int is_cma, is_reserved;
44 	unsigned long len;
45 	const char *status;
46 	__be32 *prop;
47 
48 	is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
49 	       of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
50 	is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
51 
52 	if (!is_reserved && !is_cma) {
53 		/* ignore node and scan next one */
54 		return 0;
55 	}
56 
57 	status = of_get_flat_dt_prop(node, "status", &len);
58 	if (status && strcmp(status, "okay") != 0) {
59 		/* ignore disabled node nad scan next one */
60 		return 0;
61 	}
62 
63 	prop = of_get_flat_dt_prop(node, "reg", &len);
64 	if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
65 			     sizeof(__be32))) {
66 		pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
67 		       uname);
68 		/* ignore node and scan next one */
69 		return 0;
70 	}
71 	base = dt_mem_next_cell(dt_root_addr_cells, &prop);
72 	size = dt_mem_next_cell(dt_root_size_cells, &prop);
73 
74 	if (!size) {
75 		/* ignore node and scan next one */
76 		return 0;
77 	}
78 
79 	pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
80 		uname, (unsigned long)base, (unsigned long)size / SZ_1M);
81 
82 	if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
83 		return -ENOSPC;
84 
85 	rmem->base = base;
86 	rmem->size = size;
87 	strlcpy(rmem->name, uname, sizeof(rmem->name));
88 
89 	if (is_cma) {
90 		struct cma *cma;
91 		if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
92 			rmem->cma = cma;
93 			reserved_mem_count++;
94 			if (of_get_flat_dt_prop(node,
95 						"linux,default-contiguous-region",
96 						NULL))
97 				dma_contiguous_set_default(cma);
98 		}
99 	} else if (is_reserved) {
100 		if (memblock_remove(base, size) == 0)
101 			reserved_mem_count++;
102 		else
103 			pr_err("Failed to reserve memory for %s\n", uname);
104 	}
105 
106 	return 0;
107 }
108 
109 static struct reserved_mem *get_dma_memory_region(struct device *dev)
110 {
111 	struct device_node *node;
112 	const char *name;
113 	int i;
114 
115 	node = of_parse_phandle(dev->of_node, "memory-region", 0);
116 	if (!node)
117 		return NULL;
118 
119 	name = kbasename(node->full_name);
120 	for (i = 0; i < reserved_mem_count; i++)
121 		if (strcmp(name, reserved_mem[i].name) == 0)
122 			return &reserved_mem[i];
123 	return NULL;
124 }
125 
126 /**
127  * of_reserved_mem_device_init() - assign reserved memory region to given device
128  *
129  * This function assign memory region pointed by "memory-region" device tree
130  * property to the given device.
131  */
132 void of_reserved_mem_device_init(struct device *dev)
133 {
134 	struct reserved_mem *region = get_dma_memory_region(dev);
135 	if (!region)
136 		return;
137 
138 	if (region->cma) {
139 		dev_set_cma_area(dev, region->cma);
140 		pr_info("Assigned CMA %s to %s device\n", region->name,
141 			dev_name(dev));
142 	} else {
143 		if (dma_declare_coherent_memory(dev, region->base, region->base,
144 		    region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
145 			pr_info("Declared reserved memory %s to %s device\n",
146 				region->name, dev_name(dev));
147 	}
148 }
149 
150 /**
151  * of_reserved_mem_device_release() - release reserved memory device structures
152  *
153  * This function releases structures allocated for memory region handling for
154  * the given device.
155  */
156 void of_reserved_mem_device_release(struct device *dev)
157 {
158 	struct reserved_mem *region = get_dma_memory_region(dev);
159 	if (!region && !region->cma)
160 		dma_release_declared_memory(dev);
161 }
162 
163 /**
164  * early_init_dt_scan_reserved_mem() - create reserved memory regions
165  *
166  * This function grabs memory from early allocator for device exclusive use
167  * defined in device tree structures. It should be called by arch specific code
168  * once the early allocator (memblock) has been activated and all other
169  * subsystems have already allocated/reserved memory.
170  */
171 void __init early_init_dt_scan_reserved_mem(void)
172 {
173 	of_scan_flat_dt_by_path("/memory/reserved-memory",
174 				fdt_scan_reserved_mem, NULL);
175 }
176