1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2025-04-21 12:27:27 +03:00

[ubicom32]: move new files out from platform support patch

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@19815 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
kaloz
2010-02-22 13:54:47 +00:00
parent fdcca1ea95
commit 1a29ef8e97
279 changed files with 56440 additions and 57274 deletions

View File

@@ -0,0 +1,32 @@
#
# arch/ubicom32/mm/Makefile
# <TODO: Replace with short file description>
#
# (C) Copyright 2009, Ubicom, Inc.
#
# This file is part of the Ubicom32 Linux Kernel Port.
#
# The Ubicom32 Linux Kernel Port 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.
#
# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not,
# see <http://www.gnu.org/licenses/>.
#
# Ubicom32 implementation derived from (with many thanks):
# arch/m68knommu
# arch/blackfin
# arch/parisc
#
#
# Makefile for the linux m68knommu specific parts of the memory manager.
#
obj-y += init.o fault.o memory.o kmap.o ocm-alloc.o

View File

@@ -0,0 +1,80 @@
/*
* arch/ubicom32/mm/fault.c
* Ubicom32 architecture page fault implementation.
*
* (C) Copyright 2009, Ubicom, Inc.
* Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
* Copyright (C) 2000 Lineo, Inc. (www.lineo.com)
*
* Based on:
*
* linux/arch/m68k/mm/fault.c
*
* Copyright (C) 1995 Hamish Macdonald
*
* This file is part of the Ubicom32 Linux Kernel Port.
*
* The Ubicom32 Linux Kernel Port 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.
*
* The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not,
* see <http://www.gnu.org/licenses/>.
*
* Ubicom32 implementation derived from (with many thanks):
* arch/m68knommu
* arch/blackfin
* arch/parisc
*/
#include <linux/module.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <asm/system.h>
#include <asm/pgtable.h>
extern void die_if_kernel(char *, struct pt_regs *, long);
/*
* This routine handles page faults. It determines the problem, and
* then passes it off to one of the appropriate routines.
*
* error_code:
* bit 0 == 0 means no page found, 1 means protection fault
* bit 1 == 0 means read, 1 means write
*
* If this routine detects a bad access, it returns 1, otherwise it
* returns 0.
*/
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
#ifdef DEBUG
printk (KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
regs->sr, regs->pc, address, error_code);
#endif
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
if ((unsigned long) address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
} else
printk(KERN_ALERT "Unable to handle kernel access");
printk(KERN_ALERT " at virtual address %08lx\n",address);
die_if_kernel("Oops", regs, error_code);
do_exit(SIGKILL);
return 1;
}

View File

@@ -0,0 +1,262 @@
/*
* arch/ubicom32/mm/init.c
* Ubicom32 architecture virtual memory initialization.
*
* (C) Copyright 2009, Ubicom, Inc.
* Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
* Kenneth Albanowski <kjahds@kjahds.com>,
* Copyright (C) 2000 Lineo, Inc. (www.lineo.com)
*
* Based on:
*
* linux/arch/m68k/mm/init.c
*
* Copyright (C) 1995 Hamish Macdonald
*
* JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com)
* DEC/2000 -- linux 2.4 support <davidm@snapgear.com>
*
* This file is part of the Ubicom32 Linux Kernel Port.
*
* The Ubicom32 Linux Kernel Port 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.
*
* The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not,
* see <http://www.gnu.org/licenses/>.
*
* Ubicom32 implementation derived from (with many thanks):
* arch/m68knommu
* arch/blackfin
* arch/parisc
*/
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/machdep.h>
#include <asm/ocm-alloc.h>
#include <asm/processor.h>
#undef DEBUG
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void free_initmem(void);
/*
* 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.
*/
static unsigned long empty_bad_page_table;
static unsigned long empty_bad_page;
unsigned long empty_zero_page;
void show_mem(void)
{
unsigned long i;
int free = 0, total = 0, reserved = 0, shared = 0;
int cached = 0;
printk(KERN_INFO "\nMem-info:\n");
show_free_areas();
i = max_mapnr;
while (i-- > 0) {
total++;
if (PageReserved(mem_map+i))
reserved++;
else if (PageSwapCache(mem_map+i))
cached++;
else if (!page_count(mem_map+i))
free++;
else
shared += page_count(mem_map+i) - 1;
}
printk(KERN_INFO "%d pages of RAM\n",total);
printk(KERN_INFO "%d free pages\n",free);
printk(KERN_INFO "%d reserved pages\n",reserved);
printk(KERN_INFO "%d pages shared\n",shared);
printk(KERN_INFO "%d pages swap cached\n",cached);
}
extern unsigned long memory_start;
extern unsigned long memory_end;
extern char __ocm_free_begin;
extern char __ocm_free_end;
/*
* paging_init() continues the virtual memory environment setup which
* was begun by the code in arch/head.S.
* The parameters are pointers to where to stick the starting and ending
* addresses of available kernel virtual memory.
*/
void __init paging_init(void)
{
/*
* Make sure start_mem is page aligned, otherwise bootmem and
* page_alloc get different views of the world.
*/
#ifdef DEBUG
unsigned long start_mem = PAGE_ALIGN(memory_start);
#endif
unsigned long end_mem = memory_end & PAGE_MASK;
#ifdef DEBUG
printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
start_mem, end_mem);
#endif
/*
* 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);
/*
* TODO: enable setting up for user memory management interface.
*/
#ifdef DEBUG
printk (KERN_DEBUG "before free_area_init\n");
printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
start_mem, end_mem);
#endif
{
unsigned long zones_size[MAX_NR_ZONES] = {0, };
#ifdef CONFIG_ZONE_DMA
zones_size[ZONE_DMA] = OCMSIZE >> PAGE_SHIFT;
#endif
zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
#ifdef CONFIG_HIGHMEM
zones_size[ZONE_HIGHMEM] = 0;
#endif
free_area_init(zones_size);
}
}
void __init mem_init(void)
{
int codek = 0, datak = 0, initk = 0;
unsigned long tmp, ram_start, ram_end, len;
extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end;
unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */
processor_dram(&ram_start, &ram_end);
len = (ram_end - ram_start) + OCMSIZE;
#ifdef DEBUG
printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
#endif
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
start_mem = PAGE_ALIGN(start_mem);
max_mapnr = num_physpages = (((unsigned long) high_memory) - PAGE_OFFSET) >> PAGE_SHIFT;
/* this will put all memory onto the freelists */
#ifdef CONFIG_ZONE_DMA
{
unsigned long ocm_free_begin = (unsigned long)&__ocm_free_begin;
unsigned long ocm_free_end = (unsigned long)&__ocm_free_end;
unsigned long zone_dma_begin = (ocm_free_begin + PAGE_SIZE - 1) & PAGE_MASK;
unsigned long zone_dma_end = ocm_free_end & PAGE_MASK;
if (zone_dma_end > zone_dma_begin)
free_bootmem(zone_dma_begin, zone_dma_end-zone_dma_begin);
}
#endif
totalram_pages = free_all_bootmem();
codek = (&_etext - &_stext) >> 10;
datak = (&_ebss - &_sdata) >> 10;
initk = (&__init_begin - &__init_end) >> 10;
tmp = nr_free_pages() << PAGE_SHIFT;
printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n",
tmp >> 10,
len >> 10,
codek,
datak
);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
int pages = 0;
for (; start < end; start += PAGE_SIZE) {
ClearPageReserved(virt_to_page(start));
init_page_count(virt_to_page(start));
free_page(start);
totalram_pages++;
pages++;
}
printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
}
#endif
void
free_initmem()
{
#ifdef CONFIG_RAMKERNEL
unsigned long addr;
extern char __init_begin, __init_end;
/*
* The following code should be cool even if these sections
* are not page aligned.
*/
addr = PAGE_ALIGN((unsigned long)(&__init_begin));
/* next to check that the page we free is not a partial page */
for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
free_page(addr);
totalram_pages++;
}
printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
(addr - PAGE_ALIGN((long) &__init_begin)) >> 10,
(int)(PAGE_ALIGN((unsigned long)(&__init_begin))),
(int)(addr - PAGE_SIZE));
#endif
}

View File

@@ -0,0 +1,79 @@
/*
* arch/ubicom32/mm/kmap.c
* Ubicom32 architecture non-mmu ioremap and friends implementation.
*
* (C) Copyright 2009, Ubicom, Inc.
* Copyright (C) 2000 Lineo, <davidm@snapgear.com>
* Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
*
* This file is part of the Ubicom32 Linux Kernel Port.
*
* The Ubicom32 Linux Kernel Port 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.
*
* The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not,
* see <http://www.gnu.org/licenses/>.
*
* Ubicom32 implementation derived from (with many thanks):
* arch/m68knommu
* arch/blackfin
* arch/parisc
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/io.h>
#include <asm/system.h>
#undef DEBUG
/*
* Map some physical address range into the kernel address space.
*/
void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
{
return (void *)physaddr;
}
/*
* Unmap a ioremap()ed region again.
*/
void iounmap(void *addr)
{
}
/*
* __iounmap unmaps nearly everything, so be careful
* it doesn't free currently pointer/page tables anymore but it
* wans't used anyway and might be added later.
*/
void __iounmap(void *addr, unsigned long size)
{
}
/*
* Set new cache mode for some kernel address space.
* The caller must push data for that range itself, if such data may already
* be in the cache.
*/
void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
{
}

View File

@@ -0,0 +1,58 @@
/*
* arch/ubicom32/mm/memory.c
* Ubicom32 architecture kernel_map() implementation.
*
* (C) Copyright 2009, Ubicom, Inc.
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
* Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
*
* Based on:
*
* linux/arch/m68k/mm/memory.c
*
* Copyright (C) 1995 Hamish Macdonald
*
* This file is part of the Ubicom32 Linux Kernel Port.
*
* The Ubicom32 Linux Kernel Port 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.
*
* The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not,
* see <http://www.gnu.org/licenses/>.
*
* Ubicom32 implementation derived from (with many thanks):
* arch/m68knommu
* arch/blackfin
* arch/parisc
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
/*
* Map some physical address range into the kernel address space.
* The code is copied and adapted from map_chunk().
*/
unsigned long kernel_map(unsigned long paddr, unsigned long size,
int nocacheflag, unsigned long *memavailp )
{
return paddr;
}

View File

@@ -0,0 +1,487 @@
/*
* arch/ubicom32/mm/ocm-alloc.c
* OCM allocator for Uibcom32 On-Chip memory
*
* (C) Copyright 2009, Ubicom, Inc.
* Copyright 2004-2008 Analog Devices Inc.
*
* Based on:
*
* arch/blackfin/mm/sram-alloc.c
*
*
* This file is part of the Ubicom32 Linux Kernel Port.
*
* The Ubicom32 Linux Kernel Port 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.
*
* The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not,
* see <http://www.gnu.org/licenses/>.
*
* Ubicom32 implementation derived from (with many thanks):
* arch/m68knommu
* arch/blackfin
* arch/parisc
*/
#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/mutex.h>
#include <linux/rtc.h>
#include <asm/ocm-alloc.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(fmt, a...)
#endif
/*
* the data structure for OCM heap pieces
*/
struct ocm_piece {
void *paddr;
int size;
pid_t pid;
struct ocm_piece *next;
};
/*
* struct ocm_heap
*/
struct ocm_heap {
struct ocm_piece free_head;
struct ocm_piece used_head;
struct mutex lock;
};
static struct ocm_heap ocm_inst_heap;
int ubi32_ocm_skbuf_max = 21, ubi32_ocm_skbuf, ubi32_ddr_skbuf;
/*
* OCM area for storing code
*/
extern asmlinkage void *__ocm_free_begin;
extern asmlinkage void *__ocm_free_end;
extern asmlinkage void *__ocm_inst_heap_begin;
extern asmlinkage void *__ocm_inst_heap_end;
#define OCM_INST_HEAP_BEGIN ((unsigned int)&__ocm_inst_heap_begin)
#define OCM_INST_HEAP_END ((unsigned int)&__ocm_inst_heap_end)
#define OCM_INST_HEAP_LENGTH (OCM_INST_HEAP_END - OCM_INST_HEAP_BEGIN)
static struct kmem_cache *ocm_piece_cache;
/*
* _ocm_heap_init()
*/
static int __init _ocm_heap_init(struct ocm_heap *ocmh,
unsigned int start,
unsigned int size)
{
ocmh->free_head.next = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
if (!ocmh->free_head.next)
return -1;
ocmh->free_head.next->paddr = (void *)start;
ocmh->free_head.next->size = size;
ocmh->free_head.next->pid = 0;
ocmh->free_head.next->next = 0;
ocmh->used_head.next = NULL;
/* mutex initialize */
mutex_init(&ocmh->lock);
return 0;
}
/*
* _ocm_alloc_init()
*
* starts the ocm heap(s)
*/
static int __init _ocm_alloc_init(void)
{
if (OCM_INST_HEAP_LENGTH) {
ocm_piece_cache = kmem_cache_create("ocm_piece_cache",
sizeof(struct ocm_piece),
0, SLAB_PANIC, NULL);
if (_ocm_heap_init(&ocm_inst_heap,
OCM_INST_HEAP_BEGIN,
OCM_INST_HEAP_LENGTH) == 0)
printk(KERN_INFO "OCM Instruction Heap %d KB\n",
OCM_INST_HEAP_LENGTH >> 10);
else
printk(KERN_INFO "Failed to initialize OCM "
"Instruction Heap\n");
} else
printk(KERN_INFO "No space available for OCM "
"Instruction Heap\n");
return 0;
}
pure_initcall(_ocm_alloc_init);
/*
* _ocm_alloc()
* generic alloc a block in the ocm heap, if successful
* returns the pointer.
*/
static void *_ocm_alloc(size_t size, pid_t pid, struct ocm_heap *ocmheap)
{
struct ocm_piece *pslot, *plast, *pavail;
struct ocm_piece *pfree_head = &ocmheap->free_head;
struct ocm_piece *pused_head = &ocmheap->used_head;
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) {
/*
* Unlink this block from the list
*/
plast->next = pslot->next;
pavail = pslot;
} else {
/*
* Split this block in two.
*/
pavail = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
if (!pavail)
return NULL;
pavail->paddr = pslot->paddr;
pavail->size = size;
pslot->paddr += size;
pslot->size -= size;
}
pavail->pid = 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;
DEBUGP("_ocm_alloc %d bytes at %p from in %p",
size, pavail->paddr, ocmheap);
return pavail->paddr;
}
#if 0
/* Allocate the largest available block. */
static void *_ocm_alloc_max(struct ocm_heap *ocmheap,
unsigned long *psize)
{
struct ocm_piece *pfree_head = &ocmheap->free_head;
struct ocm_piece *pslot, *pmax;
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 _ocm_alloc(*psize, ocmheap);
}
#endif
/*
* _ocm_free()
* generic free a block in the ocm heap, if successful
*/
static int _ocm_free(const void *addr,
struct ocm_heap *ocmheap)
{
struct ocm_piece *pslot, *plast, *pavail;
struct ocm_piece *pfree_head = &ocmheap->free_head;
struct ocm_piece *pused_head = &ocmheap->used_head;
/* 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) {
DEBUGP("_ocm_free %p not found in %p", addr, ocmheap);
return -1;
}
DEBUGP("_ocm_free %p from in %p", addr, ocmheap);
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(ocm_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(ocm_piece_cache, pslot);
}
return 0;
}
/*
* ocm_inst_alloc()
*
* allocates a block of size in the ocm instrction heap, if
* successful returns address allocated.
*/
void *ocm_inst_alloc(size_t size, pid_t pid)
{
void *addr;
if (!OCM_INST_HEAP_LENGTH)
return NULL;
mutex_lock(&ocm_inst_heap.lock);
addr = _ocm_alloc(size, pid, &ocm_inst_heap);
mutex_unlock(&ocm_inst_heap.lock);
return addr;
}
EXPORT_SYMBOL(ocm_inst_alloc);
/*
* ocm_inst_free()
* free a block in the ocm instrction heap, returns 0 if successful.
*/
int ocm_inst_free(const void *addr)
{
int ret;
if (!OCM_INST_HEAP_LENGTH)
return -1;
mutex_lock(&ocm_inst_heap.lock);
ret = _ocm_free(addr, &ocm_inst_heap);
mutex_unlock(&ocm_inst_heap.lock);
return ret;
}
EXPORT_SYMBOL(ocm_inst_free);
/*
* ocm_free()
* free a block in one of the ocm heaps, returns 0 if successful.
*/
int ocm_free(const void *addr)
{
if (addr >= (void *)OCM_INST_HEAP_BEGIN
&& addr < (void *)(OCM_INST_HEAP_END))
return ocm_inst_free(addr);
else
return -1;
}
EXPORT_SYMBOL(ocm_free);
#ifdef CONFIG_PROC_FS
/* Need to keep line of output the same. Currently, that is 46 bytes
* (including newline).
*/
static int _ocm_proc_read(char *buf, int *len, int count, const char *desc,
struct ocm_heap *ocmheap)
{
struct ocm_piece *pslot;
struct ocm_piece *pfree_head = &ocmheap->free_head;
struct ocm_piece *pused_head = &ocmheap->used_head;
/* The format is the following
* --- OCM 123456789012345 Size PID State \n
* 12345678-12345678 1234567890 12345 1234567890\n
*/
int l;
l = sprintf(&buf[*len], "--- OCM %-15s Size PID State \n",
desc);
*len += l;
count -= l;
mutex_lock(&ocm_inst_heap.lock);
/*
* search the relevant memory slot
*/
pslot = pused_head->next;
while (pslot != NULL && count > 46) {
l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
pslot->paddr, pslot->paddr + pslot->size,
pslot->size, pslot->pid, "ALLOCATED");
*len += l;
count -= l;
pslot = pslot->next;
}
pslot = pfree_head->next;
while (pslot != NULL && count > 46) {
l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
pslot->paddr, pslot->paddr + pslot->size,
pslot->size, pslot->pid, "FREE");
*len += l;
count -= l;
pslot = pslot->next;
}
mutex_unlock(&ocm_inst_heap.lock);
return 0;
}
static int ocm_proc_read(char *buf, char **start, off_t offset, int count,
int *eof, void *data)
{
int len = 0;
len = sprintf(&buf[len], "--- OCM SKB usage (max RX buf %d)\n"
"(SKB in OCM) %d - (SKB in DDR) %d\n",
ubi32_ocm_skbuf_max,
ubi32_ocm_skbuf,
ubi32_ddr_skbuf);
len += sprintf(&buf[len], "--- OCM Data Heap Size\n"
"%p-%p %10i\n",
((void *)&__ocm_free_begin),
((void *)&__ocm_free_end),
((unsigned int)&__ocm_free_end) -
((unsigned int)&__ocm_free_begin));
if (_ocm_proc_read(buf, &len, count - len, "Inst Heap",
&ocm_inst_heap))
goto not_done;
*eof = 1;
not_done:
return len;
}
static int ocm_proc_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
int n, v;
char in[8];
if (count > sizeof(in))
return -EINVAL;
if (copy_from_user(in, buffer, count))
return -EFAULT;
in[count-1] = 0;
printk(KERN_INFO "OCM skb alloc max = %s\n", in);
n = 0;
v = 0;
while ((in[n] >= '0') && (in[n] <= '9')) {
v = v * 10 + (int)(in[n] - '0');
n++;
}
if (v == 0)
return -EINVAL;
ubi32_ocm_skbuf_max = v;
ubi32_ocm_skbuf = ubi32_ddr_skbuf = 0;
return count;
}
static int __init sram_proc_init(void)
{
struct proc_dir_entry *ptr;
ptr = create_proc_entry("ocm", S_IFREG | S_IRUGO, NULL);
if (!ptr) {
printk(KERN_WARNING "unable to create /proc/ocm\n");
return -1;
}
ptr->read_proc = ocm_proc_read;
ptr->write_proc = ocm_proc_write;
return 0;
}
late_initcall(sram_proc_init);
#endif