mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2025-01-08 23:00:14 +02:00
1a29ef8e97
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@19815 3c298f89-4303-0410-b956-a3cf2f4a3e73
229 lines
4.7 KiB
C
229 lines
4.7 KiB
C
/*
|
|
* arch/ubicom32/kernel/thread.c
|
|
* Ubicom32 architecture hardware thread support.
|
|
*
|
|
* (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
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/profile.h>
|
|
#include <linux/clocksource.h>
|
|
#include <linux/types.h>
|
|
#include <asm/ip5000.h>
|
|
#include <asm/machdep.h>
|
|
#include <asm/asm-offsets.h>
|
|
#include <asm/thread.h>
|
|
|
|
/*
|
|
* TODO: At some point change the name here to be thread_ksp
|
|
*/
|
|
unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX];
|
|
|
|
static unsigned int thread_mask = -1;
|
|
static unsigned int thread_mainline_mask;
|
|
|
|
/*
|
|
* thread_entry()
|
|
* Returning from the called function will disable the thread.
|
|
*
|
|
* This could be a naked call to allow for hwthreads that do not have stacks.
|
|
* However, with -O0, the code still writes to thex stack, and this was
|
|
* corrupting memory just after the callers stack.
|
|
*/
|
|
static void thread_entry(void *arg, thread_exec_fn_t exec)
|
|
{
|
|
/*
|
|
* Call thread function
|
|
*/
|
|
exec(arg);
|
|
|
|
/*
|
|
* Complete => Disable self
|
|
*/
|
|
thread_disable(thread_get_self());
|
|
}
|
|
|
|
/*
|
|
* thread_start()
|
|
* Start the specified function on the specified hardware thread.
|
|
*/
|
|
thread_t thread_start(thread_t thread,
|
|
thread_exec_fn_t exec,
|
|
void *arg,
|
|
unsigned int *sp_high,
|
|
thread_type_t type)
|
|
{
|
|
/*
|
|
* Sanity check
|
|
*/
|
|
unsigned int enabled, mask, csr;
|
|
asm volatile (
|
|
"move.4 %0, MT_EN\n\t"
|
|
: "=m" (enabled)
|
|
);
|
|
|
|
mask = 1 << thread;
|
|
if (enabled & mask) {
|
|
printk(KERN_WARNING "request to enable a previously enabled thread\n");
|
|
return (thread_t)-1;
|
|
}
|
|
|
|
/*
|
|
* Update thread state
|
|
*/
|
|
csr = (thread << 15) | (1 << 14);
|
|
asm volatile (
|
|
"setcsr %0 \n\t"
|
|
"setcsr_flush 0 \n\t"
|
|
|
|
"move.4 A0, #0 \n\t"
|
|
"move.4 A1, #0 \n\t"
|
|
"move.4 A2, #0 \n\t"
|
|
"move.4 A3, #0 \n\t"
|
|
"move.4 A4, #0 \n\t"
|
|
"move.4 A5, #0 \n\t"
|
|
"move.4 A6, #0 \n\t"
|
|
"move.4 SP, %4 \n\t" /* A7 is SP */
|
|
|
|
"move.4 D0, %3 \n\t"
|
|
"move.4 D1, %2 \n\t"
|
|
"move.4 D2, #0 \n\t"
|
|
"move.4 D3, #0 \n\t"
|
|
"move.4 D4, #0 \n\t"
|
|
"move.4 D5, #0 \n\t"
|
|
"move.4 D6, #0 \n\t"
|
|
"move.4 D7, #0 \n\t"
|
|
"move.4 D8, #0 \n\t"
|
|
"move.4 D9, #0 \n\t"
|
|
"move.4 D10, #0 \n\t"
|
|
"move.4 D11, #0 \n\t"
|
|
"move.4 D12, #0 \n\t"
|
|
"move.4 D13, #0 \n\t"
|
|
"move.4 D14, #0 \n\t"
|
|
"move.4 D15, #0 \n\t"
|
|
|
|
"move.4 INT_MASK0, #0 \n\t"
|
|
"move.4 INT_MASK1, #0 \n\t"
|
|
"move.4 PC, %1 \n\t"
|
|
"setcsr #0 \n\t"
|
|
"setcsr_flush 0 \n\t"
|
|
:
|
|
: "r" (csr), "r" (thread_entry), "r" (exec),
|
|
"r" (arg), "r" (sp_high)
|
|
);
|
|
|
|
/*
|
|
* Apply HRT state
|
|
*/
|
|
if (type & THREAD_TYPE_HRT) {
|
|
asm volatile (
|
|
"or.4 MT_HRT, MT_HRT, %0\n\t"
|
|
:
|
|
: "d" (mask)
|
|
: "cc"
|
|
);
|
|
} else {
|
|
asm volatile (
|
|
"and.4 MT_HRT, MT_HRT, %0\n\t"
|
|
:
|
|
: "d" (~mask)
|
|
: "cc"
|
|
);
|
|
}
|
|
|
|
/*
|
|
* Set priority
|
|
*/
|
|
asm volatile (
|
|
"or.4 MT_HPRI, MT_HPRI, %0\n\t"
|
|
:
|
|
: "d" (mask)
|
|
: "cc"
|
|
);
|
|
|
|
/*
|
|
* Enable thread
|
|
*/
|
|
asm volatile (
|
|
"move.4 MT_ACTIVE_SET, %0 \n\t"
|
|
:
|
|
: "d" (mask)
|
|
);
|
|
thread_enable_mask(mask);
|
|
return thread;
|
|
}
|
|
|
|
/*
|
|
* thread_get_mainline()
|
|
* Return a mask of those threads that are Linux mainline threads.
|
|
*/
|
|
unsigned int thread_get_mainline(void)
|
|
{
|
|
return thread_mainline_mask;
|
|
}
|
|
|
|
/*
|
|
* thread_set_mainline()
|
|
* Indicate that the specified thread is a Linux mainline thread.
|
|
*/
|
|
void thread_set_mainline(thread_t tid)
|
|
{
|
|
thread_mainline_mask |= (1 << tid);
|
|
}
|
|
|
|
/*
|
|
* thread_alloc()
|
|
* Allocate an unused hardware thread.
|
|
*/
|
|
thread_t thread_alloc(void)
|
|
{
|
|
thread_t tid;
|
|
|
|
/*
|
|
* If this is the first time we are here get the list of unused
|
|
* threads from the processor device tree node.
|
|
*/
|
|
if (thread_mask == -1) {
|
|
thread_mask = processor_threads();
|
|
}
|
|
|
|
if (!thread_mask) {
|
|
return (thread_t)-1;
|
|
}
|
|
|
|
tid = ffs(thread_mask);
|
|
if (tid != 0) {
|
|
tid--;
|
|
thread_mask &= ~(1 << tid);
|
|
return tid;
|
|
}
|
|
|
|
return (thread_t)-1;
|
|
}
|