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:
32
target/linux/ubicom32/files/arch/ubicom32/mm/Makefile
Normal file
32
target/linux/ubicom32/files/arch/ubicom32/mm/Makefile
Normal 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
|
||||
80
target/linux/ubicom32/files/arch/ubicom32/mm/fault.c
Normal file
80
target/linux/ubicom32/files/arch/ubicom32/mm/fault.c
Normal 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;
|
||||
}
|
||||
262
target/linux/ubicom32/files/arch/ubicom32/mm/init.c
Normal file
262
target/linux/ubicom32/files/arch/ubicom32/mm/init.c
Normal 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
|
||||
}
|
||||
79
target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c
Normal file
79
target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c
Normal 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)
|
||||
{
|
||||
}
|
||||
58
target/linux/ubicom32/files/arch/ubicom32/mm/memory.c
Normal file
58
target/linux/ubicom32/files/arch/ubicom32/mm/memory.c
Normal 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;
|
||||
}
|
||||
487
target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c
Normal file
487
target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c
Normal 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
|
||||
Reference in New Issue
Block a user