aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/mm
diff options
context:
space:
mode:
authorBryan Wu <bryan.wu@analog.com>2007-05-06 17:50:22 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:12:58 -0400
commit1394f03221790a988afc3e4b3cb79f2e477246a9 (patch)
tree2c1963c9a4f2d84a5e021307fde240c5d567cf70 /arch/blackfin/mm
parent73243284463a761e04d69d22c7516b2be7de096c (diff)
blackfin architecture
This adds support for the Analog Devices Blackfin processor architecture, and currently supports the BF533, BF532, BF531, BF537, BF536, BF534, and BF561 (Dual Core) devices, with a variety of development platforms including those avaliable from Analog Devices (BF533-EZKit, BF533-STAMP, BF537-STAMP, BF561-EZKIT), and Bluetechnix! Tinyboards. The Blackfin architecture was jointly developed by Intel and Analog Devices Inc. (ADI) as the Micro Signal Architecture (MSA) core and introduced it in December of 2000. Since then ADI has put this core into its Blackfin processor family of devices. The Blackfin core has the advantages of a clean, orthogonal,RISC-like microprocessor instruction set. It combines a dual-MAC (Multiply/Accumulate), state-of-the-art signal processing engine and single-instruction, multiple-data (SIMD) multimedia capabilities into a single instruction-set architecture. The Blackfin architecture, including the instruction set, is described by the ADSP-BF53x/BF56x Blackfin Processor Programming Reference http://blackfin.uclinux.org/gf/download/frsrelease/29/2549/Blackfin_PRM.pdf The Blackfin processor is already supported by major releases of gcc, and there are binary and source rpms/tarballs for many architectures at: http://blackfin.uclinux.org/gf/project/toolchain/frs There is complete documentation, including "getting started" guides available at: http://docs.blackfin.uclinux.org/ which provides links to the sources and patches you will need in order to set up a cross-compiling environment for bfin-linux-uclibc This patch, as well as the other patches (toolchain, distribution, uClibc) are actively supported by Analog Devices Inc, at: http://blackfin.uclinux.org/ We have tested this on LTP, and our test plan (including pass/fails) can be found at: http://docs.blackfin.uclinux.org/doku.php?id=testing_the_linux_kernel [m.kozlowski@tuxland.pl: balance parenthesis in blackfin header files] Signed-off-by: Bryan Wu <bryan.wu@analog.com> Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl> Signed-off-by: Aubrey Li <aubrey.li@analog.com> Signed-off-by: Jie Zhang <jie.zhang@analog.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/blackfin/mm')
-rw-r--r--arch/blackfin/mm/Makefile5
-rw-r--r--arch/blackfin/mm/blackfin_sram.c540
-rw-r--r--arch/blackfin/mm/blackfin_sram.h38
-rw-r--r--arch/blackfin/mm/init.c208
4 files changed, 791 insertions, 0 deletions
diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile
new file mode 100644
index 00000000000..2a7202ce01f
--- /dev/null
+++ b/arch/blackfin/mm/Makefile
@@ -0,0 +1,5 @@
1#
2# arch/blackfin/mm/Makefile
3#
4
5obj-y := blackfin_sram.o init.o
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/blackfin_sram.c
new file mode 100644
index 00000000000..dd0c6501c42
--- /dev/null
+++ b/arch/blackfin/mm/blackfin_sram.c
@@ -0,0 +1,540 @@
1/*
2 * File: arch/blackfin/mm/blackfin_sram.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: SRAM driver for Blackfin ADSP-BF5xx
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
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
30#include <linux/autoconf.h>
31#include <linux/module.h>
32#include <linux/kernel.h>
33#include <linux/types.h>
34#include <linux/miscdevice.h>
35#include <linux/ioport.h>
36#include <linux/fcntl.h>
37#include <linux/init.h>
38#include <linux/poll.h>
39#include <linux/proc_fs.h>
40#include <linux/spinlock.h>
41#include <linux/rtc.h>
42#include <asm/blackfin.h>
43#include "blackfin_sram.h"
44
45spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
46
47#if CONFIG_L1_MAX_PIECE < 16
48#undef CONFIG_L1_MAX_PIECE
49#define CONFIG_L1_MAX_PIECE 16
50#endif
51
52#if CONFIG_L1_MAX_PIECE > 1024
53#undef CONFIG_L1_MAX_PIECE
54#define CONFIG_L1_MAX_PIECE 1024
55#endif
56
57#define SRAM_SLT_NULL 0
58#define SRAM_SLT_FREE 1
59#define SRAM_SLT_ALLOCATED 2
60
61/* the data structure for L1 scratchpad and DATA SRAM */
62struct l1_sram_piece {
63 void *paddr;
64 int size;
65 int flag;
66};
67
68static struct l1_sram_piece l1_ssram[CONFIG_L1_MAX_PIECE];
69
70#if L1_DATA_A_LENGTH != 0
71static struct l1_sram_piece l1_data_A_sram[CONFIG_L1_MAX_PIECE];
72#endif
73
74#if L1_DATA_B_LENGTH != 0
75static struct l1_sram_piece l1_data_B_sram[CONFIG_L1_MAX_PIECE];
76#endif
77
78#if L1_CODE_LENGTH != 0
79static struct l1_sram_piece l1_inst_sram[CONFIG_L1_MAX_PIECE];
80#endif
81
82/* L1 Scratchpad SRAM initialization function */
83void l1sram_init(void)
84{
85 printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
86 L1_SCRATCH_LENGTH >> 10);
87
88 memset(&l1_ssram, 0x00, sizeof(l1_ssram));
89 l1_ssram[0].paddr = (void*)L1_SCRATCH_START;
90 l1_ssram[0].size = L1_SCRATCH_LENGTH;
91 l1_ssram[0].flag = SRAM_SLT_FREE;
92
93 /* mutex initialize */
94 spin_lock_init(&l1sram_lock);
95}
96
97void l1_data_sram_init(void)
98{
99#if L1_DATA_A_LENGTH != 0
100 printk(KERN_INFO "Blackfin DATA_A SRAM: %d KB\n",
101 L1_DATA_A_LENGTH >> 10);
102
103 memset(&l1_data_A_sram, 0x00, sizeof(l1_data_A_sram));
104 l1_data_A_sram[0].paddr = (void*)L1_DATA_A_START +
105 (_ebss_l1 - _sdata_l1);
106 l1_data_A_sram[0].size = L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
107 l1_data_A_sram[0].flag = SRAM_SLT_FREE;
108#endif
109#if L1_DATA_B_LENGTH != 0
110 printk(KERN_INFO "Blackfin DATA_B SRAM: %d KB\n",
111 L1_DATA_B_LENGTH >> 10);
112
113 memset(&l1_data_B_sram, 0x00, sizeof(l1_data_B_sram));
114 l1_data_B_sram[0].paddr = (void*)L1_DATA_B_START;
115 l1_data_B_sram[0].size = L1_DATA_B_LENGTH;
116 l1_data_B_sram[0].flag = SRAM_SLT_FREE;
117#endif
118
119 /* mutex initialize */
120 spin_lock_init(&l1_data_sram_lock);
121}
122
123void l1_inst_sram_init(void)
124{
125#if L1_CODE_LENGTH != 0
126 printk(KERN_INFO "Blackfin Instruction SRAM: %d KB\n",
127 L1_CODE_LENGTH >> 10);
128
129 memset(&l1_inst_sram, 0x00, sizeof(l1_inst_sram));
130 l1_inst_sram[0].paddr = (void*)L1_CODE_START + (_etext_l1 - _stext_l1);
131 l1_inst_sram[0].size = L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
132 l1_inst_sram[0].flag = SRAM_SLT_FREE;
133#endif
134
135 /* mutex initialize */
136 spin_lock_init(&l1_inst_sram_lock);
137}
138
139/* L1 memory allocate function */
140static void *_l1_sram_alloc(size_t size, struct l1_sram_piece *pfree, int count)
141{
142 int i, index = 0;
143 void *addr = NULL;
144
145 if (size <= 0)
146 return NULL;
147
148 /* Align the size */
149 size = (size + 3) & ~3;
150
151 /* not use the good method to match the best slot !!! */
152 /* search an available memeory slot */
153 for (i = 0; i < count; i++) {
154 if ((pfree[i].flag == SRAM_SLT_FREE)
155 && (pfree[i].size >= size)) {
156 addr = pfree[i].paddr;
157 pfree[i].flag = SRAM_SLT_ALLOCATED;
158 index = i;
159 break;
160 }
161 }
162 if (i >= count)
163 return NULL;
164
165 /* updated the NULL memeory slot !!! */
166 if (pfree[i].size > size) {
167 for (i = 0; i < count; i++) {
168 if (pfree[i].flag == SRAM_SLT_NULL) {
169 pfree[i].flag = SRAM_SLT_FREE;
170 pfree[i].paddr = addr + size;
171 pfree[i].size = pfree[index].size - size;
172 pfree[index].size = size;
173 break;
174 }
175 }
176 }
177
178 return addr;
179}
180
181/* Allocate the largest available block. */
182static void *_l1_sram_alloc_max(struct l1_sram_piece *pfree, int count,
183 unsigned long *psize)
184{
185 unsigned long best = 0;
186 int i, index = -1;
187 void *addr = NULL;
188
189 /* search an available memeory slot */
190 for (i = 0; i < count; i++) {
191 if (pfree[i].flag == SRAM_SLT_FREE && pfree[i].size > best) {
192 addr = pfree[i].paddr;
193 index = i;
194 best = pfree[i].size;
195 }
196 }
197 if (index < 0)
198 return NULL;
199 *psize = best;
200
201 pfree[index].flag = SRAM_SLT_ALLOCATED;
202 return addr;
203}
204
205/* L1 memory free function */
206static int _l1_sram_free(const void *addr,
207 struct l1_sram_piece *pfree, int count)
208{
209 int i, index = 0;
210
211 /* search the relevant memory slot */
212 for (i = 0; i < count; i++) {
213 if (pfree[i].paddr == addr) {
214 if (pfree[i].flag != SRAM_SLT_ALLOCATED) {
215 /* error log */
216 return -1;
217 }
218 index = i;
219 break;
220 }
221 }
222 if (i >= count)
223 return -1;
224
225 pfree[index].flag = SRAM_SLT_FREE;
226
227 /* link the next address slot */
228 for (i = 0; i < count; i++) {
229 if (((pfree[index].paddr + pfree[index].size) == pfree[i].paddr)
230 && (pfree[i].flag == SRAM_SLT_FREE)) {
231 pfree[i].flag = SRAM_SLT_NULL;
232 pfree[index].size += pfree[i].size;
233 pfree[index].flag = SRAM_SLT_FREE;
234 break;
235 }
236 }
237
238 /* link the last address slot */
239 for (i = 0; i < count; i++) {
240 if (((pfree[i].paddr + pfree[i].size) == pfree[index].paddr) &&
241 (pfree[i].flag == SRAM_SLT_FREE)) {
242 pfree[index].flag = SRAM_SLT_NULL;
243 pfree[i].size += pfree[index].size;
244 break;
245 }
246 }
247
248 return 0;
249}
250
251int sram_free(const void *addr)
252{
253 if (0) {}
254#if L1_CODE_LENGTH != 0
255 else if (addr >= (void *)L1_CODE_START
256 && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
257 return l1_inst_sram_free(addr);
258#endif
259#if L1_DATA_A_LENGTH != 0
260 else if (addr >= (void *)L1_DATA_A_START
261 && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
262 return l1_data_A_sram_free(addr);
263#endif
264#if L1_DATA_B_LENGTH != 0
265 else if (addr >= (void *)L1_DATA_B_START
266 && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
267 return l1_data_B_sram_free(addr);
268#endif
269 else
270 return -1;
271}
272EXPORT_SYMBOL(sram_free);
273
274void *l1_data_A_sram_alloc(size_t size)
275{
276 unsigned flags;
277 void *addr = NULL;
278
279 /* add mutex operation */
280 spin_lock_irqsave(&l1_data_sram_lock, flags);
281
282#if L1_DATA_A_LENGTH != 0
283 addr = _l1_sram_alloc(size, l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
284#endif
285
286 /* add mutex operation */
287 spin_unlock_irqrestore(&l1_data_sram_lock, flags);
288
289 pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
290 (long unsigned int)addr, size);
291
292 return addr;
293}
294EXPORT_SYMBOL(l1_data_A_sram_alloc);
295
296int l1_data_A_sram_free(const void *addr)
297{
298 unsigned flags;
299 int ret;
300
301 /* add mutex operation */
302 spin_lock_irqsave(&l1_data_sram_lock, flags);
303
304#if L1_DATA_A_LENGTH != 0
305 ret = _l1_sram_free(addr,
306 l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
307#else
308 ret = -1;
309#endif
310
311 /* add mutex operation */
312 spin_unlock_irqrestore(&l1_data_sram_lock, flags);
313
314 return ret;
315}
316EXPORT_SYMBOL(l1_data_A_sram_free);
317
318void *l1_data_B_sram_alloc(size_t size)
319{
320#if L1_DATA_B_LENGTH != 0
321 unsigned flags;
322 void *addr;
323
324 /* add mutex operation */
325 spin_lock_irqsave(&l1_data_sram_lock, flags);
326
327 addr = _l1_sram_alloc(size, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
328
329 /* add mutex operation */
330 spin_unlock_irqrestore(&l1_data_sram_lock, flags);
331
332 pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
333 (long unsigned int)addr, size);
334
335 return addr;
336#else
337 return NULL;
338#endif
339}
340EXPORT_SYMBOL(l1_data_B_sram_alloc);
341
342int l1_data_B_sram_free(const void *addr)
343{
344#if L1_DATA_B_LENGTH != 0
345 unsigned flags;
346 int ret;
347
348 /* add mutex operation */
349 spin_lock_irqsave(&l1_data_sram_lock, flags);
350
351 ret = _l1_sram_free(addr, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
352
353 /* add mutex operation */
354 spin_unlock_irqrestore(&l1_data_sram_lock, flags);
355
356 return ret;
357#else
358 return -1;
359#endif
360}
361EXPORT_SYMBOL(l1_data_B_sram_free);
362
363void *l1_data_sram_alloc(size_t size)
364{
365 void *addr = l1_data_A_sram_alloc(size);
366
367 if (!addr)
368 addr = l1_data_B_sram_alloc(size);
369
370 return addr;
371}
372EXPORT_SYMBOL(l1_data_sram_alloc);
373
374void *l1_data_sram_zalloc(size_t size)
375{
376 void *addr = l1_data_sram_alloc(size);
377
378 if (addr)
379 memset(addr, 0x00, size);
380
381 return addr;
382}
383EXPORT_SYMBOL(l1_data_sram_zalloc);
384
385int l1_data_sram_free(const void *addr)
386{
387 int ret;
388 ret = l1_data_A_sram_free(addr);
389 if (ret == -1)
390 ret = l1_data_B_sram_free(addr);
391 return ret;
392}
393EXPORT_SYMBOL(l1_data_sram_free);
394
395void *l1_inst_sram_alloc(size_t size)
396{
397#if L1_DATA_A_LENGTH != 0
398 unsigned flags;
399 void *addr;
400
401 /* add mutex operation */
402 spin_lock_irqsave(&l1_inst_sram_lock, flags);
403
404 addr = _l1_sram_alloc(size, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
405
406 /* add mutex operation */
407 spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
408
409 pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
410 (long unsigned int)addr, size);
411
412 return addr;
413#else
414 return NULL;
415#endif
416}
417EXPORT_SYMBOL(l1_inst_sram_alloc);
418
419int l1_inst_sram_free(const void *addr)
420{
421#if L1_CODE_LENGTH != 0
422 unsigned flags;
423 int ret;
424
425 /* add mutex operation */
426 spin_lock_irqsave(&l1_inst_sram_lock, flags);
427
428 ret = _l1_sram_free(addr, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
429
430 /* add mutex operation */
431 spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
432
433 return ret;
434#else
435 return -1;
436#endif
437}
438EXPORT_SYMBOL(l1_inst_sram_free);
439
440/* L1 Scratchpad memory allocate function */
441void *l1sram_alloc(size_t size)
442{
443 unsigned flags;
444 void *addr;
445
446 /* add mutex operation */
447 spin_lock_irqsave(&l1sram_lock, flags);
448
449 addr = _l1_sram_alloc(size, l1_ssram, ARRAY_SIZE(l1_ssram));
450
451 /* add mutex operation */
452 spin_unlock_irqrestore(&l1sram_lock, flags);
453
454 return addr;
455}
456
457/* L1 Scratchpad memory allocate function */
458void *l1sram_alloc_max(size_t *psize)
459{
460 unsigned flags;
461 void *addr;
462
463 /* add mutex operation */
464 spin_lock_irqsave(&l1sram_lock, flags);
465
466 addr = _l1_sram_alloc_max(l1_ssram, ARRAY_SIZE(l1_ssram), psize);
467
468 /* add mutex operation */
469 spin_unlock_irqrestore(&l1sram_lock, flags);
470
471 return addr;
472}
473
474/* L1 Scratchpad memory free function */
475int l1sram_free(const void *addr)
476{
477 unsigned flags;
478 int ret;
479
480 /* add mutex operation */
481 spin_lock_irqsave(&l1sram_lock, flags);
482
483 ret = _l1_sram_free(addr, l1_ssram, ARRAY_SIZE(l1_ssram));
484
485 /* add mutex operation */
486 spin_unlock_irqrestore(&l1sram_lock, flags);
487
488 return ret;
489}
490
491int sram_free_with_lsl(const void *addr)
492{
493 struct sram_list_struct *lsl, **tmp;
494 struct mm_struct *mm = current->mm;
495
496 for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
497 if ((*tmp)->addr == addr)
498 goto found;
499 return -1;
500found:
501 lsl = *tmp;
502 sram_free(addr);
503 *tmp = lsl->next;
504 kfree(lsl);
505
506 return 0;
507}
508EXPORT_SYMBOL(sram_free_with_lsl);
509
510void *sram_alloc_with_lsl(size_t size, unsigned long flags)
511{
512 void *addr = NULL;
513 struct sram_list_struct *lsl = NULL;
514 struct mm_struct *mm = current->mm;
515
516 lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
517 if (!lsl)
518 return NULL;
519 memset(lsl, 0, sizeof(*lsl));
520
521 if (flags & L1_INST_SRAM)
522 addr = l1_inst_sram_alloc(size);
523
524 if (addr == NULL && (flags & L1_DATA_A_SRAM))
525 addr = l1_data_A_sram_alloc(size);
526
527 if (addr == NULL && (flags & L1_DATA_B_SRAM))
528 addr = l1_data_B_sram_alloc(size);
529
530 if (addr == NULL) {
531 kfree(lsl);
532 return NULL;
533 }
534 lsl->addr = addr;
535 lsl->length = size;
536 lsl->next = mm->context.sram_list;
537 mm->context.sram_list = lsl;
538 return addr;
539}
540EXPORT_SYMBOL(sram_alloc_with_lsl);
diff --git a/arch/blackfin/mm/blackfin_sram.h b/arch/blackfin/mm/blackfin_sram.h
new file mode 100644
index 00000000000..0fb73b78dd6
--- /dev/null
+++ b/arch/blackfin/mm/blackfin_sram.h
@@ -0,0 +1,38 @@
1/*
2 * File: arch/blackfin/mm/blackfin_sram.h
3 * Based on: arch/blackfin/mm/blackfin_sram.c
4 * Author: Mike Frysinger
5 *
6 * Created: Aug 2006
7 * Description: Local prototypes meant for internal use only
8 *
9 * Modified:
10 * Copyright 2006 Analog Devices Inc.
11 *
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
30#ifndef __BLACKFIN_SRAM_H__
31#define __BLACKFIN_SRAM_H__
32
33extern void l1sram_init(void);
34extern void l1_inst_sram_init(void);
35extern void l1_data_sram_init(void);
36extern void *l1sram_alloc(size_t);
37
38#endif
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
new file mode 100644
index 00000000000..73f72abed43
--- /dev/null
+++ b/arch/blackfin/mm/init.c
@@ -0,0 +1,208 @@
1/*
2 * File: arch/blackfin/mm/init.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
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
30#include <linux/swap.h>
31#include <linux/bootmem.h>
32#include <asm/bfin-global.h>
33#include <asm/uaccess.h>
34#include <asm/l1layout.h>
35#include "blackfin_sram.h"
36
37/*
38 * BAD_PAGE is the page that is used for page faults when linux
39 * is out-of-memory. Older versions of linux just did a
40 * do_exit(), but using this instead means there is less risk
41 * for a process dying in kernel mode, possibly leaving a inode
42 * unused etc..
43 *
44 * BAD_PAGETABLE is the accompanying page-table: it is initialized
45 * to point to BAD_PAGE entries.
46 *
47 * ZERO_PAGE is a special page that is used for zero-initialized
48 * data and COW.
49 */
50static unsigned long empty_bad_page_table;
51
52static unsigned long empty_bad_page;
53
54unsigned long empty_zero_page;
55
56void show_mem(void)
57{
58 unsigned long i;
59 int free = 0, total = 0, reserved = 0, shared = 0;
60
61 int cached = 0;
62 printk(KERN_INFO "Mem-info:\n");
63 show_free_areas();
64 i = max_mapnr;
65 while (i-- > 0) {
66 total++;
67 if (PageReserved(mem_map + i))
68 reserved++;
69 else if (PageSwapCache(mem_map + i))
70 cached++;
71 else if (!page_count(mem_map + i))
72 free++;
73 else
74 shared += page_count(mem_map + i) - 1;
75 }
76 printk(KERN_INFO "%d pages of RAM\n", total);
77 printk(KERN_INFO "%d free pages\n", free);
78 printk(KERN_INFO "%d reserved pages\n", reserved);
79 printk(KERN_INFO "%d pages shared\n", shared);
80 printk(KERN_INFO "%d pages swap cached\n", cached);
81}
82
83/*
84 * paging_init() continues the virtual memory environment setup which
85 * was begun by the code in arch/head.S.
86 * The parameters are pointers to where to stick the starting and ending
87 * addresses of available kernel virtual memory.
88 */
89void paging_init(void)
90{
91 /*
92 * make sure start_mem is page aligned, otherwise bootmem and
93 * page_alloc get different views og the world
94 */
95 unsigned long end_mem = memory_end & PAGE_MASK;
96
97 pr_debug("start_mem is %#lx virtual_end is %#lx\n", PAGE_ALIGN(memory_start), end_mem);
98
99 /*
100 * initialize the bad page table and bad page to point
101 * to a couple of allocated pages
102 */
103 empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
104 empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
105 empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
106 memset((void *)empty_zero_page, 0, PAGE_SIZE);
107
108 /*
109 * Set up SFC/DFC registers (user data space)
110 */
111 set_fs(KERNEL_DS);
112
113 pr_debug("free_area_init -> start_mem is %#lx virtual_end is %#lx\n",
114 PAGE_ALIGN(memory_start), end_mem);
115
116 {
117 unsigned long zones_size[MAX_NR_ZONES] = { 0, };
118
119 zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
120#ifdef CONFIG_HIGHMEM
121 zones_size[ZONE_HIGHMEM] = 0;
122#endif
123 free_area_init(zones_size);
124 }
125}
126
127void mem_init(void)
128{
129 unsigned int codek = 0, datak = 0, initk = 0;
130 unsigned long tmp;
131 unsigned int len = _ramend - _rambase;
132 unsigned long start_mem = memory_start;
133 unsigned long end_mem = memory_end;
134
135 end_mem &= PAGE_MASK;
136 high_memory = (void *)end_mem;
137
138 start_mem = PAGE_ALIGN(start_mem);
139 max_mapnr = num_physpages = MAP_NR(high_memory);
140 printk(KERN_INFO "Physical pages: %lx\n", num_physpages);
141
142 /* This will put all memory onto the freelists. */
143 totalram_pages = free_all_bootmem();
144
145 codek = (_etext - _stext) >> 10;
146 datak = (__bss_stop - __bss_start) >> 10;
147 initk = (__init_end - __init_begin) >> 10;
148
149 tmp = nr_free_pages() << PAGE_SHIFT;
150 printk(KERN_INFO
151 "Memory available: %luk/%uk RAM, (%uk init code, %uk kernel code, %uk data, %uk dma)\n",
152 tmp >> 10, len >> 10, initk, codek, datak, DMA_UNCACHED_REGION >> 10);
153
154 /* Initialize the blackfin L1 Memory. */
155 l1sram_init();
156 l1_data_sram_init();
157 l1_inst_sram_init();
158
159 /* Allocate this once; never free it. We assume this gives us a
160 pointer to the start of L1 scratchpad memory; panic if it
161 doesn't. */
162 tmp = (unsigned long)l1sram_alloc(sizeof(struct l1_scratch_task_info));
163 if (tmp != (unsigned long)L1_SCRATCH_TASK_INFO) {
164 printk(KERN_EMERG "mem_init(): Did not get the right address from l1sram_alloc: %08lx != %08lx\n",
165 tmp, (unsigned long)L1_SCRATCH_TASK_INFO);
166 panic("No L1, time to give up\n");
167 }
168}
169
170#ifdef CONFIG_BLK_DEV_INITRD
171void free_initrd_mem(unsigned long start, unsigned long end)
172{
173 int pages = 0;
174 for (; start < end; start += PAGE_SIZE) {
175 ClearPageReserved(virt_to_page(start));
176 init_page_count(virt_to_page(start));
177 free_page(start);
178 totalram_pages++;
179 pages++;
180 }
181 printk(KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
182}
183#endif
184
185void free_initmem(void)
186{
187#ifdef CONFIG_RAMKERNEL
188 unsigned long addr;
189/*
190 * the following code should be cool even if these sections
191 * are not page aligned.
192 */
193 addr = PAGE_ALIGN((unsigned long)(__init_begin));
194 /* next to check that the page we free is not a partial page */
195 for (; addr + PAGE_SIZE < (unsigned long)(__init_end);
196 addr += PAGE_SIZE) {
197 ClearPageReserved(virt_to_page(addr));
198 init_page_count(virt_to_page(addr));
199 free_page(addr);
200 totalram_pages++;
201 }
202 printk(KERN_NOTICE
203 "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
204 (addr - PAGE_ALIGN((long)__init_begin)) >> 10,
205 (int)(PAGE_ALIGN((unsigned long)(__init_begin))),
206 (int)(addr - PAGE_SIZE));
207#endif
208}