blob: 8f82b4c92d07e5a54cf6599feb5083ec4c61eb82 [file] [log] [blame]
Bryan Wu1394f032007-05-06 14:50:22 -07001/*
Robin Getz5e953202008-10-08 17:22:49 +08002 * File: arch/blackfin/mm/sram-alloc.c
Bryan Wu1394f032007-05-06 14:50:22 -07003 * Based on:
4 * Author:
5 *
6 * Created:
Robin Getz5e953202008-10-08 17:22:49 +08007 * Description: SRAM allocator for Blackfin L1 and L2 memory
Bryan Wu1394f032007-05-06 14:50:22 -07008 *
9 * Modified:
Robin Getz5e953202008-10-08 17:22:49 +080010 * Copyright 2004-2008 Analog Devices Inc.
Bryan Wu1394f032007-05-06 14:50:22 -070011 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
Bryan Wu1394f032007-05-06 14:50:22 -070030#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/types.h>
33#include <linux/miscdevice.h>
34#include <linux/ioport.h>
35#include <linux/fcntl.h>
36#include <linux/init.h>
37#include <linux/poll.h>
38#include <linux/proc_fs.h>
39#include <linux/spinlock.h>
40#include <linux/rtc.h>
41#include <asm/blackfin.h>
42#include "blackfin_sram.h"
43
Graf Yang8f658732008-11-18 17:48:22 +080044static DEFINE_PER_CPU(spinlock_t, l1sram_lock) ____cacheline_aligned_in_smp;
45static DEFINE_PER_CPU(spinlock_t, l1_data_sram_lock) ____cacheline_aligned_in_smp;
46static DEFINE_PER_CPU(spinlock_t, l1_inst_sram_lock) ____cacheline_aligned_in_smp;
47static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
Bryan Wu1394f032007-05-06 14:50:22 -070048
49/* the data structure for L1 scratchpad and DATA SRAM */
Sonic Zhang5d481f42008-07-19 14:51:31 +080050struct sram_piece {
Bryan Wu1394f032007-05-06 14:50:22 -070051 void *paddr;
52 int size;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +080053 pid_t pid;
Sonic Zhang5d481f42008-07-19 14:51:31 +080054 struct sram_piece *next;
Bryan Wu1394f032007-05-06 14:50:22 -070055};
56
Graf Yang8f658732008-11-18 17:48:22 +080057static DEFINE_PER_CPU(struct sram_piece, free_l1_ssram_head);
58static DEFINE_PER_CPU(struct sram_piece, used_l1_ssram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070059
60#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +080061static DEFINE_PER_CPU(struct sram_piece, free_l1_data_A_sram_head);
62static DEFINE_PER_CPU(struct sram_piece, used_l1_data_A_sram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070063#endif
64
65#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +080066static DEFINE_PER_CPU(struct sram_piece, free_l1_data_B_sram_head);
67static DEFINE_PER_CPU(struct sram_piece, used_l1_data_B_sram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070068#endif
69
70#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +080071static DEFINE_PER_CPU(struct sram_piece, free_l1_inst_sram_head);
72static DEFINE_PER_CPU(struct sram_piece, used_l1_inst_sram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070073#endif
74
Mike Frysinger07aa7be2008-08-13 16:16:11 +080075#if L2_LENGTH != 0
Sonic Zhang262c3822008-07-19 15:42:41 +080076static struct sram_piece free_l2_sram_head, used_l2_sram_head;
77#endif
78
Sonic Zhang5d481f42008-07-19 14:51:31 +080079static struct kmem_cache *sram_piece_cache;
Bryan Wu1394f032007-05-06 14:50:22 -070080
Sonic Zhang5d481f42008-07-19 14:51:31 +080081/* L1 Scratchpad SRAM initialization function */
82static void __init l1sram_init(void)
83{
Graf Yang8f658732008-11-18 17:48:22 +080084 unsigned int cpu;
85 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
86 per_cpu(free_l1_ssram_head, cpu).next =
87 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
88 if (!per_cpu(free_l1_ssram_head, cpu).next) {
89 printk(KERN_INFO "Fail to initialize Scratchpad data SRAM.\n");
90 return;
91 }
92
93 per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu);
94 per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH;
95 per_cpu(free_l1_ssram_head, cpu).next->pid = 0;
96 per_cpu(free_l1_ssram_head, cpu).next->next = NULL;
97
98 per_cpu(used_l1_ssram_head, cpu).next = NULL;
99
100 /* mutex initialize */
101 spin_lock_init(&per_cpu(l1sram_lock, cpu));
102 printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
103 L1_SCRATCH_LENGTH >> 10);
Sonic Zhang5d481f42008-07-19 14:51:31 +0800104 }
Bryan Wu1394f032007-05-06 14:50:22 -0700105}
106
Sonic Zhang5d481f42008-07-19 14:51:31 +0800107static void __init l1_data_sram_init(void)
Bryan Wu1394f032007-05-06 14:50:22 -0700108{
Graf Yang8f658732008-11-18 17:48:22 +0800109 unsigned int cpu;
Bryan Wu1394f032007-05-06 14:50:22 -0700110#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800111 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
112 per_cpu(free_l1_data_A_sram_head, cpu).next =
113 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
114 if (!per_cpu(free_l1_data_A_sram_head, cpu).next) {
115 printk(KERN_INFO "Fail to initialize L1 Data A SRAM.\n");
116 return;
117 }
118
119 per_cpu(free_l1_data_A_sram_head, cpu).next->paddr =
120 (void *)get_l1_data_a_start_cpu(cpu) + (_ebss_l1 - _sdata_l1);
121 per_cpu(free_l1_data_A_sram_head, cpu).next->size =
122 L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
123 per_cpu(free_l1_data_A_sram_head, cpu).next->pid = 0;
124 per_cpu(free_l1_data_A_sram_head, cpu).next->next = NULL;
125
126 per_cpu(used_l1_data_A_sram_head, cpu).next = NULL;
127
128 printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
129 L1_DATA_A_LENGTH >> 10,
130 per_cpu(free_l1_data_A_sram_head, cpu).next->size >> 10);
Sonic Zhang5d481f42008-07-19 14:51:31 +0800131 }
Bryan Wu1394f032007-05-06 14:50:22 -0700132#endif
133#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800134 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
135 per_cpu(free_l1_data_B_sram_head, cpu).next =
136 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
137 if (!per_cpu(free_l1_data_B_sram_head, cpu).next) {
138 printk(KERN_INFO "Fail to initialize L1 Data B SRAM.\n");
139 return;
140 }
141
142 per_cpu(free_l1_data_B_sram_head, cpu).next->paddr =
143 (void *)get_l1_data_b_start_cpu(cpu) + (_ebss_b_l1 - _sdata_b_l1);
144 per_cpu(free_l1_data_B_sram_head, cpu).next->size =
145 L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
146 per_cpu(free_l1_data_B_sram_head, cpu).next->pid = 0;
147 per_cpu(free_l1_data_B_sram_head, cpu).next->next = NULL;
148
149 per_cpu(used_l1_data_B_sram_head, cpu).next = NULL;
150
151 printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
152 L1_DATA_B_LENGTH >> 10,
153 per_cpu(free_l1_data_B_sram_head, cpu).next->size >> 10);
154 /* mutex initialize */
Sonic Zhang5d481f42008-07-19 14:51:31 +0800155 }
Bryan Wu1394f032007-05-06 14:50:22 -0700156#endif
157
Graf Yang8f658732008-11-18 17:48:22 +0800158#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
159 for (cpu = 0; cpu < num_possible_cpus(); ++cpu)
160 spin_lock_init(&per_cpu(l1_data_sram_lock, cpu));
161#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700162}
163
Sonic Zhang5d481f42008-07-19 14:51:31 +0800164static void __init l1_inst_sram_init(void)
Bryan Wu1394f032007-05-06 14:50:22 -0700165{
166#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800167 unsigned int cpu;
168 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
169 per_cpu(free_l1_inst_sram_head, cpu).next =
170 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
171 if (!per_cpu(free_l1_inst_sram_head, cpu).next) {
172 printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
173 return;
174 }
175
176 per_cpu(free_l1_inst_sram_head, cpu).next->paddr =
177 (void *)get_l1_code_start_cpu(cpu) + (_etext_l1 - _stext_l1);
178 per_cpu(free_l1_inst_sram_head, cpu).next->size =
179 L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
180 per_cpu(free_l1_inst_sram_head, cpu).next->pid = 0;
181 per_cpu(free_l1_inst_sram_head, cpu).next->next = NULL;
182
183 per_cpu(used_l1_inst_sram_head, cpu).next = NULL;
184
185 printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
186 L1_CODE_LENGTH >> 10,
187 per_cpu(free_l1_inst_sram_head, cpu).next->size >> 10);
188
189 /* mutex initialize */
190 spin_lock_init(&per_cpu(l1_inst_sram_lock, cpu));
Sonic Zhang5d481f42008-07-19 14:51:31 +0800191 }
Bryan Wu1394f032007-05-06 14:50:22 -0700192#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700193}
194
Sonic Zhang262c3822008-07-19 15:42:41 +0800195static void __init l2_sram_init(void)
196{
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800197#if L2_LENGTH != 0
Sonic Zhang262c3822008-07-19 15:42:41 +0800198 free_l2_sram_head.next =
199 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
200 if (!free_l2_sram_head.next) {
Graf Yang8f658732008-11-18 17:48:22 +0800201 printk(KERN_INFO "Fail to initialize L2 SRAM.\n");
Sonic Zhang262c3822008-07-19 15:42:41 +0800202 return;
203 }
204
Jie Zhangb2c2f302008-10-28 15:57:49 +0800205 free_l2_sram_head.next->paddr =
206 (void *)L2_START + (_ebss_l2 - _stext_l2);
207 free_l2_sram_head.next->size =
208 L2_LENGTH - (_ebss_l2 - _stext_l2);
Sonic Zhang262c3822008-07-19 15:42:41 +0800209 free_l2_sram_head.next->pid = 0;
210 free_l2_sram_head.next->next = NULL;
211
212 used_l2_sram_head.next = NULL;
213
214 printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n",
215 L2_LENGTH >> 10,
216 free_l2_sram_head.next->size >> 10);
217#endif
218
219 /* mutex initialize */
220 spin_lock_init(&l2_sram_lock);
221}
Graf Yang8f658732008-11-18 17:48:22 +0800222
Sonic Zhang5d481f42008-07-19 14:51:31 +0800223void __init bfin_sram_init(void)
Bryan Wu1394f032007-05-06 14:50:22 -0700224{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800225 sram_piece_cache = kmem_cache_create("sram_piece_cache",
226 sizeof(struct sram_piece),
227 0, SLAB_PANIC, NULL);
Bryan Wu1394f032007-05-06 14:50:22 -0700228
Sonic Zhang5d481f42008-07-19 14:51:31 +0800229 l1sram_init();
230 l1_data_sram_init();
231 l1_inst_sram_init();
Sonic Zhang262c3822008-07-19 15:42:41 +0800232 l2_sram_init();
Sonic Zhang5d481f42008-07-19 14:51:31 +0800233}
234
Sonic Zhang262c3822008-07-19 15:42:41 +0800235/* SRAM allocate function */
236static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800237 struct sram_piece *pused_head)
238{
239 struct sram_piece *pslot, *plast, *pavail;
240
241 if (size <= 0 || !pfree_head || !pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700242 return NULL;
243
244 /* Align the size */
245 size = (size + 3) & ~3;
246
Sonic Zhang5d481f42008-07-19 14:51:31 +0800247 pslot = pfree_head->next;
248 plast = pfree_head;
249
250 /* search an available piece slot */
251 while (pslot != NULL && size > pslot->size) {
252 plast = pslot;
253 pslot = pslot->next;
Bryan Wu1394f032007-05-06 14:50:22 -0700254 }
Sonic Zhang5d481f42008-07-19 14:51:31 +0800255
256 if (!pslot)
Bryan Wu1394f032007-05-06 14:50:22 -0700257 return NULL;
258
Sonic Zhang5d481f42008-07-19 14:51:31 +0800259 if (pslot->size == size) {
260 plast->next = pslot->next;
261 pavail = pslot;
262 } else {
263 pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
264
265 if (!pavail)
266 return NULL;
267
268 pavail->paddr = pslot->paddr;
269 pavail->size = size;
270 pslot->paddr += size;
271 pslot->size -= size;
Bryan Wu1394f032007-05-06 14:50:22 -0700272 }
273
Sonic Zhang5d481f42008-07-19 14:51:31 +0800274 pavail->pid = current->pid;
275
276 pslot = pused_head->next;
277 plast = pused_head;
278
279 /* insert new piece into used piece list !!! */
280 while (pslot != NULL && pavail->paddr < pslot->paddr) {
281 plast = pslot;
282 pslot = pslot->next;
283 }
284
285 pavail->next = pslot;
286 plast->next = pavail;
287
288 return pavail->paddr;
Bryan Wu1394f032007-05-06 14:50:22 -0700289}
290
291/* Allocate the largest available block. */
Sonic Zhang262c3822008-07-19 15:42:41 +0800292static void *_sram_alloc_max(struct sram_piece *pfree_head,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800293 struct sram_piece *pused_head,
Bryan Wu1394f032007-05-06 14:50:22 -0700294 unsigned long *psize)
295{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800296 struct sram_piece *pslot, *pmax;
Bryan Wu1394f032007-05-06 14:50:22 -0700297
Sonic Zhang5d481f42008-07-19 14:51:31 +0800298 if (!pfree_head || !pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700299 return NULL;
Bryan Wu1394f032007-05-06 14:50:22 -0700300
Sonic Zhang5d481f42008-07-19 14:51:31 +0800301 pmax = pslot = pfree_head->next;
302
303 /* search an available piece slot */
304 while (pslot != NULL) {
305 if (pslot->size > pmax->size)
306 pmax = pslot;
307 pslot = pslot->next;
308 }
309
310 if (!pmax)
311 return NULL;
312
313 *psize = pmax->size;
314
Sonic Zhang262c3822008-07-19 15:42:41 +0800315 return _sram_alloc(*psize, pfree_head, pused_head);
Bryan Wu1394f032007-05-06 14:50:22 -0700316}
317
Sonic Zhang262c3822008-07-19 15:42:41 +0800318/* SRAM free function */
319static int _sram_free(const void *addr,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800320 struct sram_piece *pfree_head,
321 struct sram_piece *pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700322{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800323 struct sram_piece *pslot, *plast, *pavail;
Bryan Wu1394f032007-05-06 14:50:22 -0700324
Sonic Zhang5d481f42008-07-19 14:51:31 +0800325 if (!pfree_head || !pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700326 return -1;
327
Sonic Zhang5d481f42008-07-19 14:51:31 +0800328 /* search the relevant memory slot */
329 pslot = pused_head->next;
330 plast = pused_head;
Bryan Wu1394f032007-05-06 14:50:22 -0700331
Sonic Zhang5d481f42008-07-19 14:51:31 +0800332 /* search an available piece slot */
333 while (pslot != NULL && pslot->paddr != addr) {
334 plast = pslot;
335 pslot = pslot->next;
Bryan Wu1394f032007-05-06 14:50:22 -0700336 }
337
Sonic Zhang5d481f42008-07-19 14:51:31 +0800338 if (!pslot)
339 return -1;
340
341 plast->next = pslot->next;
342 pavail = pslot;
343 pavail->pid = 0;
344
345 /* insert free pieces back to the free list */
346 pslot = pfree_head->next;
347 plast = pfree_head;
348
349 while (pslot != NULL && addr > pslot->paddr) {
350 plast = pslot;
351 pslot = pslot->next;
352 }
353
354 if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
355 plast->size += pavail->size;
356 kmem_cache_free(sram_piece_cache, pavail);
357 } else {
Sonic Zhang225f7e12008-08-25 18:00:45 +0800358 pavail->next = plast->next;
Sonic Zhang5d481f42008-07-19 14:51:31 +0800359 plast->next = pavail;
360 plast = pavail;
361 }
362
363 if (pslot && plast->paddr + plast->size == pslot->paddr) {
364 plast->size += pslot->size;
365 plast->next = pslot->next;
366 kmem_cache_free(sram_piece_cache, pslot);
Bryan Wu1394f032007-05-06 14:50:22 -0700367 }
368
369 return 0;
370}
371
372int sram_free(const void *addr)
373{
Robin Getz5e953202008-10-08 17:22:49 +0800374
Bryan Wu1394f032007-05-06 14:50:22 -0700375#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800376 if (addr >= (void *)get_l1_code_start()
377 && addr < (void *)(get_l1_code_start() + L1_CODE_LENGTH))
Bryan Wu1394f032007-05-06 14:50:22 -0700378 return l1_inst_sram_free(addr);
Robin Getz5e953202008-10-08 17:22:49 +0800379 else
Bryan Wu1394f032007-05-06 14:50:22 -0700380#endif
381#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800382 if (addr >= (void *)get_l1_data_a_start()
383 && addr < (void *)(get_l1_data_a_start() + L1_DATA_A_LENGTH))
Bryan Wu1394f032007-05-06 14:50:22 -0700384 return l1_data_A_sram_free(addr);
Robin Getz5e953202008-10-08 17:22:49 +0800385 else
Bryan Wu1394f032007-05-06 14:50:22 -0700386#endif
387#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800388 if (addr >= (void *)get_l1_data_b_start()
389 && addr < (void *)(get_l1_data_b_start() + L1_DATA_B_LENGTH))
Bryan Wu1394f032007-05-06 14:50:22 -0700390 return l1_data_B_sram_free(addr);
Robin Getz5e953202008-10-08 17:22:49 +0800391 else
Bryan Wu1394f032007-05-06 14:50:22 -0700392#endif
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800393#if L2_LENGTH != 0
Robin Getz5e953202008-10-08 17:22:49 +0800394 if (addr >= (void *)L2_START
Sonic Zhang262c3822008-07-19 15:42:41 +0800395 && addr < (void *)(L2_START + L2_LENGTH))
396 return l2_sram_free(addr);
Bryan Wu1394f032007-05-06 14:50:22 -0700397 else
Robin Getz5e953202008-10-08 17:22:49 +0800398#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700399 return -1;
400}
401EXPORT_SYMBOL(sram_free);
402
403void *l1_data_A_sram_alloc(size_t size)
404{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800405 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700406 void *addr = NULL;
Graf Yang8f658732008-11-18 17:48:22 +0800407 unsigned int cpu;
Bryan Wu1394f032007-05-06 14:50:22 -0700408
Graf Yang8f658732008-11-18 17:48:22 +0800409 cpu = get_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700410 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800411 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700412
413#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800414 addr = _sram_alloc(size, &per_cpu(free_l1_data_A_sram_head, cpu),
415 &per_cpu(used_l1_data_A_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700416#endif
417
418 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800419 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
420 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700421
422 pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
423 (long unsigned int)addr, size);
424
425 return addr;
426}
427EXPORT_SYMBOL(l1_data_A_sram_alloc);
428
429int l1_data_A_sram_free(const void *addr)
430{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800431 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700432 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800433 unsigned int cpu;
Bryan Wu1394f032007-05-06 14:50:22 -0700434
Graf Yang8f658732008-11-18 17:48:22 +0800435 cpu = get_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700436 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800437 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700438
439#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800440 ret = _sram_free(addr, &per_cpu(free_l1_data_A_sram_head, cpu),
441 &per_cpu(used_l1_data_A_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700442#else
443 ret = -1;
444#endif
445
446 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800447 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
448 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700449
450 return ret;
451}
452EXPORT_SYMBOL(l1_data_A_sram_free);
453
454void *l1_data_B_sram_alloc(size_t size)
455{
456#if L1_DATA_B_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800457 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700458 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800459 unsigned int cpu;
460
461 cpu = get_cpu();
462 /* add mutex operation */
463 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
464
465 addr = _sram_alloc(size, &per_cpu(free_l1_data_B_sram_head, cpu),
466 &per_cpu(used_l1_data_B_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700467
468 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800469 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
470 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700471
472 pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
473 (long unsigned int)addr, size);
474
475 return addr;
476#else
477 return NULL;
478#endif
479}
480EXPORT_SYMBOL(l1_data_B_sram_alloc);
481
482int l1_data_B_sram_free(const void *addr)
483{
484#if L1_DATA_B_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800485 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700486 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800487 unsigned int cpu;
488
489 cpu = get_cpu();
490 /* add mutex operation */
491 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
492
493 ret = _sram_free(addr, &per_cpu(free_l1_data_B_sram_head, cpu),
494 &per_cpu(used_l1_data_B_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700495
496 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800497 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
498 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700499
500 return ret;
501#else
502 return -1;
503#endif
504}
505EXPORT_SYMBOL(l1_data_B_sram_free);
506
507void *l1_data_sram_alloc(size_t size)
508{
509 void *addr = l1_data_A_sram_alloc(size);
510
511 if (!addr)
512 addr = l1_data_B_sram_alloc(size);
513
514 return addr;
515}
516EXPORT_SYMBOL(l1_data_sram_alloc);
517
518void *l1_data_sram_zalloc(size_t size)
519{
520 void *addr = l1_data_sram_alloc(size);
521
522 if (addr)
523 memset(addr, 0x00, size);
524
525 return addr;
526}
527EXPORT_SYMBOL(l1_data_sram_zalloc);
528
529int l1_data_sram_free(const void *addr)
530{
531 int ret;
532 ret = l1_data_A_sram_free(addr);
533 if (ret == -1)
534 ret = l1_data_B_sram_free(addr);
535 return ret;
536}
537EXPORT_SYMBOL(l1_data_sram_free);
538
539void *l1_inst_sram_alloc(size_t size)
540{
Meihui Fanc5b50df2008-04-23 08:55:26 +0800541#if L1_CODE_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800542 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700543 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800544 unsigned int cpu;
545
546 cpu = get_cpu();
547 /* add mutex operation */
548 spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
549
550 addr = _sram_alloc(size, &per_cpu(free_l1_inst_sram_head, cpu),
551 &per_cpu(used_l1_inst_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700552
553 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800554 spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
555 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700556
557 pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
558 (long unsigned int)addr, size);
559
560 return addr;
561#else
562 return NULL;
563#endif
564}
565EXPORT_SYMBOL(l1_inst_sram_alloc);
566
567int l1_inst_sram_free(const void *addr)
568{
569#if L1_CODE_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800570 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700571 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800572 unsigned int cpu;
573
574 cpu = get_cpu();
575 /* add mutex operation */
576 spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
577
578 ret = _sram_free(addr, &per_cpu(free_l1_inst_sram_head, cpu),
579 &per_cpu(used_l1_inst_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700580
581 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800582 spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
583 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700584
585 return ret;
586#else
587 return -1;
588#endif
589}
590EXPORT_SYMBOL(l1_inst_sram_free);
591
592/* L1 Scratchpad memory allocate function */
593void *l1sram_alloc(size_t size)
594{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800595 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700596 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800597 unsigned int cpu;
598
599 cpu = get_cpu();
600 /* add mutex operation */
601 spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
602
603 addr = _sram_alloc(size, &per_cpu(free_l1_ssram_head, cpu),
604 &per_cpu(used_l1_ssram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700605
606 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800607 spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
608 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700609
610 return addr;
611}
612
613/* L1 Scratchpad memory allocate function */
614void *l1sram_alloc_max(size_t *psize)
615{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800616 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700617 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800618 unsigned int cpu;
619
620 cpu = get_cpu();
621 /* add mutex operation */
622 spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
623
624 addr = _sram_alloc_max(&per_cpu(free_l1_ssram_head, cpu),
625 &per_cpu(used_l1_ssram_head, cpu), psize);
Bryan Wu1394f032007-05-06 14:50:22 -0700626
627 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800628 spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
629 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700630
631 return addr;
632}
633
634/* L1 Scratchpad memory free function */
635int l1sram_free(const void *addr)
636{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800637 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700638 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800639 unsigned int cpu;
640
641 cpu = get_cpu();
642 /* add mutex operation */
643 spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
644
645 ret = _sram_free(addr, &per_cpu(free_l1_ssram_head, cpu),
646 &per_cpu(used_l1_ssram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700647
648 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800649 spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
650 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700651
652 return ret;
653}
654
Sonic Zhang262c3822008-07-19 15:42:41 +0800655void *l2_sram_alloc(size_t size)
656{
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800657#if L2_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800658 unsigned long flags;
Sonic Zhang262c3822008-07-19 15:42:41 +0800659 void *addr;
660
661 /* add mutex operation */
662 spin_lock_irqsave(&l2_sram_lock, flags);
663
664 addr = _sram_alloc(size, &free_l2_sram_head,
665 &used_l2_sram_head);
666
667 /* add mutex operation */
668 spin_unlock_irqrestore(&l2_sram_lock, flags);
669
670 pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n",
671 (long unsigned int)addr, size);
672
673 return addr;
674#else
675 return NULL;
676#endif
677}
678EXPORT_SYMBOL(l2_sram_alloc);
679
680void *l2_sram_zalloc(size_t size)
681{
682 void *addr = l2_sram_alloc(size);
683
684 if (addr)
685 memset(addr, 0x00, size);
686
687 return addr;
688}
689EXPORT_SYMBOL(l2_sram_zalloc);
690
691int l2_sram_free(const void *addr)
692{
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800693#if L2_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800694 unsigned long flags;
Sonic Zhang262c3822008-07-19 15:42:41 +0800695 int ret;
696
697 /* add mutex operation */
698 spin_lock_irqsave(&l2_sram_lock, flags);
699
700 ret = _sram_free(addr, &free_l2_sram_head,
701 &used_l2_sram_head);
702
703 /* add mutex operation */
704 spin_unlock_irqrestore(&l2_sram_lock, flags);
705
706 return ret;
707#else
708 return -1;
709#endif
710}
711EXPORT_SYMBOL(l2_sram_free);
712
Bryan Wu1394f032007-05-06 14:50:22 -0700713int sram_free_with_lsl(const void *addr)
714{
715 struct sram_list_struct *lsl, **tmp;
716 struct mm_struct *mm = current->mm;
717
718 for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
719 if ((*tmp)->addr == addr)
720 goto found;
721 return -1;
722found:
723 lsl = *tmp;
724 sram_free(addr);
725 *tmp = lsl->next;
726 kfree(lsl);
727
728 return 0;
729}
730EXPORT_SYMBOL(sram_free_with_lsl);
731
732void *sram_alloc_with_lsl(size_t size, unsigned long flags)
733{
734 void *addr = NULL;
735 struct sram_list_struct *lsl = NULL;
736 struct mm_struct *mm = current->mm;
737
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700738 lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
Bryan Wu1394f032007-05-06 14:50:22 -0700739 if (!lsl)
740 return NULL;
Bryan Wu1394f032007-05-06 14:50:22 -0700741
742 if (flags & L1_INST_SRAM)
743 addr = l1_inst_sram_alloc(size);
744
745 if (addr == NULL && (flags & L1_DATA_A_SRAM))
746 addr = l1_data_A_sram_alloc(size);
747
748 if (addr == NULL && (flags & L1_DATA_B_SRAM))
749 addr = l1_data_B_sram_alloc(size);
750
Sonic Zhang262c3822008-07-19 15:42:41 +0800751 if (addr == NULL && (flags & L2_SRAM))
752 addr = l2_sram_alloc(size);
753
Bryan Wu1394f032007-05-06 14:50:22 -0700754 if (addr == NULL) {
755 kfree(lsl);
756 return NULL;
757 }
758 lsl->addr = addr;
759 lsl->length = size;
760 lsl->next = mm->context.sram_list;
761 mm->context.sram_list = lsl;
762 return addr;
763}
764EXPORT_SYMBOL(sram_alloc_with_lsl);
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800765
766#ifdef CONFIG_PROC_FS
767/* Once we get a real allocator, we'll throw all of this away.
768 * Until then, we need some sort of visibility into the L1 alloc.
769 */
Mike Frysinger260d5d32008-07-14 16:34:05 +0800770/* Need to keep line of output the same. Currently, that is 44 bytes
771 * (including newline).
772 */
Sonic Zhang262c3822008-07-19 15:42:41 +0800773static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800774 struct sram_piece *pfree_head,
775 struct sram_piece *pused_head)
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800776{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800777 struct sram_piece *pslot;
778
779 if (!pfree_head || !pused_head)
780 return -1;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800781
Sonic Zhang262c3822008-07-19 15:42:41 +0800782 *len += sprintf(&buf[*len], "--- SRAM %-14s Size PID State \n", desc);
Sonic Zhang5d481f42008-07-19 14:51:31 +0800783
784 /* search the relevant memory slot */
785 pslot = pused_head->next;
786
787 while (pslot != NULL) {
Sonic Zhang262c3822008-07-19 15:42:41 +0800788 *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
Sonic Zhang5d481f42008-07-19 14:51:31 +0800789 pslot->paddr, pslot->paddr + pslot->size,
790 pslot->size, pslot->pid, "ALLOCATED");
791
792 pslot = pslot->next;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800793 }
Sonic Zhang5d481f42008-07-19 14:51:31 +0800794
795 pslot = pfree_head->next;
796
797 while (pslot != NULL) {
Sonic Zhang262c3822008-07-19 15:42:41 +0800798 *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
Sonic Zhang5d481f42008-07-19 14:51:31 +0800799 pslot->paddr, pslot->paddr + pslot->size,
800 pslot->size, pslot->pid, "FREE");
801
802 pslot = pslot->next;
803 }
804
805 return 0;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800806}
Sonic Zhang262c3822008-07-19 15:42:41 +0800807static int sram_proc_read(char *buf, char **start, off_t offset, int count,
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800808 int *eof, void *data)
809{
810 int len = 0;
Graf Yang8f658732008-11-18 17:48:22 +0800811 unsigned int cpu;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800812
Graf Yang8f658732008-11-18 17:48:22 +0800813 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
814 if (_sram_proc_read(buf, &len, count, "Scratchpad",
815 &per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
816 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800817#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800818 if (_sram_proc_read(buf, &len, count, "L1 Data A",
819 &per_cpu(free_l1_data_A_sram_head, cpu),
820 &per_cpu(used_l1_data_A_sram_head, cpu)))
821 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800822#endif
823#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800824 if (_sram_proc_read(buf, &len, count, "L1 Data B",
825 &per_cpu(free_l1_data_B_sram_head, cpu),
826 &per_cpu(used_l1_data_B_sram_head, cpu)))
827 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800828#endif
829#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800830 if (_sram_proc_read(buf, &len, count, "L1 Instruction",
831 &per_cpu(free_l1_inst_sram_head, cpu),
832 &per_cpu(used_l1_inst_sram_head, cpu)))
833 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800834#endif
Graf Yang8f658732008-11-18 17:48:22 +0800835 }
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800836#if L2_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800837 if (_sram_proc_read(buf, &len, count, "L2", &free_l2_sram_head,
838 &used_l2_sram_head))
Sonic Zhang262c3822008-07-19 15:42:41 +0800839 goto not_done;
840#endif
Mike Frysinger260d5d32008-07-14 16:34:05 +0800841 *eof = 1;
842 not_done:
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800843 return len;
844}
845
Sonic Zhang262c3822008-07-19 15:42:41 +0800846static int __init sram_proc_init(void)
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800847{
848 struct proc_dir_entry *ptr;
849 ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
850 if (!ptr) {
851 printk(KERN_WARNING "unable to create /proc/sram\n");
852 return -1;
853 }
854 ptr->owner = THIS_MODULE;
Sonic Zhang262c3822008-07-19 15:42:41 +0800855 ptr->read_proc = sram_proc_read;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800856 return 0;
857}
Sonic Zhang262c3822008-07-19 15:42:41 +0800858late_initcall(sram_proc_init);
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800859#endif