aboutsummaryrefslogtreecommitdiff
path: root/arch/blackfin/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/mm')
-rw-r--r--arch/blackfin/mm/Makefile2
-rw-r--r--arch/blackfin/mm/blackfin_sram.c806
-rw-r--r--arch/blackfin/mm/blackfin_sram.h28
-rw-r--r--arch/blackfin/mm/init.c202
-rw-r--r--arch/blackfin/mm/isram-driver.c410
-rw-r--r--arch/blackfin/mm/maccess.c97
-rw-r--r--arch/blackfin/mm/sram-alloc.c897
7 files changed, 1474 insertions, 968 deletions
diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile
index 2a7202ce01f..4c011b1f661 100644
--- a/arch/blackfin/mm/Makefile
+++ b/arch/blackfin/mm/Makefile
@@ -2,4 +2,4 @@
# arch/blackfin/mm/Makefile
#
-obj-y := blackfin_sram.o init.o
+obj-y := sram-alloc.o isram-driver.o init.o maccess.o
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/blackfin_sram.c
deleted file mode 100644
index 5af3c31c936..00000000000
--- a/arch/blackfin/mm/blackfin_sram.c
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * File: arch/blackfin/mm/blackfin_sram.c
- * Based on:
- * Author:
- *
- * Created:
- * Description: SRAM driver for Blackfin ADSP-BF5xx
- *
- * 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
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/rtc.h>
-#include <asm/blackfin.h>
-#include "blackfin_sram.h"
-
-static spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
-static spinlock_t l2_sram_lock;
-
-/* the data structure for L1 scratchpad and DATA SRAM */
-struct sram_piece {
- void *paddr;
- int size;
- pid_t pid;
- struct sram_piece *next;
-};
-
-static struct sram_piece free_l1_ssram_head, used_l1_ssram_head;
-
-#if L1_DATA_A_LENGTH != 0
-static struct sram_piece free_l1_data_A_sram_head, used_l1_data_A_sram_head;
-#endif
-
-#if L1_DATA_B_LENGTH != 0
-static struct sram_piece free_l1_data_B_sram_head, used_l1_data_B_sram_head;
-#endif
-
-#if L1_CODE_LENGTH != 0
-static struct sram_piece free_l1_inst_sram_head, used_l1_inst_sram_head;
-#endif
-
-#ifdef L2_LENGTH
-static struct sram_piece free_l2_sram_head, used_l2_sram_head;
-#endif
-
-static struct kmem_cache *sram_piece_cache;
-
-/* L1 Scratchpad SRAM initialization function */
-static void __init l1sram_init(void)
-{
- free_l1_ssram_head.next =
- kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
- if (!free_l1_ssram_head.next) {
- printk(KERN_INFO"Fail to initialize Scratchpad data SRAM.\n");
- return;
- }
-
- free_l1_ssram_head.next->paddr = (void *)L1_SCRATCH_START;
- free_l1_ssram_head.next->size = L1_SCRATCH_LENGTH;
- free_l1_ssram_head.next->pid = 0;
- free_l1_ssram_head.next->next = NULL;
-
- used_l1_ssram_head.next = NULL;
-
- /* mutex initialize */
- spin_lock_init(&l1sram_lock);
-
- printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
- L1_SCRATCH_LENGTH >> 10);
-}
-
-static void __init l1_data_sram_init(void)
-{
-#if L1_DATA_A_LENGTH != 0
- free_l1_data_A_sram_head.next =
- kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
- if (!free_l1_data_A_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L1 Data A SRAM.\n");
- return;
- }
-
- free_l1_data_A_sram_head.next->paddr =
- (void *)L1_DATA_A_START + (_ebss_l1 - _sdata_l1);
- free_l1_data_A_sram_head.next->size =
- L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
- free_l1_data_A_sram_head.next->pid = 0;
- free_l1_data_A_sram_head.next->next = NULL;
-
- used_l1_data_A_sram_head.next = NULL;
-
- printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
- L1_DATA_A_LENGTH >> 10,
- free_l1_data_A_sram_head.next->size >> 10);
-#endif
-#if L1_DATA_B_LENGTH != 0
- free_l1_data_B_sram_head.next =
- kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
- if (!free_l1_data_B_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L1 Data B SRAM.\n");
- return;
- }
-
- free_l1_data_B_sram_head.next->paddr =
- (void *)L1_DATA_B_START + (_ebss_b_l1 - _sdata_b_l1);
- free_l1_data_B_sram_head.next->size =
- L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
- free_l1_data_B_sram_head.next->pid = 0;
- free_l1_data_B_sram_head.next->next = NULL;
-
- used_l1_data_B_sram_head.next = NULL;
-
- printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
- L1_DATA_B_LENGTH >> 10,
- free_l1_data_B_sram_head.next->size >> 10);
-#endif
-
- /* mutex initialize */
- spin_lock_init(&l1_data_sram_lock);
-}
-
-static void __init l1_inst_sram_init(void)
-{
-#if L1_CODE_LENGTH != 0
- free_l1_inst_sram_head.next =
- kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
- if (!free_l1_inst_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L1 Instruction SRAM.\n");
- return;
- }
-
- free_l1_inst_sram_head.next->paddr =
- (void *)L1_CODE_START + (_etext_l1 - _stext_l1);
- free_l1_inst_sram_head.next->size =
- L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
- free_l1_inst_sram_head.next->pid = 0;
- free_l1_inst_sram_head.next->next = NULL;
-
- used_l1_inst_sram_head.next = NULL;
-
- printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
- L1_CODE_LENGTH >> 10,
- free_l1_inst_sram_head.next->size >> 10);
-#endif
-
- /* mutex initialize */
- spin_lock_init(&l1_inst_sram_lock);
-}
-
-static void __init l2_sram_init(void)
-{
-#ifdef L2_LENGTH
- free_l2_sram_head.next =
- kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
- if (!free_l2_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L2 SRAM.\n");
- return;
- }
-
- free_l2_sram_head.next->paddr = (void *)L2_START +
- (_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
- free_l2_sram_head.next->size = L2_LENGTH -
- (_etext_l2 - _stext_l2) + (_edata_l2 - _sdata_l2);
- free_l2_sram_head.next->pid = 0;
- free_l2_sram_head.next->next = NULL;
-
- used_l2_sram_head.next = NULL;
-
- 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);
-}
-void __init bfin_sram_init(void)
-{
- sram_piece_cache = kmem_cache_create("sram_piece_cache",
- sizeof(struct sram_piece),
- 0, SLAB_PANIC, NULL);
-
- l1sram_init();
- l1_data_sram_init();
- l1_inst_sram_init();
- l2_sram_init();
-}
-
-/* SRAM allocate function */
-static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
- struct sram_piece *pused_head)
-{
- struct sram_piece *pslot, *plast, *pavail;
-
- if (size <= 0 || !pfree_head || !pused_head)
- return NULL;
-
- /* Align the size */
- size = (size + 3) & ~3;
-
- pslot = pfree_head->next;
- plast = pfree_head;
-
- /* search an available piece slot */
- while (pslot != NULL && size > pslot->size) {
- plast = pslot;
- pslot = pslot->next;
- }
-
- if (!pslot)
- return NULL;
-
- if (pslot->size == size) {
- plast->next = pslot->next;
- pavail = pslot;
- } else {
- pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
-
- if (!pavail)
- return NULL;
-
- pavail->paddr = pslot->paddr;
- pavail->size = size;
- pslot->paddr += size;
- pslot->size -= size;
- }
-
- pavail->pid = current->pid;
-
- pslot = pused_head->next;
- plast = pused_head;
-
- /* insert new piece into used piece list !!! */
- while (pslot != NULL && pavail->paddr < pslot->paddr) {
- plast = pslot;
- pslot = pslot->next;
- }
-
- pavail->next = pslot;
- plast->next = pavail;
-
- return pavail->paddr;
-}
-
-/* Allocate the largest available block. */
-static void *_sram_alloc_max(struct sram_piece *pfree_head,
- struct sram_piece *pused_head,
- unsigned long *psize)
-{
- struct sram_piece *pslot, *pmax;
-
- if (!pfree_head || !pused_head)
- return NULL;
-
- pmax = pslot = pfree_head->next;
-
- /* search an available piece slot */
- while (pslot != NULL) {
- if (pslot->size > pmax->size)
- pmax = pslot;
- pslot = pslot->next;
- }
-
- if (!pmax)
- return NULL;
-
- *psize = pmax->size;
-
- return _sram_alloc(*psize, pfree_head, pused_head);
-}
-
-/* SRAM free function */
-static int _sram_free(const void *addr,
- struct sram_piece *pfree_head,
- struct sram_piece *pused_head)
-{
- struct sram_piece *pslot, *plast, *pavail;
-
- if (!pfree_head || !pused_head)
- return -1;
-
- /* search the relevant memory slot */
- pslot = pused_head->next;
- plast = pused_head;
-
- /* search an available piece slot */
- while (pslot != NULL && pslot->paddr != addr) {
- plast = pslot;
- pslot = pslot->next;
- }
-
- if (!pslot)
- return -1;
-
- plast->next = pslot->next;
- pavail = pslot;
- pavail->pid = 0;
-
- /* insert free pieces back to the free list */
- pslot = pfree_head->next;
- plast = pfree_head;
-
- while (pslot != NULL && addr > pslot->paddr) {
- plast = pslot;
- pslot = pslot->next;
- }
-
- if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
- plast->size += pavail->size;
- kmem_cache_free(sram_piece_cache, pavail);
- } else {
- pavail->next = plast;
- plast->next = pavail;
- plast = pavail;
- }
-
- if (pslot && plast->paddr + plast->size == pslot->paddr) {
- plast->size += pslot->size;
- plast->next = pslot->next;
- kmem_cache_free(sram_piece_cache, pslot);
- }
-
- return 0;
-}
-
-int sram_free(const void *addr)
-{
- if (0) {}
-#if L1_CODE_LENGTH != 0
- else if (addr >= (void *)L1_CODE_START
- && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
- return l1_inst_sram_free(addr);
-#endif
-#if L1_DATA_A_LENGTH != 0
- else if (addr >= (void *)L1_DATA_A_START
- && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
- return l1_data_A_sram_free(addr);
-#endif
-#if L1_DATA_B_LENGTH != 0
- else if (addr >= (void *)L1_DATA_B_START
- && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
- return l1_data_B_sram_free(addr);
-#endif
-#ifdef L2_LENGTH
- else if (addr >= (void *)L2_START
- && addr < (void *)(L2_START + L2_LENGTH))
- return l2_sram_free(addr);
-#endif
- else
- return -1;
-}
-EXPORT_SYMBOL(sram_free);
-
-void *l1_data_A_sram_alloc(size_t size)
-{
- unsigned flags;
- void *addr = NULL;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1_data_sram_lock, flags);
-
-#if L1_DATA_A_LENGTH != 0
- addr = _sram_alloc(size, &free_l1_data_A_sram_head,
- &used_l1_data_A_sram_head);
-#endif
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
- pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
- (long unsigned int)addr, size);
-
- return addr;
-}
-EXPORT_SYMBOL(l1_data_A_sram_alloc);
-
-int l1_data_A_sram_free(const void *addr)
-{
- unsigned flags;
- int ret;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1_data_sram_lock, flags);
-
-#if L1_DATA_A_LENGTH != 0
- ret = _sram_free(addr, &free_l1_data_A_sram_head,
- &used_l1_data_A_sram_head);
-#else
- ret = -1;
-#endif
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(l1_data_A_sram_free);
-
-void *l1_data_B_sram_alloc(size_t size)
-{
-#if L1_DATA_B_LENGTH != 0
- unsigned flags;
- void *addr;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1_data_sram_lock, flags);
-
- addr = _sram_alloc(size, &free_l1_data_B_sram_head,
- &used_l1_data_B_sram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
- pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
- (long unsigned int)addr, size);
-
- return addr;
-#else
- return NULL;
-#endif
-}
-EXPORT_SYMBOL(l1_data_B_sram_alloc);
-
-int l1_data_B_sram_free(const void *addr)
-{
-#if L1_DATA_B_LENGTH != 0
- unsigned flags;
- int ret;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1_data_sram_lock, flags);
-
- ret = _sram_free(addr, &free_l1_data_B_sram_head,
- &used_l1_data_B_sram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1_data_sram_lock, flags);
-
- return ret;
-#else
- return -1;
-#endif
-}
-EXPORT_SYMBOL(l1_data_B_sram_free);
-
-void *l1_data_sram_alloc(size_t size)
-{
- void *addr = l1_data_A_sram_alloc(size);
-
- if (!addr)
- addr = l1_data_B_sram_alloc(size);
-
- return addr;
-}
-EXPORT_SYMBOL(l1_data_sram_alloc);
-
-void *l1_data_sram_zalloc(size_t size)
-{
- void *addr = l1_data_sram_alloc(size);
-
- if (addr)
- memset(addr, 0x00, size);
-
- return addr;
-}
-EXPORT_SYMBOL(l1_data_sram_zalloc);
-
-int l1_data_sram_free(const void *addr)
-{
- int ret;
- ret = l1_data_A_sram_free(addr);
- if (ret == -1)
- ret = l1_data_B_sram_free(addr);
- return ret;
-}
-EXPORT_SYMBOL(l1_data_sram_free);
-
-void *l1_inst_sram_alloc(size_t size)
-{
-#if L1_CODE_LENGTH != 0
- unsigned flags;
- void *addr;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1_inst_sram_lock, flags);
-
- addr = _sram_alloc(size, &free_l1_inst_sram_head,
- &used_l1_inst_sram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
-
- pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
- (long unsigned int)addr, size);
-
- return addr;
-#else
- return NULL;
-#endif
-}
-EXPORT_SYMBOL(l1_inst_sram_alloc);
-
-int l1_inst_sram_free(const void *addr)
-{
-#if L1_CODE_LENGTH != 0
- unsigned flags;
- int ret;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1_inst_sram_lock, flags);
-
- ret = _sram_free(addr, &free_l1_inst_sram_head,
- &used_l1_inst_sram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
-
- return ret;
-#else
- return -1;
-#endif
-}
-EXPORT_SYMBOL(l1_inst_sram_free);
-
-/* L1 Scratchpad memory allocate function */
-void *l1sram_alloc(size_t size)
-{
- unsigned flags;
- void *addr;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1sram_lock, flags);
-
- addr = _sram_alloc(size, &free_l1_ssram_head,
- &used_l1_ssram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1sram_lock, flags);
-
- return addr;
-}
-
-/* L1 Scratchpad memory allocate function */
-void *l1sram_alloc_max(size_t *psize)
-{
- unsigned flags;
- void *addr;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1sram_lock, flags);
-
- addr = _sram_alloc_max(&free_l1_ssram_head,
- &used_l1_ssram_head, psize);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1sram_lock, flags);
-
- return addr;
-}
-
-/* L1 Scratchpad memory free function */
-int l1sram_free(const void *addr)
-{
- unsigned flags;
- int ret;
-
- /* add mutex operation */
- spin_lock_irqsave(&l1sram_lock, flags);
-
- ret = _sram_free(addr, &free_l1_ssram_head,
- &used_l1_ssram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l1sram_lock, flags);
-
- return ret;
-}
-
-void *l2_sram_alloc(size_t size)
-{
-#ifdef L2_LENGTH
- unsigned flags;
- void *addr;
-
- /* add mutex operation */
- spin_lock_irqsave(&l2_sram_lock, flags);
-
- addr = _sram_alloc(size, &free_l2_sram_head,
- &used_l2_sram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l2_sram_lock, flags);
-
- pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n",
- (long unsigned int)addr, size);
-
- return addr;
-#else
- return NULL;
-#endif
-}
-EXPORT_SYMBOL(l2_sram_alloc);
-
-void *l2_sram_zalloc(size_t size)
-{
- void *addr = l2_sram_alloc(size);
-
- if (addr)
- memset(addr, 0x00, size);
-
- return addr;
-}
-EXPORT_SYMBOL(l2_sram_zalloc);
-
-int l2_sram_free(const void *addr)
-{
-#ifdef L2_LENGTH
- unsigned flags;
- int ret;
-
- /* add mutex operation */
- spin_lock_irqsave(&l2_sram_lock, flags);
-
- ret = _sram_free(addr, &free_l2_sram_head,
- &used_l2_sram_head);
-
- /* add mutex operation */
- spin_unlock_irqrestore(&l2_sram_lock, flags);
-
- return ret;
-#else
- return -1;
-#endif
-}
-EXPORT_SYMBOL(l2_sram_free);
-
-int sram_free_with_lsl(const void *addr)
-{
- struct sram_list_struct *lsl, **tmp;
- struct mm_struct *mm = current->mm;
-
- for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
- if ((*tmp)->addr == addr)
- goto found;
- return -1;
-found:
- lsl = *tmp;
- sram_free(addr);
- *tmp = lsl->next;
- kfree(lsl);
-
- return 0;
-}
-EXPORT_SYMBOL(sram_free_with_lsl);
-
-void *sram_alloc_with_lsl(size_t size, unsigned long flags)
-{
- void *addr = NULL;
- struct sram_list_struct *lsl = NULL;
- struct mm_struct *mm = current->mm;
-
- lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
- if (!lsl)
- return NULL;
-
- if (flags & L1_INST_SRAM)
- addr = l1_inst_sram_alloc(size);
-
- if (addr == NULL && (flags & L1_DATA_A_SRAM))
- addr = l1_data_A_sram_alloc(size);
-
- if (addr == NULL && (flags & L1_DATA_B_SRAM))
- addr = l1_data_B_sram_alloc(size);
-
- if (addr == NULL && (flags & L2_SRAM))
- addr = l2_sram_alloc(size);
-
- if (addr == NULL) {
- kfree(lsl);
- return NULL;
- }
- lsl->addr = addr;
- lsl->length = size;
- lsl->next = mm->context.sram_list;
- mm->context.sram_list = lsl;
- return addr;
-}
-EXPORT_SYMBOL(sram_alloc_with_lsl);
-
-#ifdef CONFIG_PROC_FS
-/* Once we get a real allocator, we'll throw all of this away.
- * Until then, we need some sort of visibility into the L1 alloc.
- */
-/* Need to keep line of output the same. Currently, that is 44 bytes
- * (including newline).
- */
-static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
- struct sram_piece *pfree_head,
- struct sram_piece *pused_head)
-{
- struct sram_piece *pslot;
-
- if (!pfree_head || !pused_head)
- return -1;
-
- *len += sprintf(&buf[*len], "--- SRAM %-14s Size PID State \n", desc);
-
- /* search the relevant memory slot */
- pslot = pused_head->next;
-
- while (pslot != NULL) {
- *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
- pslot->paddr, pslot->paddr + pslot->size,
- pslot->size, pslot->pid, "ALLOCATED");
-
- pslot = pslot->next;
- }
-
- pslot = pfree_head->next;
-
- while (pslot != NULL) {
- *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
- pslot->paddr, pslot->paddr + pslot->size,
- pslot->size, pslot->pid, "FREE");
-
- pslot = pslot->next;
- }
-
- return 0;
-}
-static int sram_proc_read(char *buf, char **start, off_t offset, int count,
- int *eof, void *data)
-{
- int len = 0;
-
- if (_sram_proc_read(buf, &len, count, "Scratchpad",
- &free_l1_ssram_head, &used_l1_ssram_head))
- goto not_done;
-#if L1_DATA_A_LENGTH != 0
- if (_sram_proc_read(buf, &len, count, "L1 Data A",
- &free_l1_data_A_sram_head,
- &used_l1_data_A_sram_head))
- goto not_done;
-#endif
-#if L1_DATA_B_LENGTH != 0
- if (_sram_proc_read(buf, &len, count, "L1 Data B",
- &free_l1_data_B_sram_head,
- &used_l1_data_B_sram_head))
- goto not_done;
-#endif
-#if L1_CODE_LENGTH != 0
- if (_sram_proc_read(buf, &len, count, "L1 Instruction",
- &free_l1_inst_sram_head, &used_l1_inst_sram_head))
- goto not_done;
-#endif
-#ifdef L2_LENGTH
- if (_sram_proc_read(buf, &len, count, "L2",
- &free_l2_sram_head, &used_l2_sram_head))
- goto not_done;
-#endif
-
- *eof = 1;
- not_done:
- return len;
-}
-
-static int __init sram_proc_init(void)
-{
- struct proc_dir_entry *ptr;
- ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
- if (!ptr) {
- printk(KERN_WARNING "unable to create /proc/sram\n");
- return -1;
- }
- ptr->owner = THIS_MODULE;
- ptr->read_proc = sram_proc_read;
- return 0;
-}
-late_initcall(sram_proc_init);
-#endif
diff --git a/arch/blackfin/mm/blackfin_sram.h b/arch/blackfin/mm/blackfin_sram.h
index 8cb0945563f..fb0b1599cfb 100644
--- a/arch/blackfin/mm/blackfin_sram.h
+++ b/arch/blackfin/mm/blackfin_sram.h
@@ -1,36 +1,14 @@
/*
- * 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__
#define __BLACKFIN_SRAM_H__
-extern void bfin_sram_init(void);
extern void *l1sram_alloc(size_t);
#endif
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index bc240abb874..166842de3dc 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -1,57 +1,36 @@
/*
- * 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/gfp.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
#include <linux/uaccess.h>
+#include <linux/export.h>
#include <asm/bfin-global.h>
-#include <asm/l1layout.h>
+#include <asm/pda.h>
+#include <asm/cplbinit.h>
+#include <asm/early_printk.h>
#include "blackfin_sram.h"
/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
+ * ZERO_PAGE is a special page that is used for zero-initialized data and COW.
+ * Let the bss do its zero-init magic so we don't have to do it ourselves.
*/
-static unsigned long empty_bad_page_table;
+char empty_zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+EXPORT_SYMBOL(empty_zero_page);
-static unsigned long empty_bad_page;
+#ifndef CONFIG_EXCEPTION_L1_SCRATCH
+#if defined CONFIG_SYSCALL_TAB_L1
+__attribute__((l1_data))
+#endif
+static unsigned long exception_stack[NR_CPUS][1024];
+#endif
-unsigned long empty_zero_page;
+struct blackfin_pda cpu_pda[NR_CPUS];
+EXPORT_SYMBOL(cpu_pda);
/*
* paging_init() continues the virtual memory environment setup which
@@ -62,122 +41,73 @@ unsigned long empty_zero_page;
void __init paging_init(void)
{
/*
- * make sure start_mem is page aligned, otherwise bootmem and
- * page_alloc get different views og the world
+ * make sure start_mem is page aligned, otherwise bootmem and
+ * page_alloc get different views of the world
*/
unsigned long end_mem = memory_end & PAGE_MASK;
- pr_debug("start_mem is %#lx virtual_end is %#lx\n", PAGE_ALIGN(memory_start), end_mem);
-
- /*
- * initialize the bad page table and bad page to point
- * to a couple of allocated pages
- */
- empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
- empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
- empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
- memset((void *)empty_zero_page, 0, PAGE_SIZE);
+ unsigned long zones_size[MAX_NR_ZONES] = {
+ [0] = 0,
+ [ZONE_DMA] = (end_mem - CONFIG_PHY_RAM_BASE_ADDRESS) >> PAGE_SHIFT,
+ [ZONE_NORMAL] = 0,
+#ifdef CONFIG_HIGHMEM
+ [ZONE_HIGHMEM] = 0,
+#endif
+ };
- /*
- * Set up SFC/DFC registers (user data space)
- */
+ /* Set up SFC/DFC registers (user data space) */
set_fs(KERNEL_DS);
- pr_debug("free_area_init -> start_mem is %#lx virtual_end is %#lx\n",
+ pr_debug("free_area_init -> start_mem is %#lx virtual_end is %#lx\n",
PAGE_ALIGN(memory_start), end_mem);
+ free_area_init_node(0, zones_size,
+ CONFIG_PHY_RAM_BASE_ADDRESS >> PAGE_SHIFT, NULL);
+}
- {
- unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+asmlinkage void __init init_pda(void)
+{
+ unsigned int cpu = raw_smp_processor_id();
- zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
- zones_size[ZONE_NORMAL] = 0;
-#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = 0;
+ 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
+ valid pointers to it. */
+ memset(&cpu_pda[cpu], 0, sizeof(cpu_pda[cpu]));
+
+#ifdef CONFIG_EXCEPTION_L1_SCRATCH
+ cpu_pda[cpu].ex_stack = (unsigned long *)(L1_SCRATCH_START + \
+ L1_SCRATCH_LENGTH);
+#else
+ cpu_pda[cpu].ex_stack = exception_stack[cpu + 1];
+#endif
+
+#ifdef CONFIG_SMP
+ cpu_pda[cpu].imask = 0x1f;
#endif
- free_area_init(zones_size);
- }
}
void __init mem_init(void)
{
- unsigned int codek = 0, datak = 0, initk = 0;
- unsigned int reservedpages = 0, freepages = 0;
- unsigned long tmp;
- unsigned long start_mem = memory_start;
- unsigned long end_mem = memory_end;
-
- end_mem &= PAGE_MASK;
- high_memory = (void *)end_mem;
-
- start_mem = PAGE_ALIGN(start_mem);
- max_mapnr = num_physpages = MAP_NR(high_memory);
- printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", num_physpages);
-
- /* This will put all memory onto the freelists. */
- totalram_pages = free_all_bootmem();
-
- reservedpages = 0;
- for (tmp = 0; tmp < max_mapnr; tmp++)
- if (PageReserved(pfn_to_page(tmp)))
- reservedpages++;
- freepages = max_mapnr - reservedpages;
-
- /* do not count in kernel image between _rambase and _ramstart */
- reservedpages -= (_ramstart - _rambase) >> PAGE_SHIFT;
-#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
- reservedpages += (_ramend - memory_end - DMA_UNCACHED_REGION) >> PAGE_SHIFT;
-#endif
+ char buf[64];
- codek = (_etext - _stext) >> 10;
- initk = (__init_end - __init_begin) >> 10;
- datak = ((_ramstart - _rambase) >> 10) - codek - initk;
+ high_memory = (void *)(memory_end & PAGE_MASK);
+ max_mapnr = MAP_NR(high_memory);
+ printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", max_mapnr);
- printk(KERN_INFO
- "Memory available: %luk/%luk RAM, "
- "(%uk init code, %uk kernel code, %uk data, %uk dma, %uk reserved)\n",
- (unsigned long) freepages << (PAGE_SHIFT-10), _ramend >> 10,
- initk, codek, datak, DMA_UNCACHED_REGION >> 10, (reservedpages << (PAGE_SHIFT-10)));
-}
+ /* This will put all low memory onto the freelists. */
+ free_all_bootmem();
-static int __init sram_init(void)
-{
- unsigned long tmp;
-
- /* Initialize the blackfin L1 Memory. */
- bfin_sram_init();
-
- /* Allocate this once; never free it. We assume this gives us a
- pointer to the start of L1 scratchpad memory; panic if it
- doesn't. */
- tmp = (unsigned long)l1sram_alloc(sizeof(struct l1_scratch_task_info));
- if (tmp != (unsigned long)L1_SCRATCH_TASK_INFO) {
- printk(KERN_EMERG "mem_init(): Did not get the right address from l1sram_alloc: %08lx != %08lx\n",
- tmp, (unsigned long)L1_SCRATCH_TASK_INFO);
- panic("No L1, time to give up\n");
- }
-
- return 0;
-}
-pure_initcall(sram_init);
-
-static void __init free_init_pages(const char *what, unsigned long begin, unsigned long end)
-{
- unsigned long addr;
- /* next to check that the page we free is not a partial page */
- for (addr = begin; addr + PAGE_SIZE <= end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+ snprintf(buf, sizeof(buf) - 1, "%uK DMA", DMA_UNCACHED_REGION >> 10);
+ mem_init_print_info(buf);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
#ifndef CONFIG_MPU
- free_init_pages("initrd memory", start, end);
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
#endif
}
#endif
@@ -185,8 +115,8 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
void __init_refok free_initmem(void)
{
#if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
- free_init_pages("unused kernel memory",
- (unsigned long)(&__init_begin),
- (unsigned long)(&__init_end));
+ free_initmem_default(-1);
+ if (memory_start == (unsigned long)(&__init_end))
+ memory_start = (unsigned long)(&__init_begin);
#endif
}
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c
new file mode 100644
index 00000000000..7e2e674ed44
--- /dev/null
+++ b/arch/blackfin/mm/isram-driver.c
@@ -0,0 +1,410 @@
+/*
+ * Instruction SRAM accessor functions for the Blackfin
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * 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>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+
+/*
+ * IMPORTANT WARNING ABOUT THESE FUNCTIONS
+ *
+ * The emulator will not function correctly if a write command is left in
+ * ITEST_COMMAND or DTEST_COMMAND AND access to cache memory is needed by
+ * the emulator. To avoid such problems, ensure that both ITEST_COMMAND
+ * and DTEST_COMMAND are zero when exiting these functions.
+ */
+
+
+/*
+ * On the Blackfin, L1 instruction sram (which operates at core speeds) can not
+ * be accessed by a normal core load, so we need to go through a few hoops to
+ * read/write it.
+ * To try to make it easier - we export a memcpy interface, where either src or
+ * dest can be in this special L1 memory area.
+ * The low level read/write functions should not be exposed to the rest of the
+ * kernel, since they operate on 64-bit data, and need specific address alignment
+ */
+
+static DEFINE_SPINLOCK(dtest_lock);
+
+/* Takes a void pointer */
+#define IADDR2DTEST(x) \
+ ({ unsigned long __addr = (unsigned long)(x); \
+ ((__addr & (1 << 11)) << (26 - 11)) | /* addr bit 11 (Way0/Way1) */ \
+ (1 << 24) | /* instruction access = 1 */ \
+ ((__addr & (1 << 15)) << (23 - 15)) | /* addr bit 15 (Data Bank) */ \
+ ((__addr & (3 << 12)) << (16 - 12)) | /* addr bits 13:12 (Subbank) */ \
+ (__addr & 0x47F8) | /* addr bits 14 & 10:3 */ \
+ (1 << 2); /* data array = 1 */ \
+ })
+
+/* Takes a pointer, and returns the offset (in bits) which things should be shifted */
+#define ADDR2OFFSET(x) ((((unsigned long)(x)) & 0x7) * 8)
+
+/* Takes a pointer, determines if it is the last byte in the isram 64-bit data type */
+#define ADDR2LAST(x) ((((unsigned long)x) & 0x7) == 0x7)
+
+static void isram_write(const void *addr, uint64_t data)
+{
+ uint32_t cmd;
+ unsigned long flags;
+
+ if (unlikely(addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH)))
+ return;
+
+ cmd = IADDR2DTEST(addr) | 2; /* write */
+
+ /*
+ * Writes to DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+ * While in exception context - atomicity is guaranteed or double fault
+ */
+ spin_lock_irqsave(&dtest_lock, flags);
+
+ bfin_write_DTEST_DATA0(data & 0xFFFFFFFF);
+ bfin_write_DTEST_DATA1(data >> 32);
+
+ /* use the builtin, since interrupts are already turned off */
+ __builtin_bfin_csync();
+ bfin_write_DTEST_COMMAND(cmd);
+ __builtin_bfin_csync();
+
+ bfin_write_DTEST_COMMAND(0);
+ __builtin_bfin_csync();
+
+ spin_unlock_irqrestore(&dtest_lock, flags);
+}
+
+static uint64_t isram_read(const void *addr)
+{
+ uint32_t cmd;
+ unsigned long flags;
+ uint64_t ret;
+
+ if (unlikely(addr > (void *)(L1_CODE_START + L1_CODE_LENGTH)))
+ return 0;
+
+ cmd = IADDR2DTEST(addr) | 0; /* read */
+
+ /*
+ * Reads of DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+ * While in exception context - atomicity is guaranteed or double fault
+ */
+ spin_lock_irqsave(&dtest_lock, flags);
+ /* use the builtin, since interrupts are already turned off */
+ __builtin_bfin_csync();
+ bfin_write_DTEST_COMMAND(cmd);
+ __builtin_bfin_csync();
+ ret = bfin_read_DTEST_DATA0() | ((uint64_t)bfin_read_DTEST_DATA1() << 32);
+
+ bfin_write_DTEST_COMMAND(0);
+ __builtin_bfin_csync();
+ spin_unlock_irqrestore(&dtest_lock, flags);
+
+ return ret;
+}
+
+static bool isram_check_addr(const void *addr, size_t n)
+{
+ if ((addr >= (void *)L1_CODE_START) &&
+ (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
+ if (unlikely((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
+ show_stack(NULL, NULL);
+ pr_err("copy involving %p length (%zu) too long\n", addr, n);
+ }
+ return true;
+ }
+ return false;
+}
+
+/*
+ * The isram_memcpy() function copies n bytes from memory area src to memory area dest.
+ * The isram_memcpy() function returns a pointer to dest.
+ * Either dest or src can be in L1 instruction sram.
+ */
+void *isram_memcpy(void *dest, const void *src, size_t n)
+{
+ uint64_t data_in = 0, data_out = 0;
+ size_t count;
+ bool dest_in_l1, src_in_l1, need_data, put_data;
+ unsigned char byte, *src_byte, *dest_byte;
+
+ src_byte = (unsigned char *)src;
+ dest_byte = (unsigned char *)dest;
+
+ dest_in_l1 = isram_check_addr(dest, n);
+ src_in_l1 = isram_check_addr(src, n);
+
+ need_data = true;
+ put_data = true;
+ for (count = 0; count < n; count++) {
+ if (src_in_l1) {
+ if (need_data) {
+ data_in = isram_read(src + count);
+ need_data = false;
+ }
+
+ if (ADDR2LAST(src + count))
+ need_data = true;
+
+ byte = (unsigned char)((data_in >> ADDR2OFFSET(src + count)) & 0xff);
+
+ } else {
+ /* src is in L2 or L3 - so just dereference*/
+ byte = src_byte[count];
+ }
+
+ if (dest_in_l1) {
+ if (put_data) {
+ data_out = isram_read(dest + count);
+ put_data = false;
+ }
+
+ data_out &= ~((uint64_t)0xff << ADDR2OFFSET(dest + count));
+ data_out |= ((uint64_t)byte << ADDR2OFFSET(dest + count));
+
+ if (ADDR2LAST(dest + count)) {
+ put_data = true;
+ isram_write(dest + count, data_out);
+ }
+ } else {
+ /* dest in L2 or L3 - so just dereference */
+ dest_byte[count] = byte;
+ }
+ }
+
+ /* make sure we dump the last byte if necessary */
+ if (dest_in_l1 && !put_data)
+ isram_write(dest + count, data_out);
+
+ return dest;
+}
+EXPORT_SYMBOL(isram_memcpy);
+
+#ifdef CONFIG_BFIN_ISRAM_SELF_TEST
+
+static int test_len = 0x20000;
+
+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 % 255;
+ 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 (data1 != data2) {
+ 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 % 255;
+
+ /* 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 (data1 != data2) {
+ 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");
+
+ /* setup some different data to play with */
+ for (i = 0; i < test_len; ++i)
+ sdram[i] = i % 255;
+ 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;
+
+ /* Try to test as much of L1SRAM as possible */
+ while (test_len) {
+ test_len >>= 1;
+ l1inst = l1_inst_sram_alloc(test_len);
+ if (l1inst)
+ break;
+ }
+ if (!l1inst) {
+ pr_warning("SKIP: could not allocate L1 inst\n");
+ return 0;
+ }
+ pr_info("INFO: testing %#x bytes (%p - %p)\n",
+ test_len, l1inst, l1inst + test_len);
+
+ sdram = kmalloc(test_len * 2, GFP_KERNEL);
+ if (!sdram) {
+ sram_free(l1inst);
+ pr_warning("SKIP: could not allocate sdram\n");
+ return 0;
+ }
+
+ /* sanity check initial L1 inst state */
+ ret = 1;
+ pr_info("INFO: running initial dma_memcpy checks %p\n", sdram);
+ 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/maccess.c b/arch/blackfin/mm/maccess.c
new file mode 100644
index 00000000000..e2532114c5f
--- /dev/null
+++ b/arch/blackfin/mm/maccess.c
@@ -0,0 +1,97 @@
+/*
+ * safe read and write memory routines callable while atomic
+ *
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/uaccess.h>
+#include <asm/dma.h>
+
+static int validate_memory_access_address(unsigned long addr, int size)
+{
+ if (size < 0 || addr == 0)
+ return -EFAULT;
+ return bfin_mem_access_type(addr, size);
+}
+
+long probe_kernel_read(void *dst, const void *src, size_t size)
+{
+ unsigned long lsrc = (unsigned long)src;
+ int mem_type;
+
+ mem_type = validate_memory_access_address(lsrc, size);
+ if (mem_type < 0)
+ return mem_type;
+
+ if (lsrc >= SYSMMR_BASE) {
+ if (size == 2 && lsrc % 2 == 0) {
+ u16 mmr = bfin_read16(src);
+ memcpy(dst, &mmr, sizeof(mmr));
+ return 0;
+ } else if (size == 4 && lsrc % 4 == 0) {
+ u32 mmr = bfin_read32(src);
+ memcpy(dst, &mmr, sizeof(mmr));
+ return 0;
+ }
+ } else {
+ switch (mem_type) {
+ case BFIN_MEM_ACCESS_CORE:
+ case BFIN_MEM_ACCESS_CORE_ONLY:
+ return __probe_kernel_read(dst, src, size);
+ /* XXX: should support IDMA here with SMP */
+ case BFIN_MEM_ACCESS_DMA:
+ if (dma_memcpy(dst, src, size))
+ return 0;
+ break;
+ case BFIN_MEM_ACCESS_ITEST:
+ if (isram_memcpy(dst, src, size))
+ return 0;
+ break;
+ }
+ }
+
+ return -EFAULT;
+}
+
+long probe_kernel_write(void *dst, const void *src, size_t size)
+{
+ unsigned long ldst = (unsigned long)dst;
+ int mem_type;
+
+ mem_type = validate_memory_access_address(ldst, size);
+ if (mem_type < 0)
+ return mem_type;
+
+ if (ldst >= SYSMMR_BASE) {
+ if (size == 2 && ldst % 2 == 0) {
+ u16 mmr;
+ memcpy(&mmr, src, sizeof(mmr));
+ bfin_write16(dst, mmr);
+ return 0;
+ } else if (size == 4 && ldst % 4 == 0) {
+ u32 mmr;
+ memcpy(&mmr, src, sizeof(mmr));
+ bfin_write32(dst, mmr);
+ return 0;
+ }
+ } else {
+ switch (mem_type) {
+ case BFIN_MEM_ACCESS_CORE:
+ case BFIN_MEM_ACCESS_CORE_ONLY:
+ return __probe_kernel_write(dst, src, size);
+ /* XXX: should support IDMA here with SMP */
+ case BFIN_MEM_ACCESS_DMA:
+ if (dma_memcpy(dst, src, size))
+ return 0;
+ break;
+ case BFIN_MEM_ACCESS_ITEST:
+ if (isram_memcpy(dst, src, size))
+ return 0;
+ break;
+ }
+ }
+
+ return -EFAULT;
+}
diff --git a/arch/blackfin/mm/sram-alloc.c b/arch/blackfin/mm/sram-alloc.c
new file mode 100644
index 00000000000..1f3b3ef3e10
--- /dev/null
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -0,0 +1,897 @@
+/*
+ * SRAM allocator for Blackfin on-chip memory
+ *
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <asm/blackfin.h>
+#include <asm/mem_map.h>
+#include "blackfin_sram.h"
+
+/* the data structure for L1 scratchpad and DATA SRAM */
+struct sram_piece {
+ void *paddr;
+ int size;
+ pid_t pid;
+ 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);
+
+#if L1_DATA_A_LENGTH != 0
+static DEFINE_PER_CPU(struct sram_piece, free_l1_data_A_sram_head);
+static DEFINE_PER_CPU(struct sram_piece, used_l1_data_A_sram_head);
+#endif
+
+#if L1_DATA_B_LENGTH != 0
+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
+
+static struct kmem_cache *sram_piece_cache;
+
+/* L1 Scratchpad SRAM initialization function */
+static void __init l1sram_init(void)
+{
+ unsigned int cpu;
+ unsigned long reserve;
+
+#ifdef CONFIG_SMP
+ reserve = 0;
+#else
+ reserve = sizeof(struct l1_scratch_task_info);
+#endif
+
+ for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
+ per_cpu(free_l1_ssram_head, cpu).next =
+ kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+ if (!per_cpu(free_l1_ssram_head, cpu).next) {
+ printk(KERN_INFO "Fail to initialize Scratchpad data SRAM.\n");
+ return;
+ }
+
+ per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu) + reserve;
+ per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH - reserve;
+ per_cpu(free_l1_ssram_head, cpu).next->pid = 0;
+ per_cpu(free_l1_ssram_head, cpu).next->next = NULL;
+
+ per_cpu(used_l1_ssram_head, cpu).next = NULL;
+
+ /* mutex initialize */
+ spin_lock_init(&per_cpu(l1sram_lock, cpu));
+ printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
+ L1_SCRATCH_LENGTH >> 10);
+ }
+}
+
+static void __init l1_data_sram_init(void)
+{
+#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
+ unsigned int cpu;
+#endif
+#if L1_DATA_A_LENGTH != 0
+ for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
+ per_cpu(free_l1_data_A_sram_head, cpu).next =
+ kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+ if (!per_cpu(free_l1_data_A_sram_head, cpu).next) {
+ printk(KERN_INFO "Fail to initialize L1 Data A SRAM.\n");
+ return;
+ }
+
+ per_cpu(free_l1_data_A_sram_head, cpu).next->paddr =
+ (void *)get_l1_data_a_start_cpu(cpu) + (_ebss_l1 - _sdata_l1);
+ per_cpu(free_l1_data_A_sram_head, cpu).next->size =
+ L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
+ per_cpu(free_l1_data_A_sram_head, cpu).next->pid = 0;
+ per_cpu(free_l1_data_A_sram_head, cpu).next->next = NULL;
+
+ per_cpu(used_l1_data_A_sram_head, cpu).next = NULL;
+
+ printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
+ L1_DATA_A_LENGTH >> 10,
+ per_cpu(free_l1_data_A_sram_head, cpu).next->size >> 10);
+ }
+#endif
+#if L1_DATA_B_LENGTH != 0
+ for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
+ per_cpu(free_l1_data_B_sram_head, cpu).next =
+ kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+ if (!per_cpu(free_l1_data_B_sram_head, cpu).next) {
+ printk(KERN_INFO "Fail to initialize L1 Data B SRAM.\n");
+ return;
+ }
+
+ per_cpu(free_l1_data_B_sram_head, cpu).next->paddr =
+ (void *)get_l1_data_b_start_cpu(cpu) + (_ebss_b_l1 - _sdata_b_l1);
+ per_cpu(free_l1_data_B_sram_head, cpu).next->size =
+ L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
+ per_cpu(free_l1_data_B_sram_head, cpu).next->pid = 0;
+ per_cpu(free_l1_data_B_sram_head, cpu).next->next = NULL;
+
+ per_cpu(used_l1_data_B_sram_head, cpu).next = NULL;
+
+ printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
+ L1_DATA_B_LENGTH >> 10,
+ per_cpu(free_l1_data_B_sram_head, cpu).next->size >> 10);
+ /* mutex initialize */
+ }
+#endif
+
+#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
+ for (cpu = 0; cpu < num_possible_cpus(); ++cpu)
+ spin_lock_init(&per_cpu(l1_data_sram_lock, cpu));
+#endif
+}
+
+static void __init l1_inst_sram_init(void)
+{
+#if L1_CODE_LENGTH != 0
+ unsigned int cpu;
+ for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
+ per_cpu(free_l1_inst_sram_head, cpu).next =
+ kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+ if (!per_cpu(free_l1_inst_sram_head, cpu).next) {
+ printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
+ return;
+ }
+
+ per_cpu(free_l1_inst_sram_head, cpu).next->paddr =
+ (void *)get_l1_code_start_cpu(cpu) + (_etext_l1 - _stext_l1);
+ per_cpu(free_l1_inst_sram_head, cpu).next->size =
+ L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
+ per_cpu(free_l1_inst_sram_head, cpu).next->pid = 0;
+ per_cpu(free_l1_inst_sram_head, cpu).next->next = NULL;
+
+ per_cpu(used_l1_inst_sram_head, cpu).next = NULL;
+
+ printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
+ L1_CODE_LENGTH >> 10,
+ per_cpu(free_l1_inst_sram_head, cpu).next->size >> 10);
+
+ /* mutex initialize */
+ spin_lock_init(&per_cpu(l1_inst_sram_lock, cpu));
+ }
+#endif
+}
+
+#ifdef __ADSPBF60x__
+static irqreturn_t l2_ecc_err(int irq, void *dev_id)
+{
+ int status;
+
+ printk(KERN_ERR "L2 ecc error happened\n");
+ status = bfin_read32(L2CTL0_STAT);
+ if (status & 0x1)
+ printk(KERN_ERR "Core channel error type:0x%x, addr:0x%x\n",
+ bfin_read32(L2CTL0_ET0), bfin_read32(L2CTL0_EADDR0));
+ if (status & 0x2)
+ printk(KERN_ERR "System channel error type:0x%x, addr:0x%x\n",
+ bfin_read32(L2CTL0_ET1), bfin_read32(L2CTL0_EADDR1));
+
+ status = status >> 8;
+ if (status)
+ printk(KERN_ERR "L2 Bank%d error, addr:0x%x\n",
+ status, bfin_read32(L2CTL0_ERRADDR0 + status));
+
+ panic("L2 Ecc error");
+ return IRQ_HANDLED;
+}
+#endif
+
+static void __init l2_sram_init(void)
+{
+#if L2_LENGTH != 0
+
+#ifdef __ADSPBF60x__
+ int ret;
+
+ ret = request_irq(IRQ_L2CTL0_ECC_ERR, l2_ecc_err, 0, "l2-ecc-err",
+ NULL);
+ if (unlikely(ret < 0)) {
+ printk(KERN_INFO "Fail to request l2 ecc error interrupt");
+ return;
+ }
+#endif
+
+ free_l2_sram_head.next =
+ kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
+ if (!free_l2_sram_head.next) {
+ printk(KERN_INFO "Fail to initialize L2 SRAM.\n");
+ return;
+ }
+
+ free_l2_sram_head.next->paddr =
+ (void *)L2_START + (_ebss_l2 - _stext_l2);
+ free_l2_sram_head.next->size =
+ L2_LENGTH - (_ebss_l2 - _stext_l2);
+ free_l2_sram_head.next->pid = 0;
+ free_l2_sram_head.next->next = NULL;
+
+ used_l2_sram_head.next = NULL;
+
+ printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n",
+ L2_LENGTH >> 10,
+ free_l2_sram_head.next->size >> 10);
+
+ /* mutex initialize */
+ spin_lock_init(&l2_sram_lock);
+#endif
+}
+
+static int __init bfin_sram_init(void)
+{
+ sram_piece_cache = kmem_cache_create("sram_piece_cache",
+ sizeof(struct sram_piece),
+ 0, SLAB_PANIC, NULL);
+
+ l1sram_init();
+ l1_data_sram_init();
+ l1_inst_sram_init();
+ l2_sram_init();
+
+ return 0;
+}
+pure_initcall(bfin_sram_init);
+
+/* SRAM allocate function */
+static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
+ struct sram_piece *pused_head)
+{
+ struct sram_piece *pslot, *plast, *pavail;
+
+ if (size <= 0 || !pfree_head || !pused_head)
+ return NULL;
+
+ /* Align the size */
+ size = (size + 3) & ~3;
+
+ pslot = pfree_head->next;
+ plast = pfree_head;
+
+ /* search an available piece slot */
+ while (pslot != NULL && size > pslot->size) {
+ plast = pslot;
+ pslot = pslot->next;
+ }
+
+ if (!pslot)
+ return NULL;
+
+ if (pslot->size == size) {
+ plast->next = pslot->next;
+ pavail = pslot;
+ } else {
+ /* use atomic so our L1 allocator can be used atomically */
+ pavail = kmem_cache_alloc(sram_piece_cache, GFP_ATOMIC);
+
+ if (!pavail)
+ return NULL;
+
+ pavail->paddr = pslot->paddr;
+ pavail->size = size;
+ pslot->paddr += size;
+ pslot->size -= size;
+ }
+
+ pavail->pid = current->pid;
+
+ pslot = pused_head->next;
+ plast = pused_head;
+
+ /* insert new piece into used piece list !!! */
+ while (pslot != NULL && pavail->paddr < pslot->paddr) {
+ plast = pslot;
+ pslot = pslot->next;
+ }
+
+ pavail->next = pslot;
+ plast->next = pavail;
+
+ return pavail->paddr;
+}
+
+/* Allocate the largest available block. */
+static void *_sram_alloc_max(struct sram_piece *pfree_head,
+ struct sram_piece *pused_head,
+ unsigned long *psize)
+{
+ struct sram_piece *pslot, *pmax;
+
+ if (!pfree_head || !pused_head)
+ return NULL;
+
+ pmax = pslot = pfree_head->next;
+
+ /* search an available piece slot */
+ while (pslot != NULL) {
+ if (pslot->size > pmax->size)
+ pmax = pslot;
+ pslot = pslot->next;
+ }
+
+ if (!pmax)
+ return NULL;
+
+ *psize = pmax->size;
+
+ return _sram_alloc(*psize, pfree_head, pused_head);
+}
+
+/* SRAM free function */
+static int _sram_free(const void *addr,
+ struct sram_piece *pfree_head,
+ struct sram_piece *pused_head)
+{
+ struct sram_piece *pslot, *plast, *pavail;
+
+ if (!pfree_head || !pused_head)
+ return -1;
+
+ /* search the relevant memory slot */
+ pslot = pused_head->next;
+ plast = pused_head;
+
+ /* search an available piece slot */
+ while (pslot != NULL && pslot->paddr != addr) {
+ plast = pslot;
+ pslot = pslot->next;
+ }
+
+ if (!pslot)
+ return -1;
+
+ plast->next = pslot->next;
+ pavail = pslot;
+ pavail->pid = 0;
+
+ /* insert free pieces back to the free list */
+ pslot = pfree_head->next;
+ plast = pfree_head;
+
+ while (pslot != NULL && addr > pslot->paddr) {
+ plast = pslot;
+ pslot = pslot->next;
+ }
+
+ if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
+ plast->size += pavail->size;
+ kmem_cache_free(sram_piece_cache, pavail);
+ } else {
+ pavail->next = plast->next;
+ plast->next = pavail;
+ plast = pavail;
+ }
+
+ if (pslot && plast->paddr + plast->size == pslot->paddr) {
+ plast->size += pslot->size;
+ plast->next = pslot->next;
+ kmem_cache_free(sram_piece_cache, pslot);
+ }
+
+ return 0;
+}
+
+int sram_free(const void *addr)
+{
+
+#if L1_CODE_LENGTH != 0
+ if (addr >= (void *)get_l1_code_start()
+ && addr < (void *)(get_l1_code_start() + L1_CODE_LENGTH))
+ return l1_inst_sram_free(addr);
+ else
+#endif
+#if L1_DATA_A_LENGTH != 0
+ if (addr >= (void *)get_l1_data_a_start()
+ && addr < (void *)(get_l1_data_a_start() + L1_DATA_A_LENGTH))
+ return l1_data_A_sram_free(addr);
+ else
+#endif
+#if L1_DATA_B_LENGTH != 0
+ if (addr >= (void *)get_l1_data_b_start()
+ && addr < (void *)(get_l1_data_b_start() + L1_DATA_B_LENGTH))
+ return l1_data_B_sram_free(addr);
+ else
+#endif
+#if L2_LENGTH != 0
+ if (addr >= (void *)L2_START
+ && addr < (void *)(L2_START + L2_LENGTH))
+ return l2_sram_free(addr);
+ else
+#endif
+ return -1;
+}
+EXPORT_SYMBOL(sram_free);
+
+void *l1_data_A_sram_alloc(size_t size)
+{
+#if L1_DATA_A_LENGTH != 0
+ unsigned long flags;
+ void *addr;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ addr = _sram_alloc(size, &per_cpu(free_l1_data_A_sram_head, cpu),
+ &per_cpu(used_l1_data_A_sram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
+ (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;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ ret = _sram_free(addr, &per_cpu(free_l1_data_A_sram_head, cpu),
+ &per_cpu(used_l1_data_A_sram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_data_A_sram_free);
+
+void *l1_data_B_sram_alloc(size_t size)
+{
+#if L1_DATA_B_LENGTH != 0
+ unsigned long flags;
+ void *addr;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ addr = _sram_alloc(size, &per_cpu(free_l1_data_B_sram_head, cpu),
+ &per_cpu(used_l1_data_B_sram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
+ (long unsigned int)addr, size);
+
+ return addr;
+#else
+ return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_alloc);
+
+int l1_data_B_sram_free(const void *addr)
+{
+#if L1_DATA_B_LENGTH != 0
+ unsigned long flags;
+ int ret;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ ret = _sram_free(addr, &per_cpu(free_l1_data_B_sram_head, cpu),
+ &per_cpu(used_l1_data_B_sram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_free);
+
+void *l1_data_sram_alloc(size_t size)
+{
+ void *addr = l1_data_A_sram_alloc(size);
+
+ if (!addr)
+ addr = l1_data_B_sram_alloc(size);
+
+ return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_alloc);
+
+void *l1_data_sram_zalloc(size_t size)
+{
+ void *addr = l1_data_sram_alloc(size);
+
+ if (addr)
+ memset(addr, 0x00, size);
+
+ return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_zalloc);
+
+int l1_data_sram_free(const void *addr)
+{
+ int ret;
+ ret = l1_data_A_sram_free(addr);
+ if (ret == -1)
+ ret = l1_data_B_sram_free(addr);
+ return ret;
+}
+EXPORT_SYMBOL(l1_data_sram_free);
+
+void *l1_inst_sram_alloc(size_t size)
+{
+#if L1_CODE_LENGTH != 0
+ unsigned long flags;
+ void *addr;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
+
+ addr = _sram_alloc(size, &per_cpu(free_l1_inst_sram_head, cpu),
+ &per_cpu(used_l1_inst_sram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
+
+ pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
+ (long unsigned int)addr, size);
+
+ return addr;
+#else
+ return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_alloc);
+
+int l1_inst_sram_free(const void *addr)
+{
+#if L1_CODE_LENGTH != 0
+ unsigned long flags;
+ int ret;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
+
+ ret = _sram_free(addr, &per_cpu(free_l1_inst_sram_head, cpu),
+ &per_cpu(used_l1_inst_sram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_free);
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc(size_t size)
+{
+ unsigned long flags;
+ void *addr;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
+
+ addr = _sram_alloc(size, &per_cpu(free_l1_ssram_head, cpu),
+ &per_cpu(used_l1_ssram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
+
+ return addr;
+}
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc_max(size_t *psize)
+{
+ unsigned long flags;
+ void *addr;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
+
+ addr = _sram_alloc_max(&per_cpu(free_l1_ssram_head, cpu),
+ &per_cpu(used_l1_ssram_head, cpu), psize);
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
+
+ return addr;
+}
+
+/* L1 Scratchpad memory free function */
+int l1sram_free(const void *addr)
+{
+ unsigned long flags;
+ int ret;
+ unsigned int cpu;
+
+ cpu = smp_processor_id();
+ /* add mutex operation */
+ spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
+
+ ret = _sram_free(addr, &per_cpu(free_l1_ssram_head, cpu),
+ &per_cpu(used_l1_ssram_head, cpu));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
+
+ return ret;
+}
+
+void *l2_sram_alloc(size_t size)
+{
+#if L2_LENGTH != 0
+ unsigned long flags;
+ void *addr;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l2_sram_lock, flags);
+
+ addr = _sram_alloc(size, &free_l2_sram_head,
+ &used_l2_sram_head);
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l2_sram_lock, flags);
+
+ pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n",
+ (long unsigned int)addr, size);
+
+ return addr;
+#else
+ return NULL;
+#endif
+}
+EXPORT_SYMBOL(l2_sram_alloc);
+
+void *l2_sram_zalloc(size_t size)
+{
+ void *addr = l2_sram_alloc(size);
+
+ if (addr)
+ memset(addr, 0x00, size);
+
+ return addr;
+}
+EXPORT_SYMBOL(l2_sram_zalloc);
+
+int l2_sram_free(const void *addr)
+{
+#if L2_LENGTH != 0
+ unsigned long flags;
+ int ret;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l2_sram_lock, flags);
+
+ ret = _sram_free(addr, &free_l2_sram_head,
+ &used_l2_sram_head);
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l2_sram_lock, flags);
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+EXPORT_SYMBOL(l2_sram_free);
+
+int sram_free_with_lsl(const void *addr)
+{
+ struct sram_list_struct *lsl, **tmp;
+ struct mm_struct *mm = current->mm;
+ int ret = -1;
+
+ for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
+ if ((*tmp)->addr == addr) {
+ lsl = *tmp;
+ ret = sram_free(addr);
+ *tmp = lsl->next;
+ kfree(lsl);
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(sram_free_with_lsl);
+
+/* Allocate memory and keep in L1 SRAM List (lsl) so that the resources are
+ * tracked. These are designed for userspace so that when a process exits,
+ * we can safely reap their resources.
+ */
+void *sram_alloc_with_lsl(size_t size, unsigned long flags)
+{
+ void *addr = NULL;
+ struct sram_list_struct *lsl = NULL;
+ struct mm_struct *mm = current->mm;
+
+ lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
+ if (!lsl)
+ return NULL;
+
+ if (flags & L1_INST_SRAM)
+ addr = l1_inst_sram_alloc(size);
+
+ if (addr == NULL && (flags & L1_DATA_A_SRAM))
+ addr = l1_data_A_sram_alloc(size);
+
+ if (addr == NULL && (flags & L1_DATA_B_SRAM))
+ addr = l1_data_B_sram_alloc(size);
+
+ if (addr == NULL && (flags & L2_SRAM))
+ addr = l2_sram_alloc(size);
+
+ if (addr == NULL) {
+ kfree(lsl);
+ return NULL;
+ }
+ lsl->addr = addr;
+ lsl->length = size;
+ lsl->next = mm->context.sram_list;
+ mm->context.sram_list = lsl;
+ return addr;
+}
+EXPORT_SYMBOL(sram_alloc_with_lsl);
+
+#ifdef CONFIG_PROC_FS
+/* Once we get a real allocator, we'll throw all of this away.
+ * Until then, we need some sort of visibility into the L1 alloc.
+ */
+/* Need to keep line of output the same. Currently, that is 44 bytes
+ * (including newline).
+ */
+static int _sram_proc_show(struct seq_file *m, const char *desc,
+ struct sram_piece *pfree_head,
+ struct sram_piece *pused_head)
+{
+ struct sram_piece *pslot;
+
+ if (!pfree_head || !pused_head)
+ return -1;
+
+ seq_printf(m, "--- SRAM %-14s Size PID State \n", desc);
+
+ /* search the relevant memory slot */
+ pslot = pused_head->next;
+
+ while (pslot != NULL) {
+ seq_printf(m, "%p-%p %10i %5i %-10s\n",
+ pslot->paddr, pslot->paddr + pslot->size,
+ pslot->size, pslot->pid, "ALLOCATED");
+
+ pslot = pslot->next;
+ }
+
+ pslot = pfree_head->next;
+
+ while (pslot != NULL) {
+ seq_printf(m, "%p-%p %10i %5i %-10s\n",
+ pslot->paddr, pslot->paddr + pslot->size,
+ pslot->size, pslot->pid, "FREE");
+
+ pslot = pslot->next;
+ }
+
+ return 0;
+}
+static int sram_proc_show(struct seq_file *m, void *v)
+{
+ unsigned int cpu;
+
+ for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
+ if (_sram_proc_show(m, "Scratchpad",
+ &per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
+ goto not_done;
+#if L1_DATA_A_LENGTH != 0
+ if (_sram_proc_show(m, "L1 Data A",
+ &per_cpu(free_l1_data_A_sram_head, cpu),
+ &per_cpu(used_l1_data_A_sram_head, cpu)))
+ goto not_done;
+#endif
+#if L1_DATA_B_LENGTH != 0
+ if (_sram_proc_show(m, "L1 Data B",
+ &per_cpu(free_l1_data_B_sram_head, cpu),
+ &per_cpu(used_l1_data_B_sram_head, cpu)))
+ goto not_done;
+#endif
+#if L1_CODE_LENGTH != 0
+ if (_sram_proc_show(m, "L1 Instruction",
+ &per_cpu(free_l1_inst_sram_head, cpu),
+ &per_cpu(used_l1_inst_sram_head, cpu)))
+ goto not_done;
+#endif
+ }
+#if L2_LENGTH != 0
+ if (_sram_proc_show(m, "L2", &free_l2_sram_head, &used_l2_sram_head))
+ goto not_done;
+#endif
+ not_done:
+ return 0;
+}
+
+static int sram_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, sram_proc_show, NULL);
+}
+
+static const struct file_operations sram_proc_ops = {
+ .open = sram_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init sram_proc_init(void)
+{
+ struct proc_dir_entry *ptr;
+
+ ptr = proc_create("sram", S_IRUGO, NULL, &sram_proc_ops);
+ if (!ptr) {
+ printk(KERN_WARNING "unable to create /proc/sram\n");
+ return -1;
+ }
+ return 0;
+}
+late_initcall(sram_proc_init);
+#endif