summaryrefslogtreecommitdiffstats
path: root/arch/blackfin/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/mm')
-rw-r--r--arch/blackfin/mm/blackfin_sram.h27
-rw-r--r--arch/blackfin/mm/init.c30
-rw-r--r--arch/blackfin/mm/isram-driver.c236
-rw-r--r--arch/blackfin/mm/sram-alloc.c57
4 files changed, 246 insertions, 104 deletions
diff --git a/arch/blackfin/mm/blackfin_sram.h b/arch/blackfin/mm/blackfin_sram.h
index bc0062884fde..fb0b1599cfb7 100644
--- a/arch/blackfin/mm/blackfin_sram.h
+++ b/arch/blackfin/mm/blackfin_sram.h
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mm/blackfin_sram.h
- * Based on: arch/blackfin/mm/blackfin_sram.c
- * Author: Mike Frysinger
+ * Local prototypes meant for internal use only
*
- * Created: Aug 2006
- * Description: Local prototypes meant for internal use only
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __BLACKFIN_SRAM_H__
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index 68bd0bd680cd..bb9c98f9cb5b 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/mm/init.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/swap.h>
@@ -33,6 +10,7 @@
#include <asm/bfin-global.h>
#include <asm/pda.h>
#include <asm/cplbinit.h>
+#include <asm/early_printk.h>
#include "blackfin_sram.h"
/*
@@ -113,6 +91,8 @@ asmlinkage void __init init_pda(void)
{
unsigned int cpu = raw_smp_processor_id();
+ early_shadow_stamp();
+
/* Initialize the PDA fields holding references to other parts
of the memory. The content of such memory is still
undefined at the time of the call, we are only setting up
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c
index c080e70f98b0..84cdc5a1c139 100644
--- a/arch/blackfin/mm/isram-driver.c
+++ b/arch/blackfin/mm/isram-driver.c
@@ -1,21 +1,13 @@
/*
- * Description: Instruction SRAM accessor functions for the Blackfin
+ * Instruction SRAM accessor functions for the Blackfin
*
* Copyright 2008 Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
+#define pr_fmt(fmt) "isram: " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -23,6 +15,7 @@
#include <linux/sched.h>
#include <asm/blackfin.h>
+#include <asm/dma.h>
/*
* IMPORTANT WARNING ABOUT THESE FUNCTIONS
@@ -50,10 +43,12 @@ static DEFINE_SPINLOCK(dtest_lock);
#define IADDR2DTEST(x) \
({ unsigned long __addr = (unsigned long)(x); \
(__addr & 0x47F8) | /* address bits 14 & 10:3 */ \
+ (__addr & 0x8000) << 23 | /* Bank A/B */ \
(__addr & 0x0800) << 15 | /* address bit 11 */ \
- (__addr & 0x3000) << 4 | /* address bits 13:12 */ \
- (__addr & 0x8000) << 8 | /* address bit 15 */ \
- (0x1000004); /* isram access */ \
+ (__addr & 0x3000) << 4 | /* address bits 13:12 */ \
+ (__addr & 0x8000) << 8 | /* address bit 15 */ \
+ (0x1000000) | /* instruction access = 1 */ \
+ (0x4); /* data array = 1 */ \
})
/* Takes a pointer, and returns the offset (in bits) which things should be shifted */
@@ -70,7 +65,7 @@ static void isram_write(const void *addr, uint64_t data)
if (addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH))
return;
- cmd = IADDR2DTEST(addr) | 1; /* write */
+ cmd = IADDR2DTEST(addr) | 2; /* write */
/*
* Writes to DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
@@ -127,8 +122,7 @@ static bool isram_check_addr(const void *addr, size_t n)
(addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
if ((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
show_stack(NULL, NULL);
- printk(KERN_ERR "isram_memcpy: copy involving %p length "
- "(%zu) too long\n", addr, n);
+ pr_err("copy involving %p length (%zu) too long\n", addr, n);
}
return true;
}
@@ -199,3 +193,209 @@ void *isram_memcpy(void *dest, const void *src, size_t n)
}
EXPORT_SYMBOL(isram_memcpy);
+#ifdef CONFIG_BFIN_ISRAM_SELF_TEST
+
+#define TEST_LEN 0x100
+
+static __init void hex_dump(unsigned char *buf, int len)
+{
+ while (len--)
+ pr_cont("%02x", *buf++);
+}
+
+static __init int isram_read_test(char *sdram, void *l1inst)
+{
+ int i, ret = 0;
+ uint64_t data1, data2;
+
+ pr_info("INFO: running isram_read tests\n");
+
+ /* setup some different data to play with */
+ for (i = 0; i < TEST_LEN; ++i)
+ sdram[i] = i;
+ dma_memcpy(l1inst, sdram, TEST_LEN);
+
+ /* make sure we can read the L1 inst */
+ for (i = 0; i < TEST_LEN; i += sizeof(uint64_t)) {
+ data1 = isram_read(l1inst + i);
+ memcpy(&data2, sdram + i, sizeof(data2));
+ if (memcmp(&data1, &data2, sizeof(uint64_t))) {
+ pr_err("FAIL: isram_read(%p) returned %#llx but wanted %#llx\n",
+ l1inst + i, data1, data2);
+ ++ret;
+ }
+ }
+
+ return ret;
+}
+
+static __init int isram_write_test(char *sdram, void *l1inst)
+{
+ int i, ret = 0;
+ uint64_t data1, data2;
+
+ pr_info("INFO: running isram_write tests\n");
+
+ /* setup some different data to play with */
+ memset(sdram, 0, TEST_LEN * 2);
+ dma_memcpy(l1inst, sdram, TEST_LEN);
+ for (i = 0; i < TEST_LEN; ++i)
+ sdram[i] = i;
+
+ /* make sure we can write the L1 inst */
+ for (i = 0; i < TEST_LEN; i += sizeof(uint64_t)) {
+ memcpy(&data1, sdram + i, sizeof(data1));
+ isram_write(l1inst + i, data1);
+ data2 = isram_read(l1inst + i);
+ if (memcmp(&data1, &data2, sizeof(uint64_t))) {
+ pr_err("FAIL: isram_write(%p, %#llx) != %#llx\n",
+ l1inst + i, data1, data2);
+ ++ret;
+ }
+ }
+
+ dma_memcpy(sdram + TEST_LEN, l1inst, TEST_LEN);
+ if (memcmp(sdram, sdram + TEST_LEN, TEST_LEN)) {
+ pr_err("FAIL: isram_write() did not work properly\n");
+ ++ret;
+ }
+
+ return ret;
+}
+
+static __init int
+_isram_memcpy_test(char pattern, void *sdram, void *l1inst, const char *smemcpy,
+ void *(*fmemcpy)(void *, const void *, size_t))
+{
+ memset(sdram, pattern, TEST_LEN);
+ fmemcpy(l1inst, sdram, TEST_LEN);
+ fmemcpy(sdram + TEST_LEN, l1inst, TEST_LEN);
+ if (memcmp(sdram, sdram + TEST_LEN, TEST_LEN)) {
+ pr_err("FAIL: %s(%p <=> %p, %#x) failed (data is %#x)\n",
+ smemcpy, l1inst, sdram, TEST_LEN, pattern);
+ return 1;
+ }
+ return 0;
+}
+#define _isram_memcpy_test(a, b, c, d) _isram_memcpy_test(a, b, c, #d, d)
+
+static __init int isram_memcpy_test(char *sdram, void *l1inst)
+{
+ int i, j, thisret, ret = 0;
+
+ /* check broad isram_memcpy() */
+ pr_info("INFO: running broad isram_memcpy tests\n");
+ for (i = 0xf; i >= 0; --i)
+ ret += _isram_memcpy_test(i, sdram, l1inst, isram_memcpy);
+
+ /* check read of small, unaligned, and hardware 64bit limits */
+ pr_info("INFO: running isram_memcpy (read) tests\n");
+
+ for (i = 0; i < TEST_LEN; ++i)
+ sdram[i] = i;
+ dma_memcpy(l1inst, sdram, TEST_LEN);
+
+ thisret = 0;
+ for (i = 0; i < TEST_LEN - 32; ++i) {
+ unsigned char cmp[32];
+ for (j = 1; j <= 32; ++j) {
+ memset(cmp, 0, sizeof(cmp));
+ isram_memcpy(cmp, l1inst + i, j);
+ if (memcmp(cmp, sdram + i, j)) {
+ pr_err("FAIL: %p:", l1inst + 1);
+ hex_dump(cmp, j);
+ pr_cont(" SDRAM:");
+ hex_dump(sdram + i, j);
+ pr_cont("\n");
+ if (++thisret > 20) {
+ pr_err("FAIL: skipping remaining series\n");
+ i = TEST_LEN;
+ break;
+ }
+ }
+ }
+ }
+ ret += thisret;
+
+ /* check write of small, unaligned, and hardware 64bit limits */
+ pr_info("INFO: running isram_memcpy (write) tests\n");
+
+ memset(sdram + TEST_LEN, 0, TEST_LEN);
+ dma_memcpy(l1inst, sdram + TEST_LEN, TEST_LEN);
+
+ thisret = 0;
+ for (i = 0; i < TEST_LEN - 32; ++i) {
+ unsigned char cmp[32];
+ for (j = 1; j <= 32; ++j) {
+ isram_memcpy(l1inst + i, sdram + i, j);
+ dma_memcpy(cmp, l1inst + i, j);
+ if (memcmp(cmp, sdram + i, j)) {
+ pr_err("FAIL: %p:", l1inst + i);
+ hex_dump(cmp, j);
+ pr_cont(" SDRAM:");
+ hex_dump(sdram + i, j);
+ pr_cont("\n");
+ if (++thisret > 20) {
+ pr_err("FAIL: skipping remaining series\n");
+ i = TEST_LEN;
+ break;
+ }
+ }
+ }
+ }
+ ret += thisret;
+
+ return ret;
+}
+
+static __init int isram_test_init(void)
+{
+ int ret;
+ char *sdram;
+ void *l1inst;
+
+ sdram = kmalloc(TEST_LEN * 2, GFP_KERNEL);
+ if (!sdram) {
+ pr_warning("SKIP: could not allocate sdram\n");
+ return 0;
+ }
+
+ l1inst = l1_inst_sram_alloc(TEST_LEN);
+ if (!l1inst) {
+ kfree(sdram);
+ pr_warning("SKIP: could not allocate L1 inst\n");
+ return 0;
+ }
+
+ /* sanity check initial L1 inst state */
+ ret = 1;
+ pr_info("INFO: running initial dma_memcpy checks\n");
+ if (_isram_memcpy_test(0xa, sdram, l1inst, dma_memcpy))
+ goto abort;
+ if (_isram_memcpy_test(0x5, sdram, l1inst, dma_memcpy))
+ goto abort;
+
+ ret = 0;
+ ret += isram_read_test(sdram, l1inst);
+ ret += isram_write_test(sdram, l1inst);
+ ret += isram_memcpy_test(sdram, l1inst);
+
+ abort:
+ sram_free(l1inst);
+ kfree(sdram);
+
+ if (ret)
+ return -EIO;
+
+ pr_info("PASS: all tests worked !\n");
+ return 0;
+}
+late_initcall(isram_test_init);
+
+static __exit void isram_test_exit(void)
+{
+ /* stub to allow unloading */
+}
+module_exit(isram_test_exit);
+
+#endif
diff --git a/arch/blackfin/mm/sram-alloc.c b/arch/blackfin/mm/sram-alloc.c
index 0bc3c4ef0aad..f068c11ea98f 100644
--- a/arch/blackfin/mm/sram-alloc.c
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mm/sram-alloc.c
- * Based on:
- * Author:
+ * SRAM allocator for Blackfin on-chip memory
*
- * Created:
- * Description: SRAM allocator for Blackfin L1 and L2 memory
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
@@ -42,11 +21,6 @@
#include <asm/mem_map.h>
#include "blackfin_sram.h"
-static DEFINE_PER_CPU(spinlock_t, l1sram_lock) ____cacheline_aligned_in_smp;
-static DEFINE_PER_CPU(spinlock_t, l1_data_sram_lock) ____cacheline_aligned_in_smp;
-static DEFINE_PER_CPU(spinlock_t, l1_inst_sram_lock) ____cacheline_aligned_in_smp;
-static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
-
/* the data structure for L1 scratchpad and DATA SRAM */
struct sram_piece {
void *paddr;
@@ -55,6 +29,7 @@ struct sram_piece {
struct sram_piece *next;
};
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1sram_lock);
static DEFINE_PER_CPU(struct sram_piece, free_l1_ssram_head);
static DEFINE_PER_CPU(struct sram_piece, used_l1_ssram_head);
@@ -68,12 +43,18 @@ static DEFINE_PER_CPU(struct sram_piece, free_l1_data_B_sram_head);
static DEFINE_PER_CPU(struct sram_piece, used_l1_data_B_sram_head);
#endif
+#if L1_DATA_A_LENGTH || L1_DATA_B_LENGTH
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_data_sram_lock);
+#endif
+
#if L1_CODE_LENGTH != 0
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_inst_sram_lock);
static DEFINE_PER_CPU(struct sram_piece, free_l1_inst_sram_head);
static DEFINE_PER_CPU(struct sram_piece, used_l1_inst_sram_head);
#endif
#if L2_LENGTH != 0
+static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
static struct sram_piece free_l2_sram_head, used_l2_sram_head;
#endif
@@ -225,10 +206,10 @@ static void __init l2_sram_init(void)
printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n",
L2_LENGTH >> 10,
free_l2_sram_head.next->size >> 10);
-#endif
/* mutex initialize */
spin_lock_init(&l2_sram_lock);
+#endif
}
static int __init bfin_sram_init(void)
@@ -416,18 +397,17 @@ EXPORT_SYMBOL(sram_free);
void *l1_data_A_sram_alloc(size_t size)
{
+#if L1_DATA_A_LENGTH != 0
unsigned long flags;
- void *addr = NULL;
+ void *addr;
unsigned int cpu;
cpu = get_cpu();
/* add mutex operation */
spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
-#if L1_DATA_A_LENGTH != 0
addr = _sram_alloc(size, &per_cpu(free_l1_data_A_sram_head, cpu),
&per_cpu(used_l1_data_A_sram_head, cpu));
-#endif
/* add mutex operation */
spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
@@ -437,11 +417,15 @@ void *l1_data_A_sram_alloc(size_t size)
(long unsigned int)addr, size);
return addr;
+#else
+ return NULL;
+#endif
}
EXPORT_SYMBOL(l1_data_A_sram_alloc);
int l1_data_A_sram_free(const void *addr)
{
+#if L1_DATA_A_LENGTH != 0
unsigned long flags;
int ret;
unsigned int cpu;
@@ -450,18 +434,17 @@ int l1_data_A_sram_free(const void *addr)
/* add mutex operation */
spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
-#if L1_DATA_A_LENGTH != 0
ret = _sram_free(addr, &per_cpu(free_l1_data_A_sram_head, cpu),
&per_cpu(used_l1_data_A_sram_head, cpu));
-#else
- ret = -1;
-#endif
/* add mutex operation */
spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
put_cpu();
return ret;
+#else
+ return -1;
+#endif
}
EXPORT_SYMBOL(l1_data_A_sram_free);