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 <linux/of_address.h>
30 #include <asm/rheap.h>
31 #include <asm/ppc4xx_ocm.h>
32 #include <linux/slab.h>
33 #include <linux/debugfs.h>
35 #define OCM_DISABLED 0
39 struct list_head list
;
45 /* non-cached or cached region */
54 struct list_head list
;
68 struct ocm_region nc
; /* non-cached region */
69 struct ocm_region c
; /* cached region */
72 static struct ocm_info
*ocm_nodes
;
75 static struct ocm_info
*ocm_get_node(unsigned int index
)
77 if (index
>= ocm_count
) {
78 printk(KERN_ERR
"PPC4XX OCM: invalid index");
82 return &ocm_nodes
[index
];
85 static int ocm_free_region(struct ocm_region
*ocm_reg
, const void *addr
)
87 struct ocm_block
*blk
, *tmp
;
93 list_for_each_entry_safe(blk
, tmp
, &ocm_reg
->list
, list
) {
94 if (blk
->addr
== addr
) {
95 offset
= addr
- ocm_reg
->virt
;
96 ocm_reg
->memfree
+= blk
->size
;
97 rh_free(ocm_reg
->rh
, offset
);
107 static void __init
ocm_init_node(int count
, struct device_node
*node
)
109 struct ocm_info
*ocm
;
111 const unsigned int *cell_index
;
112 const unsigned int *cache_size
;
115 struct resource rsrc
;
118 ocm
= ocm_get_node(count
);
120 cell_index
= of_get_property(node
, "cell-index", &len
);
122 printk(KERN_ERR
"PPC4XX OCM: missing cell-index property");
125 ocm
->index
= *cell_index
;
127 if (of_device_is_available(node
))
128 ocm
->status
= OCM_ENABLED
;
130 cache_size
= of_get_property(node
, "cached-region-size", &len
);
132 ocm
->cache_size
= *cache_size
;
134 if (of_address_to_resource(node
, 0, &rsrc
)) {
135 printk(KERN_ERR
"PPC4XX OCM%d: could not get resource address\n",
140 ocm
->phys
= rsrc
.start
;
141 ocm
->memtotal
= (rsrc
.end
- rsrc
.start
+ 1);
143 printk(KERN_INFO
"PPC4XX OCM%d: %d Bytes (%s)\n",
144 ocm
->index
, ocm
->memtotal
,
145 (ocm
->status
== OCM_DISABLED
) ? "disabled" : "enabled");
147 if (ocm
->status
== OCM_DISABLED
)
152 if (!request_mem_region(ocm
->phys
, ocm
->memtotal
, "ppc4xx_ocm")) {
153 printk(KERN_ERR
"PPC4XX OCM%d: could not request region\n",
158 /* Configure non-cached and cached regions */
160 ocm
->nc
.phys
= ocm
->phys
;
161 ocm
->nc
.memtotal
= ocm
->memtotal
- ocm
->cache_size
;
162 ocm
->nc
.memfree
= ocm
->nc
.memtotal
;
164 ocm
->c
.phys
= ocm
->phys
+ ocm
->nc
.memtotal
;
165 ocm
->c
.memtotal
= ocm
->cache_size
;
166 ocm
->c
.memfree
= ocm
->c
.memtotal
;
168 if (ocm
->nc
.memtotal
== 0)
171 if (ocm
->c
.memtotal
== 0)
174 printk(KERN_INFO
"PPC4XX OCM%d: %d Bytes (non-cached)\n",
175 ocm
->index
, ocm
->nc
.memtotal
);
177 printk(KERN_INFO
"PPC4XX OCM%d: %d Bytes (cached)\n",
178 ocm
->index
, ocm
->c
.memtotal
);
180 /* ioremap the non-cached region */
181 if (ocm
->nc
.memtotal
) {
182 ioflags
= _PAGE_NO_CACHE
| _PAGE_GUARDED
| _PAGE_EXEC
;
183 ocm
->nc
.virt
= __ioremap(ocm
->nc
.phys
, ocm
->nc
.memtotal
,
188 "PPC4XX OCM%d: failed to ioremap non-cached memory\n",
195 /* ioremap the cached region */
197 if (ocm
->c
.memtotal
) {
198 ioflags
= _PAGE_EXEC
;
199 ocm
->c
.virt
= __ioremap(ocm
->c
.phys
, ocm
->c
.memtotal
,
204 "PPC4XX OCM%d: failed to ioremap cached memory\n",
211 /* Create Remote Heaps */
213 ocm
->alignment
= 4; /* default 4 byte alignment */
216 ocm
->nc
.rh
= rh_create(ocm
->alignment
);
217 rh_attach_region(ocm
->nc
.rh
, 0, ocm
->nc
.memtotal
);
221 ocm
->c
.rh
= rh_create(ocm
->alignment
);
222 rh_attach_region(ocm
->c
.rh
, 0, ocm
->c
.memtotal
);
225 INIT_LIST_HEAD(&ocm
->nc
.list
);
226 INIT_LIST_HEAD(&ocm
->c
.list
);
233 static int ocm_debugfs_show(struct seq_file
*m
, void *v
)
235 struct ocm_block
*blk
, *tmp
;
238 for (i
= 0; i
< ocm_count
; i
++) {
239 struct ocm_info
*ocm
= ocm_get_node(i
);
241 if (!ocm
|| !ocm
->ready
)
244 seq_printf(m
, "PPC4XX OCM : %d\n", ocm
->index
);
245 seq_printf(m
, "PhysAddr : 0x%llx\n", ocm
->phys
);
246 seq_printf(m
, "MemTotal : %d Bytes\n", ocm
->memtotal
);
247 seq_printf(m
, "MemTotal(NC) : %d Bytes\n", ocm
->nc
.memtotal
);
248 seq_printf(m
, "MemTotal(C) : %d Bytes\n", ocm
->c
.memtotal
);
252 seq_printf(m
, "NC.PhysAddr : 0x%llx\n", ocm
->nc
.phys
);
253 seq_printf(m
, "NC.VirtAddr : 0x%p\n", ocm
->nc
.virt
);
254 seq_printf(m
, "NC.MemTotal : %d Bytes\n", ocm
->nc
.memtotal
);
255 seq_printf(m
, "NC.MemFree : %d Bytes\n", ocm
->nc
.memfree
);
257 list_for_each_entry_safe(blk
, tmp
, &ocm
->nc
.list
, list
) {
258 seq_printf(m
, "NC.MemUsed : %d Bytes (%s)\n",
259 blk
->size
, blk
->owner
);
264 seq_printf(m
, "C.PhysAddr : 0x%llx\n", ocm
->c
.phys
);
265 seq_printf(m
, "C.VirtAddr : 0x%p\n", ocm
->c
.virt
);
266 seq_printf(m
, "C.MemTotal : %d Bytes\n", ocm
->c
.memtotal
);
267 seq_printf(m
, "C.MemFree : %d Bytes\n", ocm
->c
.memfree
);
269 list_for_each_entry_safe(blk
, tmp
, &ocm
->c
.list
, list
) {
270 seq_printf(m
, "C.MemUsed : %d Bytes (%s)\n",
271 blk
->size
, blk
->owner
);
280 static int ocm_debugfs_open(struct inode
*inode
, struct file
*file
)
282 return single_open(file
, ocm_debugfs_show
, NULL
);
285 static const struct file_operations ocm_debugfs_fops
= {
286 .open
= ocm_debugfs_open
,
289 .release
= single_release
,
292 static int ocm_debugfs_init(void)
296 junk
= debugfs_create_dir("ppc4xx_ocm", 0);
298 printk(KERN_ALERT
"debugfs ppc4xx ocm: failed to create dir\n");
302 if (debugfs_create_file("info", 0644, junk
, NULL
, &ocm_debugfs_fops
)) {
303 printk(KERN_ALERT
"debugfs ppc4xx ocm: failed to create file\n");
310 void *ppc4xx_ocm_alloc(phys_addr_t
*phys
, int size
, int align
,
311 int flags
, const char *owner
)
313 void __iomem
*addr
= NULL
;
314 unsigned long offset
;
315 struct ocm_info
*ocm
;
316 struct ocm_region
*ocm_reg
;
317 struct ocm_block
*ocm_blk
;
320 for (i
= 0; i
< ocm_count
; i
++) {
321 ocm
= ocm_get_node(i
);
323 if (!ocm
|| !ocm
->ready
)
326 if (flags
== PPC4XX_OCM_NON_CACHED
)
334 if (align
< ocm
->alignment
)
335 align
= ocm
->alignment
;
337 offset
= rh_alloc_align(ocm_reg
->rh
, size
, align
, NULL
);
339 if (IS_ERR_VALUE(offset
))
342 ocm_blk
= kzalloc(sizeof(struct ocm_block
), GFP_KERNEL
);
344 printk(KERN_ERR
"PPC4XX OCM: could not allocate ocm block");
345 rh_free(ocm_reg
->rh
, offset
);
349 *phys
= ocm_reg
->phys
+ offset
;
350 addr
= ocm_reg
->virt
+ offset
;
351 size
= ALIGN(size
, align
);
353 ocm_blk
->addr
= addr
;
354 ocm_blk
->size
= size
;
355 ocm_blk
->owner
= owner
;
356 list_add_tail(&ocm_blk
->list
, &ocm_reg
->list
);
358 ocm_reg
->memfree
-= size
;
366 void ppc4xx_ocm_free(const void *addr
)
373 for (i
= 0; i
< ocm_count
; i
++) {
374 struct ocm_info
*ocm
= ocm_get_node(i
);
376 if (!ocm
|| !ocm
->ready
)
379 if (ocm_free_region(&ocm
->nc
, addr
) ||
380 ocm_free_region(&ocm
->c
, addr
))
385 static int __init
ppc4xx_ocm_init(void)
387 struct device_node
*np
;
391 for_each_compatible_node(np
, NULL
, "ibm,ocm")
397 ocm_nodes
= kzalloc((count
* sizeof(struct ocm_info
)), GFP_KERNEL
);
399 printk(KERN_ERR
"PPC4XX OCM: failed to allocate OCM nodes!\n");
406 for_each_compatible_node(np
, NULL
, "ibm,ocm") {
407 ocm_init_node(count
, np
);
416 arch_initcall(ppc4xx_ocm_init
);