blob: 36376d8418fa807ce24aaa9305e2096d7b861413 [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>
Graf Yangdbc895f2009-01-07 23:14:39 +080042#include <asm/mem_map.h>
Bryan Wu1394f032007-05-06 14:50:22 -070043#include "blackfin_sram.h"
44
Graf Yang8f658732008-11-18 17:48:22 +080045static DEFINE_PER_CPU(spinlock_t, l1sram_lock) ____cacheline_aligned_in_smp;
46static DEFINE_PER_CPU(spinlock_t, l1_data_sram_lock) ____cacheline_aligned_in_smp;
47static DEFINE_PER_CPU(spinlock_t, l1_inst_sram_lock) ____cacheline_aligned_in_smp;
48static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
Bryan Wu1394f032007-05-06 14:50:22 -070049
50/* the data structure for L1 scratchpad and DATA SRAM */
Sonic Zhang5d481f42008-07-19 14:51:31 +080051struct sram_piece {
Bryan Wu1394f032007-05-06 14:50:22 -070052 void *paddr;
53 int size;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +080054 pid_t pid;
Sonic Zhang5d481f42008-07-19 14:51:31 +080055 struct sram_piece *next;
Bryan Wu1394f032007-05-06 14:50:22 -070056};
57
Graf Yang8f658732008-11-18 17:48:22 +080058static DEFINE_PER_CPU(struct sram_piece, free_l1_ssram_head);
59static DEFINE_PER_CPU(struct sram_piece, used_l1_ssram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070060
61#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +080062static DEFINE_PER_CPU(struct sram_piece, free_l1_data_A_sram_head);
63static DEFINE_PER_CPU(struct sram_piece, used_l1_data_A_sram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070064#endif
65
66#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +080067static DEFINE_PER_CPU(struct sram_piece, free_l1_data_B_sram_head);
68static DEFINE_PER_CPU(struct sram_piece, used_l1_data_B_sram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070069#endif
70
71#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +080072static DEFINE_PER_CPU(struct sram_piece, free_l1_inst_sram_head);
73static DEFINE_PER_CPU(struct sram_piece, used_l1_inst_sram_head);
Bryan Wu1394f032007-05-06 14:50:22 -070074#endif
75
Mike Frysinger07aa7be2008-08-13 16:16:11 +080076#if L2_LENGTH != 0
Sonic Zhang262c3822008-07-19 15:42:41 +080077static struct sram_piece free_l2_sram_head, used_l2_sram_head;
78#endif
79
Sonic Zhang5d481f42008-07-19 14:51:31 +080080static struct kmem_cache *sram_piece_cache;
Bryan Wu1394f032007-05-06 14:50:22 -070081
Sonic Zhang5d481f42008-07-19 14:51:31 +080082/* L1 Scratchpad SRAM initialization function */
83static void __init l1sram_init(void)
84{
Graf Yang8f658732008-11-18 17:48:22 +080085 unsigned int cpu;
86 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
87 per_cpu(free_l1_ssram_head, cpu).next =
88 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
89 if (!per_cpu(free_l1_ssram_head, cpu).next) {
90 printk(KERN_INFO "Fail to initialize Scratchpad data SRAM.\n");
91 return;
92 }
93
94 per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu);
95 per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH;
96 per_cpu(free_l1_ssram_head, cpu).next->pid = 0;
97 per_cpu(free_l1_ssram_head, cpu).next->next = NULL;
98
99 per_cpu(used_l1_ssram_head, cpu).next = NULL;
100
101 /* mutex initialize */
102 spin_lock_init(&per_cpu(l1sram_lock, cpu));
103 printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
104 L1_SCRATCH_LENGTH >> 10);
Sonic Zhang5d481f42008-07-19 14:51:31 +0800105 }
Bryan Wu1394f032007-05-06 14:50:22 -0700106}
107
Sonic Zhang5d481f42008-07-19 14:51:31 +0800108static void __init l1_data_sram_init(void)
Bryan Wu1394f032007-05-06 14:50:22 -0700109{
Mike Frysinger0b82e272008-11-18 17:48:22 +0800110#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800111 unsigned int cpu;
Mike Frysinger0b82e272008-11-18 17:48:22 +0800112#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700113#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800114 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
115 per_cpu(free_l1_data_A_sram_head, cpu).next =
116 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
117 if (!per_cpu(free_l1_data_A_sram_head, cpu).next) {
118 printk(KERN_INFO "Fail to initialize L1 Data A SRAM.\n");
119 return;
120 }
121
122 per_cpu(free_l1_data_A_sram_head, cpu).next->paddr =
123 (void *)get_l1_data_a_start_cpu(cpu) + (_ebss_l1 - _sdata_l1);
124 per_cpu(free_l1_data_A_sram_head, cpu).next->size =
125 L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
126 per_cpu(free_l1_data_A_sram_head, cpu).next->pid = 0;
127 per_cpu(free_l1_data_A_sram_head, cpu).next->next = NULL;
128
129 per_cpu(used_l1_data_A_sram_head, cpu).next = NULL;
130
131 printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
132 L1_DATA_A_LENGTH >> 10,
133 per_cpu(free_l1_data_A_sram_head, cpu).next->size >> 10);
Sonic Zhang5d481f42008-07-19 14:51:31 +0800134 }
Bryan Wu1394f032007-05-06 14:50:22 -0700135#endif
136#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800137 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
138 per_cpu(free_l1_data_B_sram_head, cpu).next =
139 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
140 if (!per_cpu(free_l1_data_B_sram_head, cpu).next) {
141 printk(KERN_INFO "Fail to initialize L1 Data B SRAM.\n");
142 return;
143 }
144
145 per_cpu(free_l1_data_B_sram_head, cpu).next->paddr =
146 (void *)get_l1_data_b_start_cpu(cpu) + (_ebss_b_l1 - _sdata_b_l1);
147 per_cpu(free_l1_data_B_sram_head, cpu).next->size =
148 L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
149 per_cpu(free_l1_data_B_sram_head, cpu).next->pid = 0;
150 per_cpu(free_l1_data_B_sram_head, cpu).next->next = NULL;
151
152 per_cpu(used_l1_data_B_sram_head, cpu).next = NULL;
153
154 printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
155 L1_DATA_B_LENGTH >> 10,
156 per_cpu(free_l1_data_B_sram_head, cpu).next->size >> 10);
157 /* mutex initialize */
Sonic Zhang5d481f42008-07-19 14:51:31 +0800158 }
Bryan Wu1394f032007-05-06 14:50:22 -0700159#endif
160
Graf Yang8f658732008-11-18 17:48:22 +0800161#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
162 for (cpu = 0; cpu < num_possible_cpus(); ++cpu)
163 spin_lock_init(&per_cpu(l1_data_sram_lock, cpu));
164#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700165}
166
Sonic Zhang5d481f42008-07-19 14:51:31 +0800167static void __init l1_inst_sram_init(void)
Bryan Wu1394f032007-05-06 14:50:22 -0700168{
169#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800170 unsigned int cpu;
171 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
172 per_cpu(free_l1_inst_sram_head, cpu).next =
173 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
174 if (!per_cpu(free_l1_inst_sram_head, cpu).next) {
175 printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
176 return;
177 }
178
179 per_cpu(free_l1_inst_sram_head, cpu).next->paddr =
180 (void *)get_l1_code_start_cpu(cpu) + (_etext_l1 - _stext_l1);
181 per_cpu(free_l1_inst_sram_head, cpu).next->size =
182 L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
183 per_cpu(free_l1_inst_sram_head, cpu).next->pid = 0;
184 per_cpu(free_l1_inst_sram_head, cpu).next->next = NULL;
185
186 per_cpu(used_l1_inst_sram_head, cpu).next = NULL;
187
188 printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
189 L1_CODE_LENGTH >> 10,
190 per_cpu(free_l1_inst_sram_head, cpu).next->size >> 10);
191
192 /* mutex initialize */
193 spin_lock_init(&per_cpu(l1_inst_sram_lock, cpu));
Sonic Zhang5d481f42008-07-19 14:51:31 +0800194 }
Bryan Wu1394f032007-05-06 14:50:22 -0700195#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700196}
197
Sonic Zhang262c3822008-07-19 15:42:41 +0800198static void __init l2_sram_init(void)
199{
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800200#if L2_LENGTH != 0
Sonic Zhang262c3822008-07-19 15:42:41 +0800201 free_l2_sram_head.next =
202 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
203 if (!free_l2_sram_head.next) {
Graf Yang8f658732008-11-18 17:48:22 +0800204 printk(KERN_INFO "Fail to initialize L2 SRAM.\n");
Sonic Zhang262c3822008-07-19 15:42:41 +0800205 return;
206 }
207
Jie Zhangb2c2f302008-10-28 15:57:49 +0800208 free_l2_sram_head.next->paddr =
209 (void *)L2_START + (_ebss_l2 - _stext_l2);
210 free_l2_sram_head.next->size =
211 L2_LENGTH - (_ebss_l2 - _stext_l2);
Sonic Zhang262c3822008-07-19 15:42:41 +0800212 free_l2_sram_head.next->pid = 0;
213 free_l2_sram_head.next->next = NULL;
214
215 used_l2_sram_head.next = NULL;
216
217 printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n",
218 L2_LENGTH >> 10,
219 free_l2_sram_head.next->size >> 10);
220#endif
221
222 /* mutex initialize */
223 spin_lock_init(&l2_sram_lock);
224}
Graf Yang8f658732008-11-18 17:48:22 +0800225
Graf Yangc72aa072009-05-25 04:44:00 +0000226static int __init bfin_sram_init(void)
Bryan Wu1394f032007-05-06 14:50:22 -0700227{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800228 sram_piece_cache = kmem_cache_create("sram_piece_cache",
229 sizeof(struct sram_piece),
230 0, SLAB_PANIC, NULL);
Bryan Wu1394f032007-05-06 14:50:22 -0700231
Sonic Zhang5d481f42008-07-19 14:51:31 +0800232 l1sram_init();
233 l1_data_sram_init();
234 l1_inst_sram_init();
Sonic Zhang262c3822008-07-19 15:42:41 +0800235 l2_sram_init();
Graf Yangc72aa072009-05-25 04:44:00 +0000236
237 return 0;
Sonic Zhang5d481f42008-07-19 14:51:31 +0800238}
Graf Yangc72aa072009-05-25 04:44:00 +0000239pure_initcall(bfin_sram_init);
Sonic Zhang5d481f42008-07-19 14:51:31 +0800240
Sonic Zhang262c3822008-07-19 15:42:41 +0800241/* SRAM allocate function */
242static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800243 struct sram_piece *pused_head)
244{
245 struct sram_piece *pslot, *plast, *pavail;
246
247 if (size <= 0 || !pfree_head || !pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700248 return NULL;
249
250 /* Align the size */
251 size = (size + 3) & ~3;
252
Sonic Zhang5d481f42008-07-19 14:51:31 +0800253 pslot = pfree_head->next;
254 plast = pfree_head;
255
256 /* search an available piece slot */
257 while (pslot != NULL && size > pslot->size) {
258 plast = pslot;
259 pslot = pslot->next;
Bryan Wu1394f032007-05-06 14:50:22 -0700260 }
Sonic Zhang5d481f42008-07-19 14:51:31 +0800261
262 if (!pslot)
Bryan Wu1394f032007-05-06 14:50:22 -0700263 return NULL;
264
Sonic Zhang5d481f42008-07-19 14:51:31 +0800265 if (pslot->size == size) {
266 plast->next = pslot->next;
267 pavail = pslot;
268 } else {
269 pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
270
271 if (!pavail)
272 return NULL;
273
274 pavail->paddr = pslot->paddr;
275 pavail->size = size;
276 pslot->paddr += size;
277 pslot->size -= size;
Bryan Wu1394f032007-05-06 14:50:22 -0700278 }
279
Sonic Zhang5d481f42008-07-19 14:51:31 +0800280 pavail->pid = current->pid;
281
282 pslot = pused_head->next;
283 plast = pused_head;
284
285 /* insert new piece into used piece list !!! */
286 while (pslot != NULL && pavail->paddr < pslot->paddr) {
287 plast = pslot;
288 pslot = pslot->next;
289 }
290
291 pavail->next = pslot;
292 plast->next = pavail;
293
294 return pavail->paddr;
Bryan Wu1394f032007-05-06 14:50:22 -0700295}
296
297/* Allocate the largest available block. */
Sonic Zhang262c3822008-07-19 15:42:41 +0800298static void *_sram_alloc_max(struct sram_piece *pfree_head,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800299 struct sram_piece *pused_head,
Bryan Wu1394f032007-05-06 14:50:22 -0700300 unsigned long *psize)
301{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800302 struct sram_piece *pslot, *pmax;
Bryan Wu1394f032007-05-06 14:50:22 -0700303
Sonic Zhang5d481f42008-07-19 14:51:31 +0800304 if (!pfree_head || !pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700305 return NULL;
Bryan Wu1394f032007-05-06 14:50:22 -0700306
Sonic Zhang5d481f42008-07-19 14:51:31 +0800307 pmax = pslot = pfree_head->next;
308
309 /* search an available piece slot */
310 while (pslot != NULL) {
311 if (pslot->size > pmax->size)
312 pmax = pslot;
313 pslot = pslot->next;
314 }
315
316 if (!pmax)
317 return NULL;
318
319 *psize = pmax->size;
320
Sonic Zhang262c3822008-07-19 15:42:41 +0800321 return _sram_alloc(*psize, pfree_head, pused_head);
Bryan Wu1394f032007-05-06 14:50:22 -0700322}
323
Sonic Zhang262c3822008-07-19 15:42:41 +0800324/* SRAM free function */
325static int _sram_free(const void *addr,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800326 struct sram_piece *pfree_head,
327 struct sram_piece *pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700328{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800329 struct sram_piece *pslot, *plast, *pavail;
Bryan Wu1394f032007-05-06 14:50:22 -0700330
Sonic Zhang5d481f42008-07-19 14:51:31 +0800331 if (!pfree_head || !pused_head)
Bryan Wu1394f032007-05-06 14:50:22 -0700332 return -1;
333
Sonic Zhang5d481f42008-07-19 14:51:31 +0800334 /* search the relevant memory slot */
335 pslot = pused_head->next;
336 plast = pused_head;
Bryan Wu1394f032007-05-06 14:50:22 -0700337
Sonic Zhang5d481f42008-07-19 14:51:31 +0800338 /* search an available piece slot */
339 while (pslot != NULL && pslot->paddr != addr) {
340 plast = pslot;
341 pslot = pslot->next;
Bryan Wu1394f032007-05-06 14:50:22 -0700342 }
343
Sonic Zhang5d481f42008-07-19 14:51:31 +0800344 if (!pslot)
345 return -1;
346
347 plast->next = pslot->next;
348 pavail = pslot;
349 pavail->pid = 0;
350
351 /* insert free pieces back to the free list */
352 pslot = pfree_head->next;
353 plast = pfree_head;
354
355 while (pslot != NULL && addr > pslot->paddr) {
356 plast = pslot;
357 pslot = pslot->next;
358 }
359
360 if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
361 plast->size += pavail->size;
362 kmem_cache_free(sram_piece_cache, pavail);
363 } else {
Sonic Zhang225f7e12008-08-25 18:00:45 +0800364 pavail->next = plast->next;
Sonic Zhang5d481f42008-07-19 14:51:31 +0800365 plast->next = pavail;
366 plast = pavail;
367 }
368
369 if (pslot && plast->paddr + plast->size == pslot->paddr) {
370 plast->size += pslot->size;
371 plast->next = pslot->next;
372 kmem_cache_free(sram_piece_cache, pslot);
Bryan Wu1394f032007-05-06 14:50:22 -0700373 }
374
375 return 0;
376}
377
378int sram_free(const void *addr)
379{
Robin Getz5e953202008-10-08 17:22:49 +0800380
Bryan Wu1394f032007-05-06 14:50:22 -0700381#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800382 if (addr >= (void *)get_l1_code_start()
383 && addr < (void *)(get_l1_code_start() + L1_CODE_LENGTH))
Bryan Wu1394f032007-05-06 14:50:22 -0700384 return l1_inst_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_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800388 if (addr >= (void *)get_l1_data_a_start()
389 && addr < (void *)(get_l1_data_a_start() + L1_DATA_A_LENGTH))
Bryan Wu1394f032007-05-06 14:50:22 -0700390 return l1_data_A_sram_free(addr);
Robin Getz5e953202008-10-08 17:22:49 +0800391 else
Bryan Wu1394f032007-05-06 14:50:22 -0700392#endif
393#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800394 if (addr >= (void *)get_l1_data_b_start()
395 && addr < (void *)(get_l1_data_b_start() + L1_DATA_B_LENGTH))
Bryan Wu1394f032007-05-06 14:50:22 -0700396 return l1_data_B_sram_free(addr);
Robin Getz5e953202008-10-08 17:22:49 +0800397 else
Bryan Wu1394f032007-05-06 14:50:22 -0700398#endif
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800399#if L2_LENGTH != 0
Robin Getz5e953202008-10-08 17:22:49 +0800400 if (addr >= (void *)L2_START
Sonic Zhang262c3822008-07-19 15:42:41 +0800401 && addr < (void *)(L2_START + L2_LENGTH))
402 return l2_sram_free(addr);
Bryan Wu1394f032007-05-06 14:50:22 -0700403 else
Robin Getz5e953202008-10-08 17:22:49 +0800404#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700405 return -1;
406}
407EXPORT_SYMBOL(sram_free);
408
409void *l1_data_A_sram_alloc(size_t size)
410{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800411 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700412 void *addr = NULL;
Graf Yang8f658732008-11-18 17:48:22 +0800413 unsigned int cpu;
Bryan Wu1394f032007-05-06 14:50:22 -0700414
Graf Yang8f658732008-11-18 17:48:22 +0800415 cpu = get_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700416 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800417 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700418
419#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800420 addr = _sram_alloc(size, &per_cpu(free_l1_data_A_sram_head, cpu),
421 &per_cpu(used_l1_data_A_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700422#endif
423
424 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800425 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
426 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700427
428 pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
429 (long unsigned int)addr, size);
430
431 return addr;
432}
433EXPORT_SYMBOL(l1_data_A_sram_alloc);
434
435int l1_data_A_sram_free(const void *addr)
436{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800437 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700438 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800439 unsigned int cpu;
Bryan Wu1394f032007-05-06 14:50:22 -0700440
Graf Yang8f658732008-11-18 17:48:22 +0800441 cpu = get_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700442 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800443 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu1394f032007-05-06 14:50:22 -0700444
445#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800446 ret = _sram_free(addr, &per_cpu(free_l1_data_A_sram_head, cpu),
447 &per_cpu(used_l1_data_A_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700448#else
449 ret = -1;
450#endif
451
452 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800453 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
454 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700455
456 return ret;
457}
458EXPORT_SYMBOL(l1_data_A_sram_free);
459
460void *l1_data_B_sram_alloc(size_t size)
461{
462#if L1_DATA_B_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800463 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700464 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800465 unsigned int cpu;
466
467 cpu = get_cpu();
468 /* add mutex operation */
469 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
470
471 addr = _sram_alloc(size, &per_cpu(free_l1_data_B_sram_head, cpu),
472 &per_cpu(used_l1_data_B_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700473
474 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800475 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
476 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700477
478 pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
479 (long unsigned int)addr, size);
480
481 return addr;
482#else
483 return NULL;
484#endif
485}
486EXPORT_SYMBOL(l1_data_B_sram_alloc);
487
488int l1_data_B_sram_free(const void *addr)
489{
490#if L1_DATA_B_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800491 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700492 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800493 unsigned int cpu;
494
495 cpu = get_cpu();
496 /* add mutex operation */
497 spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
498
499 ret = _sram_free(addr, &per_cpu(free_l1_data_B_sram_head, cpu),
500 &per_cpu(used_l1_data_B_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700501
502 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800503 spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
504 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700505
506 return ret;
507#else
508 return -1;
509#endif
510}
511EXPORT_SYMBOL(l1_data_B_sram_free);
512
513void *l1_data_sram_alloc(size_t size)
514{
515 void *addr = l1_data_A_sram_alloc(size);
516
517 if (!addr)
518 addr = l1_data_B_sram_alloc(size);
519
520 return addr;
521}
522EXPORT_SYMBOL(l1_data_sram_alloc);
523
524void *l1_data_sram_zalloc(size_t size)
525{
526 void *addr = l1_data_sram_alloc(size);
527
528 if (addr)
529 memset(addr, 0x00, size);
530
531 return addr;
532}
533EXPORT_SYMBOL(l1_data_sram_zalloc);
534
535int l1_data_sram_free(const void *addr)
536{
537 int ret;
538 ret = l1_data_A_sram_free(addr);
539 if (ret == -1)
540 ret = l1_data_B_sram_free(addr);
541 return ret;
542}
543EXPORT_SYMBOL(l1_data_sram_free);
544
545void *l1_inst_sram_alloc(size_t size)
546{
Meihui Fanc5b50df2008-04-23 08:55:26 +0800547#if L1_CODE_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800548 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700549 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800550 unsigned int cpu;
551
552 cpu = get_cpu();
553 /* add mutex operation */
554 spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
555
556 addr = _sram_alloc(size, &per_cpu(free_l1_inst_sram_head, cpu),
557 &per_cpu(used_l1_inst_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700558
559 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800560 spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
561 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700562
563 pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
564 (long unsigned int)addr, size);
565
566 return addr;
567#else
568 return NULL;
569#endif
570}
571EXPORT_SYMBOL(l1_inst_sram_alloc);
572
573int l1_inst_sram_free(const void *addr)
574{
575#if L1_CODE_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800576 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700577 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800578 unsigned int cpu;
579
580 cpu = get_cpu();
581 /* add mutex operation */
582 spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
583
584 ret = _sram_free(addr, &per_cpu(free_l1_inst_sram_head, cpu),
585 &per_cpu(used_l1_inst_sram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700586
587 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800588 spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
589 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700590
591 return ret;
592#else
593 return -1;
594#endif
595}
596EXPORT_SYMBOL(l1_inst_sram_free);
597
598/* L1 Scratchpad memory allocate function */
599void *l1sram_alloc(size_t size)
600{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800601 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700602 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800603 unsigned int cpu;
604
605 cpu = get_cpu();
606 /* add mutex operation */
607 spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
608
609 addr = _sram_alloc(size, &per_cpu(free_l1_ssram_head, cpu),
610 &per_cpu(used_l1_ssram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700611
612 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800613 spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
614 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700615
616 return addr;
617}
618
619/* L1 Scratchpad memory allocate function */
620void *l1sram_alloc_max(size_t *psize)
621{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800622 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700623 void *addr;
Graf Yang8f658732008-11-18 17:48:22 +0800624 unsigned int cpu;
625
626 cpu = get_cpu();
627 /* add mutex operation */
628 spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
629
630 addr = _sram_alloc_max(&per_cpu(free_l1_ssram_head, cpu),
631 &per_cpu(used_l1_ssram_head, cpu), psize);
Bryan Wu1394f032007-05-06 14:50:22 -0700632
633 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800634 spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
635 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700636
637 return addr;
638}
639
640/* L1 Scratchpad memory free function */
641int l1sram_free(const void *addr)
642{
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800643 unsigned long flags;
Bryan Wu1394f032007-05-06 14:50:22 -0700644 int ret;
Graf Yang8f658732008-11-18 17:48:22 +0800645 unsigned int cpu;
646
647 cpu = get_cpu();
648 /* add mutex operation */
649 spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
650
651 ret = _sram_free(addr, &per_cpu(free_l1_ssram_head, cpu),
652 &per_cpu(used_l1_ssram_head, cpu));
Bryan Wu1394f032007-05-06 14:50:22 -0700653
654 /* add mutex operation */
Graf Yang8f658732008-11-18 17:48:22 +0800655 spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
656 put_cpu();
Bryan Wu1394f032007-05-06 14:50:22 -0700657
658 return ret;
659}
660
Sonic Zhang262c3822008-07-19 15:42:41 +0800661void *l2_sram_alloc(size_t size)
662{
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800663#if L2_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800664 unsigned long flags;
Sonic Zhang262c3822008-07-19 15:42:41 +0800665 void *addr;
666
667 /* add mutex operation */
668 spin_lock_irqsave(&l2_sram_lock, flags);
669
670 addr = _sram_alloc(size, &free_l2_sram_head,
671 &used_l2_sram_head);
672
673 /* add mutex operation */
674 spin_unlock_irqrestore(&l2_sram_lock, flags);
675
676 pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n",
677 (long unsigned int)addr, size);
678
679 return addr;
680#else
681 return NULL;
682#endif
683}
684EXPORT_SYMBOL(l2_sram_alloc);
685
686void *l2_sram_zalloc(size_t size)
687{
688 void *addr = l2_sram_alloc(size);
689
690 if (addr)
691 memset(addr, 0x00, size);
692
693 return addr;
694}
695EXPORT_SYMBOL(l2_sram_zalloc);
696
697int l2_sram_free(const void *addr)
698{
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800699#if L2_LENGTH != 0
Vegard Nossum226a6ec2008-08-28 17:28:46 +0800700 unsigned long flags;
Sonic Zhang262c3822008-07-19 15:42:41 +0800701 int ret;
702
703 /* add mutex operation */
704 spin_lock_irqsave(&l2_sram_lock, flags);
705
706 ret = _sram_free(addr, &free_l2_sram_head,
707 &used_l2_sram_head);
708
709 /* add mutex operation */
710 spin_unlock_irqrestore(&l2_sram_lock, flags);
711
712 return ret;
713#else
714 return -1;
715#endif
716}
717EXPORT_SYMBOL(l2_sram_free);
718
Bryan Wu1394f032007-05-06 14:50:22 -0700719int sram_free_with_lsl(const void *addr)
720{
721 struct sram_list_struct *lsl, **tmp;
722 struct mm_struct *mm = current->mm;
723
724 for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
725 if ((*tmp)->addr == addr)
726 goto found;
727 return -1;
728found:
729 lsl = *tmp;
730 sram_free(addr);
731 *tmp = lsl->next;
732 kfree(lsl);
733
734 return 0;
735}
736EXPORT_SYMBOL(sram_free_with_lsl);
737
738void *sram_alloc_with_lsl(size_t size, unsigned long flags)
739{
740 void *addr = NULL;
741 struct sram_list_struct *lsl = NULL;
742 struct mm_struct *mm = current->mm;
743
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700744 lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
Bryan Wu1394f032007-05-06 14:50:22 -0700745 if (!lsl)
746 return NULL;
Bryan Wu1394f032007-05-06 14:50:22 -0700747
748 if (flags & L1_INST_SRAM)
749 addr = l1_inst_sram_alloc(size);
750
751 if (addr == NULL && (flags & L1_DATA_A_SRAM))
752 addr = l1_data_A_sram_alloc(size);
753
754 if (addr == NULL && (flags & L1_DATA_B_SRAM))
755 addr = l1_data_B_sram_alloc(size);
756
Sonic Zhang262c3822008-07-19 15:42:41 +0800757 if (addr == NULL && (flags & L2_SRAM))
758 addr = l2_sram_alloc(size);
759
Bryan Wu1394f032007-05-06 14:50:22 -0700760 if (addr == NULL) {
761 kfree(lsl);
762 return NULL;
763 }
764 lsl->addr = addr;
765 lsl->length = size;
766 lsl->next = mm->context.sram_list;
767 mm->context.sram_list = lsl;
768 return addr;
769}
770EXPORT_SYMBOL(sram_alloc_with_lsl);
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800771
772#ifdef CONFIG_PROC_FS
773/* Once we get a real allocator, we'll throw all of this away.
774 * Until then, we need some sort of visibility into the L1 alloc.
775 */
Mike Frysinger260d5d32008-07-14 16:34:05 +0800776/* Need to keep line of output the same. Currently, that is 44 bytes
777 * (including newline).
778 */
Sonic Zhang262c3822008-07-19 15:42:41 +0800779static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
Sonic Zhang5d481f42008-07-19 14:51:31 +0800780 struct sram_piece *pfree_head,
781 struct sram_piece *pused_head)
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800782{
Sonic Zhang5d481f42008-07-19 14:51:31 +0800783 struct sram_piece *pslot;
784
785 if (!pfree_head || !pused_head)
786 return -1;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800787
Sonic Zhang262c3822008-07-19 15:42:41 +0800788 *len += sprintf(&buf[*len], "--- SRAM %-14s Size PID State \n", desc);
Sonic Zhang5d481f42008-07-19 14:51:31 +0800789
790 /* search the relevant memory slot */
791 pslot = pused_head->next;
792
793 while (pslot != NULL) {
Sonic Zhang262c3822008-07-19 15:42:41 +0800794 *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
Sonic Zhang5d481f42008-07-19 14:51:31 +0800795 pslot->paddr, pslot->paddr + pslot->size,
796 pslot->size, pslot->pid, "ALLOCATED");
797
798 pslot = pslot->next;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800799 }
Sonic Zhang5d481f42008-07-19 14:51:31 +0800800
801 pslot = pfree_head->next;
802
803 while (pslot != NULL) {
Sonic Zhang262c3822008-07-19 15:42:41 +0800804 *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
Sonic Zhang5d481f42008-07-19 14:51:31 +0800805 pslot->paddr, pslot->paddr + pslot->size,
806 pslot->size, pslot->pid, "FREE");
807
808 pslot = pslot->next;
809 }
810
811 return 0;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800812}
Sonic Zhang262c3822008-07-19 15:42:41 +0800813static int sram_proc_read(char *buf, char **start, off_t offset, int count,
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800814 int *eof, void *data)
815{
816 int len = 0;
Graf Yang8f658732008-11-18 17:48:22 +0800817 unsigned int cpu;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800818
Graf Yang8f658732008-11-18 17:48:22 +0800819 for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
820 if (_sram_proc_read(buf, &len, count, "Scratchpad",
821 &per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
822 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800823#if L1_DATA_A_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800824 if (_sram_proc_read(buf, &len, count, "L1 Data A",
825 &per_cpu(free_l1_data_A_sram_head, cpu),
826 &per_cpu(used_l1_data_A_sram_head, cpu)))
827 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800828#endif
829#if L1_DATA_B_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800830 if (_sram_proc_read(buf, &len, count, "L1 Data B",
831 &per_cpu(free_l1_data_B_sram_head, cpu),
832 &per_cpu(used_l1_data_B_sram_head, cpu)))
833 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800834#endif
835#if L1_CODE_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800836 if (_sram_proc_read(buf, &len, count, "L1 Instruction",
837 &per_cpu(free_l1_inst_sram_head, cpu),
838 &per_cpu(used_l1_inst_sram_head, cpu)))
839 goto not_done;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800840#endif
Graf Yang8f658732008-11-18 17:48:22 +0800841 }
Mike Frysinger07aa7be2008-08-13 16:16:11 +0800842#if L2_LENGTH != 0
Graf Yang8f658732008-11-18 17:48:22 +0800843 if (_sram_proc_read(buf, &len, count, "L2", &free_l2_sram_head,
844 &used_l2_sram_head))
Sonic Zhang262c3822008-07-19 15:42:41 +0800845 goto not_done;
846#endif
Mike Frysinger260d5d32008-07-14 16:34:05 +0800847 *eof = 1;
848 not_done:
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800849 return len;
850}
851
Sonic Zhang262c3822008-07-19 15:42:41 +0800852static int __init sram_proc_init(void)
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800853{
854 struct proc_dir_entry *ptr;
855 ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
856 if (!ptr) {
857 printk(KERN_WARNING "unable to create /proc/sram\n");
858 return -1;
859 }
Sonic Zhang262c3822008-07-19 15:42:41 +0800860 ptr->read_proc = sram_proc_read;
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800861 return 0;
862}
Sonic Zhang262c3822008-07-19 15:42:41 +0800863late_initcall(sram_proc_init);
Mike Frysingerbc61b4e2007-06-14 13:21:08 +0800864#endif