• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * PowerPC 4xx OCM memory allocation support
3  *
4  * (C) Copyright 2009, Applied Micro Circuits Corporation
5  * Victor Gallardo (vgallardo@amcc.com)
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
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.
14  *
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.
19  *
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,
23  * MA 02111-1307 USA
24  */
25 
26 #include <linux/kernel.h>
27 #include <linux/dma-mapping.h>
28 #include <linux/of.h>
29 #include <asm/rheap.h>
30 #include <asm/ppc4xx_ocm.h>
31 #include <linux/slab.h>
32 #include <linux/debugfs.h>
33 
34 #define OCM_DISABLED	0
35 #define OCM_ENABLED		1
36 
37 struct ocm_block {
38 	struct list_head	list;
39 	void __iomem		*addr;
40 	int					size;
41 	const char			*owner;
42 };
43 
44 /* non-cached or cached region */
45 struct ocm_region {
46 	phys_addr_t			phys;
47 	void __iomem		*virt;
48 
49 	int					memtotal;
50 	int					memfree;
51 
52 	rh_info_t			*rh;
53 	struct list_head	list;
54 };
55 
56 struct ocm_info {
57 	int					index;
58 	int					status;
59 	int					ready;
60 
61 	phys_addr_t			phys;
62 
63 	int					alignment;
64 	int					memtotal;
65 	int					cache_size;
66 
67 	struct ocm_region	nc;	/* non-cached region */
68 	struct ocm_region	c;	/* cached region */
69 };
70 
71 static struct ocm_info *ocm_nodes;
72 static int ocm_count;
73 
ocm_get_node(unsigned int index)74 static struct ocm_info *ocm_get_node(unsigned int index)
75 {
76 	if (index >= ocm_count) {
77 		printk(KERN_ERR "PPC4XX OCM: invalid index");
78 		return NULL;
79 	}
80 
81 	return &ocm_nodes[index];
82 }
83 
ocm_free_region(struct ocm_region * ocm_reg,const void * addr)84 static int ocm_free_region(struct ocm_region *ocm_reg, const void *addr)
85 {
86 	struct ocm_block *blk, *tmp;
87 	unsigned long offset;
88 
89 	if (!ocm_reg->virt)
90 		return 0;
91 
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);
97 			list_del(&blk->list);
98 			kfree(blk);
99 			return 1;
100 		}
101 	}
102 
103 	return 0;
104 }
105 
ocm_init_node(int count,struct device_node * node)106 static void __init ocm_init_node(int count, struct device_node *node)
107 {
108 	struct ocm_info *ocm;
109 
110 	const unsigned int *cell_index;
111 	const unsigned int *cache_size;
112 	int len;
113 
114 	struct resource rsrc;
115 	int ioflags;
116 
117 	ocm = ocm_get_node(count);
118 
119 	cell_index = of_get_property(node, "cell-index", &len);
120 	if (!cell_index) {
121 		printk(KERN_ERR "PPC4XX OCM: missing cell-index property");
122 		return;
123 	}
124 	ocm->index = *cell_index;
125 
126 	if (of_device_is_available(node))
127 		ocm->status = OCM_ENABLED;
128 
129 	cache_size = of_get_property(node, "cached-region-size", &len);
130 	if (cache_size)
131 		ocm->cache_size = *cache_size;
132 
133 	if (of_address_to_resource(node, 0, &rsrc)) {
134 		printk(KERN_ERR "PPC4XX OCM%d: could not get resource address\n",
135 			ocm->index);
136 		return;
137 	}
138 
139 	ocm->phys = rsrc.start;
140 	ocm->memtotal = (rsrc.end - rsrc.start + 1);
141 
142 	printk(KERN_INFO "PPC4XX OCM%d: %d Bytes (%s)\n",
143 		ocm->index, ocm->memtotal,
144 		(ocm->status == OCM_DISABLED) ? "disabled" : "enabled");
145 
146 	if (ocm->status == OCM_DISABLED)
147 		return;
148 
149 	/* request region */
150 
151 	if (!request_mem_region(ocm->phys, ocm->memtotal, "ppc4xx_ocm")) {
152 		printk(KERN_ERR "PPC4XX OCM%d: could not request region\n",
153 			ocm->index);
154 		return;
155 	}
156 
157 	/* Configure non-cached and cached regions */
158 
159 	ocm->nc.phys = ocm->phys;
160 	ocm->nc.memtotal = ocm->memtotal - ocm->cache_size;
161 	ocm->nc.memfree = ocm->nc.memtotal;
162 
163 	ocm->c.phys = ocm->phys + ocm->nc.memtotal;
164 	ocm->c.memtotal = ocm->cache_size;
165 	ocm->c.memfree = ocm->c.memtotal;
166 
167 	if (ocm->nc.memtotal == 0)
168 		ocm->nc.phys = 0;
169 
170 	if (ocm->c.memtotal == 0)
171 		ocm->c.phys = 0;
172 
173 	printk(KERN_INFO "PPC4XX OCM%d: %d Bytes (non-cached)\n",
174 		ocm->index, ocm->nc.memtotal);
175 
176 	printk(KERN_INFO "PPC4XX OCM%d: %d Bytes (cached)\n",
177 		ocm->index, ocm->c.memtotal);
178 
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,
183 					  ioflags);
184 
185 		if (!ocm->nc.virt) {
186 			printk(KERN_ERR
187 			       "PPC4XX OCM%d: failed to ioremap non-cached memory\n",
188 			       ocm->index);
189 			ocm->nc.memfree = 0;
190 			return;
191 		}
192 	}
193 
194 	/* ioremap the cached region */
195 
196 	if (ocm->c.memtotal) {
197 		ioflags = _PAGE_EXEC;
198 		ocm->c.virt = __ioremap(ocm->c.phys, ocm->c.memtotal,
199 					 ioflags);
200 
201 		if (!ocm->c.virt) {
202 			printk(KERN_ERR
203 			       "PPC4XX OCM%d: failed to ioremap cached memory\n",
204 			       ocm->index);
205 			ocm->c.memfree = 0;
206 			return;
207 		}
208 	}
209 
210 	/* Create Remote Heaps */
211 
212 	ocm->alignment = 4; /* default 4 byte alignment */
213 
214 	if (ocm->nc.virt) {
215 		ocm->nc.rh = rh_create(ocm->alignment);
216 		rh_attach_region(ocm->nc.rh, 0, ocm->nc.memtotal);
217 	}
218 
219 	if (ocm->c.virt) {
220 		ocm->c.rh = rh_create(ocm->alignment);
221 		rh_attach_region(ocm->c.rh, 0, ocm->c.memtotal);
222 	}
223 
224 	INIT_LIST_HEAD(&ocm->nc.list);
225 	INIT_LIST_HEAD(&ocm->c.list);
226 
227 	ocm->ready = 1;
228 
229 	return;
230 }
231 
ocm_debugfs_show(struct seq_file * m,void * v)232 static int ocm_debugfs_show(struct seq_file *m, void *v)
233 {
234 	struct ocm_block *blk, *tmp;
235 	unsigned int i;
236 
237 	for (i = 0; i < ocm_count; i++) {
238 		struct ocm_info *ocm = ocm_get_node(i);
239 
240 		if (!ocm || !ocm->ready)
241 			continue;
242 
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);
248 
249 		seq_printf(m, "\n");
250 
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);
255 
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);
259 		}
260 
261 		seq_printf(m, "\n");
262 
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);
267 
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);
271 		}
272 
273 		seq_printf(m, "\n");
274 	}
275 
276 	return 0;
277 }
278 
ocm_debugfs_open(struct inode * inode,struct file * file)279 static int ocm_debugfs_open(struct inode *inode, struct file *file)
280 {
281 	return single_open(file, ocm_debugfs_show, NULL);
282 }
283 
284 static const struct file_operations ocm_debugfs_fops = {
285 	.open = ocm_debugfs_open,
286 	.read = seq_read,
287 	.llseek = seq_lseek,
288 	.release = single_release,
289 };
290 
ocm_debugfs_init(void)291 static int ocm_debugfs_init(void)
292 {
293 	struct dentry *junk;
294 
295 	junk = debugfs_create_dir("ppc4xx_ocm", 0);
296 	if (!junk) {
297 		printk(KERN_ALERT "debugfs ppc4xx ocm: failed to create dir\n");
298 		return -1;
299 	}
300 
301 	if (debugfs_create_file("info", 0644, junk, NULL, &ocm_debugfs_fops)) {
302 		printk(KERN_ALERT "debugfs ppc4xx ocm: failed to create file\n");
303 		return -1;
304 	}
305 
306 	return 0;
307 }
308 
ppc4xx_ocm_alloc(phys_addr_t * phys,int size,int align,int flags,const char * owner)309 void *ppc4xx_ocm_alloc(phys_addr_t *phys, int size, int align,
310 			int flags, const char *owner)
311 {
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;
317 	int i;
318 
319 	for (i = 0; i < ocm_count; i++) {
320 		ocm = ocm_get_node(i);
321 
322 		if (!ocm || !ocm->ready)
323 			continue;
324 
325 		if (flags == PPC4XX_OCM_NON_CACHED)
326 			ocm_reg = &ocm->nc;
327 		else
328 			ocm_reg = &ocm->c;
329 
330 		if (!ocm_reg->virt)
331 			continue;
332 
333 		if (align < ocm->alignment)
334 			align = ocm->alignment;
335 
336 		offset = rh_alloc_align(ocm_reg->rh, size, align, NULL);
337 
338 		if (IS_ERR_VALUE(offset))
339 			continue;
340 
341 		ocm_blk = kzalloc(sizeof(struct ocm_block *), GFP_KERNEL);
342 		if (!ocm_blk) {
343 			printk(KERN_ERR "PPC4XX OCM: could not allocate ocm block");
344 			rh_free(ocm_reg->rh, offset);
345 			break;
346 		}
347 
348 		*phys = ocm_reg->phys + offset;
349 		addr = ocm_reg->virt + offset;
350 		size = ALIGN(size, align);
351 
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);
356 
357 		ocm_reg->memfree -= size;
358 
359 		break;
360 	}
361 
362 	return addr;
363 }
364 
ppc4xx_ocm_free(const void * addr)365 void ppc4xx_ocm_free(const void *addr)
366 {
367 	int i;
368 
369 	if (!addr)
370 		return;
371 
372 	for (i = 0; i < ocm_count; i++) {
373 		struct ocm_info *ocm = ocm_get_node(i);
374 
375 		if (!ocm || !ocm->ready)
376 			continue;
377 
378 		if (ocm_free_region(&ocm->nc, addr) ||
379 			ocm_free_region(&ocm->c, addr))
380 			return;
381 	}
382 }
383 
ppc4xx_ocm_init(void)384 static int __init ppc4xx_ocm_init(void)
385 {
386 	struct device_node *np;
387 	int count;
388 
389 	count = 0;
390 	for_each_compatible_node(np, NULL, "ibm,ocm")
391 		count++;
392 
393 	if (!count)
394 		return 0;
395 
396 	ocm_nodes = kzalloc((count * sizeof(struct ocm_info)), GFP_KERNEL);
397 	if (!ocm_nodes) {
398 		printk(KERN_ERR "PPC4XX OCM: failed to allocate OCM nodes!\n");
399 		return -ENOMEM;
400 	}
401 
402 	ocm_count = count;
403 	count = 0;
404 
405 	for_each_compatible_node(np, NULL, "ibm,ocm") {
406 		ocm_init_node(count, np);
407 		count++;
408 	}
409 
410 	ocm_debugfs_init();
411 
412 	return 0;
413 }
414 
415 arch_initcall(ppc4xx_ocm_init);
416