aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-09 13:26:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-09 13:26:33 -0400
commit64c353864e3f7ccba0ade1bd6f562f9a3bc7e68d (patch)
treefdd4d4c0cc90ef920cd755b835f0acf1e6ef8fbf
parentd8cacd3a259bf522ea5e6c4c60eba67ba22f599c (diff)
parent10bcdfb8ba24760f715f0a700c3812747eddddf5 (diff)
Merge branch 'for-v3.12' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping
Pull DMA mapping update from Marek Szyprowski: "This contains an addition of Device Tree support for reserved memory regions (Contiguous Memory Allocator is one of the drivers for it) and changes required by the KVM extensions for PowerPC architectue" * 'for-v3.12' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping: ARM: init: add support for reserved memory defined by device tree drivers: of: add initialization code for dma reserved memory drivers: of: add function to scan fdt nodes given by path drivers: dma-contiguous: clean source code and prepare for device tree
-rw-r--r--Documentation/devicetree/bindings/memory.txt168
-rw-r--r--arch/arm/include/asm/dma-contiguous.h1
-rw-r--r--arch/arm/mm/init.c3
-rw-r--r--arch/x86/include/asm/dma-contiguous.h1
-rw-r--r--drivers/base/dma-contiguous.c119
-rw-r--r--drivers/of/Kconfig6
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/fdt.c76
-rw-r--r--drivers/of/of_reserved_mem.c175
-rw-r--r--drivers/of/platform.c4
-rw-r--r--include/asm-generic/dma-contiguous.h28
-rw-r--r--include/linux/device.h2
-rw-r--r--include/linux/dma-contiguous.h62
-rw-r--r--include/linux/of_fdt.h3
-rw-r--r--include/linux/of_reserved_mem.h14
15 files changed, 555 insertions, 108 deletions
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
new file mode 100644
index 000000000000..eb2469365593
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -0,0 +1,168 @@
1*** Memory binding ***
2
3The /memory node provides basic information about the address and size
4of the physical memory. This node is usually filled or updated by the
5bootloader, depending on the actual memory configuration of the given
6hardware.
7
8The memory layout is described by the following node:
9
10/ {
11 #address-cells = <(n)>;
12 #size-cells = <(m)>;
13 memory {
14 device_type = "memory";
15 reg = <(baseaddr1) (size1)
16 (baseaddr2) (size2)
17 ...
18 (baseaddrN) (sizeN)>;
19 };
20 ...
21};
22
23A memory node follows the typical device tree rules for "reg" property:
24n: number of cells used to store base address value
25m: number of cells used to store size value
26baseaddrX: defines a base address of the defined memory bank
27sizeX: the size of the defined memory bank
28
29
30More than one memory bank can be defined.
31
32
33*** Reserved memory regions ***
34
35In /memory/reserved-memory node one can create child nodes describing
36particular reserved (excluded from normal use) memory regions. Such
37memory regions are usually designed for the special usage by various
38device drivers. A good example are contiguous memory allocations or
39memory sharing with other operating system on the same hardware board.
40Those special memory regions might depend on the board configuration and
41devices used on the target system.
42
43Parameters for each memory region can be encoded into the device tree
44with the following convention:
45
46[(label):] (name) {
47 compatible = "linux,contiguous-memory-region", "reserved-memory-region";
48 reg = <(address) (size)>;
49 (linux,default-contiguous-region);
50};
51
52compatible: one or more of:
53 - "linux,contiguous-memory-region" - enables binding of this
54 region to Contiguous Memory Allocator (special region for
55 contiguous memory allocations, shared with movable system
56 memory, Linux kernel-specific).
57 - "reserved-memory-region" - compatibility is defined, given
58 region is assigned for exclusive usage for by the respective
59 devices.
60
61reg: standard property defining the base address and size of
62 the memory region
63
64linux,default-contiguous-region: property indicating that the region
65 is the default region for all contiguous memory
66 allocations, Linux specific (optional)
67
68It is optional to specify the base address, so if one wants to use
69autoconfiguration of the base address, '0' can be specified as a base
70address in the 'reg' property.
71
72The /memory/reserved-memory node must contain the same #address-cells
73and #size-cells value as the root node.
74
75
76*** Device node's properties ***
77
78Once regions in the /memory/reserved-memory node have been defined, they
79may be referenced by other device nodes. Bindings that wish to reference
80memory regions should explicitly document their use of the following
81property:
82
83memory-region = <&phandle_to_defined_region>;
84
85This property indicates that the device driver should use the memory
86region pointed by the given phandle.
87
88
89*** Example ***
90
91This example defines a memory consisting of 4 memory banks. 3 contiguous
92regions are defined for Linux kernel, one default of all device drivers
93(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the
94framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB)
95and one for multimedia processing (labelled multimedia_mem, placed at
960x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000
97device for DMA memory allocations (Linux kernel drivers will use CMA is
98available or dma-exclusive usage otherwise). 'multimedia_mem' is
99assigned to scaler@12500000 and codec@12600000 devices for contiguous
100memory allocations when CMA driver is enabled.
101
102The reason for creating a separate region for framebuffer device is to
103match the framebuffer base address to the one configured by bootloader,
104so once Linux kernel drivers starts no glitches on the displayed boot
105logo appears. Scaller and codec drivers should share the memory
106allocations.
107
108/ {
109 #address-cells = <1>;
110 #size-cells = <1>;
111
112 /* ... */
113
114 memory {
115 reg = <0x40000000 0x10000000
116 0x50000000 0x10000000
117 0x60000000 0x10000000
118 0x70000000 0x10000000>;
119
120 reserved-memory {
121 #address-cells = <1>;
122 #size-cells = <1>;
123
124 /*
125 * global autoconfigured region for contiguous allocations
126 * (used only with Contiguous Memory Allocator)
127 */
128 contig_region@0 {
129 compatible = "linux,contiguous-memory-region";
130 reg = <0x0 0x4000000>;
131 linux,default-contiguous-region;
132 };
133
134 /*
135 * special region for framebuffer
136 */
137 display_region: region@78000000 {
138 compatible = "linux,contiguous-memory-region", "reserved-memory-region";
139 reg = <0x78000000 0x800000>;
140 };
141
142 /*
143 * special region for multimedia processing devices
144 */
145 multimedia_region: region@77000000 {
146 compatible = "linux,contiguous-memory-region";
147 reg = <0x77000000 0x4000000>;
148 };
149 };
150 };
151
152 /* ... */
153
154 fb0: fb@12300000 {
155 status = "okay";
156 memory-region = <&display_region>;
157 };
158
159 scaler: scaler@12500000 {
160 status = "okay";
161 memory-region = <&multimedia_region>;
162 };
163
164 codec: codec@12600000 {
165 status = "okay";
166 memory-region = <&multimedia_region>;
167 };
168};
diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h
index e072bb2ba1b1..4f8e9e5514b1 100644
--- a/arch/arm/include/asm/dma-contiguous.h
+++ b/arch/arm/include/asm/dma-contiguous.h
@@ -5,7 +5,6 @@
5#ifdef CONFIG_DMA_CMA 5#ifdef CONFIG_DMA_CMA
6 6
7#include <linux/types.h> 7#include <linux/types.h>
8#include <asm-generic/dma-contiguous.h>
9 8
10void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size); 9void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
11 10
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 2958e74fc42c..7b0cb3b524f1 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -17,6 +17,7 @@
17#include <linux/nodemask.h> 17#include <linux/nodemask.h>
18#include <linux/initrd.h> 18#include <linux/initrd.h>
19#include <linux/of_fdt.h> 19#include <linux/of_fdt.h>
20#include <linux/of_reserved_mem.h>
20#include <linux/highmem.h> 21#include <linux/highmem.h>
21#include <linux/gfp.h> 22#include <linux/gfp.h>
22#include <linux/memblock.h> 23#include <linux/memblock.h>
@@ -378,6 +379,8 @@ void __init arm_memblock_init(struct meminfo *mi,
378 if (mdesc->reserve) 379 if (mdesc->reserve)
379 mdesc->reserve(); 380 mdesc->reserve();
380 381
382 early_init_dt_scan_reserved_mem();
383
381 /* 384 /*
382 * reserve memory for DMA contigouos allocations, 385 * reserve memory for DMA contigouos allocations,
383 * must come from DMA area inside low memory 386 * must come from DMA area inside low memory
diff --git a/arch/x86/include/asm/dma-contiguous.h b/arch/x86/include/asm/dma-contiguous.h
index c09241659971..b4b38bacb404 100644
--- a/arch/x86/include/asm/dma-contiguous.h
+++ b/arch/x86/include/asm/dma-contiguous.h
@@ -4,7 +4,6 @@
4#ifdef __KERNEL__ 4#ifdef __KERNEL__
5 5
6#include <linux/types.h> 6#include <linux/types.h>
7#include <asm-generic/dma-contiguous.h>
8 7
9static inline void 8static inline void
10dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { } 9dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { }
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 6c9cdaa9200d..99802d6f3c60 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -96,7 +96,7 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
96#endif 96#endif
97 97
98/** 98/**
99 * dma_contiguous_reserve() - reserve area for contiguous memory handling 99 * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling
100 * @limit: End address of the reserved memory (optional, 0 for any). 100 * @limit: End address of the reserved memory (optional, 0 for any).
101 * 101 *
102 * This function reserves memory from early allocator. It should be 102 * This function reserves memory from early allocator. It should be
@@ -124,22 +124,29 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
124#endif 124#endif
125 } 125 }
126 126
127 if (selected_size) { 127 if (selected_size && !dma_contiguous_default_area) {
128 pr_debug("%s: reserving %ld MiB for global area\n", __func__, 128 pr_debug("%s: reserving %ld MiB for global area\n", __func__,
129 (unsigned long)selected_size / SZ_1M); 129 (unsigned long)selected_size / SZ_1M);
130 130
131 dma_declare_contiguous(NULL, selected_size, 0, limit); 131 dma_contiguous_reserve_area(selected_size, 0, limit,
132 &dma_contiguous_default_area);
132 } 133 }
133}; 134};
134 135
135static DEFINE_MUTEX(cma_mutex); 136static DEFINE_MUTEX(cma_mutex);
136 137
137static int __init cma_activate_area(unsigned long base_pfn, unsigned long count) 138static int __init cma_activate_area(struct cma *cma)
138{ 139{
139 unsigned long pfn = base_pfn; 140 int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long);
140 unsigned i = count >> pageblock_order; 141 unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
142 unsigned i = cma->count >> pageblock_order;
141 struct zone *zone; 143 struct zone *zone;
142 144
145 cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
146
147 if (!cma->bitmap)
148 return -ENOMEM;
149
143 WARN_ON_ONCE(!pfn_valid(pfn)); 150 WARN_ON_ONCE(!pfn_valid(pfn));
144 zone = page_zone(pfn_to_page(pfn)); 151 zone = page_zone(pfn_to_page(pfn));
145 152
@@ -153,92 +160,53 @@ static int __init cma_activate_area(unsigned long base_pfn, unsigned long count)
153 } 160 }
154 init_cma_reserved_pageblock(pfn_to_page(base_pfn)); 161 init_cma_reserved_pageblock(pfn_to_page(base_pfn));
155 } while (--i); 162 } while (--i);
156 return 0;
157}
158
159static struct cma * __init cma_create_area(unsigned long base_pfn,
160 unsigned long count)
161{
162 int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
163 struct cma *cma;
164 int ret = -ENOMEM;
165
166 pr_debug("%s(base %08lx, count %lx)\n", __func__, base_pfn, count);
167
168 cma = kmalloc(sizeof *cma, GFP_KERNEL);
169 if (!cma)
170 return ERR_PTR(-ENOMEM);
171
172 cma->base_pfn = base_pfn;
173 cma->count = count;
174 cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
175 163
176 if (!cma->bitmap) 164 return 0;
177 goto no_mem;
178
179 ret = cma_activate_area(base_pfn, count);
180 if (ret)
181 goto error;
182
183 pr_debug("%s: returned %p\n", __func__, (void *)cma);
184 return cma;
185
186error:
187 kfree(cma->bitmap);
188no_mem:
189 kfree(cma);
190 return ERR_PTR(ret);
191} 165}
192 166
193static struct cma_reserved { 167static struct cma cma_areas[MAX_CMA_AREAS];
194 phys_addr_t start; 168static unsigned cma_area_count;
195 unsigned long size;
196 struct device *dev;
197} cma_reserved[MAX_CMA_AREAS] __initdata;
198static unsigned cma_reserved_count __initdata;
199 169
200static int __init cma_init_reserved_areas(void) 170static int __init cma_init_reserved_areas(void)
201{ 171{
202 struct cma_reserved *r = cma_reserved; 172 int i;
203 unsigned i = cma_reserved_count;
204
205 pr_debug("%s()\n", __func__);
206 173
207 for (; i; --i, ++r) { 174 for (i = 0; i < cma_area_count; i++) {
208 struct cma *cma; 175 int ret = cma_activate_area(&cma_areas[i]);
209 cma = cma_create_area(PFN_DOWN(r->start), 176 if (ret)
210 r->size >> PAGE_SHIFT); 177 return ret;
211 if (!IS_ERR(cma))
212 dev_set_cma_area(r->dev, cma);
213 } 178 }
179
214 return 0; 180 return 0;
215} 181}
216core_initcall(cma_init_reserved_areas); 182core_initcall(cma_init_reserved_areas);
217 183
218/** 184/**
219 * dma_declare_contiguous() - reserve area for contiguous memory handling 185 * dma_contiguous_reserve_area() - reserve custom contiguous area
220 * for particular device 186 * @size: Size of the reserved area (in bytes),
221 * @dev: Pointer to device structure. 187 * @base: Base address of the reserved area optional, use 0 for any
222 * @size: Size of the reserved memory.
223 * @base: Start address of the reserved memory (optional, 0 for any).
224 * @limit: End address of the reserved memory (optional, 0 for any). 188 * @limit: End address of the reserved memory (optional, 0 for any).
189 * @res_cma: Pointer to store the created cma region.
225 * 190 *
226 * This function reserves memory for specified device. It should be 191 * This function reserves memory from early allocator. It should be
227 * called by board specific code when early allocator (memblock or bootmem) 192 * called by arch specific code once the early allocator (memblock or bootmem)
228 * is still activate. 193 * has been activated and all other subsystems have already allocated/reserved
194 * memory. This function allows to create custom reserved areas for specific
195 * devices.
229 */ 196 */
230int __init dma_declare_contiguous(struct device *dev, phys_addr_t size, 197int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
231 phys_addr_t base, phys_addr_t limit) 198 phys_addr_t limit, struct cma **res_cma)
232{ 199{
233 struct cma_reserved *r = &cma_reserved[cma_reserved_count]; 200 struct cma *cma = &cma_areas[cma_area_count];
234 phys_addr_t alignment; 201 phys_addr_t alignment;
202 int ret = 0;
235 203
236 pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__, 204 pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
237 (unsigned long)size, (unsigned long)base, 205 (unsigned long)size, (unsigned long)base,
238 (unsigned long)limit); 206 (unsigned long)limit);
239 207
240 /* Sanity checks */ 208 /* Sanity checks */
241 if (cma_reserved_count == ARRAY_SIZE(cma_reserved)) { 209 if (cma_area_count == ARRAY_SIZE(cma_areas)) {
242 pr_err("Not enough slots for CMA reserved regions!\n"); 210 pr_err("Not enough slots for CMA reserved regions!\n");
243 return -ENOSPC; 211 return -ENOSPC;
244 } 212 }
@@ -256,7 +224,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
256 if (base) { 224 if (base) {
257 if (memblock_is_region_reserved(base, size) || 225 if (memblock_is_region_reserved(base, size) ||
258 memblock_reserve(base, size) < 0) { 226 memblock_reserve(base, size) < 0) {
259 base = -EBUSY; 227 ret = -EBUSY;
260 goto err; 228 goto err;
261 } 229 }
262 } else { 230 } else {
@@ -266,7 +234,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
266 */ 234 */
267 phys_addr_t addr = __memblock_alloc_base(size, alignment, limit); 235 phys_addr_t addr = __memblock_alloc_base(size, alignment, limit);
268 if (!addr) { 236 if (!addr) {
269 base = -ENOMEM; 237 ret = -ENOMEM;
270 goto err; 238 goto err;
271 } else { 239 } else {
272 base = addr; 240 base = addr;
@@ -277,10 +245,11 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
277 * Each reserved area must be initialised later, when more kernel 245 * Each reserved area must be initialised later, when more kernel
278 * subsystems (like slab allocator) are available. 246 * subsystems (like slab allocator) are available.
279 */ 247 */
280 r->start = base; 248 cma->base_pfn = PFN_DOWN(base);
281 r->size = size; 249 cma->count = size >> PAGE_SHIFT;
282 r->dev = dev; 250 *res_cma = cma;
283 cma_reserved_count++; 251 cma_area_count++;
252
284 pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M, 253 pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
285 (unsigned long)base); 254 (unsigned long)base);
286 255
@@ -289,7 +258,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
289 return 0; 258 return 0;
290err: 259err:
291 pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M); 260 pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
292 return base; 261 return ret;
293} 262}
294 263
295/** 264/**
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 78cc76053328..9d2009a9004d 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -74,4 +74,10 @@ config OF_MTD
74 depends on MTD 74 depends on MTD
75 def_bool y 75 def_bool y
76 76
77config OF_RESERVED_MEM
78 depends on OF_FLATTREE && (DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK))
79 def_bool y
80 help
81 Initialization code for DMA reserved memory
82
77endmenu # OF 83endmenu # 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
9obj-$(CONFIG_OF_PCI) += of_pci.o 9obj-$(CONFIG_OF_PCI) += of_pci.o
10obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o 10obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
11obj-$(CONFIG_OF_MTD) += of_mtd.o 11obj-$(CONFIG_OF_MTD) += of_mtd.o
12obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index b10ba00cc3e6..4fb06f3e7b3c 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -545,6 +545,82 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
545 return of_fdt_match(initial_boot_params, node, compat); 545 return of_fdt_match(initial_boot_params, node, compat);
546} 546}
547 547
548struct fdt_scan_status {
549 const char *name;
550 int namelen;
551 int depth;
552 int found;
553 int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
554 void *data;
555};
556
557/**
558 * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
559 */
560static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
561 int depth, void *data)
562{
563 struct fdt_scan_status *st = data;
564
565 /*
566 * if scan at the requested fdt node has been completed,
567 * return -ENXIO to abort further scanning
568 */
569 if (depth <= st->depth)
570 return -ENXIO;
571
572 /* requested fdt node has been found, so call iterator function */
573 if (st->found)
574 return st->iterator(node, uname, depth, st->data);
575
576 /* check if scanning automata is entering next level of fdt nodes */
577 if (depth == st->depth + 1 &&
578 strncmp(st->name, uname, st->namelen) == 0 &&
579 uname[st->namelen] == 0) {
580 st->depth += 1;
581 if (st->name[st->namelen] == 0) {
582 st->found = 1;
583 } else {
584 const char *next = st->name + st->namelen + 1;
585 st->name = next;
586 st->namelen = strcspn(next, "/");
587 }
588 return 0;
589 }
590
591 /* scan next fdt node */
592 return 0;
593}
594
595/**
596 * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
597 * child of the given path.
598 * @path: path to start searching for children
599 * @it: callback function
600 * @data: context data pointer
601 *
602 * This function is used to scan the flattened device-tree starting from the
603 * node given by path. It is used to extract information (like reserved
604 * memory), which is required on ealy boot before we can unflatten the tree.
605 */
606int __init of_scan_flat_dt_by_path(const char *path,
607 int (*it)(unsigned long node, const char *name, int depth, void *data),
608 void *data)
609{
610 struct fdt_scan_status st = {path, 0, -1, 0, it, data};
611 int ret = 0;
612
613 if (initial_boot_params)
614 ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
615
616 if (!st.found)
617 return -ENOENT;
618 else if (ret == -ENXIO) /* scan has been completed */
619 return 0;
620 else
621 return ret;
622}
623
548#ifdef CONFIG_BLK_DEV_INITRD 624#ifdef CONFIG_BLK_DEV_INITRD
549/** 625/**
550 * early_init_dt_check_for_initrd - Decode initrd location from flat tree 626 * early_init_dt_check_for_initrd - Decode initrd location from flat tree
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
new file mode 100644
index 000000000000..a754b84ba016
--- /dev/null
+++ b/drivers/of/of_reserved_mem.c
@@ -0,0 +1,175 @@
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
29struct reserved_mem {
30 phys_addr_t base;
31 unsigned long size;
32 struct cma *cma;
33 char name[32];
34};
35static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
36static int reserved_mem_count;
37
38static 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
109static 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 */
132void 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 */
156void 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 */
171void __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}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e0a6514ab46c..eeca8a596973 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -21,6 +21,7 @@
21#include <linux/of_device.h> 21#include <linux/of_device.h>
22#include <linux/of_irq.h> 22#include <linux/of_irq.h>
23#include <linux/of_platform.h> 23#include <linux/of_platform.h>
24#include <linux/of_reserved_mem.h>
24#include <linux/platform_device.h> 25#include <linux/platform_device.h>
25 26
26const struct of_device_id of_default_bus_match_table[] = { 27const struct of_device_id of_default_bus_match_table[] = {
@@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
218 dev->dev.bus = &platform_bus_type; 219 dev->dev.bus = &platform_bus_type;
219 dev->dev.platform_data = platform_data; 220 dev->dev.platform_data = platform_data;
220 221
222 of_reserved_mem_device_init(&dev->dev);
223
221 /* We do not fill the DMA ops for platform devices by default. 224 /* We do not fill the DMA ops for platform devices by default.
222 * This is currently the responsibility of the platform code 225 * This is currently the responsibility of the platform code
223 * to do such, possibly using a device notifier 226 * to do such, possibly using a device notifier
@@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
225 228
226 if (of_device_add(dev) != 0) { 229 if (of_device_add(dev) != 0) {
227 platform_device_put(dev); 230 platform_device_put(dev);
231 of_reserved_mem_device_release(&dev->dev);
228 return NULL; 232 return NULL;
229 } 233 }
230 234
diff --git a/include/asm-generic/dma-contiguous.h b/include/asm-generic/dma-contiguous.h
deleted file mode 100644
index 294b1e755ab2..000000000000
--- a/include/asm-generic/dma-contiguous.h
+++ /dev/null
@@ -1,28 +0,0 @@
1#ifndef ASM_DMA_CONTIGUOUS_H
2#define ASM_DMA_CONTIGUOUS_H
3
4#ifdef __KERNEL__
5#ifdef CONFIG_CMA
6
7#include <linux/device.h>
8#include <linux/dma-contiguous.h>
9
10static inline struct cma *dev_get_cma_area(struct device *dev)
11{
12 if (dev && dev->cma_area)
13 return dev->cma_area;
14 return dma_contiguous_default_area;
15}
16
17static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
18{
19 if (dev)
20 dev->cma_area = cma;
21 if (!dev && !dma_contiguous_default_area)
22 dma_contiguous_default_area = cma;
23}
24
25#endif
26#endif
27
28#endif
diff --git a/include/linux/device.h b/include/linux/device.h
index f46646e49235..2a9d6ed59579 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -737,7 +737,7 @@ struct device {
737 737
738 struct dma_coherent_mem *dma_mem; /* internal for coherent mem 738 struct dma_coherent_mem *dma_mem; /* internal for coherent mem
739 override */ 739 override */
740#ifdef CONFIG_CMA 740#ifdef CONFIG_DMA_CMA
741 struct cma *cma_area; /* contiguous memory area for dma 741 struct cma *cma_area; /* contiguous memory area for dma
742 allocations */ 742 allocations */
743#endif 743#endif
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 00141d3325fe..3b28f937d959 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -67,9 +67,53 @@ struct device;
67 67
68extern struct cma *dma_contiguous_default_area; 68extern struct cma *dma_contiguous_default_area;
69 69
70static inline struct cma *dev_get_cma_area(struct device *dev)
71{
72 if (dev && dev->cma_area)
73 return dev->cma_area;
74 return dma_contiguous_default_area;
75}
76
77static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
78{
79 if (dev)
80 dev->cma_area = cma;
81}
82
83static inline void dma_contiguous_set_default(struct cma *cma)
84{
85 dma_contiguous_default_area = cma;
86}
87
70void dma_contiguous_reserve(phys_addr_t addr_limit); 88void dma_contiguous_reserve(phys_addr_t addr_limit);
71int dma_declare_contiguous(struct device *dev, phys_addr_t size, 89
72 phys_addr_t base, phys_addr_t limit); 90int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
91 phys_addr_t limit, struct cma **res_cma);
92
93/**
94 * dma_declare_contiguous() - reserve area for contiguous memory handling
95 * for particular device
96 * @dev: Pointer to device structure.
97 * @size: Size of the reserved memory.
98 * @base: Start address of the reserved memory (optional, 0 for any).
99 * @limit: End address of the reserved memory (optional, 0 for any).
100 *
101 * This function reserves memory for specified device. It should be
102 * called by board specific code when early allocator (memblock or bootmem)
103 * is still activate.
104 */
105
106static inline int dma_declare_contiguous(struct device *dev, phys_addr_t size,
107 phys_addr_t base, phys_addr_t limit)
108{
109 struct cma *cma;
110 int ret;
111 ret = dma_contiguous_reserve_area(size, base, limit, &cma);
112 if (ret == 0)
113 dev_set_cma_area(dev, cma);
114
115 return ret;
116}
73 117
74struct page *dma_alloc_from_contiguous(struct device *dev, int count, 118struct page *dma_alloc_from_contiguous(struct device *dev, int count,
75 unsigned int order); 119 unsigned int order);
@@ -80,8 +124,22 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
80 124
81#define MAX_CMA_AREAS (0) 125#define MAX_CMA_AREAS (0)
82 126
127static inline struct cma *dev_get_cma_area(struct device *dev)
128{
129 return NULL;
130}
131
132static inline void dev_set_cma_area(struct device *dev, struct cma *cma) { }
133
134static inline void dma_contiguous_set_default(struct cma *cma) { }
135
83static inline void dma_contiguous_reserve(phys_addr_t limit) { } 136static inline void dma_contiguous_reserve(phys_addr_t limit) { }
84 137
138static inline int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
139 phys_addr_t limit, struct cma **res_cma) {
140 return -ENOSYS;
141}
142
85static inline 143static inline
86int dma_declare_contiguous(struct device *dev, phys_addr_t size, 144int dma_declare_contiguous(struct device *dev, phys_addr_t size,
87 phys_addr_t base, phys_addr_t limit) 145 phys_addr_t base, phys_addr_t limit)
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index ed136ad698ce..19f26f8d2202 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -90,6 +90,9 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
90extern int of_flat_dt_is_compatible(unsigned long node, const char *name); 90extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
91extern int of_flat_dt_match(unsigned long node, const char *const *matches); 91extern int of_flat_dt_match(unsigned long node, const char *const *matches);
92extern unsigned long of_get_flat_dt_root(void); 92extern unsigned long of_get_flat_dt_root(void);
93extern int of_scan_flat_dt_by_path(const char *path,
94 int (*it)(unsigned long node, const char *name, int depth, void *data),
95 void *data);
93 96
94extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, 97extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
95 int depth, void *data); 98 int depth, void *data);
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
new file mode 100644
index 000000000000..c84128255814
--- /dev/null
+++ b/include/linux/of_reserved_mem.h
@@ -0,0 +1,14 @@
1#ifndef __OF_RESERVED_MEM_H
2#define __OF_RESERVED_MEM_H
3
4#ifdef CONFIG_OF_RESERVED_MEM
5void of_reserved_mem_device_init(struct device *dev);
6void of_reserved_mem_device_release(struct device *dev);
7void early_init_dt_scan_reserved_mem(void);
8#else
9static inline void of_reserved_mem_device_init(struct device *dev) { }
10static inline void of_reserved_mem_device_release(struct device *dev) { }
11static inline void early_init_dt_scan_reserved_mem(void) { }
12#endif
13
14#endif /* __OF_RESERVED_MEM_H */