2 * PowerPC 4xx OCM memory allocation support
4 * (C) Copyright 2009, Applied Micro Circuits Corporation
5 * Victor Gallardo (vgallardo@amcc.com)
7 * See file CREDITS for list of people who contributed to this
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 #include <linux/kernel.h>
27 #include <linux/dma-mapping.h>
29 #include <asm/rheap.h>
30 #include <asm/ppc4xx_ocm.h>
31 #include <linux/slab.h>
32 #include <linux/debugfs.h>
34 #define OCM_DISABLED 0
38 struct list_head list
;
44 /* non-cached or cached region */
53 struct list_head list
;
67 struct ocm_region nc
; /* non-cached region */
68 struct ocm_region c
; /* cached region */
71 static struct ocm_info
*ocm_nodes
;
74 static struct ocm_info
*ocm_get_node(unsigned int index
)
76 if (index
>= ocm_count
) {
77 printk(KERN_ERR
"PPC4XX OCM: invalid index");
81 return &ocm_nodes
[index
];
84 static int ocm_free_region(struct ocm_region
*ocm_reg
, const void *addr
)
86 struct ocm_block
*blk
, *tmp
;
92 list_for_each_entry_safe(blk
, tmp
, &ocm_reg
->list
, list
) {
93 if (blk
->addr
== addr
) {
94 offset
= addr
- ocm_reg
->virt
;
95 ocm_reg
->memfree
+= blk
->size
;
96 rh_free(ocm_reg
->rh
, offset
);
106 static void __init
ocm_init_node(int count
, struct device_node
*node
)
108 struct ocm_info
*ocm
;
110 const unsigned int *cell_index
;
111 const unsigned int *cache_size
;
114 struct resource rsrc
;
117 ocm
= ocm_get_node(count
);
119 cell_index
= of_get_property(node
, "cell-index", &len
);
121 printk(KERN_ERR
"PPC4XX OCM: missing cell-index property");
124 ocm
->index
= *cell_index
;
126 if (of_device_is_available(node
))
127 ocm
->status
= OCM_ENABLED
;
129 cache_size
= of_get_property(node
, "cached-region-size", &len
);
131 ocm
->cache_size
= *cache_size
;
133 if (of_address_to_resource(node
, 0, &rsrc
)) {
134 printk(KERN_ERR
"PPC4XX OCM%d: could not get resource address\n",
139 ocm
->phys
= rsrc
.start
;
140 ocm
->memtotal
= (rsrc
.end
- rsrc
.start
+ 1);
142 printk(KERN_INFO
"PPC4XX OCM%d: %d Bytes (%s)\n",
143 ocm
->index
, ocm
->memtotal
,
144 (ocm
->status
== OCM_DISABLED
) ? "disabled" : "enabled");
146 if (ocm
->status
== OCM_DISABLED
)
151 if (!request_mem_region(ocm
->phys
, ocm
->memtotal
, "ppc4xx_ocm")) {
152 printk(KERN_ERR
"PPC4XX OCM%d: could not request region\n",
157 /* Configure non-cached and cached regions */
159 ocm
->nc
.phys
= ocm
->phys
;
160 ocm
->nc
.memtotal
= ocm
->memtotal
- ocm
->cache_size
;
161 ocm
->nc
.memfree
= ocm
->nc
.memtotal
;
163 ocm
->c
.phys
= ocm
->phys
+ ocm
->nc
.memtotal
;
164 ocm
->c
.memtotal
= ocm
->cache_size
;
165 ocm
->c
.memfree
= ocm
->c
.memtotal
;
167 if (ocm
->nc
.memtotal
== 0)
170 if (ocm
->c
.memtotal
== 0)
173 printk(KERN_INFO
"PPC4XX OCM%d: %d Bytes (non-cached)\n",
174 ocm
->index
, ocm
->nc
.memtotal
);
176 printk(KERN_INFO
"PPC4XX OCM%d: %d Bytes (cached)\n",
177 ocm
->index
, ocm
->c
.memtotal
);
179 /* ioremap the non-cached region */
180 if (ocm
->nc
.memtotal
) {
181 ioflags
= _PAGE_NO_CACHE
| _PAGE_GUARDED
| _PAGE_EXEC
;
182 ocm
->nc
.virt
= __ioremap(ocm
->nc
.phys
, ocm
->nc
.memtotal
,
187 "PPC4XX OCM%d: failed to ioremap non-cached memory\n",
194 /* ioremap the cached region */
196 if (ocm
->c
.memtotal
) {
197 ioflags
= _PAGE_EXEC
;
198 ocm
->c
.virt
= __ioremap(ocm
->c
.phys
, ocm
->c
.memtotal
,
203 "PPC4XX OCM%d: failed to ioremap cached memory\n",
210 /* Create Remote Heaps */
212 ocm
->alignment
= 4; /* default 4 byte alignment */
215 ocm
->nc
.rh
= rh_create(ocm
->alignment
);
216 rh_attach_region(ocm
->nc
.rh
, 0, ocm
->nc
.memtotal
);
220 ocm
->c
.rh
= rh_create(ocm
->alignment
);
221 rh_attach_region(ocm
->c
.rh
, 0, ocm
->c
.memtotal
);
224 INIT_LIST_HEAD(&ocm
->nc
.list
);
225 INIT_LIST_HEAD(&ocm
->c
.list
);
232 static int ocm_debugfs_show(struct seq_file
*m
, void *v
)
234 struct ocm_block
*blk
, *tmp
;
237 for (i
= 0; i
< ocm_count
; i
++) {
238 struct ocm_info
*ocm
= ocm_get_node(i
);
240 if (!ocm
|| !ocm
->ready
)
243 seq_printf(m
, "PPC4XX OCM : %d\n", ocm
->index
);
244 seq_printf(m
, "PhysAddr : 0x%llx\n", ocm
->phys
);
245 seq_printf(m
, "MemTotal : %d Bytes\n", ocm
->memtotal
);
246 seq_printf(m
, "MemTotal(NC) : %d Bytes\n", ocm
->nc
.memtotal
);
247 seq_printf(m
, "MemTotal(C) : %d Bytes\n", ocm
->c
.memtotal
);
251 seq_printf(m
, "NC.PhysAddr : 0x%llx\n", ocm
->nc
.phys
);
252 seq_printf(m
, "NC.VirtAddr : 0x%p\n", ocm
->nc
.virt
);
253 seq_printf(m
, "NC.MemTotal : %d Bytes\n", ocm
->nc
.memtotal
);
254 seq_printf(m
, "NC.MemFree : %d Bytes\n", ocm
->nc
.memfree
);
256 list_for_each_entry_safe(blk
, tmp
, &ocm
->nc
.list
, list
) {
257 seq_printf(m
, "NC.MemUsed : %d Bytes (%s)\n",
258 blk
->size
, blk
->owner
);
263 seq_printf(m
, "C.PhysAddr : 0x%llx\n", ocm
->c
.phys
);
264 seq_printf(m
, "C.VirtAddr : 0x%p\n", ocm
->c
.virt
);
265 seq_printf(m
, "C.MemTotal : %d Bytes\n", ocm
->c
.memtotal
);
266 seq_printf(m
, "C.MemFree : %d Bytes\n", ocm
->c
.memfree
);
268 list_for_each_entry_safe(blk
, tmp
, &ocm
->c
.list
, list
) {
269 seq_printf(m
, "C.MemUsed : %d Bytes (%s)\n",
270 blk
->size
, blk
->owner
);
279 static int ocm_debugfs_open(struct inode
*inode
, struct file
*file
)
281 return single_open(file
, ocm_debugfs_show
, NULL
);
284 static const struct file_operations ocm_debugfs_fops
= {
285 .open
= ocm_debugfs_open
,
288 .release
= single_release
,
291 static int ocm_debugfs_init(void)
295 junk
= debugfs_create_dir("ppc4xx_ocm", 0);
297 printk(KERN_ALERT
"debugfs ppc4xx ocm: failed to create dir\n");
301 if (debugfs_create_file("info", 0644, junk
, NULL
, &ocm_debugfs_fops
)) {
302 printk(KERN_ALERT
"debugfs ppc4xx ocm: failed to create file\n");
309 void *ppc4xx_ocm_alloc(phys_addr_t
*phys
, int size
, int align
,
310 int flags
, const char *owner
)
312 void __iomem
*addr
= NULL
;
313 unsigned long offset
;
314 struct ocm_info
*ocm
;
315 struct ocm_region
*ocm_reg
;
316 struct ocm_block
*ocm_blk
;
319 for (i
= 0; i
< ocm_count
; i
++) {
320 ocm
= ocm_get_node(i
);
322 if (!ocm
|| !ocm
->ready
)
325 if (flags
== PPC4XX_OCM_NON_CACHED
)
333 if (align
< ocm
->alignment
)
334 align
= ocm
->alignment
;
336 offset
= rh_alloc_align(ocm_reg
->rh
, size
, align
, NULL
);
338 if (IS_ERR_VALUE(offset
))
341 ocm_blk
= kzalloc(sizeof(struct ocm_block
*), GFP_KERNEL
);
343 printk(KERN_ERR
"PPC4XX OCM: could not allocate ocm block");
344 rh_free(ocm_reg
->rh
, offset
);
348 *phys
= ocm_reg
->phys
+ offset
;
349 addr
= ocm_reg
->virt
+ offset
;
350 size
= ALIGN(size
, align
);
352 ocm_blk
->addr
= addr
;
353 ocm_blk
->size
= size
;
354 ocm_blk
->owner
= owner
;
355 list_add_tail(&ocm_blk
->list
, &ocm_reg
->list
);
357 ocm_reg
->memfree
-= size
;
365 void ppc4xx_ocm_free(const void *addr
)
372 for (i
= 0; i
< ocm_count
; i
++) {
373 struct ocm_info
*ocm
= ocm_get_node(i
);
375 if (!ocm
|| !ocm
->ready
)
378 if (ocm_free_region(&ocm
->nc
, addr
) ||
379 ocm_free_region(&ocm
->c
, addr
))
384 static int __init
ppc4xx_ocm_init(void)
386 struct device_node
*np
;
390 for_each_compatible_node(np
, NULL
, "ibm,ocm")
396 ocm_nodes
= kzalloc((count
* sizeof(struct ocm_info
)), GFP_KERNEL
);
398 printk(KERN_ERR
"PPC4XX OCM: failed to allocate OCM nodes!\n");
405 for_each_compatible_node(np
, NULL
, "ibm,ocm") {
406 ocm_init_node(count
, np
);
415 arch_initcall(ppc4xx_ocm_init
);