aboutsummaryrefslogtreecommitdiff
path: root/arch/cris/arch-v10/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/cris/arch-v10/kernel')
-rw-r--r--arch/cris/arch-v10/kernel/Makefile1
-rw-r--r--arch/cris/arch-v10/kernel/asm-offsets.c47
-rw-r--r--arch/cris/arch-v10/kernel/crisksyms.c2
-rw-r--r--arch/cris/arch-v10/kernel/debugport.c164
-rw-r--r--arch/cris/arch-v10/kernel/dma.c10
-rw-r--r--arch/cris/arch-v10/kernel/entry.S536
-rw-r--r--arch/cris/arch-v10/kernel/fasttimer.c649
-rw-r--r--arch/cris/arch-v10/kernel/head.S352
-rw-r--r--arch/cris/arch-v10/kernel/io_interface_mux.c521
-rw-r--r--arch/cris/arch-v10/kernel/irq.c128
-rw-r--r--arch/cris/arch-v10/kernel/kgdb.c985
-rw-r--r--arch/cris/arch-v10/kernel/process.c141
-rw-r--r--arch/cris/arch-v10/kernel/ptrace.c98
-rw-r--r--arch/cris/arch-v10/kernel/setup.c6
-rw-r--r--arch/cris/arch-v10/kernel/shadows.c5
-rw-r--r--arch/cris/arch-v10/kernel/signal.c293
-rw-r--r--arch/cris/arch-v10/kernel/time.c218
-rw-r--r--arch/cris/arch-v10/kernel/traps.c201
18 files changed, 1643 insertions, 2714 deletions
diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile
index dcfec41d353..4841e822cdd 100644
--- a/arch/cris/arch-v10/kernel/Makefile
+++ b/arch/cris/arch-v10/kernel/Makefile
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $
#
# Makefile for the linux kernel.
#
diff --git a/arch/cris/arch-v10/kernel/asm-offsets.c b/arch/cris/arch-v10/kernel/asm-offsets.c
deleted file mode 100644
index 1aa3cc4e710..00000000000
--- a/arch/cris/arch-v10/kernel/asm-offsets.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <linux/sched.h>
-#include <asm/thread_info.h>
-
-/*
- * Generate definitions needed by assembly language modules.
- * This code generates raw asm output which is post-processed to extract
- * and format the required data.
- */
-
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
-int main(void)
-{
-#define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry))
- ENTRY(orig_r10);
- ENTRY(r13);
- ENTRY(r12);
- ENTRY(r11);
- ENTRY(r10);
- ENTRY(r9);
- ENTRY(mof);
- ENTRY(dccr);
- ENTRY(srp);
- BLANK();
-#undef ENTRY
-#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry))
- ENTRY(task);
- ENTRY(flags);
- ENTRY(preempt_count);
- BLANK();
-#undef ENTRY
-#define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry))
- ENTRY(ksp);
- ENTRY(usp);
- ENTRY(dccr);
- BLANK();
-#undef ENTRY
-#define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry))
- ENTRY(pid);
- BLANK();
- DEFINE(LCLONE_VM, CLONE_VM);
- DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED);
- return 0;
-}
diff --git a/arch/cris/arch-v10/kernel/crisksyms.c b/arch/cris/arch-v10/kernel/crisksyms.c
index e6b80135502..1ca6fc28323 100644
--- a/arch/cris/arch-v10/kernel/crisksyms.c
+++ b/arch/cris/arch-v10/kernel/crisksyms.c
@@ -1,6 +1,6 @@
#include <linux/module.h>
#include <asm/io.h>
-#include <asm/arch/svinto.h>
+#include <arch/svinto.h>
/* Export shadow registers for the CPU I/O pins */
EXPORT_SYMBOL(genconfig_shadow);
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c
index 2b536ca6f44..7d307cce8bd 100644
--- a/arch/cris/arch-v10/kernel/debugport.c
+++ b/arch/cris/arch-v10/kernel/debugport.c
@@ -1,6 +1,6 @@
/* Serialport functions for debugging
*
- * Copyright (c) 2000 Axis Communications AB
+ * Copyright (c) 2000-2007 Axis Communications AB
*
* Authors: Bjorn Wesen
*
@@ -11,96 +11,6 @@
* enableDebugIRQ()
* init_etrax_debug()
*
- * $Log: debugport.c,v $
- * Revision 1.27 2005/06/10 10:34:14 starvik
- * Real console support
- *
- * Revision 1.26 2005/06/07 07:06:07 starvik
- * Added LF->CR translation to make ETRAX customers happy.
- *
- * Revision 1.25 2005/03/08 08:56:47 mikaelam
- * Do only set index as port->index if port is defined, otherwise use the index from the command line
- *
- * Revision 1.24 2005/01/19 10:26:33 mikaelam
- * Return the cris serial driver in console device driver callback function
- *
- * Revision 1.23 2005/01/14 10:12:17 starvik
- * KGDB on separate port.
- * Console fixes from 2.4.
- *
- * Revision 1.22 2005/01/11 16:06:13 starvik
- * typo
- *
- * Revision 1.21 2005/01/11 13:49:14 starvik
- * Added raw_printk to be used where we don't trust the console.
- *
- * Revision 1.20 2004/12/27 11:18:32 starvik
- * Merge of Linux 2.6.10 (not functional yet).
- *
- * Revision 1.19 2004/10/21 07:26:16 starvik
- * Made it possible to specify console settings on kernel command line.
- *
- * Revision 1.18 2004/10/19 13:07:37 starvik
- * Merge of Linux 2.6.9
- *
- * Revision 1.17 2004/09/29 10:33:46 starvik
- * Resolved a dealock when printing debug from kernel.
- *
- * Revision 1.16 2004/08/24 06:12:19 starvik
- * Whitespace cleanup
- *
- * Revision 1.15 2004/08/16 12:37:19 starvik
- * Merge of Linux 2.6.8
- *
- * Revision 1.14 2004/05/17 13:11:29 starvik
- * Disable DMA until real serial driver is up
- *
- * Revision 1.13 2004/05/14 07:58:01 starvik
- * Merge of changes from 2.4
- *
- * Revision 1.12 2003/09/11 07:29:49 starvik
- * Merge of Linux 2.6.0-test5
- *
- * Revision 1.11 2003/07/07 09:53:36 starvik
- * Revert all the 2.5.74 merge changes to make the console work again
- *
- * Revision 1.9 2003/02/17 17:07:23 starvik
- * Solved the problem with corrupted debug output (from Linux 2.4)
- * * Wait until DMA, FIFO and pipe is empty before and after transmissions
- * * Buffer data until a FIFO flush can be triggered.
- *
- * Revision 1.8 2003/01/22 06:48:36 starvik
- * Fixed warnings issued by GCC 3.2.1
- *
- * Revision 1.7 2002/12/12 08:26:32 starvik
- * Don't use C-comments inside CVS comments
- *
- * Revision 1.6 2002/12/11 15:42:02 starvik
- * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
- *
- * Revision 1.5 2002/11/20 06:58:03 starvik
- * Compiles with kgdb
- *
- * Revision 1.4 2002/11/19 14:35:24 starvik
- * Changes from linux 2.4
- * Changed struct initializer syntax to the currently prefered notation
- *
- * Revision 1.3 2002/11/06 09:47:03 starvik
- * Modified for new interrupt macros
- *
- * Revision 1.2 2002/01/21 15:21:50 bjornw
- * Update for kdev_t changes
- *
- * Revision 1.6 2001/04/17 13:58:39 orjanf
- * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
- *
- * Revision 1.5 2001/03/26 14:22:05 bjornw
- * Namechange of some config options
- *
- * Revision 1.4 2000/10/06 12:37:26 bjornw
- * Use physical addresses when talking to DMA
- *
- *
*/
#include <linux/console.h>
@@ -108,9 +18,9 @@
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/tty.h>
-#include <asm/system.h>
-#include <asm/arch/svinto.h>
-#include <asm/io.h> /* Get SIMCOUT. */
+#include <arch/svinto.h>
+
+extern void reset_watchdog(void);
struct dbg_port
{
@@ -188,7 +98,9 @@ struct dbg_port ports[]=
}
};
+#ifdef CONFIG_ETRAX_SERIAL
extern struct tty_driver *serial_driver;
+#endif
struct dbg_port* port =
#if defined(CONFIG_ETRAX_DEBUG_PORT0)
@@ -368,11 +280,12 @@ console_write_direct(struct console *co, const char *buf, unsigned int len)
{
int i;
unsigned long flags;
- local_irq_save(flags);
if (!port)
return;
+ local_irq_save(flags);
+
/* Send data */
for (i = 0; i < len; i++) {
/* LF -> CRLF */
@@ -386,26 +299,16 @@ console_write_direct(struct console *co, const char *buf, unsigned int len)
;
*port->write = buf[i];
}
- local_irq_restore(flags);
-}
-int raw_printk(const char *fmt, ...)
-{
- static char buf[1024];
- int printed_len;
- static int first = 1;
- if (first) {
- /* Force reinitialization of the port to get manual mode. */
- port->started = 0;
- start_port(port);
- first = 0;
- }
- va_list args;
- va_start(args, fmt);
- printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
- va_end(args);
- console_write_direct(NULL, buf, strlen(buf));
- return printed_len;
+ /*
+ * Feed the watchdog, otherwise it will reset the chip during boot.
+ * The time to send an ordinary boot message line (10-90 chars)
+ * varies between 1-8ms at 115200. What makes up for the additional
+ * 90ms that allows the watchdog to bite?
+ */
+ reset_watchdog();
+
+ local_irq_restore(flags);
}
static void
@@ -414,12 +317,6 @@ console_write(struct console *co, const char *buf, unsigned int len)
if (!port)
return;
-#ifdef CONFIG_SVINTO_SIM
- /* no use to simulate the serial debug output */
- SIMCOUT(buf, len);
- return;
-#endif
-
console_write_direct(co, buf, len);
}
@@ -500,6 +397,7 @@ console_setup(struct console *co, char *options)
return 0;
}
+
/* This is a dummy serial device that throws away anything written to it.
* This is used when no debug output is wanted.
*/
@@ -520,12 +418,18 @@ static int dummy_write(struct tty_struct * tty,
return count;
}
-static int
-dummy_write_room(struct tty_struct *tty)
+static int dummy_write_room(struct tty_struct *tty)
{
return 8192;
}
+static const struct tty_operations dummy_ops = {
+ .open = dummy_open,
+ .close = dummy_close,
+ .write = dummy_write,
+ .write_room = dummy_write_room,
+};
+
void __init
init_dummy_console(void)
{
@@ -538,14 +442,14 @@ init_dummy_console(void)
dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
dummy_driver.subtype = SERIAL_TYPE_NORMAL;
dummy_driver.init_termios = tty_std_termios;
+ /* Normally B9600 default... */
dummy_driver.init_termios.c_cflag =
- B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+ B115200 | CS8 | CREAD | HUPCL | CLOCAL;
dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ dummy_driver.init_termios.c_ispeed = 115200;
+ dummy_driver.init_termios.c_ospeed = 115200;
- dummy_driver.open = dummy_open;
- dummy_driver.close = dummy_close;
- dummy_driver.write = dummy_write;
- dummy_driver.write_room = dummy_write_room;
+ dummy_driver.ops = &dummy_ops;
if (tty_register_driver(&dummy_driver))
panic("Couldn't register dummy serial driver\n");
}
@@ -555,7 +459,13 @@ etrax_console_device(struct console* co, int *index)
{
if (port)
*index = port->index;
+ else
+ *index = 0;
+#ifdef CONFIG_ETRAX_SERIAL
return port ? serial_driver : &dummy_driver;
+#else
+ return &dummy_driver;
+#endif
}
static struct console sercons = {
diff --git a/arch/cris/arch-v10/kernel/dma.c b/arch/cris/arch-v10/kernel/dma.c
index e9a0311b141..5795047359b 100644
--- a/arch/cris/arch-v10/kernel/dma.c
+++ b/arch/cris/arch-v10/kernel/dma.c
@@ -1,6 +1,5 @@
/* Wrapper for DMA channel allocator that updates DMA client muxing.
- * Copyright 2004, Axis Communications AB
- * $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $
+ * Copyright 2004-2007, Axis Communications AB
*/
#include <linux/kernel.h>
@@ -8,7 +7,8 @@
#include <linux/errno.h>
#include <asm/dma.h>
-#include <asm/arch/svinto.h>
+#include <arch/svinto.h>
+#include <arch/system.h>
/* Macro to access ETRAX 100 registers */
#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
@@ -25,7 +25,7 @@ int cris_request_dma(unsigned int dmanr, const char * device_id,
unsigned long int gens;
int fail = -EINVAL;
- if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
+ if (dmanr >= MAX_DMA_CHANNELS) {
printk(KERN_CRIT "cris_request_dma: invalid DMA channel %u\n", dmanr);
return -EINVAL;
}
@@ -214,7 +214,7 @@ int cris_request_dma(unsigned int dmanr, const char * device_id,
void cris_free_dma(unsigned int dmanr, const char * device_id)
{
unsigned long flags;
- if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
+ if (dmanr >= MAX_DMA_CHANNELS) {
printk(KERN_CRIT "cris_free_dma: invalid DMA channel %u\n", dmanr);
return;
}
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
index ae45d4522e6..81570fcd041 100644
--- a/arch/cris/arch-v10/kernel/entry.S
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -1,252 +1,9 @@
-/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 starvik Exp $
- *
+/*
* linux/arch/cris/entry.S
*
* Copyright (C) 2000, 2001, 2002 Axis Communications AB
*
* Authors: Bjorn Wesen (bjornw@axis.com)
- *
- * $Log: entry.S,v $
- * Revision 1.28 2005/06/20 05:06:30 starvik
- * Remove unnecessary diff to kernel.org tree
- *
- * Revision 1.27 2005/03/04 08:16:16 starvik
- * Merge of Linux 2.6.11.
- *
- * Revision 1.26 2005/01/11 13:49:47 starvik
- * Added NMI handler.
- *
- * Revision 1.25 2004/12/27 11:18:32 starvik
- * Merge of Linux 2.6.10 (not functional yet).
- *
- * Revision 1.24 2004/12/22 10:41:23 starvik
- * Updates to make v10 compile with the latest SMP aware generic code (even
- * though v10 will never have SMP).
- *
- * Revision 1.23 2004/10/19 13:07:37 starvik
- * Merge of Linux 2.6.9
- *
- * Revision 1.22 2004/06/21 10:29:55 starvik
- * Merge of Linux 2.6.7
- *
- * Revision 1.21 2004/06/09 05:30:27 starvik
- * Clean up multiple interrupt handling.
- * Prevent interrupts from interrupting each other.
- * Handle all active interrupts.
- *
- * Revision 1.20 2004/06/08 08:55:32 starvik
- * Removed unused code
- *
- * Revision 1.19 2004/06/04 11:56:15 starvik
- * Implemented page table lookup for refills in assembler for improved performance.
- *
- * Revision 1.18 2004/05/11 12:28:25 starvik
- * Merge of Linux 2.6.6
- *
- * Revision 1.17 2003/09/11 07:29:49 starvik
- * Merge of Linux 2.6.0-test5
- *
- * Revision 1.16 2003/07/04 08:27:41 starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.15 2003/04/09 07:32:55 starvik
- * resume should return task_struct, not thread_info
- *
- * Revision 1.14 2003/04/09 05:20:44 starvik
- * Merge of Linux 2.5.67
- *
- * Revision 1.13 2002/12/11 15:42:02 starvik
- * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
- *
- * Revision 1.12 2002/12/10 09:00:10 starvik
- * Merge of Linux 2.5.51
- *
- * Revision 1.11 2002/12/05 07:53:10 starvik
- * Corrected constants used with btstq
- *
- * Revision 1.10 2002/11/27 08:45:10 starvik
- * pid is in task_struct, not thread_info
- *
- * Revision 1.9 2002/11/26 09:52:05 starvik
- * Added preemptive kernel scheduling (if CONFIG_PREEMPT)
- *
- * Revision 1.8 2002/11/20 11:56:11 starvik
- * Merge of Linux 2.5.48
- *
- * Revision 1.7 2002/11/18 13:02:42 starvik
- * Added fourth parameter to do_notify_resume
- * Minor cleanup
- *
- * Revision 1.6 2002/11/11 10:37:50 starvik
- * Use new asm-offset defines
- * Modified for new location of current->work etc
- * Removed SYMBOL_NAME from syscalls
- * Added some new syscalls
- *
- * Revision 1.5 2002/11/05 06:45:11 starvik
- * Merge of Linux 2.5.45
- *
- * Revision 1.4 2002/02/05 15:41:31 bjornw
- * Rewritten to conform better to current 2.5 code (similar to arch/i386)
- *
- * Revision 1.3 2002/01/21 15:22:20 bjornw
- * NICE_DOGGY fix from 2.4 arch/cris
- *
- * Revision 1.37 2001/12/07 17:03:55 bjornw
- * Call a c-hook called watchdog_bite_hook instead of show_registers directly
- *
- * Revision 1.36 2001/11/22 13:36:36 bjornw
- * * In ret_from_intr, check regs->dccr for usermode reentrance instead of
- * DCCR explicitely (because the latter might not reflect current reality)
- * * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before
- * since $r9 is call-clobbered and is potentially needed afterwards
- *
- * Revision 1.35 2001/10/30 17:10:15 bjornw
- * Add some syscalls
- *
- * Revision 1.34 2001/10/01 14:45:03 bjornw
- * Removed underscores and added register prefixes
- *
- * Revision 1.33 2001/08/21 13:48:01 jonashg
- * Added fix by HP to avoid oops when doing a hard_reset_now.
- *
- * Revision 1.32 2001/08/14 04:32:02 hp
- * In _resume, add comment why R9 is saved; don't sound like it's call-saved.
- *
- * Revision 1.31 2001/07/25 16:07:42 bjornw
- * softirq_active/mask -> softirq_pending only
- *
- * Revision 1.30 2001/07/05 01:03:32 hp
- * - include asm/errno.h to get ENOSYS.
- * - Use ENOSYS, not local constant LENOSYS; tweak comments.
- * - Explain why .include, not #include is used.
- * - Make oops-register-dump if watchdog bits and it's not expected.
- * - Don't jsr, use jump _hard_reset_now, and skip spurious nop.
- * - Use correct section attribute for section .rodata.
- * - Adjust sys_ni_syscall fill number.
- *
- * Revision 1.29 2001/06/25 14:07:00 hp
- * Fix review comment.
- * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
- * magic numbers. Add comment that -traditional must not be used.
- * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
- * Correct and update comment.
- * * Makefile (.S.o): Don't use -traditional. Add comment why the
- * toplevel rule can't be used (now that there's a reason).
- *
- * Revision 1.28 2001/06/21 02:00:40 hp
- * * entry.S: Include asm/unistd.h.
- * (_sys_call_table): Use section .rodata, not .data.
- * (_kernel_thread): Move from...
- * * process.c: ... here.
- * * entryoffsets.c (VAL): Break out from...
- * (OF): Use VAL.
- * (LCLONE_VM): New asmified value from CLONE_VM.
- *
- * Revision 1.27 2001/05/29 11:25:27 markusl
- * In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
- *
- * Revision 1.26 2001/05/15 15:46:03 bjornw
- * Include config.h now that we use some CONFIG_ options
- *
- * Revision 1.25 2001/05/15 05:38:47 hp
- * Tweaked code in _ret_from_sys_call
- *
- * Revision 1.24 2001/05/15 05:27:49 hp
- * Save r9 in r1 over function call rather than on stack.
- *
- * Revision 1.23 2001/05/15 05:10:00 hp
- * Generate entry.S structure offsets from C
- *
- * Revision 1.22 2001/04/17 13:58:39 orjanf
- * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
- *
- * Revision 1.21 2001/04/17 11:33:29 orjanf
- * Updated according to review:
- * * Included asm/sv_addr_ag.h to get macro for internal register.
- * * Corrected comment regarding system call argument passing.
- * * Removed comment about instruction being in a delay slot.
- * * Added comment about SYMBOL_NAME macro.
- *
- * Revision 1.20 2001/04/12 08:51:07 hp
- * - Add entry for sys_fcntl64. In fact copy last piece from i386 including ...
- * - .rept to fill table to safe state with sys_ni_syscall.
- *
- * Revision 1.19 2001/04/04 09:43:32 orjanf
- * * Moved do_sigtrap from traps.c to entry.S.
- * * LTASK_PID need not be global anymore.
- *
- * Revision 1.18 2001/03/26 09:25:02 markusl
- * Updated after review, should now handle USB interrupts correctly.
- *
- * Revision 1.17 2001/03/21 16:12:55 bjornw
- * * Always make room for the cpu status record in the frame, in order to
- * use the same framelength and layout for both mmu busfaults and normal
- * irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore.
- * * Fixed bug with using addq for popping the stack in the epilogue - it
- * destroyed the flag register. Use instructions that don't affect the
- * flag register instead.
- * * Removed write to R_PORT_PA_DATA during spurious_interrupt
- *
- * Revision 1.16 2001/03/20 19:43:02 bjornw
- * * Get rid of esp0 setting
- * * Give a 7th argument to a systemcall - the stackframe
- *
- * Revision 1.15 2001/03/05 13:14:30 bjornw
- * Spelling fix
- *
- * Revision 1.14 2001/02/23 08:36:36 perf
- * New ABI; syscallnr=r9, arg5=mof, arg6=srp.
- * Corrected tracesys call check.
- *
- * Revision 1.13 2001/02/15 08:40:55 perf
- * H-P by way of perf;
- * - (_system_call): Don't read system call function address into r1.
- * - (RBFExit): There is no such thing as a null pop. Adjust sp by addq.
- * - (_system_call): Don't use r10 and don't save and restore it.
- * - (THREAD_ESP0): New constant.
- * - (_system_call): Inline set_esp0.
- *
- * Revision 1.12 2001/01/31 17:56:25 orjanf
- * Added definition of LTASK_PID and made it global.
- *
- * Revision 1.11 2001/01/10 21:13:29 bjornw
- * SYMBOL_NAME is defined incorrectly for the compiler options we currently use
- *
- * Revision 1.10 2000/12/18 23:47:56 bjornw
- * * Added syscall trace support (ptrace), completely untested of course
- * * Removed redundant check for NULL entries in syscall_table
- *
- * Revision 1.9 2000/11/21 16:40:51 bjornw
- * * New frame type used when an SBFS frame needs to be popped without
- * actually restarting the instruction
- * * Enable interrupts in signal_return (they did so in x86, I hope it's a good
- * idea)
- *
- * Revision 1.8 2000/11/17 16:53:35 bjornw
- * Added detection of frame-type in Rexit, so that mmu_bus_fault can
- * use ret_from_intr in the return-path to check for signals (like SEGV)
- * and other foul things that might have occurred during the fault.
- *
- * Revision 1.7 2000/10/06 15:04:28 bjornw
- * Include mof in register savings
- *
- * Revision 1.6 2000/09/12 16:02:44 bjornw
- * Linux-2.4.0-test7 derived updates
- *
- * Revision 1.5 2000/08/17 15:35:15 bjornw
- * 2.4.0-test6 changed local_irq_count and friends API
- *
- * Revision 1.4 2000/08/02 13:59:30 bjornw
- * Removed olduname and uname from the syscall list
- *
- * Revision 1.3 2000/07/31 13:32:58 bjornw
- * * Export ret_from_intr
- * * _resume updated (prev/last tjohejsan)
- * * timer_interrupt obsolete
- * * SIGSEGV detection in mmu_bus_fault temporarily disabled
- *
- *
*/
/*
@@ -256,8 +13,8 @@
* after a timer-interrupt and after each system call.
*
* Stack layout in 'ret_from_system_call':
- * ptrace needs to have all regs on the stack.
- * if the order here is changed, it needs to be
+ * ptrace needs to have all regs on the stack.
+ * if the order here is changed, it needs to be
* updated in fork.c:copy_process, signal.c:do_signal,
* ptrace.c and ptrace.h
*
@@ -266,7 +23,7 @@
#include <linux/linkage.h>
#include <linux/sys.h>
#include <asm/unistd.h>
-#include <asm/arch/sv_addr_ag.h>
+#include <arch/sv_addr_ag.h>
#include <asm/errno.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
@@ -274,10 +31,11 @@
#include <asm/pgtable.h>
;; functions exported from this file
-
+
.globl system_call
.globl ret_from_intr
.globl ret_from_fork
+ .globl ret_from_kernel_thread
.globl resume
.globl multiple_interrupt
.globl hwbreakpoint
@@ -288,10 +46,10 @@
.globl do_sigtrap
.globl gdb_handle_breakpoint
.globl sys_call_table
-
+
;; below are various parts of system_call which are not in the fast-path
-
-#ifdef CONFIG_PREEMPT
+
+#ifdef CONFIG_PREEMPT
; Check if preemptive kernel scheduling should be done
_resume_kernel:
di
@@ -316,7 +74,7 @@ _need_resched:
nop
#else
#define _resume_kernel _Rexit
-#endif
+#endif
; Called at exit from fork. schedule_tail must be called to drop
; spinlock if CONFIG_PREEMPT
@@ -324,18 +82,25 @@ ret_from_fork:
jsr schedule_tail
ba ret_from_sys_call
nop
-
+
+ret_from_kernel_thread:
+ jsr schedule_tail
+ move.d $r2, $r10 ; argument is here
+ jsr $r1 ; call the payload
+ moveq 0, $r9 ; no syscall restarts, TYVM...
+ ba ret_from_sys_call
+
ret_from_intr:
- ;; check for resched if preemptive kernel or if we're going back to user-mode
+ ;; check for resched if preemptive kernel or if we're going back to user-mode
;; this test matches the user_regs(regs) macro
;; we cannot simply test $dccr, because that does not necessarily
;; reflect what mode we'll return into.
-
+
move.d [$sp + PT_dccr], $r0; regs->dccr
btstq 8, $r0 ; U-flag
bpl _resume_kernel
- ; Note that di below is in delay slot
-
+ ; Note that di below is in delay slot
+
_resume_userspace:
di ; so need_resched and sigpending don't change
@@ -348,7 +113,7 @@ _resume_userspace:
nop
ba _Rexit
nop
-
+
;; The system_call is called by a BREAK instruction, which works like
;; an interrupt call but it stores the return PC in BRP instead of IRP.
;; Since we dont really want to have two epilogues (one for system calls
@@ -358,7 +123,7 @@ _resume_userspace:
;;
;; Since we can't have system calls inside interrupts, it should not matter
;; that we don't stack IRP.
- ;;
+ ;;
;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp
;;
;; This function looks on the _surface_ like spaghetti programming, but it's
@@ -375,7 +140,7 @@ system_call:
movem $r13, [$sp] ; push r0-r13
push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe
-
+
movs.w -ENOSYS, $r0
move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame
@@ -383,17 +148,17 @@ system_call:
movs.w -8192, $r0 ; THREAD_SIZE == 8192
and.d $sp, $r0
-
+
move.d [$r0+TI_flags], $r0
btstq TIF_SYSCALL_TRACE, $r0
bmi _syscall_trace_entry
- nop
+ nop
-_syscall_traced:
+_syscall_traced:
;; check for sanity in the requested syscall number
-
- cmpu.w NR_syscalls, $r9
+
+ cmpu.w NR_syscalls, $r9
bcc ret_from_sys_call
lslq 2, $r9 ; multiply by 4, in the delay slot
@@ -401,28 +166,28 @@ _syscall_traced:
;; of the register structure itself. some syscalls need this.
push $sp
-
+
;; the parameter carrying registers r10, r11, r12 and 13 are intact.
- ;; the fifth and sixth parameters (if any) was in mof and srp
+ ;; the fifth and sixth parameters (if any) was in mof and srp
;; respectively, and we need to put them on the stack.
push $srp
push $mof
-
+
jsr [$r9+sys_call_table] ; actually do the system call
addq 3*4, $sp ; pop the mof, srp and regs parameters
move.d $r10, [$sp+PT_r10] ; save the return value
moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call
-
+
;; fall through into ret_from_sys_call to return
-
+
ret_from_sys_call:
;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq
-
+
;; get the current task-struct pointer (see top for defs)
- movs.w -8192, $r0 ; THREAD_SIZE == 8192
+ movs.w -8192, $r0 ; THREAD_SIZE == 8192
and.d $sp, $r0
di ; make sure need_resched and sigpending don't change
@@ -437,7 +202,7 @@ _Rexit:
bne _RBFexit ; was not CRIS_FRAME_NORMAL, handle otherwise
addq 4, $sp ; skip orig_r10, in delayslot
movem [$sp+], $r13 ; registers r0-r13
- pop $mof ; multiply overflow register
+ pop $mof ; multiply overflow register
pop $dccr ; condition codes
pop $srp ; subroutine return pointer
;; now we have a 4-word SBFS frame which we do not want to restore
@@ -451,14 +216,14 @@ _Rexit:
_RBFexit:
movem [$sp+], $r13 ; registers r0-r13, in delay slot
- pop $mof ; multiply overflow register
+ pop $mof ; multiply overflow register
pop $dccr ; condition codes
pop $srp ; subroutine return pointer
rbf [$sp+] ; return by popping the CPU status
;; We get here after doing a syscall if extra work might need to be done
;; perform syscall exit tracing if needed
-
+
_syscall_exit_work:
;; $r0 contains current at this point and irq's are disabled
@@ -466,22 +231,22 @@ _syscall_exit_work:
btstq TIF_SYSCALL_TRACE, $r1
bpl _work_pending
nop
-
+
ei
move.d $r9, $r1 ; preserve r9
jsr do_syscall_trace
move.d $r1, $r9
-
+
ba _resume_userspace
nop
-
+
_work_pending:
move.d [$r0+TI_flags], $r1
btstq TIF_NEED_RESCHED, $r1
bpl _work_notifysig ; was neither trace nor sched, must be signal/notify
nop
-
+
_work_resched:
move.d $r9, $r1 ; preserve r9
jsr schedule
@@ -500,21 +265,20 @@ _work_notifysig:
;; deal with pending signals and notify-resume requests
move.d $r9, $r10 ; do_notify_resume syscall/irq param
- moveq 0, $r11 ; oldset param - 0 in this case
- move.d $sp, $r12 ; the regs param
- move.d $r1, $r13 ; the thread_info_flags parameter
+ move.d $sp, $r11 ; the regs param
+ move.d $r1, $r12 ; the thread_info_flags parameter
jsr do_notify_resume
-
+
ba _Rexit
nop
;; We get here as a sidetrack when we've entered a syscall with the
;; trace-bit set. We need to call do_syscall_trace and then continue
;; with the call.
-
+
_syscall_trace_entry:
;; PT_r10 in the frame contains -ENOSYS as required, at this point
-
+
jsr do_syscall_trace
;; now re-enter the syscall code to do the syscall itself
@@ -528,10 +292,10 @@ _syscall_trace_entry:
move.d [$sp+PT_r13], $r13
move [$sp+PT_mof], $mof
move [$sp+PT_srp], $srp
-
+
ba _syscall_traced
nop
-
+
;; resume performs the actual task-switching, by switching stack pointers
;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct
;; returns old current in r10
@@ -539,29 +303,29 @@ _syscall_trace_entry:
;; TODO: see the i386 version. The switch_to which calls resume in our version
;; could really be an inline asm of this.
-resume:
- push $srp ; we keep the old/new PC on the stack
+resume:
+ push $srp ; we keep the old/new PC on the stack
add.d $r12, $r10 ; r10 = current tasks tss
move $dccr, [$r10+THREAD_dccr]; save irq enable state
di
move $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer
-
+
;; See copy_thread for the reason why register R9 is saved.
subq 10*4, $sp
movem $r9, [$sp] ; save non-scratch registers and R9.
-
+
move.d $sp, [$r10+THREAD_ksp] ; save the kernel stack pointer for the old task
move.d $sp, $r10 ; return last running task in r10
and.d -8192, $r10 ; get thread_info from stackpointer
- move.d [$r10+TI_task], $r10 ; get task
+ move.d [$r10+TI_task], $r10 ; get task
add.d $r12, $r11 ; find the new tasks tss
move.d [$r11+THREAD_ksp], $sp ; switch into the new stackframe by restoring kernel sp
movem [$sp+], $r9 ; restore non-scratch registers and R9.
move [$r11+THREAD_usp], $usp ; restore user-mode stackpointer
-
+
move [$r11+THREAD_dccr], $dccr ; restore irq enable status
jump [$sp+] ; restore PC
@@ -602,7 +366,7 @@ mmu_bus_fault:
1: btstq 12, $r1 ; Refill?
bpl 2f
lsrq 24, $r1 ; Get PGD index (bit 24-31)
- move.d [per_cpu__current_pgd], $r0 ; PGD for the current process
+ move.d [current_pgd], $r0 ; PGD for the current process
move.d [$r0+$r1.d], $r0 ; Get PMD
beq 2f
nop
@@ -637,7 +401,7 @@ mmu_bus_fault:
push $r10 ; frametype == 1, BUSFAULT frame type
move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault
-
+
jsr handle_mmu_bus_fault ; in arch/cris/arch-v10/mm/fault.c
;; now we need to return through the normal path, we cannot just
@@ -646,10 +410,10 @@ mmu_bus_fault:
;; whatever.
moveq 0, $r9 ; busfault is equivalent to an irq
-
+
ba ret_from_intr
nop
-
+
;; special handlers for breakpoint and NMI
hwbreakpoint:
push $dccr
@@ -665,7 +429,7 @@ hwbreakpoint:
pop $dccr
retb
nop
-
+
IRQ1_interrupt:
;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
@@ -678,16 +442,22 @@ IRQ1_interrupt:
push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal frame
+ ;; If there is a glitch on the NMI pin shorter than ~100ns
+ ;; (i.e. non-active by the time we get here) then the nmi_pin bit
+ ;; in R_IRQ_MASK0_RD will already be cleared. The watchdog_nmi bit
+ ;; is cleared by us however (when feeding the watchdog), which is why
+ ;; we use that bit to determine what brought us here.
+
move.d [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog?
- and.d 0x80000000, $r1
- beq wdog
+ and.d (1<<30), $r1
+ bne wdog
move.d $sp, $r10
jsr handle_nmi
setf m ; Enable NMI again
- retb ; Return from NMI
+ ba _Rexit ; Return the standard way
nop
wdog:
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
;; Check if we're waiting for reset to happen, as signalled by
;; hard_reset_now setting cause_of_death to a magic value. If so, just
;; get stuck until reset happens.
@@ -730,7 +500,7 @@ Watchdog_bite:
move.d $r10, [$r11]
#endif
-
+
;; Note that we don't do "setf m" here (or after two necessary NOPs),
;; since *not* doing that saves us from re-entrancy checks. We don't want
;; to get here again due to possible subsequent NMIs; we want the watchdog
@@ -753,16 +523,16 @@ _watchdogmsg:
.ascii "Oops: bitten by watchdog\n\0"
.previous
-#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */
+#endif /* CONFIG_ETRAX_WATCHDOG */
-spurious_interrupt:
+spurious_interrupt:
di
jump hard_reset_now
;; this handles the case when multiple interrupts arrive at the same time
;; we jump to the first set interrupt bit in a priority fashion
;; the hardware will call the unserved interrupts after the handler finishes
-
+
multiple_interrupt:
;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
move $irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
@@ -774,27 +544,14 @@ multiple_interrupt:
movem $r13, [$sp]
push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal frame
-
- moveq 2, $r2 ; first bit we care about is the timer0 irq
- move.d [R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq
- move.d $r0, [R_VECT_MASK_CLR] ; Block all active IRQs
-1:
- btst $r2, $r0 ; check for the irq given by bit r2
- bpl 2f
- move.d $r2, $r10 ; First argument to do_IRQ
- move.d $sp, $r11 ; second argument to do_IRQ
- jsr do_IRQ
-2:
- addq 1, $r2 ; next vector bit
- cmp.b 32, $r2
- bne 1b ; process all irq's up to and including number 31
- moveq 0, $r9 ; make ret_from_intr realise we came from an ir
-
- move.d $r0, [R_VECT_MASK_SET] ; Unblock all the IRQs
+
+ move.d $sp, $r10
+ jsr do_multiple_IRQ
+
jump ret_from_intr
do_sigtrap:
- ;;
+ ;;
;; SIGTRAP the process that executed the break instruction.
;; Make a frame that Rexit in entry.S expects.
;;
@@ -811,32 +568,32 @@ do_sigtrap:
movs.w -8192,$r9 ; THREAD_SIZE == 8192
and.d $sp, $r9
move.d [$r9+TI_task], $r10
- move.d [$r10+TASK_pid], $r10 ; current->pid as arg1.
+ move.d [$r10+TASK_pid], $r10 ; current->pid as arg1.
moveq 5, $r11 ; SIGTRAP as arg2.
- jsr sys_kill
+ jsr sys_kill
jump ret_from_intr ; Use the return routine for interrupts.
-gdb_handle_breakpoint:
+gdb_handle_breakpoint:
push $dccr
push $r0
#ifdef CONFIG_ETRAX_KGDB
- move $dccr, $r0 ; U-flag not affected by previous insns.
+ move $dccr, $r0 ; U-flag not affected by previous insns.
btstq 8, $r0 ; Test the U-flag.
- bmi _ugdb_handle_breakpoint ; Go to user mode debugging.
- nop ; Empty delay slot (cannot pop r0 here).
+ bmi _ugdb_handle_breakpoint ; Go to user mode debugging.
+ nop ; Empty delay slot (cannot pop r0 here).
pop $r0 ; Restore r0.
- ba kgdb_handle_breakpoint ; Go to kernel debugging.
+ ba kgdb_handle_breakpoint ; Go to kernel debugging.
pop $dccr ; Restore dccr in delay slot.
#endif
-
-_ugdb_handle_breakpoint:
+
+_ugdb_handle_breakpoint:
move $brp, $r0 ; Use r0 temporarily for calculation.
subq 2, $r0 ; Set to address of previous instruction.
move $r0, $brp
- pop $r0 ; Restore r0.
- ba do_sigtrap ; SIGTRAP the offending process.
+ pop $r0 ; Restore r0.
+ ba do_sigtrap ; SIGTRAP the offending process.
pop $dccr ; Restore dccr in delay slot.
-
+
.data
hw_bp_trigs:
@@ -845,7 +602,7 @@ hw_bp_trig_ptr:
.dword hw_bp_trigs
.section .rodata,"a"
-sys_call_table:
+sys_call_table:
.long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
.long sys_exit
.long sys_fork
@@ -935,8 +692,8 @@ sys_call_table:
.long sys_uselib
.long sys_swapon
.long sys_reboot
- .long old_readdir
- .long old_mmap /* 90 */
+ .long sys_old_readdir
+ .long sys_old_mmap /* 90 */
.long sys_munmap
.long sys_truncate
.long sys_ftruncate
@@ -956,7 +713,7 @@ sys_call_table:
.long sys_newlstat
.long sys_newfstat
.long sys_ni_syscall /* old sys_uname holder */
- .long sys_ni_syscall /* sys_iopl in i386 */
+ .long sys_ni_syscall /* 110 */ /* sys_iopl in i386 */
.long sys_vhangup
.long sys_ni_syscall /* old "idle" system call */
.long sys_ni_syscall /* vm86old in i386 */
@@ -973,7 +730,7 @@ sys_call_table:
.long sys_adjtimex
.long sys_mprotect /* 125 */
.long sys_sigprocmask
- .long sys_ni_syscall /* old "create_module" */
+ .long sys_ni_syscall /* old "create_module" */
.long sys_init_module
.long sys_delete_module
.long sys_ni_syscall /* 130: old "get_kernel_syms" */
@@ -1015,7 +772,7 @@ sys_call_table:
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
@@ -1038,7 +795,7 @@ sys_call_table:
.long sys_ni_syscall /* streams2 */
.long sys_vfork /* 190 */
.long sys_getrlimit
- .long sys_mmap2
+ .long sys_mmap2 /* mmap_pgoff */
.long sys_truncate64
.long sys_ftruncate64
.long sys_stat64 /* 195 */
@@ -1104,21 +861,21 @@ sys_call_table:
.long sys_epoll_ctl /* 255 */
.long sys_epoll_wait
.long sys_remap_file_pages
- .long sys_set_tid_address
- .long sys_timer_create
- .long sys_timer_settime /* 260 */
- .long sys_timer_gettime
- .long sys_timer_getoverrun
- .long sys_timer_delete
- .long sys_clock_settime
- .long sys_clock_gettime /* 265 */
- .long sys_clock_getres
- .long sys_clock_nanosleep
+ .long sys_set_tid_address
+ .long sys_timer_create
+ .long sys_timer_settime /* 260 */
+ .long sys_timer_gettime
+ .long sys_timer_getoverrun
+ .long sys_timer_delete
+ .long sys_clock_settime
+ .long sys_clock_gettime /* 265 */
+ .long sys_clock_getres
+ .long sys_clock_nanosleep
.long sys_statfs64
- .long sys_fstatfs64
- .long sys_tgkill /* 270 */
+ .long sys_fstatfs64
+ .long sys_tgkill /* 270 */
.long sys_utimes
- .long sys_fadvise64_64
+ .long sys_fadvise64_64
.long sys_ni_syscall /* sys_vserver */
.long sys_ni_syscall /* sys_mbind */
.long sys_ni_syscall /* 275 sys_get_mempolicy */
@@ -1129,12 +886,75 @@ sys_call_table:
.long sys_mq_timedreceive /* 280 */
.long sys_mq_notify
.long sys_mq_getsetattr
- .long sys_ni_syscall /* reserved for kexec */
+ .long sys_ni_syscall
.long sys_waitid
.long sys_ni_syscall /* 285 */ /* available */
.long sys_add_key
.long sys_request_key
.long sys_keyctl
+ .long sys_ioprio_set
+ .long sys_ioprio_get /* 290 */
+ .long sys_inotify_init
+ .long sys_inotify_add_watch
+ .long sys_inotify_rm_watch
+ .long sys_migrate_pages
+ .long sys_openat /* 295 */
+ .long sys_mkdirat
+ .long sys_mknodat
+ .long sys_fchownat
+ .long sys_futimesat
+ .long sys_fstatat64 /* 300 */
+ .long sys_unlinkat
+ .long sys_renameat
+ .long sys_linkat
+ .long sys_symlinkat
+ .long sys_readlinkat /* 305 */
+ .long sys_fchmodat
+ .long sys_faccessat
+ .long sys_pselect6
+ .long sys_ppoll
+ .long sys_unshare /* 310 */
+ .long sys_set_robust_list
+ .long sys_get_robust_list
+ .long sys_splice
+ .long sys_sync_file_range
+ .long sys_tee /* 315 */
+ .long sys_vmsplice
+ .long sys_move_pages
+ .long sys_getcpu
+ .long sys_epoll_pwait
+ .long sys_utimensat /* 320 */
+ .long sys_signalfd
+ .long sys_timerfd_create
+ .long sys_eventfd
+ .long sys_fallocate
+ .long sys_timerfd_settime /* 325 */
+ .long sys_timerfd_gettime
+ .long sys_signalfd4
+ .long sys_eventfd2
+ .long sys_epoll_create1
+ .long sys_dup3 /* 330 */
+ .long sys_pipe2
+ .long sys_inotify_init1
+ .long sys_preadv
+ .long sys_pwritev
+ .long sys_setns /* 335 */
+ .long sys_name_to_handle_at
+ .long sys_open_by_handle_at
+ .long sys_rt_tgsigqueueinfo
+ .long sys_perf_event_open
+ .long sys_recvmmsg /* 340 */
+ .long sys_accept4
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
+ .long sys_clock_adjtime /* 345 */
+ .long sys_syncfs
+ .long sys_sendmmsg
+ .long sys_process_vm_readv
+ .long sys_process_vm_writev
+ .long sys_kcmp /* 350 */
+ .long sys_finit_module
/*
* NOTE!! This doesn't have to be exact - we just have
@@ -1146,4 +966,4 @@ sys_call_table:
.rept NR_syscalls-(.-sys_call_table)/4
.long sys_ni_syscall
.endr
-
+
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c
index 8cbdf594b36..48a59afbeeb 100644
--- a/arch/cris/arch-v10/kernel/fasttimer.c
+++ b/arch/cris/arch-v10/kernel/fasttimer.c
@@ -1,97 +1,9 @@
-/* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 starvik Exp $
+/*
* linux/arch/cris/kernel/fasttimer.c
*
* Fast timers for ETRAX100/ETRAX100LX
- * This may be useful in other OS than Linux so use 2 space indentation...
*
- * $Log: fasttimer.c,v $
- * Revision 1.9 2005/03/04 08:16:16 starvik
- * Merge of Linux 2.6.11.
- *
- * Revision 1.8 2005/01/05 06:09:29 starvik
- * cli()/sti() will be obsolete in 2.6.11.
- *
- * Revision 1.7 2005/01/03 13:35:46 starvik
- * Removed obsolete stuff.
- * Mark fast timer IRQ as not shared.
- *
- * Revision 1.6 2004/05/14 10:18:39 starvik
- * Export fast_timer_list
- *
- * Revision 1.5 2004/05/14 07:58:01 starvik
- * Merge of changes from 2.4
- *
- * Revision 1.4 2003/07/04 08:27:41 starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.3 2002/12/12 08:26:32 starvik
- * Don't use C-comments inside CVS comments
- *
- * Revision 1.2 2002/12/11 15:42:02 starvik
- * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
- *
- * Revision 1.1 2002/11/18 07:58:06 starvik
- * Fast timers (from Linux 2.4)
- *
- * Revision 1.5 2002/10/15 06:21:39 starvik
- * Added call to init_waitqueue_head
- *
- * Revision 1.4 2002/05/28 17:47:59 johana
- * Added del_fast_timer()
- *
- * Revision 1.3 2002/05/28 16:16:07 johana
- * Handle empty fast_timer_list
- *
- * Revision 1.2 2002/05/27 15:38:42 johana
- * Made it compile without warnings on Linux 2.4.
- * (includes, wait_queue, PROC_FS and snprintf)
- *
- * Revision 1.1 2002/05/27 15:32:25 johana
- * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
- *
- * Revision 1.8 2001/11/27 13:50:40 pkj
- * Disable interrupts while stopping the timer and while modifying the
- * list of active timers in timer1_handler() as it may be interrupted
- * by other interrupts (e.g., the serial interrupt) which may add fast
- * timers.
- *
- * Revision 1.7 2001/11/22 11:50:32 pkj
- * * Only store information about the last 16 timers.
- * * proc_fasttimer_read() now uses an allocated buffer, since it
- * requires more space than just a page even for only writing the
- * last 16 timers. The buffer is only allocated on request, so
- * unless /proc/fasttimer is read, it is never allocated.
- * * Renamed fast_timer_started to fast_timers_started to match
- * fast_timers_added and fast_timers_expired.
- * * Some clean-up.
- *
- * Revision 1.6 2000/12/13 14:02:08 johana
- * Removed volatile for fast_timer_list
- *
- * Revision 1.5 2000/12/13 13:55:35 johana
- * Added DEBUG_LOG, added som cli() and cleanup
- *
- * Revision 1.4 2000/12/05 13:48:50 johana
- * Added range check when writing proc file, modified timer int handling
- *
- * Revision 1.3 2000/11/23 10:10:20 johana
- * More debug/logging possibilities.
- * Moved GET_JIFFIES_USEC() to timex.h and time.c
- *
- * Revision 1.2 2000/11/01 13:41:04 johana
- * Clean up and bugfixes.
- * Created new do_gettimeofday_fast() that gets a timeval struct
- * with time based on jiffies and *R_TIMER0_DATA, uses a table
- * for fast conversion of timer value to microseconds.
- * (Much faster the standard do_gettimeofday() and we don't really
- * wan't to use the true time - we wan't the "uptime" so timers don't screw up
- * when we change the time.
- * TODO: Add efficient support for continuous timers as well.
- *
- * Revision 1.1 2000/10/26 15:49:16 johana
- * Added fasttimer, highresolution timers.
- *
- * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden
+ * Copyright (C) 2000-2007 Axis Communications AB, Lund, Sweden
*/
#include <linux/errno.h>
@@ -109,40 +21,34 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
-#include <asm/rtc.h>
-
-#include <asm/arch/svinto.h>
+#include <arch/svinto.h>
#include <asm/fasttimer.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#define DEBUG_LOG_INCLUDED
#define FAST_TIMER_LOG
-//#define FAST_TIMER_TEST
+/* #define FAST_TIMER_TEST */
#define FAST_TIMER_SANITY_CHECKS
#ifdef FAST_TIMER_SANITY_CHECKS
-#define SANITYCHECK(x) x
-static int sanity_failed = 0;
-#else
-#define SANITYCHECK(x)
+static int sanity_failed;
#endif
#define D1(x)
#define D2(x)
#define DP(x)
-#define __INLINE__ inline
-
-static int fast_timer_running = 0;
-static int fast_timers_added = 0;
-static int fast_timers_started = 0;
-static int fast_timers_expired = 0;
-static int fast_timers_deleted = 0;
-static int fast_timer_is_init = 0;
-static int fast_timer_ints = 0;
+static unsigned int fast_timer_running;
+static unsigned int fast_timers_added;
+static unsigned int fast_timers_started;
+static unsigned int fast_timers_expired;
+static unsigned int fast_timers_deleted;
+static unsigned int fast_timer_is_init;
+static unsigned int fast_timer_ints;
struct fast_timer *fast_timer_list = NULL;
@@ -150,8 +56,8 @@ struct fast_timer *fast_timer_list = NULL;
#define DEBUG_LOG_MAX 128
static const char * debug_log_string[DEBUG_LOG_MAX];
static unsigned long debug_log_value[DEBUG_LOG_MAX];
-static int debug_log_cnt = 0;
-static int debug_log_cnt_wrapped = 0;
+static unsigned int debug_log_cnt;
+static unsigned int debug_log_cnt_wrapped;
#define DEBUG_LOG(string, value) \
{ \
@@ -206,45 +112,29 @@ int timer_freq_settings[NUM_TIMER_STATS];
int timer_delay_settings[NUM_TIMER_STATS];
/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
-void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+inline void do_gettimeofday_fast(struct fasttime_t *tv)
{
- unsigned long sec = jiffies;
- unsigned long usec = GET_JIFFIES_USEC();
-
- usec += (sec % HZ) * (1000000 / HZ);
- sec = sec / HZ;
-
- if (usec > 1000000)
- {
- usec -= 1000000;
- sec++;
- }
- tv->tv_sec = sec;
- tv->tv_usec = usec;
+ tv->tv_jiff = jiffies;
+ tv->tv_usec = GET_JIFFIES_USEC();
}
-int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1)
{
- if (t0->tv_sec < t1->tv_sec)
- {
- return -1;
- }
- else if (t0->tv_sec > t1->tv_sec)
- {
- return 1;
- }
- if (t0->tv_usec < t1->tv_usec)
- {
- return -1;
- }
- else if (t0->tv_usec > t1->tv_usec)
- {
- return 1;
- }
- return 0;
+ /* Compare jiffies. Takes care of wrapping */
+ if (time_before(t0->tv_jiff, t1->tv_jiff))
+ return -1;
+ else if (time_after(t0->tv_jiff, t1->tv_jiff))
+ return 1;
+
+ /* Compare us */
+ if (t0->tv_usec < t1->tv_usec)
+ return -1;
+ else if (t0->tv_usec > t1->tv_usec)
+ return 1;
+ return 0;
}
-void __INLINE__ start_timer1(unsigned long delay_us)
+inline void start_timer1(unsigned long delay_us)
{
int freq_index = 0; /* This is the lowest resolution */
unsigned long upper_limit = MAX_DELAY_US;
@@ -285,7 +175,7 @@ void __INLINE__ start_timer1(unsigned long delay_us)
timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index;
timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
- D1(printk("start_timer1 : %d us freq: %i div: %i\n",
+ D1(printk(KERN_DEBUG "start_timer1 : %d us freq: %i div: %i\n",
delay_us, freq_index, div));
/* Clear timer1 irq */
*R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
@@ -332,23 +222,19 @@ void start_one_shot_timer(struct fast_timer *t,
do_gettimeofday_fast(&t->tv_set);
tmp = fast_timer_list;
- SANITYCHECK({ /* Check so this is not in the list already... */
- while (tmp != NULL)
- {
- if (tmp == t)
- {
- printk(KERN_WARNING
- "timer name: %s data: 0x%08lX already in list!\n", name, data);
- sanity_failed++;
- return;
- }
- else
- {
- tmp = tmp->next;
- }
- }
- tmp = fast_timer_list;
- });
+#ifdef FAST_TIMER_SANITY_CHECKS
+ /* Check so this is not in the list already... */
+ while (tmp != NULL) {
+ if (tmp == t) {
+ printk(KERN_WARNING "timer name: %s data: "
+ "0x%08lX already in list!\n", name, data);
+ sanity_failed++;
+ goto done;
+ } else
+ tmp = tmp->next;
+ }
+ tmp = fast_timer_list;
+#endif
t->delay_us = delay_us;
t->function = function;
@@ -356,11 +242,11 @@ void start_one_shot_timer(struct fast_timer *t,
t->name = name;
t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
- t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000;
+ t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;
if (t->tv_expires.tv_usec > 1000000)
{
t->tv_expires.tv_usec -= 1000000;
- t->tv_expires.tv_sec++;
+ t->tv_expires.tv_jiff += HZ;
}
#ifdef FAST_TIMER_LOG
timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
@@ -368,7 +254,7 @@ void start_one_shot_timer(struct fast_timer *t,
fast_timers_added++;
/* Check if this should timeout before anything else */
- if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
+ if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
{
/* Put first in list and modify the timer value */
t->prev = NULL;
@@ -384,8 +270,8 @@ void start_one_shot_timer(struct fast_timer *t,
start_timer1(delay_us);
} else {
/* Put in correct place in list */
- while (tmp->next &&
- timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
+ while (tmp->next && fasttime_cmp(&t->tv_expires,
+ &tmp->next->tv_expires) > 0)
{
tmp = tmp->next;
}
@@ -401,6 +287,7 @@ void start_one_shot_timer(struct fast_timer *t,
D2(printk("start_one_shot_timer: %d us done\n", delay_us));
+done:
local_irq_restore(flags);
} /* start_one_shot_timer */
@@ -444,11 +331,18 @@ int del_fast_timer(struct fast_timer * t)
/* Timer 1 interrupt handler */
static irqreturn_t
-timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
+timer1_handler(int irq, void *dev_id)
{
struct fast_timer *t;
unsigned long flags;
+ /* We keep interrupts disabled not only when we modify the
+ * fast timer list, but any time we hold a reference to a
+ * timer in the list, since del_fast_timer may be called
+ * from (another) interrupt context. Thus, the only time
+ * when interrupts are enabled is when calling the timer
+ * callback function.
+ */
local_irq_save(flags);
/* Clear timer1 irq */
@@ -466,18 +360,19 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
fast_timer_running = 0;
fast_timer_ints++;
- local_irq_restore(flags);
-
t = fast_timer_list;
while (t)
{
- struct timeval tv;
+ struct fasttime_t tv;
+ fast_timer_function_type *f;
+ unsigned long d;
/* Has it really expired? */
do_gettimeofday_fast(&tv);
- D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+ D1(printk(KERN_DEBUG "t: %is %06ius\n",
+ tv.tv_jiff, tv.tv_usec));
- if (timeval_cmp(&t->tv_expires, &tv) <= 0)
+ if (fasttime_cmp(&t->tv_expires, &tv) <= 0)
{
/* Yes it has expired */
#ifdef FAST_TIMER_LOG
@@ -486,7 +381,6 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
fast_timers_expired++;
/* Remove this timer before call, since it may reuse the timer */
- local_irq_save(flags);
if (t->prev)
{
t->prev->next = t->next;
@@ -501,16 +395,23 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
}
t->prev = NULL;
t->next = NULL;
- local_irq_restore(flags);
- if (t->function != NULL)
- {
- t->function(t->data);
- }
- else
- {
+ /* Save function callback data before enabling
+ * interrupts, since the timer may be removed and
+ * we don't know how it was allocated
+ * (e.g. ->function and ->data may become overwritten
+ * after deletion if the timer was stack-allocated).
+ */
+ f = t->function;
+ d = t->data;
+
+ if (f != NULL) {
+ /* Run callback with interrupts enabled. */
+ local_irq_restore(flags);
+ f(d);
+ local_irq_save(flags);
+ } else
DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints);
- }
}
else
{
@@ -518,16 +419,20 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
D1(printk(".\n"));
}
- local_irq_save(flags);
if ((t = fast_timer_list) != NULL)
{
/* Start next timer.. */
- long us;
- struct timeval tv;
+ long us = 0;
+ struct fasttime_t tv;
do_gettimeofday_fast(&tv);
- us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
- t->tv_expires.tv_usec - tv.tv_usec);
+
+ /* time_after_eq takes care of wrapping */
+ if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))
+ us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *
+ 1000000 / HZ + t->tv_expires.tv_usec -
+ tv.tv_usec);
+
if (us > 0)
{
if (!fast_timer_running)
@@ -537,7 +442,6 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
#endif
start_timer1(us);
}
- local_irq_restore(flags);
break;
}
else
@@ -548,9 +452,10 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
D1(printk("e! %d\n", us));
}
}
- local_irq_restore(flags);
}
+ local_irq_restore(flags);
+
if (!t)
{
D1(printk("t1 stop!\n"));
@@ -561,11 +466,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
static void wake_up_func(unsigned long data)
{
-#ifdef DECLARE_WAITQUEUE
- wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data;
-#else
- struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
-#endif
+ wait_queue_head_t *sleep_wait_p = (wait_queue_head_t *)data;
wake_up(sleep_wait_p);
}
@@ -575,221 +476,176 @@ static void wake_up_func(unsigned long data)
void schedule_usleep(unsigned long us)
{
struct fast_timer t;
-#ifdef DECLARE_WAITQUEUE
wait_queue_head_t sleep_wait;
init_waitqueue_head(&sleep_wait);
- {
- DECLARE_WAITQUEUE(wait, current);
-#else
- struct wait_queue *sleep_wait = NULL;
- struct wait_queue wait = { current, NULL };
-#endif
D1(printk("schedule_usleep(%d)\n", us));
- add_wait_queue(&sleep_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
"usleep");
- schedule();
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&sleep_wait, &wait);
+ /* Uninterruptible sleep on the fast timer. (The condition is somewhat
+ * redundant since the timer is what wakes us up.) */
+ wait_event(sleep_wait, !fast_timer_pending(&t));
+
D1(printk("done schedule_usleep(%d)\n", us));
-#ifdef DECLARE_WAITQUEUE
- }
-#endif
}
#ifdef CONFIG_PROC_FS
-static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
- ,int *eof, void *data_unused);
-static struct proc_dir_entry *fasttimer_proc_entry;
-#endif /* CONFIG_PROC_FS */
-
-#ifdef CONFIG_PROC_FS
-
/* This value is very much based on testing */
#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
-static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
- ,int *eof, void *data_unused)
+static int proc_fasttimer_show(struct seq_file *m, void *v)
{
- unsigned long flags;
- int i = 0;
- int num_to_show;
- struct timeval tv;
- struct fast_timer *t, *nextt;
- static char *bigbuf = NULL;
- static unsigned long used;
-
- if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
- {
- used = 0;
- bigbuf[0] = '\0';
- return 0;
- }
-
- if (!offset || !used)
- {
- do_gettimeofday_fast(&tv);
-
- used = 0;
- used += sprintf(bigbuf + used, "Fast timers added: %i\n",
- fast_timers_added);
- used += sprintf(bigbuf + used, "Fast timers started: %i\n",
- fast_timers_started);
- used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
- fast_timer_ints);
- used += sprintf(bigbuf + used, "Fast timers expired: %i\n",
- fast_timers_expired);
- used += sprintf(bigbuf + used, "Fast timers deleted: %i\n",
- fast_timers_deleted);
- used += sprintf(bigbuf + used, "Fast timer running: %s\n",
- fast_timer_running ? "yes" : "no");
- used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n",
- (unsigned long)tv.tv_sec,
- (unsigned long)tv.tv_usec);
+ unsigned long flags;
+ int i = 0;
+ int num_to_show;
+ struct fasttime_t tv;
+ struct fast_timer *t, *nextt;
+
+ do_gettimeofday_fast(&tv);
+
+ seq_printf(m, "Fast timers added: %i\n", fast_timers_added);
+ seq_printf(m, "Fast timers started: %i\n", fast_timers_started);
+ seq_printf(m, "Fast timer interrupts: %i\n", fast_timer_ints);
+ seq_printf(m, "Fast timers expired: %i\n", fast_timers_expired);
+ seq_printf(m, "Fast timers deleted: %i\n", fast_timers_deleted);
+ seq_printf(m, "Fast timer running: %s\n",
+ fast_timer_running ? "yes" : "no");
+ seq_printf(m, "Current time: %lu.%06lu\n",
+ (unsigned long)tv.tv_jiff,
+ (unsigned long)tv.tv_usec);
#ifdef FAST_TIMER_SANITY_CHECKS
- used += sprintf(bigbuf + used, "Sanity failed: %i\n",
- sanity_failed);
+ seq_printf(m, "Sanity failed: %i\n", sanity_failed);
#endif
- used += sprintf(bigbuf + used, "\n");
+ seq_putc(m, '\n');
#ifdef DEBUG_LOG_INCLUDED
- {
- int end_i = debug_log_cnt;
- i = 0;
-
- if (debug_log_cnt_wrapped)
- {
- i = debug_log_cnt;
- }
-
- while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
- used+100 < BIG_BUF_SIZE)
- {
- used += sprintf(bigbuf + used, debug_log_string[i],
- debug_log_value[i]);
- i = (i+1) % DEBUG_LOG_MAX;
- }
- }
- used += sprintf(bigbuf + used, "\n");
+ {
+ int end_i = debug_log_cnt;
+ i = 0;
+
+ if (debug_log_cnt_wrapped)
+ i = debug_log_cnt;
+
+ while (i != end_i || debug_log_cnt_wrapped) {
+ if (seq_printf(m, debug_log_string[i], debug_log_value[i]) < 0)
+ return 0;
+ i = (i+1) % DEBUG_LOG_MAX;
+ }
+ }
+ seq_putc(m, '\n');
#endif
- num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
- NUM_TIMER_STATS);
- used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
- for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
- {
- int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
+ num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
+ NUM_TIMER_STATS);
+ seq_printf(m, "Timers started: %i\n", fast_timers_started);
+ for (i = 0; i < num_to_show; i++) {
+ int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
#if 1 //ndef FAST_TIMER_LOG
- used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i"
- "\n",
- timer_div_settings[cur],
- timer_freq_settings[cur],
- timer_delay_settings[cur]
- );
+ seq_printf(m, "div: %i freq: %i delay: %i"
+ "\n",
+ timer_div_settings[cur],
+ timer_freq_settings[cur],
+ timer_delay_settings[cur]);
#endif
#ifdef FAST_TIMER_LOG
- t = &timer_started_log[cur];
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
- );
+ t = &timer_started_log[cur];
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data) < 0)
+ return 0;
#endif
- }
- used += sprintf(bigbuf + used, "\n");
+ }
+ seq_putc(m, '\n');
#ifdef FAST_TIMER_LOG
- num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
- NUM_TIMER_STATS);
- used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
- for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
- {
- t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
- );
- }
- used += sprintf(bigbuf + used, "\n");
-
- num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
- NUM_TIMER_STATS);
- used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
- for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
- {
- t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
- );
- }
- used += sprintf(bigbuf + used, "\n");
+ num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
+ NUM_TIMER_STATS);
+ seq_printf(m, "Timers added: %i\n", fast_timers_added);
+ for (i = 0; i < num_to_show; i++) {
+ t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data) < 0)
+ return 0;
+ }
+ seq_putc(m, '\n');
+
+ num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
+ NUM_TIMER_STATS);
+ seq_printf(m, "Timers expired: %i\n", fast_timers_expired);
+ for (i = 0; i < num_to_show; i++) {
+ t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data) < 0)
+ return 0;
+ }
+ seq_putc(m, '\n');
#endif
- used += sprintf(bigbuf + used, "Active timers:\n");
- local_irq_save(flags);
- t = fast_timer_list;
- while (t != NULL && (used+100 < BIG_BUF_SIZE))
- {
- nextt = t->next;
- local_irq_restore(flags);
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
+ seq_puts(m, "Active timers:\n");
+ local_irq_save(flags);
+ t = fast_timer_list;
+ while (t) {
+ nextt = t->next;
+ local_irq_restore(flags);
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
/* " func: 0x%08lX" */
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data
/* , t->function */
- );
- local_irq_disable();
- if (t->next != nextt)
- {
- printk(KERN_WARNING "timer removed!\n");
- }
- t = nextt;
- }
- local_irq_restore(flags);
- }
-
- if (used - offset < len)
- {
- len = used - offset;
- }
-
- memcpy(buf, bigbuf + offset, len);
- *start = buf;
- *eof = 1;
+ ) < 0)
+ return 0;
+ local_irq_save(flags);
+ if (t->next != nextt)
+ printk(KERN_WARNING "timer removed!\n");
+ t = nextt;
+ }
+ local_irq_restore(flags);
+
+ return 0;
+}
- return len;
+static int proc_fasttimer_open(struct inode *inode, struct file *file)
+{
+ return single_open_size(file, proc_fasttimer_show, PDE_DATA(inode), BIG_BUF_SIZE);
}
+
+static const struct file_operations proc_fasttimer_fops = {
+ .open = proc_fasttimer_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* PROC_FS */
#ifdef FAST_TIMER_TEST
@@ -798,7 +654,7 @@ static volatile int num_test_timeout = 0;
static struct fast_timer tr[10];
static int exp_num[10];
-static struct timeval tv_exp[100];
+static struct fasttime_t tv_exp[100];
static void test_timeout(unsigned long data)
{
@@ -836,7 +692,7 @@ static void fast_timer_test(void)
int prev_num;
int j;
- struct timeval tv, tv0, tv1, tv2;
+ struct fasttime_t tv, tv0, tv1, tv2;
printk("fast_timer_test() start\n");
do_gettimeofday_fast(&tv);
@@ -849,7 +705,8 @@ static void fast_timer_test(void)
{
do_gettimeofday_fast(&tv_exp[j]);
}
- printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+ printk(KERN_DEBUG "fast_timer_test() %is %06i\n",
+ tv.tv_jiff, tv.tv_usec);
for (j = 0; j < 1000; j++)
{
@@ -858,12 +715,12 @@ static void fast_timer_test(void)
}
for (j = 0; j < 100; j++)
{
- printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
- tv_exp[j].tv_sec,tv_exp[j].tv_usec,
- tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
- tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
- tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
- tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
+ printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+ tv_exp[j].tv_jiff, tv_exp[j].tv_usec,
+ tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,
+ tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,
+ tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,
+ tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);
j += 4;
}
do_gettimeofday_fast(&tv0);
@@ -895,9 +752,12 @@ static void fast_timer_test(void)
}
}
do_gettimeofday_fast(&tv2);
- printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec);
- printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
- printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec);
+ printk(KERN_DEBUG "Timers started %is %06i\n",
+ tv0.tv_jiff, tv0.tv_usec);
+ printk(KERN_DEBUG "Timers started at %is %06i\n",
+ tv1.tv_jiff, tv1.tv_usec);
+ printk(KERN_DEBUG "Timers done %is %06i\n",
+ tv2.tv_jiff, tv2.tv_usec);
DP(printk("buf0:\n");
printk(buf0);
printk("buf1:\n");
@@ -919,9 +779,9 @@ static void fast_timer_test(void)
printk("%-10s set: %6is %06ius exp: %6is %06ius "
"data: 0x%08X func: 0x%08X\n",
t->name,
- t->tv_set.tv_sec,
+ t->tv_set.tv_jiff,
t->tv_set.tv_usec,
- t->tv_expires.tv_sec,
+ t->tv_expires.tv_jiff,
t->tv_expires.tv_usec,
t->data,
t->function
@@ -929,10 +789,12 @@ static void fast_timer_test(void)
printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n",
t->delay_us,
- tv_exp[j].tv_sec,
+ tv_exp[j].tv_jiff,
tv_exp[j].tv_usec,
exp_num[j],
- (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
+ (tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *
+ 1000000 + tv_exp[j].tv_usec -
+ t->tv_expires.tv_usec);
}
proc_fasttimer_read(buf5, NULL, 0, 0, 0);
printk("buf5 after all done:\n");
@@ -942,7 +804,7 @@ static void fast_timer_test(void)
#endif
-void fast_timer_init(void)
+int fast_timer_init(void)
{
/* For some reason, request_irq() hangs when called froom time_init() */
if (!fast_timer_is_init)
@@ -961,8 +823,7 @@ void fast_timer_init(void)
}
#endif
#ifdef CONFIG_PROC_FS
- if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
- fasttimer_proc_entry->read_proc = proc_fasttimer_read;
+ proc_create("fasttimer", 0, NULL, &proc_fasttimer_fops);
#endif /* PROC_FS */
if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0,
"fast timer int", NULL))
@@ -975,4 +836,6 @@ void fast_timer_init(void)
fast_timer_test();
#endif
}
+ return 0;
}
+__initcall(fast_timer_init);
diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S
index d946d8b8d27..4a146e1749c 100644
--- a/arch/cris/arch-v10/kernel/head.S
+++ b/arch/cris/arch-v10/kernel/head.S
@@ -1,192 +1,14 @@
-/* $Id: head.S,v 1.10 2005/06/20 05:12:54 starvik Exp $
- *
+/*
* Head of the kernel - alter with care
*
- * Copyright (C) 2000, 2001 Axis Communications AB
- *
- * Authors: Bjorn Wesen (bjornw@axis.com)
- *
- * $Log: head.S,v $
- * Revision 1.10 2005/06/20 05:12:54 starvik
- * Remove unnecessary diff to kernel.org tree
- *
- * Revision 1.9 2004/12/13 12:21:51 starvik
- * Added I/O and DMA allocators from Linux 2.4
- *
- * Revision 1.8 2004/11/22 11:41:14 starvik
- * Kernel command line may be supplied to kernel. Not used by Axis but may
- * be used by customers.
- *
- * Revision 1.7 2004/05/14 07:58:01 starvik
- * Merge of changes from 2.4
- *
- * Revision 1.6 2003/04/28 05:31:46 starvik
- * Added section attributes
- *
- * Revision 1.5 2002/12/11 15:42:02 starvik
- * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
- *
- * Revision 1.4 2002/11/07 09:00:44 starvik
- * Names changed for init sections
- * init_task_union -> init_thread_union
- *
- * Revision 1.3 2002/02/05 15:38:23 bjornw
- * Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it...
- *
- * Revision 1.2 2001/12/18 13:35:19 bjornw
- * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
- *
- * Revision 1.43 2001/11/08 15:09:43 starvik
- * Only start MII clock if Ethernet is configured
- *
- * Revision 1.42 2001/11/08 14:37:34 starvik
- * Start MII clock early to make sure that it is running at tranceiver reset
- *
- * Revision 1.41 2001/10/29 14:55:58 pkj
- * Corrected pa$r0 to par0.
- *
- * Revision 1.40 2001/10/03 14:59:57 pkj
- * Added support for resetting the Bluetooth hardware.
- *
- * Revision 1.39 2001/10/01 14:45:03 bjornw
- * Removed underscores and added register prefixes
- *
- * Revision 1.38 2001/09/21 07:14:11 jonashg
- * Made root filesystem (cramfs) use mtdblock driver when booting from flash.
- *
- * Revision 1.37 2001/09/11 13:44:29 orjanf
- * Decouple usage of serial ports for debug and kgdb.
- *
- * Revision 1.36 2001/06/29 12:39:31 pkj
- * Added support for mirroring the first flash to just below the
- * second one, to make them look consecutive to cramfs.
- *
- * Revision 1.35 2001/06/25 14:07:00 hp
- * Fix review comment.
- * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
- * magic numbers. Add comment that -traditional must not be used.
- * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
- * Correct and update comment.
- * * Makefile (.S.o): Don't use -traditional. Add comment why the
- * toplevel rule can't be used (now that there's a reason).
- *
- * Revision 1.34 2001/05/15 07:08:14 hp
- * Tweak "notice" to reflect that both r8 r9 are used
- *
- * Revision 1.33 2001/05/15 06:40:05 hp
- * Put bulk of code in .text.init, data in .data.init
- *
- * Revision 1.32 2001/05/15 06:18:56 hp
- * Execute review comment: s/bcc/bhs/g; s/bcs/blo/g
- *
- * Revision 1.31 2001/05/15 06:08:40 hp
- * Add sentence about autodetecting the bit31-MMU-bug
- *
- * Revision 1.30 2001/05/15 06:00:05 hp
- * Update comment: LOW_MAP is not forced on xsim anymore.
- *
- * Revision 1.29 2001/04/18 12:51:59 orjanf
- * * Reverted review change regarding the use of bcs/bcc.
- * * Removed non-working LED-clearing code.
- *
- * Revision 1.28 2001/04/17 13:58:39 orjanf
- * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
- *
- * Revision 1.27 2001/04/17 11:42:35 orjanf
- * Changed according to review:
- * * Added comment explaining memory map bug.
- * * Changed bcs and bcc to blo and bhs, respectively.
- * * Removed mentioning of Stallone and Olga boards.
- *
- * Revision 1.26 2001/04/06 12:31:07 jonashg
- * Check for cramfs in flash before RAM instead of RAM before flash.
- *
- * Revision 1.25 2001/04/04 06:23:53 starvik
- * Initialize DRAM if not already initialized
- *
- * Revision 1.24 2001/04/03 11:12:00 starvik
- * Removed dram init (done by rescue or etrax100boot
- * Corrected include
- *
- * Revision 1.23 2001/04/03 09:53:03 starvik
- * Include hw_settings.S
- *
- * Revision 1.22 2001/03/26 14:23:26 bjornw
- * Namechange of some config options
- *
- * Revision 1.21 2001/03/08 12:14:41 bjornw
- * * Config name for ETRAX IDE was renamed
- * * Removed G27 auto-setting when JULIETTE is chosen (need to make this
- * a new config option later)
- *
- * Revision 1.20 2001/02/23 12:47:56 bjornw
- * MMU regs during LOW_MAP updated to reflect a newer reality
- *
- * Revision 1.19 2001/02/19 11:12:07 bjornw
- * Changed comment header format
- *
- * Revision 1.18 2001/02/15 07:25:38 starvik
- * Added support for synchronous serial ports
- *
- * Revision 1.17 2001/02/08 15:53:13 starvik
- * Last commit removed some important ifdefs
- *
- * Revision 1.16 2001/02/08 15:20:38 starvik
- * Include dram_init.S as inline
- *
- * Revision 1.15 2001/01/29 18:12:01 bjornw
- * Corrected some comments
- *
- * Revision 1.14 2001/01/29 13:11:29 starvik
- * Include dram_init.S (with DRAM/SDRAM initialization)
- *
- * Revision 1.13 2001/01/23 14:54:57 markusl
- * Updated for USB
- * i.e. added r_gen_config settings
- *
- * Revision 1.12 2001/01/19 16:16:29 perf
- * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion.
- * Renamed serial options from ETRAX100 to ETRAX.
- *
- * Revision 1.11 2001/01/16 16:31:38 bjornw
- * * Changed name and semantics of running_from_flash to romfs_in_flash,
- * set by head.S to indicate to setup.c whether there is a cramfs image
- * after the kernels BSS or not. Should work for all three boot-cases
- * (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot),
- * and flash with cramfs in flash)
- *
- * Revision 1.10 2001/01/16 14:12:21 bjornw
- * * Check for cramfs start passed in r9 from the decompressor, if all other
- * cramfs options fail (if we boot from DRAM but don't find a cramfs image
- * after the kernel in DRAM, it is probably still in the flash)
- * * Check magic in cramfs detection when booting from flash directly
- *
- * Revision 1.9 2001/01/15 17:17:02 bjornw
- * * Corrected the code that detects the cramfs lengths
- * * Added a comment saying that the above does not work due to other
- * reasons..
- *
- * Revision 1.8 2001/01/15 16:27:51 jonashg
- * Made boot after flashing work.
- * * end destination is __vmlinux_end in RAM.
- * * _romfs_start moved because of virtual memory.
- *
- * Revision 1.7 2000/11/21 13:55:29 bjornw
- * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
- *
- * Revision 1.6 2000/10/06 12:36:55 bjornw
- * Forgot swapper_pg_dir when changing memory map..
- *
- * Revision 1.5 2000/10/04 16:49:30 bjornw
- * * Fixed memory mapping in LX
- * * Check for cramfs instead of romfs
+ * Copyright (C) 2000, 2001, 2010 Axis Communications AB
*
*/
-
+
#define ASSEMBLER_MACROS_ONLY
/* The IO_* macros use the ## token concatenation operator, so
-traditional must not be used when assembling this file. */
-#include <asm/arch/sv_addr_ag.h>
+#include <arch/sv_addr_ag.h>
#define CRAMFS_MAGIC 0x28cd3d45
#define RAM_INIT_MAGIC 0x56902387
@@ -194,15 +16,15 @@
#define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)
-
+
;; exported symbols
-
+
.globl etrax_irv
.globl romfs_start
.globl romfs_length
.globl romfs_in_flash
.globl swapper_pg_dir
-
+
.text
;; This is the entry point of the kernel. We are in supervisor mode.
@@ -211,10 +33,10 @@
;; put a nop (2 bytes) here first so we dont accidentally skip the di
;;
;; NOTICE! The registers r8 and r9 are used as parameters carrying
- ;; information from the decompressor (if the kernel was compressed).
+ ;; information from the decompressor (if the kernel was compressed).
;; They should not be used in the code below until read.
-
- nop
+
+ nop
di
;; First setup the kseg_c mapping from where the kernel is linked
@@ -234,19 +56,19 @@
#ifdef CONFIG_CRIS_LOW_MAP
; kseg mappings, temporary map of 0xc0->0x40
- move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \
+ move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \
| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb) \
| IO_FIELD (R_MMU_KBASE_HI, base_9, 9) \
| IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0
move.d $r0, [R_MMU_KBASE_HI]
- ; temporary map of 0x40->0x40 and 0x60->0x40
- move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \
+ ; temporary map of 0x40->0x40 and 0x60->0x40
+ move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \
| IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
move.d $r0, [R_MMU_KBASE_LO]
; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped
- move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \
+ move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \
| IO_STATE (R_MMU_CONFIG, inv_excp, enable) \
| IO_STATE (R_MMU_CONFIG, acc_excp, enable) \
| IO_STATE (R_MMU_CONFIG, we_excp, enable) \
@@ -269,17 +91,17 @@
move.d $r0, [R_MMU_CONFIG]
#else
; kseg mappings
- move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \
+ move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \
| IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \
| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0
move.d $r0, [R_MMU_KBASE_HI]
- ; temporary map of 0x40->0x40 and 0x00->0x00
+ ; temporary map of 0x40->0x40 and 0x00->0x00
move.d IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
move.d $r0, [R_MMU_KBASE_LO]
; mmu enable, segs f,e,c,b,4,0 segment mapped
- move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \
+ move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \
| IO_STATE (R_MMU_CONFIG, inv_excp, enable) \
| IO_STATE (R_MMU_CONFIG, acc_excp, enable) \
| IO_STATE (R_MMU_CONFIG, we_excp, enable) \
@@ -317,12 +139,12 @@
;;
;; In both cases, we start in un-cached mode, and need to jump into a
;; cached PC after we're done fiddling around with the segments.
- ;;
+ ;;
;; arch/etrax100/etrax100.ld sets some symbols that define the start
;; and end of each segment.
;; Check if we start from DRAM or FLASH by testing PC
-
+
move.d $pc,$r0
and.d 0x7fffffff,$r0 ; get rid of the non-cache bit
cmp.d 0x10000,$r0 ; arbitrary... just something above this code
@@ -339,30 +161,28 @@ _inflash0:
;; after init.
.section ".init.text", "ax"
_inflash:
-#ifdef CONFIG_ETRAX_ETHERNET
+#ifdef CONFIG_ETRAX_ETHERNET
;; Start MII clock to make sure it is running when tranceiver is reset
move.d START_ETHERNET_CLOCK, $r0
move.d $r0, [R_NETWORK_GEN_CONFIG]
#endif
;; Set up waitstates etc according to kernel configuration.
-#ifndef CONFIG_SVINTO_SIM
move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0
move.d $r0, [R_WAITSTATES]
move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0
move.d $r0, [R_BUS_CONFIG]
-#endif
;; We need to initialze DRAM registers before we start using the DRAM
cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized?
beq _dram_init_finished
nop
-
+
#include "../lib/dram_init.S"
-_dram_init_finished:
+_dram_init_finished:
;; Copy text+data to DRAM
;; This is fragile - the calculation of r4 as the image size depends
;; on that the labels below actually are the first and last positions
@@ -374,7 +194,7 @@ _dram_init_finished:
;; between the physical start of the flash and the flash-image start,
;; and when run with compression, the kernel is actually unpacked to
;; DRAM and we never get here in the first place :))
-
+
moveq 0, $r0 ; source
move.d text_start, $r1 ; destination
move.d __vmlinux_end, $r2 ; end destination
@@ -405,10 +225,10 @@ _dram_init_finished:
add.d 0xf0000000, $r4 ; add flash start in virtual memory (cached)
#endif
move.d $r4, [romfs_start]
-1:
+1:
moveq 1, $r0
move.d $r0, [romfs_in_flash]
-
+
jump _start_it ; enter code, cached this time
_inram:
@@ -417,7 +237,7 @@ _inram:
moveq 0, $r0
move.d $r0, [romfs_length] ; default if there is no cramfs
-
+
;; The kernel could have been unpacked to DRAM by the loader, but
;; the cramfs image could still be in the Flash directly after the
;; compressed kernel image. The loader passes the address of the
@@ -427,7 +247,7 @@ _inram:
;; (Notice that if this is not booted from the loader, r9 will be
;; garbage but we do sanity checks on it, the chance that it points
;; to a cramfs magic is small.. )
-
+
cmp.d 0x0ffffff8, $r9
bhs _no_romfs_in_flash ; r9 points outside the flash area
nop
@@ -450,20 +270,20 @@ _inram:
jump _start_it ; enter code, cached this time
_no_romfs_in_flash:
-
+
;; Check if there is a cramfs (magic value).
;; Notice that we check for cramfs magic value - which is
;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does
;; not need this mechanism anyway)
- move.d __vmlinux_end, $r0; the image will be after the vmlinux end address
+ move.d __init_end, $r0; the image will be after the end of init
move.d [$r0], $r1 ; cramfs assumes same endian on host/target
cmp.d CRAMFS_MAGIC, $r1; magic value in cramfs superblock
bne 2f
nop
- ;; Ok. What is its size ?
-
+ ;; Ok. What is its size ?
+
move.d [$r0 + 4], $r2 ; cramfs_super.size (again, no need to swapwb)
;; We want to copy it to the end of the BSS
@@ -479,7 +299,7 @@ _no_romfs_in_flash:
add.d $r2, $r0
add.d $r2, $r1
-
+
;; Go ahead. Make my loop.
lsrq 1, $r2 ; size is in bytes, we copy words
@@ -490,14 +310,14 @@ _no_romfs_in_flash:
bne 1b
nop
-2:
+2:
;; Dont worry that the BSS is tainted. It will be cleared later.
moveq 0, $r0
move.d $r0, [romfs_in_flash]
jump _start_it ; better skip the additional cramfs check below
-
+
_start_it:
;; Check if kernel command line is supplied
@@ -524,7 +344,7 @@ no_command_line:
move.d ibr_start,$r0 ; this symbol is set by the linker script
move $r0,$ibr
move.d $r0,[etrax_irv] ; set the interrupt base register and pointer
-
+
;; Clear BSS region, from _bss_start to _end
move.d __bss_start, $r0
@@ -533,7 +353,7 @@ no_command_line:
cmp.d $r1, $r0
blo 1b
nop
-
+
#ifdef CONFIG_BLK_DEV_ETRAXIDE
;; disable ATA before enabling it in genconfig below
moveq 0,$r0
@@ -556,7 +376,7 @@ no_command_line:
#ifdef CONFIG_JULIETTE
;; configure external DMA channel 0 before enabling it in genconfig
-
+
moveq 0,$r0
move.d $r0,[R_EXT_DMA_0_ADDR]
; cnt enable, word size, output, stop, size 0
@@ -571,7 +391,7 @@ no_command_line:
move.d $r0,[R_EXT_DMA_0_CMD]
;; reset dma4 and wait for completion
-
+
moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0
move.b $r0,[R_DMA_CH4_CMD]
1: move.b [R_DMA_CH4_CMD],$r0
@@ -581,7 +401,7 @@ no_command_line:
nop
;; reset dma5 and wait for completion
-
+
moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
move.b $r0,[R_DMA_CH5_CMD]
1: move.b [R_DMA_CH5_CMD],$r0
@@ -589,17 +409,23 @@ no_command_line:
cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
beq 1b
nop
-#endif
-
+#endif
+
;; Etrax product HW genconfig setup
moveq 0,$r0
+ ;; Select or disable serial port 2
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+ or.d IO_STATE (R_GEN_CONFIG, ser2, select),$r0
+#else
+ or.d IO_STATE (R_GEN_CONFIG, ser2, disable),$r0
+#endif
+
;; Init interfaces (disable them).
or.d IO_STATE (R_GEN_CONFIG, scsi0, disable) \
| IO_STATE (R_GEN_CONFIG, ata, disable) \
| IO_STATE (R_GEN_CONFIG, par0, disable) \
- | IO_STATE (R_GEN_CONFIG, ser2, disable) \
| IO_STATE (R_GEN_CONFIG, mio, disable) \
| IO_STATE (R_GEN_CONFIG, scsi1, disable) \
| IO_STATE (R_GEN_CONFIG, scsi0w, disable) \
@@ -638,7 +464,6 @@ no_command_line:
move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
-#ifndef CONFIG_SVINTO_SIM
move.d $r0,[R_GEN_CONFIG]
#if 0
@@ -656,7 +481,7 @@ no_command_line:
beq 1b
nop
#endif
-
+
moveq IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0
move.b $r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out)
move.b $r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in)
@@ -673,7 +498,7 @@ no_command_line:
;; setup port PA and PB default initial directions and data
;; including their shadow registers
-
+
move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0
#if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7)
or.b IO_STATE (R_PORT_PA_DIR, dir7, output),$r0
@@ -690,7 +515,7 @@ no_command_line:
#endif
move.b $r0,[port_pa_data_shadow]
move.b $r0,[R_PORT_PA_DATA]
-
+
move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0
move.b $r0,[port_pb_config_shadow]
move.b $r0,[R_PORT_PB_CONFIG]
@@ -732,13 +557,13 @@ no_command_line:
#endif
move.d $r0,[port_g_data_shadow]
move.d $r0,[R_PORT_G_DATA]
-
+
;; setup the serial port 0 at 115200 baud for debug purposes
-
+
moveq IO_STATE (R_SERIAL0_XOFF, tx_stop, enable) \
| IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable) \
| IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0
- move.d $r0,[R_SERIAL0_XOFF]
+ move.d $r0,[R_SERIAL0_XOFF]
; 115.2kbaud for both transmit and receive
move.b IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz) \
@@ -754,8 +579,8 @@ no_command_line:
| IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even) \
| IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable) \
| IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0
- move.b $r0,[R_SERIAL0_REC_CTRL]
-
+ move.b $r0,[R_SERIAL0_REC_CTRL]
+
; Set up and enable the serial0 transmitter.
move.b IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0) \
| IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable) \
@@ -768,11 +593,11 @@ no_command_line:
move.b $r0,[R_SERIAL0_TR_CTRL]
;; setup the serial port 1 at 115200 baud for debug purposes
-
+
moveq IO_STATE (R_SERIAL1_XOFF, tx_stop, enable) \
| IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable) \
| IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0
- move.d $r0,[R_SERIAL1_XOFF]
+ move.d $r0,[R_SERIAL1_XOFF]
; 115.2kbaud for both transmit and receive
move.b IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz) \
@@ -788,8 +613,8 @@ no_command_line:
| IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even) \
| IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable) \
| IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0
- move.b $r0,[R_SERIAL1_REC_CTRL]
-
+ move.b $r0,[R_SERIAL1_REC_CTRL]
+
; Set up and enable the serial1 transmitter.
move.b IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0) \
| IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable) \
@@ -801,14 +626,49 @@ no_command_line:
| IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),$r0
move.b $r0,[R_SERIAL1_TR_CTRL]
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+ ;; setup the serial port 2 at 115200 baud for debug purposes
+
+ moveq IO_STATE (R_SERIAL2_XOFF, tx_stop, enable) \
+ | IO_STATE (R_SERIAL2_XOFF, auto_xoff, disable) \
+ | IO_FIELD (R_SERIAL2_XOFF, xoff_char, 0),$r0
+ move.d $r0,[R_SERIAL2_XOFF]
+
+ ; 115.2kbaud for both transmit and receive
+ move.b IO_STATE (R_SERIAL2_BAUD, tr_baud, c115k2Hz) \
+ | IO_STATE (R_SERIAL2_BAUD, rec_baud, c115k2Hz),$r0
+ move.b $r0,[R_SERIAL2_BAUD]
+
+ ; Set up and enable the serial2 receiver.
+ move.b IO_STATE (R_SERIAL2_REC_CTRL, dma_err, stop) \
+ | IO_STATE (R_SERIAL2_REC_CTRL, rec_enable, enable) \
+ | IO_STATE (R_SERIAL2_REC_CTRL, rts_, active) \
+ | IO_STATE (R_SERIAL2_REC_CTRL, sampling, middle) \
+ | IO_STATE (R_SERIAL2_REC_CTRL, rec_stick_par, normal) \
+ | IO_STATE (R_SERIAL2_REC_CTRL, rec_par, even) \
+ | IO_STATE (R_SERIAL2_REC_CTRL, rec_par_en, disable) \
+ | IO_STATE (R_SERIAL2_REC_CTRL, rec_bitnr, rec_8bit),$r0
+ move.b $r0,[R_SERIAL2_REC_CTRL]
+
+ ; Set up and enable the serial2 transmitter.
+ move.b IO_FIELD (R_SERIAL2_TR_CTRL, txd, 0) \
+ | IO_STATE (R_SERIAL2_TR_CTRL, tr_enable, enable) \
+ | IO_STATE (R_SERIAL2_TR_CTRL, auto_cts, disabled) \
+ | IO_STATE (R_SERIAL2_TR_CTRL, stop_bits, one_bit) \
+ | IO_STATE (R_SERIAL2_TR_CTRL, tr_stick_par, normal) \
+ | IO_STATE (R_SERIAL2_TR_CTRL, tr_par, even) \
+ | IO_STATE (R_SERIAL2_TR_CTRL, tr_par_en, disable) \
+ | IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0
+ move.b $r0,[R_SERIAL2_TR_CTRL]
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
;; setup the serial port 3 at 115200 baud for debug purposes
-
+
moveq IO_STATE (R_SERIAL3_XOFF, tx_stop, enable) \
| IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable) \
| IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0
- move.d $r0,[R_SERIAL3_XOFF]
+ move.d $r0,[R_SERIAL3_XOFF]
; 115.2kbaud for both transmit and receive
move.b IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz) \
@@ -824,8 +684,8 @@ no_command_line:
| IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even) \
| IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable) \
| IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0
- move.b $r0,[R_SERIAL3_REC_CTRL]
-
+ move.b $r0,[R_SERIAL3_REC_CTRL]
+
; Set up and enable the serial3 transmitter.
move.b IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0) \
| IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable) \
@@ -837,13 +697,11 @@ no_command_line:
| IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0
move.b $r0,[R_SERIAL3_TR_CTRL]
#endif
-
-#endif /* CONFIG_SVINTO_SIM */
jump start_kernel ; jump into the C-function start_kernel in init/main.c
-
+
.data
-etrax_irv:
+etrax_irv:
.dword 0
romfs_start:
.dword 0
@@ -851,13 +709,13 @@ romfs_length:
.dword 0
romfs_in_flash:
.dword 0
-
+
;; put some special pages at the beginning of the kernel aligned
;; to page boundaries - the kernel cannot start until after this
#ifdef CONFIG_CRIS_LOW_MAP
swapper_pg_dir = 0x60002000
-#else
+#else
swapper_pg_dir = 0xc0002000
#endif
diff --git a/arch/cris/arch-v10/kernel/io_interface_mux.c b/arch/cris/arch-v10/kernel/io_interface_mux.c
index 29d48ad00df..ad64cd1c861 100644
--- a/arch/cris/arch-v10/kernel/io_interface_mux.c
+++ b/arch/cris/arch-v10/kernel/io_interface_mux.c
@@ -1,10 +1,9 @@
/* IO interface mux allocator for ETRAX100LX.
- * Copyright 2004, Axis Communications AB
- * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $
+ * Copyright 2004-2007, Axis Communications AB
*/
-/* C.f. ETRAX100LX Designer's Reference 20.9 */
+/* C.f. ETRAX100LX Designer's Reference chapter 19.9 */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -12,9 +11,10 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <asm/arch/svinto.h>
+#include <arch/svinto.h>
#include <asm/io.h>
-#include <asm/arch/io_interface_mux.h>
+#include <arch/io_interface_mux.h>
+#include <arch/system.h>
#define DBG(s)
@@ -45,17 +45,39 @@ struct watcher
struct if_group
{
enum io_if_group group;
- unsigned char used;
- enum cris_io_interface owner;
+ /* name - the name of the group 'A' to 'F' */
+ char *name;
+ /* used - a bit mask of all pins in the group in the order listed
+ * in the tables in 19.9.1 to 19.9.6. Note that no
+ * distinction is made between in, out and in/out pins. */
+ unsigned int used;
};
struct interface
{
enum cris_io_interface ioif;
+ /* name - the name of the interface */
+ char *name;
+ /* groups - OR'ed together io_if_group flags describing what pin groups
+ * the interface uses pins in. */
unsigned char groups;
+ /* used - set when the interface is allocated. */
unsigned char used;
char *owner;
+ /* group_a through group_f - bit masks describing what pins in the
+ * pin groups the interface uses. */
+ unsigned int group_a;
+ unsigned int group_b;
+ unsigned int group_c;
+ unsigned int group_d;
+ unsigned int group_e;
+ unsigned int group_f;
+
+ /* gpio_g_in, gpio_g_out, gpio_b - bit masks telling what pins in the
+ * GPIO ports the interface uses. This could be reconstucted using
+ * the group_X masks and a table of what pins the GPIO ports use,
+ * but that would be messy. */
unsigned int gpio_g_in;
unsigned int gpio_g_out;
unsigned char gpio_b;
@@ -64,26 +86,32 @@ struct interface
static struct if_group if_groups[6] = {
{
.group = group_a,
+ .name = "A",
.used = 0,
},
{
.group = group_b,
+ .name = "B",
.used = 0,
},
{
.group = group_c,
+ .name = "C",
.used = 0,
},
{
.group = group_d,
+ .name = "D",
.used = 0,
},
{
.group = group_e,
+ .name = "E",
.used = 0,
},
{
.group = group_f,
+ .name = "F",
.used = 0,
}
};
@@ -94,14 +122,32 @@ static struct interface interfaces[] = {
/* Begin Non-multiplexed interfaces */
{
.ioif = if_eth,
+ .name = "ethernet",
.groups = 0,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0,
.gpio_g_out = 0,
.gpio_b = 0
},
{
.ioif = if_serial_0,
+ .name = "serial_0",
.groups = 0,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0,
.gpio_g_out = 0,
.gpio_b = 0
@@ -109,172 +155,385 @@ static struct interface interfaces[] = {
/* End Non-multiplexed interfaces */
{
.ioif = if_serial_1,
+ .name = "serial_1",
.groups = group_e,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0x0f,
+ .group_f = 0,
+
.gpio_g_in = 0x00000000,
.gpio_g_out = 0x00000000,
.gpio_b = 0x00
},
{
.ioif = if_serial_2,
+ .name = "serial_2",
.groups = group_b,
+
+ .group_a = 0,
+ .group_b = 0x0f,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x000000c0,
.gpio_g_out = 0x000000c0,
.gpio_b = 0x00
},
{
.ioif = if_serial_3,
+ .name = "serial_3",
.groups = group_c,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0x0f,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0xc0000000,
.gpio_g_out = 0xc0000000,
.gpio_b = 0x00
},
{
.ioif = if_sync_serial_1,
- .groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3
- can be used simultaneously */
+ .name = "sync_serial_1",
+ .groups = group_e | group_f,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0x0f,
+ .group_f = 0x10,
+
.gpio_g_in = 0x00000000,
.gpio_g_out = 0x00000000,
.gpio_b = 0x10
},
{
.ioif = if_sync_serial_3,
+ .name = "sync_serial_3",
.groups = group_c | group_f,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0x0f,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0x80,
+
.gpio_g_in = 0xc0000000,
.gpio_g_out = 0xc0000000,
.gpio_b = 0x80
},
{
.ioif = if_shared_ram,
+ .name = "shared_ram",
.groups = group_a,
+
+ .group_a = 0x7f8ff,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x0000ff3e,
.gpio_g_out = 0x0000ff38,
.gpio_b = 0x00
},
{
.ioif = if_shared_ram_w,
+ .name = "shared_ram_w",
.groups = group_a | group_d,
+
+ .group_a = 0x7f8ff,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0xff,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x00ffff3e,
.gpio_g_out = 0x00ffff38,
.gpio_b = 0x00
},
{
.ioif = if_par_0,
+ .name = "par_0",
.groups = group_a,
+
+ .group_a = 0x7fbff,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x0000ff3e,
.gpio_g_out = 0x0000ff3e,
.gpio_b = 0x00
},
{
.ioif = if_par_1,
+ .name = "par_1",
.groups = group_d,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0x7feff,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x3eff0000,
.gpio_g_out = 0x3eff0000,
.gpio_b = 0x00
},
{
.ioif = if_par_w,
+ .name = "par_w",
.groups = group_a | group_d,
+
+ .group_a = 0x7fbff,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0xff,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x00ffff3e,
.gpio_g_out = 0x00ffff3e,
.gpio_b = 0x00
},
{
.ioif = if_scsi8_0,
- .groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1
- can be used simultaneously */
+ .name = "scsi8_0",
+ .groups = group_a | group_b | group_f,
+
+ .group_a = 0x7ffff,
+ .group_b = 0x0f,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0x10,
+
.gpio_g_in = 0x0000ffff,
.gpio_g_out = 0x0000ffff,
.gpio_b = 0x10
},
{
.ioif = if_scsi8_1,
- .groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1
- can be used simultaneously */
+ .name = "scsi8_1",
+ .groups = group_c | group_d | group_f,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0x0f,
+ .group_d = 0x7ffff,
+ .group_e = 0,
+ .group_f = 0x80,
+
.gpio_g_in = 0xffff0000,
.gpio_g_out = 0xffff0000,
.gpio_b = 0x80
},
{
.ioif = if_scsi_w,
+ .name = "scsi_w",
.groups = group_a | group_b | group_d | group_f,
+
+ .group_a = 0x7ffff,
+ .group_b = 0x0f,
+ .group_c = 0,
+ .group_d = 0x601ff,
+ .group_e = 0,
+ .group_f = 0x90,
+
.gpio_g_in = 0x01ffffff,
.gpio_g_out = 0x07ffffff,
.gpio_b = 0x80
},
{
.ioif = if_ata,
+ .name = "ata",
.groups = group_a | group_b | group_c | group_d,
+
+ .group_a = 0x7ffff,
+ .group_b = 0x0f,
+ .group_c = 0x0f,
+ .group_d = 0x7cfff,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0xf9ffffff,
.gpio_g_out = 0xffffffff,
.gpio_b = 0x80
},
{
.ioif = if_csp,
- .groups = group_f, /* if_csp and if_i2c can be used simultaneously */
+ .name = "csp",
+ .groups = group_f,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0xfc,
+
.gpio_g_in = 0x00000000,
.gpio_g_out = 0x00000000,
.gpio_b = 0xfc
},
{
.ioif = if_i2c,
- .groups = group_f, /* if_csp and if_i2c can be used simultaneously */
+ .name = "i2c",
+ .groups = group_f,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0x03,
+
.gpio_g_in = 0x00000000,
.gpio_g_out = 0x00000000,
.gpio_b = 0x03
},
{
.ioif = if_usb_1,
+ .name = "usb_1",
.groups = group_e | group_f,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0x0f,
+ .group_f = 0x2c,
+
.gpio_g_in = 0x00000000,
.gpio_g_out = 0x00000000,
.gpio_b = 0x2c
},
{
.ioif = if_usb_2,
+ .name = "usb_2",
.groups = group_d,
- .gpio_g_in = 0x0e000000,
- .gpio_g_out = 0x3c000000,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0x33e00,
+ .group_f = 0,
+
+ .gpio_g_in = 0x3e000000,
+ .gpio_g_out = 0x0c000000,
.gpio_b = 0x00
},
/* GPIO pins */
{
.ioif = if_gpio_grp_a,
+ .name = "gpio_a",
.groups = group_a,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x0000ff3f,
.gpio_g_out = 0x0000ff3f,
.gpio_b = 0x00
},
{
.ioif = if_gpio_grp_b,
+ .name = "gpio_b",
.groups = group_b,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x000000c0,
.gpio_g_out = 0x000000c0,
.gpio_b = 0x00
},
{
.ioif = if_gpio_grp_c,
+ .name = "gpio_c",
.groups = group_c,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0xc0000000,
.gpio_g_out = 0xc0000000,
.gpio_b = 0x00
},
{
.ioif = if_gpio_grp_d,
+ .name = "gpio_d",
.groups = group_d,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x3fff0000,
.gpio_g_out = 0x3fff0000,
.gpio_b = 0x00
},
{
.ioif = if_gpio_grp_e,
+ .name = "gpio_e",
.groups = group_e,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x00000000,
.gpio_g_out = 0x00000000,
.gpio_b = 0x00
},
{
.ioif = if_gpio_grp_f,
+ .name = "gpio_f",
.groups = group_f,
+
+ .group_a = 0,
+ .group_b = 0,
+ .group_c = 0,
+ .group_d = 0,
+ .group_e = 0,
+ .group_f = 0,
+
.gpio_g_in = 0x00000000,
.gpio_g_out = 0x00000000,
.gpio_b = 0xff
@@ -284,11 +543,13 @@ static struct interface interfaces[] = {
static struct watcher *watchers = NULL;
+/* The pins that are free to use in the GPIO ports. */
static unsigned int gpio_in_pins = 0xffffffff;
static unsigned int gpio_out_pins = 0xffffffff;
static unsigned char gpio_pb_pins = 0xff;
static unsigned char gpio_pa_pins = 0xff;
+/* Identifiers for the owners of the GPIO pins. */
static enum cris_io_interface gpio_pa_owners[8];
static enum cris_io_interface gpio_pb_owners[8];
static enum cris_io_interface gpio_pg_owners[32];
@@ -304,7 +565,7 @@ static unsigned char clear_group_from_set(const unsigned char groups, struct if_
static struct if_group *get_group(const unsigned char groups)
{
int i;
- for (i = 0; i < sizeof(if_groups)/sizeof(struct if_group); i++) {
+ for (i = 0; i < ARRAY_SIZE(if_groups); i++) {
if (groups & if_groups[i].group) {
return &if_groups[i];
}
@@ -338,13 +599,15 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
struct if_group *grp;
unsigned char group_set;
unsigned long flags;
+ int res = 0;
(void)cris_io_interface_init();
DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id));
if ((ioif >= if_max_interfaces) || (ioif < 0)) {
- printk(KERN_CRIT "cris_request_io_interface: Bad interface %u submitted for %s\n",
+ printk(KERN_CRIT "cris_request_io_interface: Bad interface "
+ "%u submitted for %s\n",
ioif,
device_id);
return -EINVAL;
@@ -353,58 +616,69 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
local_irq_save(flags);
if (interfaces[ioif].used) {
- local_irq_restore(flags);
- printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n",
+ printk(KERN_CRIT "cris_io_interface: Cannot allocate interface "
+ "%s for %s, in use by %s\n",
+ interfaces[ioif].name,
device_id,
interfaces[ioif].owner);
- return -EBUSY;
+ res = -EBUSY;
+ goto exit;
}
- /* Check that all required groups are free before allocating, */
+ /* Check that all required pins in the used groups are free
+ * before allocating. */
group_set = interfaces[ioif].groups;
while (NULL != (grp = get_group(group_set))) {
- if (grp->used) {
- if (grp->group == group_f) {
- if ((if_sync_serial_1 == ioif) ||
- (if_sync_serial_3 == ioif)) {
- if ((grp->owner != if_sync_serial_1) &&
- (grp->owner != if_sync_serial_3)) {
- local_irq_restore(flags);
- return -EBUSY;
- }
- } else if ((if_scsi8_0 == ioif) ||
- (if_scsi8_1 == ioif)) {
- if ((grp->owner != if_scsi8_0) &&
- (grp->owner != if_scsi8_1)) {
- local_irq_restore(flags);
- return -EBUSY;
- }
- }
- } else {
- local_irq_restore(flags);
- return -EBUSY;
- }
+ unsigned int if_group_use = 0;
+
+ switch (grp->group) {
+ case group_a:
+ if_group_use = interfaces[ioif].group_a;
+ break;
+ case group_b:
+ if_group_use = interfaces[ioif].group_b;
+ break;
+ case group_c:
+ if_group_use = interfaces[ioif].group_c;
+ break;
+ case group_d:
+ if_group_use = interfaces[ioif].group_d;
+ break;
+ case group_e:
+ if_group_use = interfaces[ioif].group_e;
+ break;
+ case group_f:
+ if_group_use = interfaces[ioif].group_f;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ if (if_group_use & grp->used) {
+ printk(KERN_INFO "cris_request_io_interface: group "
+ "%s needed by %s not available\n",
+ grp->name, interfaces[ioif].name);
+ res = -EBUSY;
+ goto exit;
}
+
group_set = clear_group_from_set(group_set, grp);
}
/* Are the required GPIO pins available too? */
- if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) ||
- ((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) ||
- ((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) {
- printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n",
- ioif);
- return -EBUSY;
- }
-
- /* All needed I/O pins and pin groups are free, allocate. */
- group_set = interfaces[ioif].groups;
- while (NULL != (grp = get_group(group_set))) {
- grp->used = 1;
- grp->owner = ioif;
- group_set = clear_group_from_set(group_set, grp);
+ if (((interfaces[ioif].gpio_g_in & gpio_in_pins) !=
+ interfaces[ioif].gpio_g_in) ||
+ ((interfaces[ioif].gpio_g_out & gpio_out_pins) !=
+ interfaces[ioif].gpio_g_out) ||
+ ((interfaces[ioif].gpio_b & gpio_pb_pins) !=
+ interfaces[ioif].gpio_b)) {
+ printk(KERN_CRIT "cris_request_io_interface: Could not get "
+ "required pins for interface %u\n", ioif);
+ res = -EBUSY;
+ goto exit;
}
+ /* Check which registers need to be reconfigured. */
gens = genconfig_shadow;
gens_ii = gen_config_ii_shadow;
@@ -494,9 +768,43 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
set_gen_config = 0;
break;
default:
- panic("cris_request_io_interface: Bad interface %u submitted for %s\n",
- ioif,
- device_id);
+ printk(KERN_INFO "cris_request_io_interface: Bad interface "
+ "%u submitted for %s\n",
+ ioif, device_id);
+ res = -EBUSY;
+ goto exit;
+ }
+
+ /* All needed I/O pins and pin groups are free, allocate. */
+ group_set = interfaces[ioif].groups;
+ while (NULL != (grp = get_group(group_set))) {
+ unsigned int if_group_use = 0;
+
+ switch (grp->group) {
+ case group_a:
+ if_group_use = interfaces[ioif].group_a;
+ break;
+ case group_b:
+ if_group_use = interfaces[ioif].group_b;
+ break;
+ case group_c:
+ if_group_use = interfaces[ioif].group_c;
+ break;
+ case group_d:
+ if_group_use = interfaces[ioif].group_d;
+ break;
+ case group_e:
+ if_group_use = interfaces[ioif].group_e;
+ break;
+ case group_f:
+ if_group_use = interfaces[ioif].group_f;
+ break;
+ default:
+ BUG_ON(1);
+ }
+ grp->used |= if_group_use;
+
+ group_set = clear_group_from_set(group_set, grp);
}
interfaces[ioif].used = 1;
@@ -515,25 +823,28 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
*R_GEN_CONFIG_II = gen_config_ii_shadow;
}
- DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- gpio_in_pins, gpio_out_pins, gpio_pb_pins));
- DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- interfaces[ioif].gpio_g_in,
- interfaces[ioif].gpio_g_out,
- interfaces[ioif].gpio_b));
+ DBG(printk(KERN_DEBUG "GPIO pins: available before: "
+ "g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+ gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+ DBG(printk(KERN_DEBUG
+ "grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+ interfaces[ioif].gpio_g_in,
+ interfaces[ioif].gpio_g_out,
+ interfaces[ioif].gpio_b));
gpio_in_pins &= ~interfaces[ioif].gpio_g_in;
gpio_out_pins &= ~interfaces[ioif].gpio_g_out;
gpio_pb_pins &= ~interfaces[ioif].gpio_b;
- DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+ DBG(printk(KERN_DEBUG "GPIO pins: available after: "
+ "g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+ gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+exit:
local_irq_restore(flags);
-
- notify_watchers();
-
- return 0;
+ if (res == 0)
+ notify_watchers();
+ return res;
}
@@ -559,43 +870,35 @@ void cris_free_io_interface(enum cris_io_interface ioif)
}
group_set = interfaces[ioif].groups;
while (NULL != (grp = get_group(group_set))) {
- if (grp->group == group_f) {
- switch (ioif)
- {
- case if_sync_serial_1:
- if ((grp->owner == if_sync_serial_1) &&
- interfaces[if_sync_serial_3].used) {
- grp->owner = if_sync_serial_3;
- } else
- grp->used = 0;
- break;
- case if_sync_serial_3:
- if ((grp->owner == if_sync_serial_3) &&
- interfaces[if_sync_serial_1].used) {
- grp->owner = if_sync_serial_1;
- } else
- grp->used = 0;
- break;
- case if_scsi8_0:
- if ((grp->owner == if_scsi8_0) &&
- interfaces[if_scsi8_1].used) {
- grp->owner = if_scsi8_1;
- } else
- grp->used = 0;
- break;
- case if_scsi8_1:
- if ((grp->owner == if_scsi8_1) &&
- interfaces[if_scsi8_0].used) {
- grp->owner = if_scsi8_0;
- } else
- grp->used = 0;
- break;
- default:
- grp->used = 0;
- }
- } else {
- grp->used = 0;
+ unsigned int if_group_use = 0;
+
+ switch (grp->group) {
+ case group_a:
+ if_group_use = interfaces[ioif].group_a;
+ break;
+ case group_b:
+ if_group_use = interfaces[ioif].group_b;
+ break;
+ case group_c:
+ if_group_use = interfaces[ioif].group_c;
+ break;
+ case group_d:
+ if_group_use = interfaces[ioif].group_d;
+ break;
+ case group_e:
+ if_group_use = interfaces[ioif].group_e;
+ break;
+ case group_f:
+ if_group_use = interfaces[ioif].group_f;
+ break;
+ default:
+ BUG_ON(1);
}
+
+ if ((grp->used & if_group_use) != if_group_use)
+ BUG_ON(1);
+ grp->used = grp->used & ~if_group_use;
+
group_set = clear_group_from_set(group_set, grp);
}
interfaces[ioif].used = 0;
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index 96094cbf125..09cae80a834 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -1,23 +1,27 @@
-/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $
- *
+/*
* linux/arch/cris/kernel/irq.c
*
* Copyright (c) 2000-2002 Axis Communications AB
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*
- * This file contains the interrupt vectors and some
+ * This file contains the interrupt vectors and some
* helper functions
*
*/
#include <asm/irq.h>
+#include <asm/current.h>
#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
-#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
+#define crisv10_mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
+#define crisv10_unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
+
+extern void kgdb_init(void);
+extern void breakpoint(void);
/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
* global just so that the kernel gdb can use it.
@@ -75,8 +79,8 @@ BUILD_IRQ(12, 0x1000)
BUILD_IRQ(13, 0x2000)
void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */
void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */
-BUILD_IRQ(16, 0x10000)
-BUILD_IRQ(17, 0x20000)
+BUILD_IRQ(16, 0x10000 | 0x20000) /* ethernet tx interrupt needs to block rx */
+BUILD_IRQ(17, 0x20000 | 0x10000) /* ...and vice versa */
BUILD_IRQ(18, 0x40000)
BUILD_IRQ(19, 0x80000)
BUILD_IRQ(20, 0x100000)
@@ -103,43 +107,21 @@ static void (*interrupt[NR_IRQS])(void) = {
IRQ31_interrupt
};
-static void enable_crisv10_irq(unsigned int irq);
-
-static unsigned int startup_crisv10_irq(unsigned int irq)
-{
- enable_crisv10_irq(irq);
- return 0;
-}
-
-#define shutdown_crisv10_irq disable_crisv10_irq
-
-static void enable_crisv10_irq(unsigned int irq)
-{
- unmask_irq(irq);
-}
-
-static void disable_crisv10_irq(unsigned int irq)
-{
- mask_irq(irq);
-}
-
-static void ack_crisv10_irq(unsigned int irq)
+static void enable_crisv10_irq(struct irq_data *data)
{
+ crisv10_unmask_irq(data->irq);
}
-static void end_crisv10_irq(unsigned int irq)
+static void disable_crisv10_irq(struct irq_data *data)
{
+ crisv10_mask_irq(data->irq);
}
-static struct hw_interrupt_type crisv10_irq_type = {
- .typename = "CRISv10",
- .startup = startup_crisv10_irq,
- .shutdown = shutdown_crisv10_irq,
- .enable = enable_crisv10_irq,
- .disable = disable_crisv10_irq,
- .ack = ack_crisv10_irq,
- .end = end_crisv10_irq,
- .set_affinity = NULL
+static struct irq_chip crisv10_irq_type = {
+ .name = "CRISv10",
+ .irq_shutdown = disable_crisv10_irq,
+ .irq_enable = enable_crisv10_irq,
+ .irq_disable = disable_crisv10_irq,
};
void weird_irq(void);
@@ -147,31 +129,76 @@ void system_call(void); /* from entry.S */
void do_sigtrap(void); /* from entry.S */
void gdb_handle_breakpoint(void); /* from entry.S */
+extern void do_IRQ(int irq, struct pt_regs * regs);
+
+/* Handle multiple IRQs */
+void do_multiple_IRQ(struct pt_regs* regs)
+{
+ int bit;
+ unsigned masked;
+ unsigned mask;
+ unsigned ethmask = 0;
+
+ /* Get interrupts to mask and handle */
+ mask = masked = *R_VECT_MASK_RD;
+
+ /* Never mask timer IRQ */
+ mask &= ~(IO_MASK(R_VECT_MASK_RD, timer0));
+
+ /*
+ * If either ethernet interrupt (rx or tx) is active then block
+ * the other one too. Unblock afterwards also.
+ */
+ if (mask &
+ (IO_STATE(R_VECT_MASK_RD, dma0, active) |
+ IO_STATE(R_VECT_MASK_RD, dma1, active))) {
+ ethmask = (IO_MASK(R_VECT_MASK_RD, dma0) |
+ IO_MASK(R_VECT_MASK_RD, dma1));
+ }
+
+ /* Block them */
+ *R_VECT_MASK_CLR = (mask | ethmask);
+
+ /* An extra irq_enter here to prevent softIRQs to run after
+ * each do_IRQ. This will decrease the interrupt latency.
+ */
+ irq_enter();
+
+ /* Handle all IRQs */
+ for (bit = 2; bit < 32; bit++) {
+ if (masked & (1 << bit)) {
+ do_IRQ(bit, regs);
+ }
+ }
+
+ /* This irq_exit() will trigger the soft IRQs. */
+ irq_exit();
+
+ /* Unblock the IRQs again */
+ *R_VECT_MASK_SET = (masked | ethmask);
+}
+
/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and
setting the irq vector table.
*/
-void __init
-init_IRQ(void)
+void __init init_IRQ(void)
{
int i;
/* clear all interrupt masks */
-
-#ifndef CONFIG_SVINTO_SIM
*R_IRQ_MASK0_CLR = 0xffffffff;
*R_IRQ_MASK1_CLR = 0xffffffff;
*R_IRQ_MASK2_CLR = 0xffffffff;
-#endif
-
*R_VECT_MASK_CLR = 0xffffffff;
for (i = 0; i < 256; i++)
etrax_irv->v[i] = weird_irq;
- /* Initialize IRQ handler descriptiors. */
+ /* Initialize IRQ handler descriptors. */
for(i = 2; i < NR_IRQS; i++) {
- irq_desc[i].chip = &crisv10_irq_type;
+ irq_set_chip_and_handler(i, &crisv10_irq_type,
+ handle_simple_irq);
set_int_vector(i, interrupt[i]);
}
@@ -179,25 +206,20 @@ init_IRQ(void)
executed by the associated break handler, rather than just a jump
address. therefore we need to setup a default breakpoint handler
for all breakpoints */
-
for (i = 0; i < 16; i++)
set_break_vector(i, do_sigtrap);
-
- /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
+ /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
set_int_vector(15, multiple_interrupt);
-
- /* 0 and 1 which are special breakpoint/NMI traps */
+ /* 0 and 1 which are special breakpoint/NMI traps */
set_int_vector(0, hwbreakpoint);
set_int_vector(1, IRQ1_interrupt);
/* and irq 14 which is the mmu bus fault handler */
-
set_int_vector(14, mmu_bus_fault);
/* setup the system-call trap, which is reached by BREAK 13 */
-
set_break_vector(13, system_call);
/* setup a breakpoint handler for debugging used for both user and
diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c
index 07628a13c6c..22d846bfc57 100644
--- a/arch/cris/arch-v10/kernel/kgdb.c
+++ b/arch/cris/arch-v10/kernel/kgdb.c
@@ -17,66 +17,8 @@
*! Jun 17 1999 Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'.
*! Jul 21 1999 Bjorn Wesen eLinux port
*!
-*! $Log: kgdb.c,v $
-*! Revision 1.6 2005/01/14 10:12:17 starvik
-*! KGDB on separate port.
-*! Console fixes from 2.4.
-*!
-*! Revision 1.5 2004/10/07 13:59:08 starvik
-*! Corrected call to set_int_vector
-*!
-*! Revision 1.4 2003/04/09 05:20:44 starvik
-*! Merge of Linux 2.5.67
-*!
-*! Revision 1.3 2003/01/21 19:11:08 starvik
-*! Modified include path for new dir layout
-*!
-*! Revision 1.2 2002/11/19 14:35:24 starvik
-*! Changes from linux 2.4
-*! Changed struct initializer syntax to the currently preferred notation
-*!
-*! Revision 1.1 2001/12/17 13:59:27 bjornw
-*! Initial revision
-*!
-*! Revision 1.6 2001/10/09 13:10:03 matsfg
-*! Added $ on registers and removed some underscores
-*!
-*! Revision 1.5 2001/04/17 13:58:39 orjanf
-*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
-*!
-*! Revision 1.4 2001/02/23 13:45:19 bjornw
-*! config.h check
-*!
-*! Revision 1.3 2001/01/31 18:08:23 orjanf
-*! Removed kgdb_handle_breakpoint from being the break 8 handler.
-*!
-*! Revision 1.2 2001/01/12 14:22:25 orjanf
-*! Updated kernel debugging support to work with ETRAX 100LX.
-*!
-*! Revision 1.1 2000/07/10 16:25:21 bjornw
-*! Initial revision
-*!
-*! Revision 1.1.1.1 1999/12/03 14:57:31 bjornw
-*! * Initial version of arch/cris, the latest CRIS architecture with an MMU.
-*! Mostly copied from arch/etrax100 with appropriate renames of files.
-*! The mm/ subdir is copied from arch/i386.
-*! This does not compile yet at all.
-*!
-*!
-*! Revision 1.4 1999/07/22 17:25:25 bjornw
-*! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors.
-*!
-*! Revision 1.3 1999/07/21 19:51:18 bjornw
-*! Check if the interrupting char is a ctrl-C, ignore otherwise.
-*!
-*! Revision 1.2 1999/07/21 18:09:39 bjornw
-*! Ported to eLinux architecture, and added some kgdb documentation.
-*!
-*!
*!---------------------------------------------------------------------------
*!
-*! $Id: kgdb.c,v 1.6 2005/01/14 10:12:17 starvik Exp $
-*!
*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
*!
*!**************************************************************************/
@@ -234,7 +176,7 @@
#include <asm/setup.h>
#include <asm/ptrace.h>
-#include <asm/arch/svinto.h>
+#include <arch/svinto.h>
#include <asm/irq.h>
static int kgdb_started = 0;
@@ -288,46 +230,6 @@ struct register_image
unsigned int usp; /* 0x66 User mode stack pointer */
} registers;
-/************** Prototypes for local library functions ***********************/
-
-/* Copy of strcpy from libc. */
-static char *gdb_cris_strcpy (char *s1, const char *s2);
-
-/* Copy of strlen from libc. */
-static int gdb_cris_strlen (const char *s);
-
-/* Copy of memchr from libc. */
-static void *gdb_cris_memchr (const void *s, int c, int n);
-
-/* Copy of strtol from libc. Does only support base 16. */
-static int gdb_cris_strtol (const char *s, char **endptr, int base);
-
-/********************** Prototypes for local functions. **********************/
-/* Copy the content of a register image into another. The size n is
- the size of the register image. Due to struct assignment generation of
- memcpy in libc. */
-static void copy_registers (registers *dptr, registers *sptr, int n);
-
-/* Copy the stored registers from the stack. Put the register contents
- of thread thread_id in the struct reg. */
-static void copy_registers_from_stack (int thread_id, registers *reg);
-
-/* Copy the registers to the stack. Put the register contents of thread
- thread_id from struct reg to the stack. */
-static void copy_registers_to_stack (int thread_id, registers *reg);
-
-/* Write a value to a specified register regno in the register image
- of the current thread. */
-static int write_register (int regno, char *val);
-
-/* Write a value to a specified register in the stack of a thread other
- than the current thread. */
-static write_stack_register (int thread_id, int regno, char *valptr);
-
-/* Read a value from a specified register in the register image. Returns the
- status of the read operation. The register value is returned in valptr. */
-static int read_register (char regno, unsigned int *valptr);
-
/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
int getDebugChar (void);
@@ -336,50 +238,6 @@ void putDebugChar (int val);
void enableDebugIRQ (void);
-/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
- represented by int x. */
-static char highhex (int x);
-
-/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
- represented by int x. */
-static char lowhex (int x);
-
-/* Returns the integer equivalent of a hexadecimal character. */
-static int hex (char ch);
-
-/* Convert the memory, pointed to by mem into hexadecimal representation.
- Put the result in buf, and return a pointer to the last character
- in buf (null). */
-static char *mem2hex (char *buf, unsigned char *mem, int count);
-
-/* Convert the array, in hexadecimal representation, pointed to by buf into
- binary representation. Put the result in mem, and return a pointer to
- the character after the last byte written. */
-static unsigned char *hex2mem (unsigned char *mem, char *buf, int count);
-
-/* Put the content of the array, in binary representation, pointed to by buf
- into memory pointed to by mem, and return a pointer to
- the character after the last byte written. */
-static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count);
-
-/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
- returned. */
-static void getpacket (char *buffer);
-
-/* Send $<data>#<checksum> from the <data> in the array buffer. */
-static void putpacket (char *buffer);
-
-/* Build and send a response packet in order to inform the host the
- stub is stopped. */
-static void stub_is_stopped (int sigval);
-
-/* All expected commands are sent from remote.c. Send a response according
- to the description in remote.c. */
-static void handle_exception (int sigval);
-
-/* Performs a complete re-start from scratch. ETRAX specific. */
-static void kill_restart (void);
-
/******************** Prototypes for global functions. ***********************/
/* The string str is prepended with the GDB printout token and sent. */
@@ -402,10 +260,6 @@ extern unsigned char executing_task;
/* The number of characters used for a 64 bit thread identifier. */
#define HEXCHARS_IN_THREAD_ID 16
-/* Avoid warning as the internal_stack is not used in the C-code. */
-#define USEDVAR(name) { if (name) { ; } }
-#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) }
-
/********************************** Packet I/O ******************************/
/* BUFMAX defines the maximum number of characters in
inbound/outbound buffers */
@@ -414,9 +268,6 @@ extern unsigned char executing_task;
/* Run-length encoding maximum length. Send 64 at most. */
#define RUNLENMAX 64
-/* Definition of all valid hexadecimal characters */
-static const char hexchars[] = "0123456789abcdef";
-
/* The inbound/outbound buffers used in packet I/O */
static char remcomInBuffer[BUFMAX];
static char remcomOutBuffer[BUFMAX];
@@ -474,7 +325,7 @@ static int register_size[] =
/* Contains the register image of the executing thread in the assembler
part of the code in order to avoid horrible addressing modes. */
-static registers reg;
+registers cris_reg;
/* FIXME: Should this be used? Delete otherwise. */
/* Contains the assumed consistency state of the register image. Uses the
@@ -482,7 +333,7 @@ static registers reg;
static int consistency_status = SUCCESS;
/********************************** Handle exceptions ************************/
-/* The variable reg contains the register image associated with the
+/* The variable cris_reg contains the register image associated with the
current_thread_c variable. It is a complete register image created at
entry. The reg_g contains a register image of a task where the general
registers are taken from the stack and all special registers are taken
@@ -490,18 +341,10 @@ static int consistency_status = SUCCESS;
in order to provide access mainly for 'g', 'G' and 'P'.
*/
-/* Need two task id pointers in order to handle Hct and Hgt commands. */
-static int current_thread_c = 0;
-static int current_thread_g = 0;
-
-/* Need two register images in order to handle Hct and Hgt commands. The
- variable reg_g is in addition to reg above. */
-static registers reg_g;
-
/********************************** Breakpoint *******************************/
/* Use an internal stack in the breakpoint and interrupt response routines */
#define INTERNAL_STACK_SIZE 1024
-static char internal_stack[INTERNAL_STACK_SIZE];
+char internal_stack[INTERNAL_STACK_SIZE];
/* Due to the breakpoint return pointer, a state variable is needed to keep
track of whether it is a static (compiled) or dynamic (gdb-invoked)
@@ -557,8 +400,8 @@ gdb_cris_strtol (const char *s, char **endptr, int base)
char *sd;
int x = 0;
- for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1)
- x = x * base + (sd - hexchars);
+ for (s1 = (char*)s; (sd = gdb_cris_memchr(hex_asc, *s1, base)) != NULL; ++s1)
+ x = x * base + (sd - hex_asc);
if (endptr)
{
@@ -569,181 +412,7 @@ gdb_cris_strtol (const char *s, char **endptr, int base)
return x;
}
-/********************************* Register image ****************************/
-/* Copy the content of a register image into another. The size n is
- the size of the register image. Due to struct assignment generation of
- memcpy in libc. */
-static void
-copy_registers (registers *dptr, registers *sptr, int n)
-{
- unsigned char *dreg;
- unsigned char *sreg;
-
- for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--)
- *dreg++ = *sreg++;
-}
-
-#ifdef PROCESS_SUPPORT
-/* Copy the stored registers from the stack. Put the register contents
- of thread thread_id in the struct reg. */
-static void
-copy_registers_from_stack (int thread_id, registers *regptr)
-{
- int j;
- stack_registers *s = (stack_registers *)stack_list[thread_id];
- unsigned int *d = (unsigned int *)regptr;
-
- for (j = 13; j >= 0; j--)
- *d++ = s->r[j];
- regptr->sp = (unsigned int)stack_list[thread_id];
- regptr->pc = s->pc;
- regptr->dccr = s->dccr;
- regptr->srp = s->srp;
-}
-
-/* Copy the registers to the stack. Put the register contents of thread
- thread_id from struct reg to the stack. */
-static void
-copy_registers_to_stack (int thread_id, registers *regptr)
-{
- int i;
- stack_registers *d = (stack_registers *)stack_list[thread_id];
- unsigned int *s = (unsigned int *)regptr;
-
- for (i = 0; i < 14; i++) {
- d->r[i] = *s++;
- }
- d->pc = regptr->pc;
- d->dccr = regptr->dccr;
- d->srp = regptr->srp;
-}
-#endif
-
-/* Write a value to a specified register in the register image of the current
- thread. Returns status code SUCCESS, E02 or E05. */
-static int
-write_register (int regno, char *val)
-{
- int status = SUCCESS;
- registers *current_reg = &reg;
-
- if (regno >= R0 && regno <= PC) {
- /* 32-bit register with simple offset. */
- hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
- val, sizeof(unsigned int));
- }
- else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
- /* Do not support read-only registers. */
- status = E02;
- }
- else if (regno == CCR) {
- /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented,
- and P7 (MOF) is 32 bits in ETRAX 100LX. */
- hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
- val, sizeof(unsigned short));
- }
- else if (regno >= MOF && regno <= USP) {
- /* 32 bit register with complex offset. (P8 has been taken care of.) */
- hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
- val, sizeof(unsigned int));
- }
- else {
- /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
- status = E05;
- }
- return status;
-}
-
-#ifdef PROCESS_SUPPORT
-/* Write a value to a specified register in the stack of a thread other
- than the current thread. Returns status code SUCCESS or E07. */
-static int
-write_stack_register (int thread_id, int regno, char *valptr)
-{
- int status = SUCCESS;
- stack_registers *d = (stack_registers *)stack_list[thread_id];
- unsigned int val;
-
- hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int));
- if (regno >= R0 && regno < SP) {
- d->r[regno] = val;
- }
- else if (regno == SP) {
- stack_list[thread_id] = val;
- }
- else if (regno == PC) {
- d->pc = val;
- }
- else if (regno == SRP) {
- d->srp = val;
- }
- else if (regno == DCCR) {
- d->dccr = val;
- }
- else {
- /* Do not support registers in the current thread. */
- status = E07;
- }
- return status;
-}
-#endif
-
-/* Read a value from a specified register in the register image. Returns the
- value in the register or -1 for non-implemented registers.
- Should check consistency_status after a call which may be E05 after changes
- in the implementation. */
-static int
-read_register (char regno, unsigned int *valptr)
-{
- registers *current_reg = &reg;
-
- if (regno >= R0 && regno <= PC) {
- /* 32-bit register with simple offset. */
- *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
- return SUCCESS;
- }
- else if (regno == P0 || regno == VR) {
- /* 8 bit register with complex offset. */
- *valptr = (unsigned int)(*(unsigned char *)
- ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
- return SUCCESS;
- }
- else if (regno == P4 || regno == CCR) {
- /* 16 bit register with complex offset. */
- *valptr = (unsigned int)(*(unsigned short *)
- ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
- return SUCCESS;
- }
- else if (regno >= MOF && regno <= USP) {
- /* 32 bit register with complex offset. */
- *valptr = *(unsigned int *)((char *)&(current_reg->p8)
- + (regno-P8) * sizeof(unsigned int));
- return SUCCESS;
- }
- else {
- /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
- consistency_status = E05;
- return E05;
- }
-}
-
/********************************** Packet I/O ******************************/
-/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
- represented by int x. */
-static inline char
-highhex(int x)
-{
- return hexchars[(x >> 4) & 0xf];
-}
-
-/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
- represented by int x. */
-static inline char
-lowhex(int x)
-{
- return hexchars[x & 0xf];
-}
-
/* Returns the integer equivalent of a hexadecimal character. */
static int
hex (char ch)
@@ -761,8 +430,6 @@ hex (char ch)
Put the result in buf, and return a pointer to the last character
in buf (null). */
-static int do_printk = 0;
-
static char *
mem2hex(char *buf, unsigned char *mem, int count)
{
@@ -779,8 +446,7 @@ mem2hex(char *buf, unsigned char *mem, int count)
/* Valid mem address. */
for (i = 0; i < count; i++) {
ch = *mem++;
- *buf++ = highhex (ch);
- *buf++ = lowhex (ch);
+ buf = hex_byte_pack(buf, ch);
}
}
@@ -847,7 +513,7 @@ getpacket (char *buffer)
xmitcsum = -1;
count = 0;
/* Read until a # or the end of the buffer is reached */
- while (count < BUFMAX) {
+ while (count < BUFMAX - 1) {
ch = getDebugChar ();
if (ch == '#')
break;
@@ -915,9 +581,9 @@ putpacket(char *buffer)
src++;
}
}
- putDebugChar ('#');
- putDebugChar (highhex (checksum));
- putDebugChar (lowhex (checksum));
+ putDebugChar('#');
+ putDebugChar(hex_asc_hi(checksum));
+ putDebugChar(hex_asc_lo(checksum));
} while(kgdb_started && (getDebugChar() != '+'));
}
@@ -931,6 +597,81 @@ putDebugString (const unsigned char *str, int length)
putpacket(remcomOutBuffer);
}
+/********************************* Register image ****************************/
+/* Write a value to a specified register in the register image of the current
+ thread. Returns status code SUCCESS, E02 or E05. */
+static int
+write_register (int regno, char *val)
+{
+ int status = SUCCESS;
+ registers *current_reg = &cris_reg;
+
+ if (regno >= R0 && regno <= PC) {
+ /* 32-bit register with simple offset. */
+ hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
+ val, sizeof(unsigned int));
+ }
+ else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
+ /* Do not support read-only registers. */
+ status = E02;
+ }
+ else if (regno == CCR) {
+ /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented,
+ and P7 (MOF) is 32 bits in ETRAX 100LX. */
+ hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
+ val, sizeof(unsigned short));
+ }
+ else if (regno >= MOF && regno <= USP) {
+ /* 32 bit register with complex offset. (P8 has been taken care of.) */
+ hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
+ val, sizeof(unsigned int));
+ }
+ else {
+ /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+ status = E05;
+ }
+ return status;
+}
+
+/* Read a value from a specified register in the register image. Returns the
+ value in the register or -1 for non-implemented registers.
+ Should check consistency_status after a call which may be E05 after changes
+ in the implementation. */
+static int
+read_register (char regno, unsigned int *valptr)
+{
+ registers *current_reg = &cris_reg;
+
+ if (regno >= R0 && regno <= PC) {
+ /* 32-bit register with simple offset. */
+ *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
+ return SUCCESS;
+ }
+ else if (regno == P0 || regno == VR) {
+ /* 8 bit register with complex offset. */
+ *valptr = (unsigned int)(*(unsigned char *)
+ ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
+ return SUCCESS;
+ }
+ else if (regno == P4 || regno == CCR) {
+ /* 16 bit register with complex offset. */
+ *valptr = (unsigned int)(*(unsigned short *)
+ ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
+ return SUCCESS;
+ }
+ else if (regno >= MOF && regno <= USP) {
+ /* 32 bit register with complex offset. */
+ *valptr = *(unsigned int *)((char *)&(current_reg->p8)
+ + (regno-P8) * sizeof(unsigned int));
+ return SUCCESS;
+ }
+ else {
+ /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+ consistency_status = E05;
+ return E05;
+ }
+}
+
/********************************** Handle exceptions ************************/
/* Build and send a response packet in order to inform the host the
stub is stopped. TAAn...:r...;n...:r...;n...:r...;
@@ -953,13 +694,12 @@ stub_is_stopped(int sigval)
/* Send trap type (converted to signal) */
- *ptr++ = 'T';
- *ptr++ = highhex (sigval);
- *ptr++ = lowhex (sigval);
+ *ptr++ = 'T';
+ ptr = hex_byte_pack(ptr, sigval);
/* Send register contents. We probably only need to send the
* PC, frame pointer and stack pointer here. Other registers will be
- * explicitely asked for. But for now, send all.
+ * explicitly asked for. But for now, send all.
*/
for (regno = R0; regno <= USP; regno++) {
@@ -968,9 +708,7 @@ stub_is_stopped(int sigval)
status = read_register (regno, &reg_cont);
if (status == SUCCESS) {
-
- *ptr++ = highhex (regno);
- *ptr++ = lowhex (regno);
+ ptr = hex_byte_pack(ptr, regno);
*ptr++ = ':';
ptr = mem2hex(ptr, (unsigned char *)&reg_cont,
@@ -980,26 +718,6 @@ stub_is_stopped(int sigval)
}
-#ifdef PROCESS_SUPPORT
- /* Store the registers of the executing thread. Assume that both step,
- continue, and register content requests are with respect to this
- thread. The executing task is from the operating system scheduler. */
-
- current_thread_c = executing_task;
- current_thread_g = executing_task;
-
- /* A struct assignment translates into a libc memcpy call. Avoid
- all libc functions in order to prevent recursive break points. */
- copy_registers (&reg_g, &reg, sizeof(registers));
-
- /* Store thread:r...; with the executing task TID. */
- gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:");
- pos += gdb_cris_strlen ("thread:");
- remcomOutBuffer[pos++] = highhex (executing_task);
- remcomOutBuffer[pos++] = lowhex (executing_task);
- gdb_cris_strcpy (&remcomOutBuffer[pos], ";");
-#endif
-
/* null-terminate and send it off */
*ptr = 0;
@@ -1007,16 +725,18 @@ stub_is_stopped(int sigval)
putpacket (remcomOutBuffer);
}
+/* Performs a complete re-start from scratch. */
+static void
+kill_restart (void)
+{
+ machine_restart("");
+}
+
/* All expected commands are sent from remote.c. Send a response according
to the description in remote.c. */
-static void
+void
handle_exception (int sigval)
{
- /* Avoid warning of not used. */
-
- USEDFUN(handle_exception);
- USEDVAR(internal_stack[0]);
-
/* Send response. */
stub_is_stopped (sigval);
@@ -1032,19 +752,7 @@ handle_exception (int sigval)
in a register are in the same order the machine uses.
Failure: void. */
- {
-#ifdef PROCESS_SUPPORT
- /* Use the special register content in the executing thread. */
- copy_registers (&reg_g, &reg, sizeof(registers));
- /* Replace the content available on the stack. */
- if (current_thread_g != executing_task) {
- copy_registers_from_stack (current_thread_g, &reg_g);
- }
- mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)&reg_g, sizeof(registers));
-#else
- mem2hex(remcomOutBuffer, (char *)&reg, sizeof(registers));
-#endif
- }
+ mem2hex(remcomOutBuffer, (char *)&cris_reg, sizeof(registers));
break;
case 'G':
@@ -1052,17 +760,7 @@ handle_exception (int sigval)
Each byte of register data is described by two hex digits.
Success: OK
Failure: void. */
-#ifdef PROCESS_SUPPORT
- hex2mem ((unsigned char *)&reg_g, &remcomInBuffer[1], sizeof(registers));
- if (current_thread_g == executing_task) {
- copy_registers (&reg, &reg_g, sizeof(registers));
- }
- else {
- copy_registers_to_stack(current_thread_g, &reg_g);
- }
-#else
- hex2mem((char *)&reg, &remcomInBuffer[1], sizeof(registers));
-#endif
+ hex2mem((char *)&cris_reg, &remcomInBuffer[1], sizeof(registers));
gdb_cris_strcpy (remcomOutBuffer, "OK");
break;
@@ -1078,12 +776,7 @@ handle_exception (int sigval)
char *suffix;
int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
int status;
-#ifdef PROCESS_SUPPORT
- if (current_thread_g != executing_task)
- status = write_stack_register (current_thread_g, regno, suffix+1);
- else
-#endif
- status = write_register (regno, suffix+1);
+ status = write_register (regno, suffix+1);
switch (status) {
case E02:
@@ -1162,7 +855,7 @@ handle_exception (int sigval)
Success: return to the executing thread.
Failure: will never know. */
if (remcomInBuffer[1] != '\0') {
- reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+ cris_reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
}
enableDebugIRQ();
return;
@@ -1184,8 +877,8 @@ handle_exception (int sigval)
Success: SAA, where AA is the signal number.
Failure: void. */
remcomOutBuffer[0] = 'S';
- remcomOutBuffer[1] = highhex (sigval);
- remcomOutBuffer[2] = lowhex (sigval);
+ remcomOutBuffer[1] = hex_asc_hi(sigval);
+ remcomOutBuffer[2] = hex_asc_lo(sigval);
remcomOutBuffer[3] = 0;
break;
@@ -1218,119 +911,6 @@ handle_exception (int sigval)
Not supported: E04 */
gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
break;
-#ifdef PROCESS_SUPPORT
-
- case 'T':
- /* Thread alive. TXX
- Is thread XX alive?
- Success: OK, thread XX is alive.
- Failure: E03, thread XX is dead. */
- {
- int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
- /* Cannot tell whether it is alive or not. */
- if (thread_id >= 0 && thread_id < number_of_tasks)
- gdb_cris_strcpy (remcomOutBuffer, "OK");
- }
- break;
-
- case 'H':
- /* Set thread for subsequent operations: Hct
- c = 'c' for thread used in step and continue;
- t can be -1 for all threads.
- c = 'g' for thread used in other operations.
- t = 0 means pick any thread.
- Success: OK
- Failure: E01 */
- {
- int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16);
- if (remcomInBuffer[1] == 'c') {
- /* c = 'c' for thread used in step and continue */
- /* Do not change current_thread_c here. It would create a mess in
- the scheduler. */
- gdb_cris_strcpy (remcomOutBuffer, "OK");
- }
- else if (remcomInBuffer[1] == 'g') {
- /* c = 'g' for thread used in other operations.
- t = 0 means pick any thread. Impossible since the scheduler does
- not allow that. */
- if (thread_id >= 0 && thread_id < number_of_tasks) {
- current_thread_g = thread_id;
- gdb_cris_strcpy (remcomOutBuffer, "OK");
- }
- else {
- /* Not expected - send an error message. */
- gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
- }
- }
- else {
- /* Not expected - send an error message. */
- gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
- }
- }
- break;
-
- case 'q':
- case 'Q':
- /* Query of general interest. qXXXX
- Set general value XXXX. QXXXX=yyyy */
- {
- int pos;
- int nextpos;
- int thread_id;
-
- switch (remcomInBuffer[1]) {
- case 'C':
- /* Identify the remote current thread. */
- gdb_cris_strcpy (&remcomOutBuffer[0], "QC");
- remcomOutBuffer[2] = highhex (current_thread_c);
- remcomOutBuffer[3] = lowhex (current_thread_c);
- remcomOutBuffer[4] = '\0';
- break;
- case 'L':
- gdb_cris_strcpy (&remcomOutBuffer[0], "QM");
- /* Reply with number of threads. */
- if (os_is_started()) {
- remcomOutBuffer[2] = highhex (number_of_tasks);
- remcomOutBuffer[3] = lowhex (number_of_tasks);
- }
- else {
- remcomOutBuffer[2] = highhex (0);
- remcomOutBuffer[3] = lowhex (1);
- }
- /* Done with the reply. */
- remcomOutBuffer[4] = lowhex (1);
- pos = 5;
- /* Expects the argument thread id. */
- for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++)
- remcomOutBuffer[pos] = remcomInBuffer[pos];
- /* Reply with the thread identifiers. */
- if (os_is_started()) {
- /* Store the thread identifiers of all tasks. */
- for (thread_id = 0; thread_id < number_of_tasks; thread_id++) {
- nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
- for (; pos < nextpos; pos ++)
- remcomOutBuffer[pos] = lowhex (0);
- remcomOutBuffer[pos++] = lowhex (thread_id);
- }
- }
- else {
- /* Store the thread identifier of the boot task. */
- nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
- for (; pos < nextpos; pos ++)
- remcomOutBuffer[pos] = lowhex (0);
- remcomOutBuffer[pos++] = lowhex (current_thread_c);
- }
- remcomOutBuffer[pos] = '\0';
- break;
- default:
- /* Not supported: "" */
- /* Request information about section offsets: qOffsets. */
- remcomOutBuffer[0] = 0;
- break;
- }
- }
- break;
-#endif /* PROCESS_SUPPORT */
default:
/* The stub should ignore other request and send an empty
@@ -1343,13 +923,6 @@ handle_exception (int sigval)
}
}
-/* Performs a complete re-start from scratch. */
-static void
-kill_restart ()
-{
- machine_restart("");
-}
-
/********************************** Breakpoint *******************************/
/* The hook for both a static (compiled) and a dynamic breakpoint set by GDB.
An internal stack is used by the stub. The register image of the caller is
@@ -1359,93 +932,93 @@ kill_restart ()
void kgdb_handle_breakpoint(void);
-asm ("
- .global kgdb_handle_breakpoint
-kgdb_handle_breakpoint:
-;;
-;; Response to the break-instruction
-;;
-;; Create a register image of the caller
-;;
- move $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts
- di ; Disable interrupts
- move.d $r0,[reg] ; Save R0
- move.d $r1,[reg+0x04] ; Save R1
- move.d $r2,[reg+0x08] ; Save R2
- move.d $r3,[reg+0x0C] ; Save R3
- move.d $r4,[reg+0x10] ; Save R4
- move.d $r5,[reg+0x14] ; Save R5
- move.d $r6,[reg+0x18] ; Save R6
- move.d $r7,[reg+0x1C] ; Save R7
- move.d $r8,[reg+0x20] ; Save R8
- move.d $r9,[reg+0x24] ; Save R9
- move.d $r10,[reg+0x28] ; Save R10
- move.d $r11,[reg+0x2C] ; Save R11
- move.d $r12,[reg+0x30] ; Save R12
- move.d $r13,[reg+0x34] ; Save R13
- move.d $sp,[reg+0x38] ; Save SP (R14)
-;; Due to the old assembler-versions BRP might not be recognized
- .word 0xE670 ; move brp,$r0
- subq 2,$r0 ; Set to address of previous instruction.
- move.d $r0,[reg+0x3c] ; Save the address in PC (R15)
- clear.b [reg+0x40] ; Clear P0
- move $vr,[reg+0x41] ; Save special register P1
- clear.w [reg+0x42] ; Clear P4
- move $ccr,[reg+0x44] ; Save special register CCR
- move $mof,[reg+0x46] ; P7
- clear.d [reg+0x4A] ; Clear P8
- move $ibr,[reg+0x4E] ; P9,
- move $irp,[reg+0x52] ; P10,
- move $srp,[reg+0x56] ; P11,
- move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
- ; P13, register DCCR already saved
-;; Due to the old assembler-versions BRP might not be recognized
- .word 0xE670 ; move brp,r0
-;; Static (compiled) breakpoints must return to the next instruction in order
-;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction
-;; in order to execute it when execution is continued.
- test.b [is_dyn_brkp] ; Is this a dynamic breakpoint?
- beq is_static ; No, a static breakpoint
- nop
- subq 2,$r0 ; rerun the instruction the break replaced
-is_static:
- moveq 1,$r1
- move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint
- move.d $r0,[reg+0x62] ; Save the return address in BRP
- move $usp,[reg+0x66] ; USP
-;;
-;; Handle the communication
-;;
- move.d internal_stack+1020,$sp ; Use the internal stack which grows upward
- moveq 5,$r10 ; SIGTRAP
- jsr handle_exception ; Interactive routine
-;;
-;; Return to the caller
-;;
- move.d [reg],$r0 ; Restore R0
- move.d [reg+0x04],$r1 ; Restore R1
- move.d [reg+0x08],$r2 ; Restore R2
- move.d [reg+0x0C],$r3 ; Restore R3
- move.d [reg+0x10],$r4 ; Restore R4
- move.d [reg+0x14],$r5 ; Restore R5
- move.d [reg+0x18],$r6 ; Restore R6
- move.d [reg+0x1C],$r7 ; Restore R7
- move.d [reg+0x20],$r8 ; Restore R8
- move.d [reg+0x24],$r9 ; Restore R9
- move.d [reg+0x28],$r10 ; Restore R10
- move.d [reg+0x2C],$r11 ; Restore R11
- move.d [reg+0x30],$r12 ; Restore R12
- move.d [reg+0x34],$r13 ; Restore R13
-;;
-;; FIXME: Which registers should be restored?
-;;
- move.d [reg+0x38],$sp ; Restore SP (R14)
- move [reg+0x56],$srp ; Restore the subroutine return pointer.
- move [reg+0x5E],$dccr ; Restore DCCR
- move [reg+0x66],$usp ; Restore USP
- jump [reg+0x62] ; A jump to the content in register BRP works.
- nop ;
-");
+asm ("\n"
+" .global kgdb_handle_breakpoint\n"
+"kgdb_handle_breakpoint:\n"
+";;\n"
+";; Response to the break-instruction\n"
+";;\n"
+";; Create a register image of the caller\n"
+";;\n"
+" move $dccr,[cris_reg+0x5E] ; Save the flags in DCCR before disable interrupts\n"
+" di ; Disable interrupts\n"
+" move.d $r0,[cris_reg] ; Save R0\n"
+" move.d $r1,[cris_reg+0x04] ; Save R1\n"
+" move.d $r2,[cris_reg+0x08] ; Save R2\n"
+" move.d $r3,[cris_reg+0x0C] ; Save R3\n"
+" move.d $r4,[cris_reg+0x10] ; Save R4\n"
+" move.d $r5,[cris_reg+0x14] ; Save R5\n"
+" move.d $r6,[cris_reg+0x18] ; Save R6\n"
+" move.d $r7,[cris_reg+0x1C] ; Save R7\n"
+" move.d $r8,[cris_reg+0x20] ; Save R8\n"
+" move.d $r9,[cris_reg+0x24] ; Save R9\n"
+" move.d $r10,[cris_reg+0x28] ; Save R10\n"
+" move.d $r11,[cris_reg+0x2C] ; Save R11\n"
+" move.d $r12,[cris_reg+0x30] ; Save R12\n"
+" move.d $r13,[cris_reg+0x34] ; Save R13\n"
+" move.d $sp,[cris_reg+0x38] ; Save SP (R14)\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+" .word 0xE670 ; move brp,$r0\n"
+" subq 2,$r0 ; Set to address of previous instruction.\n"
+" move.d $r0,[cris_reg+0x3c] ; Save the address in PC (R15)\n"
+" clear.b [cris_reg+0x40] ; Clear P0\n"
+" move $vr,[cris_reg+0x41] ; Save special register P1\n"
+" clear.w [cris_reg+0x42] ; Clear P4\n"
+" move $ccr,[cris_reg+0x44] ; Save special register CCR\n"
+" move $mof,[cris_reg+0x46] ; P7\n"
+" clear.d [cris_reg+0x4A] ; Clear P8\n"
+" move $ibr,[cris_reg+0x4E] ; P9,\n"
+" move $irp,[cris_reg+0x52] ; P10,\n"
+" move $srp,[cris_reg+0x56] ; P11,\n"
+" move $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n"
+" ; P13, register DCCR already saved\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+" .word 0xE670 ; move brp,r0\n"
+";; Static (compiled) breakpoints must return to the next instruction in order\n"
+";; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction\n"
+";; in order to execute it when execution is continued.\n"
+" test.b [is_dyn_brkp] ; Is this a dynamic breakpoint?\n"
+" beq is_static ; No, a static breakpoint\n"
+" nop\n"
+" subq 2,$r0 ; rerun the instruction the break replaced\n"
+"is_static:\n"
+" moveq 1,$r1\n"
+" move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint\n"
+" move.d $r0,[cris_reg+0x62] ; Save the return address in BRP\n"
+" move $usp,[cris_reg+0x66] ; USP\n"
+";;\n"
+";; Handle the communication\n"
+";;\n"
+" move.d internal_stack+1020,$sp ; Use the internal stack which grows upward\n"
+" moveq 5,$r10 ; SIGTRAP\n"
+" jsr handle_exception ; Interactive routine\n"
+";;\n"
+";; Return to the caller\n"
+";;\n"
+" move.d [cris_reg],$r0 ; Restore R0\n"
+" move.d [cris_reg+0x04],$r1 ; Restore R1\n"
+" move.d [cris_reg+0x08],$r2 ; Restore R2\n"
+" move.d [cris_reg+0x0C],$r3 ; Restore R3\n"
+" move.d [cris_reg+0x10],$r4 ; Restore R4\n"
+" move.d [cris_reg+0x14],$r5 ; Restore R5\n"
+" move.d [cris_reg+0x18],$r6 ; Restore R6\n"
+" move.d [cris_reg+0x1C],$r7 ; Restore R7\n"
+" move.d [cris_reg+0x20],$r8 ; Restore R8\n"
+" move.d [cris_reg+0x24],$r9 ; Restore R9\n"
+" move.d [cris_reg+0x28],$r10 ; Restore R10\n"
+" move.d [cris_reg+0x2C],$r11 ; Restore R11\n"
+" move.d [cris_reg+0x30],$r12 ; Restore R12\n"
+" move.d [cris_reg+0x34],$r13 ; Restore R13\n"
+";;\n"
+";; FIXME: Which registers should be restored?\n"
+";;\n"
+" move.d [cris_reg+0x38],$sp ; Restore SP (R14)\n"
+" move [cris_reg+0x56],$srp ; Restore the subroutine return pointer.\n"
+" move [cris_reg+0x5E],$dccr ; Restore DCCR\n"
+" move [cris_reg+0x66],$usp ; Restore USP\n"
+" jump [cris_reg+0x62] ; A jump to the content in register BRP works.\n"
+" nop ;\n"
+"\n");
/* The hook for an interrupt generated by GDB. An internal stack is used
by the stub. The register image of the caller is stored in the structure
@@ -1456,94 +1029,94 @@ is_static:
void kgdb_handle_serial(void);
-asm ("
- .global kgdb_handle_serial
-kgdb_handle_serial:
-;;
-;; Response to a serial interrupt
-;;
-
- move $dccr,[reg+0x5E] ; Save the flags in DCCR
- di ; Disable interrupts
- move.d $r0,[reg] ; Save R0
- move.d $r1,[reg+0x04] ; Save R1
- move.d $r2,[reg+0x08] ; Save R2
- move.d $r3,[reg+0x0C] ; Save R3
- move.d $r4,[reg+0x10] ; Save R4
- move.d $r5,[reg+0x14] ; Save R5
- move.d $r6,[reg+0x18] ; Save R6
- move.d $r7,[reg+0x1C] ; Save R7
- move.d $r8,[reg+0x20] ; Save R8
- move.d $r9,[reg+0x24] ; Save R9
- move.d $r10,[reg+0x28] ; Save R10
- move.d $r11,[reg+0x2C] ; Save R11
- move.d $r12,[reg+0x30] ; Save R12
- move.d $r13,[reg+0x34] ; Save R13
- move.d $sp,[reg+0x38] ; Save SP (R14)
- move $irp,[reg+0x3c] ; Save the address in PC (R15)
- clear.b [reg+0x40] ; Clear P0
- move $vr,[reg+0x41] ; Save special register P1,
- clear.w [reg+0x42] ; Clear P4
- move $ccr,[reg+0x44] ; Save special register CCR
- move $mof,[reg+0x46] ; P7
- clear.d [reg+0x4A] ; Clear P8
- move $ibr,[reg+0x4E] ; P9,
- move $irp,[reg+0x52] ; P10,
- move $srp,[reg+0x56] ; P11,
- move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
- ; P13, register DCCR already saved
-;; Due to the old assembler-versions BRP might not be recognized
- .word 0xE670 ; move brp,r0
- move.d $r0,[reg+0x62] ; Save the return address in BRP
- move $usp,[reg+0x66] ; USP
-
-;; get the serial character (from debugport.c) and check if it is a ctrl-c
-
- jsr getDebugChar
- cmp.b 3, $r10
- bne goback
- nop
-
- move.d [reg+0x5E], $r10 ; Get DCCR
- btstq 8, $r10 ; Test the U-flag.
- bmi goback
- nop
-
-;;
-;; Handle the communication
-;;
- move.d internal_stack+1020,$sp ; Use the internal stack
- moveq 2,$r10 ; SIGINT
- jsr handle_exception ; Interactive routine
-
-goback:
-;;
-;; Return to the caller
-;;
- move.d [reg],$r0 ; Restore R0
- move.d [reg+0x04],$r1 ; Restore R1
- move.d [reg+0x08],$r2 ; Restore R2
- move.d [reg+0x0C],$r3 ; Restore R3
- move.d [reg+0x10],$r4 ; Restore R4
- move.d [reg+0x14],$r5 ; Restore R5
- move.d [reg+0x18],$r6 ; Restore R6
- move.d [reg+0x1C],$r7 ; Restore R7
- move.d [reg+0x20],$r8 ; Restore R8
- move.d [reg+0x24],$r9 ; Restore R9
- move.d [reg+0x28],$r10 ; Restore R10
- move.d [reg+0x2C],$r11 ; Restore R11
- move.d [reg+0x30],$r12 ; Restore R12
- move.d [reg+0x34],$r13 ; Restore R13
-;;
-;; FIXME: Which registers should be restored?
-;;
- move.d [reg+0x38],$sp ; Restore SP (R14)
- move [reg+0x56],$srp ; Restore the subroutine return pointer.
- move [reg+0x5E],$dccr ; Restore DCCR
- move [reg+0x66],$usp ; Restore USP
- reti ; Return from the interrupt routine
- nop
-");
+asm ("\n"
+" .global kgdb_handle_serial\n"
+"kgdb_handle_serial:\n"
+";;\n"
+";; Response to a serial interrupt\n"
+";;\n"
+"\n"
+" move $dccr,[cris_reg+0x5E] ; Save the flags in DCCR\n"
+" di ; Disable interrupts\n"
+" move.d $r0,[cris_reg] ; Save R0\n"
+" move.d $r1,[cris_reg+0x04] ; Save R1\n"
+" move.d $r2,[cris_reg+0x08] ; Save R2\n"
+" move.d $r3,[cris_reg+0x0C] ; Save R3\n"
+" move.d $r4,[cris_reg+0x10] ; Save R4\n"
+" move.d $r5,[cris_reg+0x14] ; Save R5\n"
+" move.d $r6,[cris_reg+0x18] ; Save R6\n"
+" move.d $r7,[cris_reg+0x1C] ; Save R7\n"
+" move.d $r8,[cris_reg+0x20] ; Save R8\n"
+" move.d $r9,[cris_reg+0x24] ; Save R9\n"
+" move.d $r10,[cris_reg+0x28] ; Save R10\n"
+" move.d $r11,[cris_reg+0x2C] ; Save R11\n"
+" move.d $r12,[cris_reg+0x30] ; Save R12\n"
+" move.d $r13,[cris_reg+0x34] ; Save R13\n"
+" move.d $sp,[cris_reg+0x38] ; Save SP (R14)\n"
+" move $irp,[cris_reg+0x3c] ; Save the address in PC (R15)\n"
+" clear.b [cris_reg+0x40] ; Clear P0\n"
+" move $vr,[cris_reg+0x41] ; Save special register P1,\n"
+" clear.w [cris_reg+0x42] ; Clear P4\n"
+" move $ccr,[cris_reg+0x44] ; Save special register CCR\n"
+" move $mof,[cris_reg+0x46] ; P7\n"
+" clear.d [cris_reg+0x4A] ; Clear P8\n"
+" move $ibr,[cris_reg+0x4E] ; P9,\n"
+" move $irp,[cris_reg+0x52] ; P10,\n"
+" move $srp,[cris_reg+0x56] ; P11,\n"
+" move $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n"
+" ; P13, register DCCR already saved\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+" .word 0xE670 ; move brp,r0\n"
+" move.d $r0,[cris_reg+0x62] ; Save the return address in BRP\n"
+" move $usp,[cris_reg+0x66] ; USP\n"
+"\n"
+";; get the serial character (from debugport.c) and check if it is a ctrl-c\n"
+"\n"
+" jsr getDebugChar\n"
+" cmp.b 3, $r10\n"
+" bne goback\n"
+" nop\n"
+"\n"
+" move.d [cris_reg+0x5E], $r10 ; Get DCCR\n"
+" btstq 8, $r10 ; Test the U-flag.\n"
+" bmi goback\n"
+" nop\n"
+"\n"
+";;\n"
+";; Handle the communication\n"
+";;\n"
+" move.d internal_stack+1020,$sp ; Use the internal stack\n"
+" moveq 2,$r10 ; SIGINT\n"
+" jsr handle_exception ; Interactive routine\n"
+"\n"
+"goback:\n"
+";;\n"
+";; Return to the caller\n"
+";;\n"
+" move.d [cris_reg],$r0 ; Restore R0\n"
+" move.d [cris_reg+0x04],$r1 ; Restore R1\n"
+" move.d [cris_reg+0x08],$r2 ; Restore R2\n"
+" move.d [cris_reg+0x0C],$r3 ; Restore R3\n"
+" move.d [cris_reg+0x10],$r4 ; Restore R4\n"
+" move.d [cris_reg+0x14],$r5 ; Restore R5\n"
+" move.d [cris_reg+0x18],$r6 ; Restore R6\n"
+" move.d [cris_reg+0x1C],$r7 ; Restore R7\n"
+" move.d [cris_reg+0x20],$r8 ; Restore R8\n"
+" move.d [cris_reg+0x24],$r9 ; Restore R9\n"
+" move.d [cris_reg+0x28],$r10 ; Restore R10\n"
+" move.d [cris_reg+0x2C],$r11 ; Restore R11\n"
+" move.d [cris_reg+0x30],$r12 ; Restore R12\n"
+" move.d [cris_reg+0x34],$r13 ; Restore R13\n"
+";;\n"
+";; FIXME: Which registers should be restored?\n"
+";;\n"
+" move.d [cris_reg+0x38],$sp ; Restore SP (R14)\n"
+" move [cris_reg+0x56],$srp ; Restore the subroutine return pointer.\n"
+" move [cris_reg+0x5E],$dccr ; Restore DCCR\n"
+" move [cris_reg+0x66],$usp ; Restore USP\n"
+" reti ; Return from the interrupt routine\n"
+" nop\n"
+"\n");
/* Use this static breakpoint in the start-up only. */
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
index b6831ceb6a6..02b783457be 100644
--- a/arch/cris/arch-v10/kernel/process.c
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -1,5 +1,4 @@
-/* $Id: process.c,v 1.12 2004/12/27 11:18:32 starvik Exp $
- *
+/*
* linux/arch/cris/kernel/process.c
*
* Copyright (C) 1995 Linus Torvalds
@@ -12,11 +11,13 @@
*/
#include <linux/sched.h>
+#include <linux/slab.h>
#include <linux/err.h>
#include <linux/fs.h>
-#include <linux/slab.h>
-#include <asm/arch/svinto.h>
+#include <arch/svinto.h>
#include <linux/init.h>
+#include <arch/system.h>
+#include <linux/ptrace.h>
#ifdef CONFIG_ETRAX_GPIO
void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
@@ -29,8 +30,9 @@ void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
void default_idle(void)
{
#ifdef CONFIG_ETRAX_GPIO
- etrax_gpio_wake_up_check();
+ etrax_gpio_wake_up_check();
#endif
+ local_irq_enable();
}
/*
@@ -54,17 +56,17 @@ void hard_reset_now (void)
* code to know about it than the watchdog handler in entry.S and
* this code, implementing hard reset through the watchdog.
*/
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
extern int cause_of_death;
#endif
printk("*** HARD RESET ***\n");
local_irq_disable();
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
cause_of_death = 0xbedead;
#else
- /* Since we dont plan to keep on reseting the watchdog,
+ /* Since we dont plan to keep on resetting the watchdog,
the key can be arbitrary hence three */
*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) |
IO_STATE(R_WATCHDOG, enable, start);
@@ -81,31 +83,6 @@ unsigned long thread_saved_pc(struct task_struct *t)
return task_pt_regs(t)->irp;
}
-static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)
-{
- fn(arg);
- do_exit(-1); /* Should never be called, return bad exit value */
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- /* Don't use r10 since that is set to 0 in copy_thread */
- regs.r11 = (unsigned long)fn;
- regs.r12 = (unsigned long)arg;
- regs.irp = (unsigned long)kernel_thread_helper;
- regs.dccr = 1 << I_DCCR_BITNR;
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-
/* setup the child's kernel stack with a pt_regs and switch_stack on it.
* it will be un-nested during _resume and _ret_from_sys_call when the
* new thread is scheduled.
@@ -115,29 +92,34 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
*
*/
asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
- unsigned long unused,
- struct task_struct *p, struct pt_regs *regs)
+int copy_thread(unsigned long clone_flags, unsigned long usp,
+ unsigned long arg, struct task_struct *p)
{
- struct pt_regs * childregs;
- struct switch_stack *swstack;
+ struct pt_regs *childregs = task_pt_regs(p);
+ struct switch_stack *swstack = ((struct switch_stack *)childregs) - 1;
/* put the pt_regs structure at the end of the new kernel stack page and fix it up
* remember that the task_struct doubles as the kernel stack for the task
*/
- childregs = task_pt_regs(p);
-
- *childregs = *regs; /* struct copy of pt_regs */
-
- p->set_child_tid = p->clear_child_tid = NULL;
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(swstack, 0,
+ sizeof(struct switch_stack) + sizeof(struct pt_regs));
+ swstack->r1 = usp;
+ swstack->r2 = arg;
+ childregs->dccr = 1 << I_DCCR_BITNR;
+ swstack->return_ip = (unsigned long) ret_from_kernel_thread;
+ p->thread.ksp = (unsigned long) swstack;
+ p->thread.usp = 0;
+ return 0;
+ }
+ *childregs = *current_pt_regs(); /* struct copy of pt_regs */
childregs->r10 = 0; /* child returns 0 after a fork/clone */
-
- /* put the switch stack right below the pt_regs */
- swstack = ((struct switch_stack *)childregs) - 1;
+ /* put the switch stack right below the pt_regs */
swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */
@@ -147,7 +129,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
/* fix the user-mode stackpointer */
- p->thread.usp = usp;
+ p->thread.usp = usp ?: rdusp();
/* and the kernel-mode one */
@@ -161,68 +143,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
return 0;
}
-/*
- * Be aware of the "magic" 7th argument in the four system-calls below.
- * They need the latest stackframe, which is put as the 7th argument by
- * entry.S. The previous arguments are dummies or actually used, but need
- * to be defined to reach the 7th argument.
- *
- * N.B.: Another method to get the stackframe is to use current_regs(). But
- * it returns the latest stack-frame stacked when going from _user mode_ and
- * some of these (at least sys_clone) are called from kernel-mode sometimes
- * (for example during kernel_thread, above) and thus cannot use it. Thus,
- * to be sure not to get any surprises, we use the method for the other calls
- * as well.
- */
-
-asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
-{
- return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/* if newusp is 0, we just grab the old usp */
-/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */
-asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
- int* parent_tid, int* child_tid, long mof, long srp,
- struct pt_regs *regs)
-{
- if (!newusp)
- newusp = rdusp();
- return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
-}
-
-/* vfork is a system call in i386 because of register-pressure - maybe
- * we can remove it and handle it in libc but we put it here until then.
- */
-
-asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
-{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
- long r13, long mof, long srp,
- struct pt_regs *regs)
-{
- int error;
- char *filename;
-
- filename = getname(fname);
- error = PTR_ERR(filename);
-
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename, argv, envp, regs);
- putname(filename);
- out:
- return error;
-}
-
unsigned long get_wchan(struct task_struct *p)
{
#if 0
@@ -256,6 +176,9 @@ unsigned long get_wchan(struct task_struct *p)
void show_regs(struct pt_regs * regs)
{
unsigned long usp = rdusp();
+
+ show_regs_print_info(KERN_DEFAULT);
+
printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
regs->irp, regs->srp, regs->dccr, usp, regs->mof );
printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
index fd2129a0458..bfddfb99401 100644
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -15,7 +15,6 @@
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include <asm/processor.h>
/*
@@ -65,6 +64,7 @@ void
ptrace_disable(struct task_struct *child)
{
/* Todo - pending singlesteps? */
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
/*
@@ -75,37 +75,29 @@ ptrace_disable(struct task_struct *child)
* (in user space) where the result of the ptrace call is written (instead of
* being returned).
*/
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ unsigned int regno = addr >> 2;
unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
/* Read word at location address. */
case PTRACE_PEEKTEXT:
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
-
- if (copied != sizeof(tmp))
- break;
-
- ret = put_user(tmp,datap);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* Read the word at location address in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long tmp;
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- tmp = get_reg(child, addr >> 2);
+ tmp = get_reg(child, regno);
ret = put_user(tmp, datap);
break;
}
@@ -113,89 +105,27 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Write the word at location address. */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = 0;
-
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
-
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
/* Write the word at location address in the USER area. */
case PTRACE_POKEUSR:
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- addr >>= 2;
-
- if (addr == PT_DCCR) {
+ if (regno == PT_DCCR) {
/* don't allow the tracing process to change stuff like
* interrupt enable, kernel/user bit, dma enables etc.
*/
data &= DCCR_MASK;
data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
}
- if (put_reg(child, addr, data))
- break;
- ret = 0;
- break;
-
- case PTRACE_SYSCALL:
- case PTRACE_CONT:
- ret = -EIO;
-
- if (!valid_signal(data))
- break;
-
- if (request == PTRACE_SYSCALL) {
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- else {
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
-
- child->exit_code = data;
-
- /* TODO: make sure any pending breakpoint is killed */
- wake_up_process(child);
- ret = 0;
-
- break;
-
- /* Make the child exit by sending it a sigkill. */
- case PTRACE_KILL:
- ret = 0;
-
- if (child->exit_state == EXIT_ZOMBIE)
+ if (put_reg(child, regno, data))
break;
-
- child->exit_code = SIGKILL;
-
- /* TODO: make sure any pending breakpoint is killed */
- wake_up_process(child);
- break;
-
- /* Set the trap flag. */
- case PTRACE_SINGLESTEP:
- ret = -EIO;
-
- if (!valid_signal(data))
- break;
-
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
- /* TODO: set some clever breakpoint mechanism... */
-
- child->exit_code = data;
- wake_up_process(child);
ret = 0;
break;
- case PTRACE_DETACH:
- ret = ptrace_detach(child, data);
- break;
-
/* Get all GP registers from the child. */
case PTRACE_GETREGS: {
int i;
@@ -210,7 +140,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
- data += sizeof(long);
+ datap++;
}
break;
@@ -234,7 +164,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
put_reg(child, i, tmp);
- data += sizeof(long);
+ datap++;
}
break;
diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c
index 682ef955aec..4f96d71b515 100644
--- a/arch/cris/arch-v10/kernel/setup.c
+++ b/arch/cris/arch-v10/kernel/setup.c
@@ -13,6 +13,8 @@
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
+#include <linux/param.h>
+#include <arch/system.h>
#ifdef CONFIG_PROC_FS
#define HAS_FPU 0x0001
@@ -56,8 +58,8 @@ int show_cpuinfo(struct seq_file *m, void *v)
revision = rdvr();
- if (revision >= sizeof cpu_info/sizeof *cpu_info)
- info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1];
+ if (revision >= ARRAY_SIZE(cpu_info))
+ info = &cpu_info[ARRAY_SIZE(cpu_info) - 1];
else
info = &cpu_info[revision];
diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c
index 38fd44dfbc5..2454a0b02f5 100644
--- a/arch/cris/arch-v10/kernel/shadows.c
+++ b/arch/cris/arch-v10/kernel/shadows.c
@@ -1,5 +1,4 @@
-/* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $
- *
+/*
* Various shadow registers. Defines for these are in include/asm-etrax100/io.h
*/
@@ -20,7 +19,7 @@ unsigned long r_timer_ctrl_shadow;
* These are only usable if there actually IS a latch connected
* to the corresponding external chip-select pin.
*
- * A common usage is that CSP0 controls LED's and CSP4 video chips.
+ * A common usage is that CSP0 controls LEDs and CSP4 video chips.
*/
unsigned long port_cse1_shadow;
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index 41d4a5f9328..61ce6273a89 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -7,7 +7,7 @@
*
* Ideas also taken from arch/arm.
*
- * Copyright (C) 2000, 2001 Axis Communications AB
+ * Copyright (C) 2000-2007 Axis Communications AB
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*
@@ -27,11 +27,10 @@
#include <asm/processor.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
+#include <arch/system.h>
#define DEBUG_SIG 0
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
/* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */
/* manipulate regs so that upon return, it will be re-executed */
@@ -40,119 +39,7 @@
*/
#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2;
-int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal. Define
- * dummy arguments to be able to reach the regs argument. (Note that this
- * arrangement relies on old_sigset_t occupying one register.)
- */
-int
-sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
-{
- sigset_t saveset;
-
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->r10 = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(0, &saveset, regs))
- /* We will get here twice: once to call the signal
- handler, then again to return from the
- sigsuspend system call. When calling the
- signal handler, R10 holds the signal number as
- set through do_signal. The sigsuspend call
- will return with the restored value set above;
- always -EINTR. */
- return regs->r10;
- }
-}
-
-/* Define dummy arguments to be able to reach the regs argument. (Note that
- * this arrangement relies on size_t occupying one register.)
- */
-int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13,
- long mof, long srp, struct pt_regs *regs)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->r10 = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(0, &saveset, regs))
- /* We will get here twice: once to call the signal
- handler, then again to return from the
- sigsuspend system call. When calling the
- signal handler, R10 holds the signal number as
- set through do_signal. The sigsuspend call
- will return with the restored value set above;
- always -EINTR. */
- return regs->r10;
- }
-}
-
-int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
- return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
- return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
- }
-
- return ret;
-}
-
-int
-sys_sigaltstack(const stack_t *uss, stack_t __user *uoss)
-{
- return do_sigaltstack(uss, uoss, rdusp());
-}
-
+void do_signal(int canrestart, struct pt_regs *regs);
/*
* Do a signal return; undo the signal stack.
@@ -205,7 +92,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
/* TODO: the other ports use regs->orig_XX to disable syscall checks
* after this completes, but we don't use that mechanism. maybe we can
- * use it now ?
+ * use it now ?
*/
return err;
@@ -214,11 +101,9 @@ badframe:
return 1;
}
-/* Define dummy arguments to be able to reach the regs argument. */
-
-asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
+asmlinkage int sys_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct sigframe __user *frame = (struct sigframe *)rdusp();
sigset_t set;
@@ -238,12 +123,8 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
sizeof(frame->extramask))))
goto badframe;
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
+ set_current_blocked(&set);
+
if (restore_sigcontext(regs, &frame->sc))
goto badframe;
@@ -254,13 +135,11 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
badframe:
force_sig(SIGSEGV, current);
return 0;
-}
-
-/* Define dummy arguments to be able to reach the regs argument. */
+}
-asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
- long mof, long srp, struct pt_regs *regs)
+asmlinkage int sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp();
sigset_t set;
@@ -277,16 +156,12 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
+ set_current_blocked(&set);
+
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return regs->r10;
@@ -294,14 +169,14 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
badframe:
force_sig(SIGSEGV, current);
return 0;
-}
+}
/*
* Set up a signal frame.
*/
-static int
-setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask)
+static int setup_sigcontext(struct sigcontext __user *sc,
+ struct pt_regs *regs, unsigned long mask)
{
int err = 0;
unsigned long usp = rdusp();
@@ -324,10 +199,11 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned lo
return err;
}
-/* figure out where we want to put the new signal frame - usually on the stack */
+/* Figure out where we want to put the new signal frame
+ * - usually on the stack. */
static inline void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
{
unsigned long sp = rdusp();
@@ -345,15 +221,15 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
}
/* grab and setup a signal frame.
- *
+ *
* basically we stack a lot of state info, and arrange for the
* user-mode program to return to the kernel using either a
* trampoline which performs the syscall sigreturn, or a provided
* user-mode trampoline.
*/
-static void setup_frame(int sig, struct k_sigaction *ka,
- sigset_t *set, struct pt_regs * regs)
+static int setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs *regs)
{
struct sigframe __user *frame;
unsigned long return_ip;
@@ -401,14 +277,15 @@ static void setup_frame(int sig, struct k_sigaction *ka,
wrusp((unsigned long)frame);
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs * regs)
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
unsigned long return_ip;
@@ -432,6 +309,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
+
if (err)
goto give_sigsegv;
@@ -443,9 +322,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* trampoline - the desired return ip is the retcode itself */
return_ip = (unsigned long)&frame->retcode;
/* This is movu.w __NR_rt_sigreturn, r9; break 13; */
- err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
- err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2));
- err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
+ err |= __put_user(0x9c5f, (short __user *)(frame->retcode+0));
+ err |= __put_user(__NR_rt_sigreturn,
+ (short __user *)(frame->retcode+2));
+ err |= __put_user(0xe93d, (short __user *)(frame->retcode+4));
}
if (err)
@@ -455,73 +335,74 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up registers for signal handler */
- regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */
- regs->srp = return_ip; /* what we enter LATER */
- regs->r10 = sig; /* first argument is signo */
- regs->r11 = (unsigned long) &frame->info; /* second argument is (siginfo_t *) */
- regs->r12 = 0; /* third argument is unused */
-
- /* actually move the usp to reflect the stacked frame */
-
+ /* What we enter NOW */
+ regs->irp = (unsigned long) ka->sa.sa_handler;
+ /* What we enter LATER */
+ regs->srp = return_ip;
+ /* First argument is signo */
+ regs->r10 = sig;
+ /* Second argument is (siginfo_t *) */
+ regs->r11 = (unsigned long)&frame->info;
+ /* Third argument is unused */
+ regs->r12 = 0;
+
+ /* Actually move the usp to reflect the stacked frame */
wrusp((unsigned long)frame);
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
/*
* OK, we're invoking a handler
- */
+ */
-static inline void
-handle_signal(int canrestart, unsigned long sig,
- siginfo_t *info, struct k_sigaction *ka,
- sigset_t *oldset, struct pt_regs * regs)
+static inline void handle_signal(int canrestart, unsigned long sig,
+ siginfo_t *info, struct k_sigaction *ka,
+ struct pt_regs *regs)
{
+ sigset_t *oldset = sigmask_to_save();
+ int ret;
+
/* Are we from a system call? */
if (canrestart) {
/* If so, check system call restarting.. */
switch (regs->r10) {
- case -ERESTART_RESTARTBLOCK:
- case -ERESTARTNOHAND:
- /* ERESTARTNOHAND means that the syscall should only be
- restarted if there was no handler for the signal, and since
- we only get here if there is a handler, we don't restart */
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ /* ERESTARTNOHAND means that the syscall should
+ * only be restarted if there was no handler for
+ * the signal, and since we only get here if there
+ * is a handler, we don't restart */
+ regs->r10 = -EINTR;
+ break;
+ case -ERESTARTSYS:
+ /* ERESTARTSYS means to restart the syscall if
+ * there is no handler or the handler was
+ * registered with SA_RESTART */
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->r10 = -EINTR;
break;
-
- case -ERESTARTSYS:
- /* ERESTARTSYS means to restart the syscall if there is no
- handler or the handler was registered with SA_RESTART */
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->r10 = -EINTR;
- break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- /* ERESTARTNOINTR means that the syscall should be called again
- after the signal handler returns. */
- RESTART_CRIS_SYS(regs);
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ /* ERESTARTNOINTR means that the syscall should
+ * be called again after the signal handler returns. */
+ RESTART_CRIS_SYS(regs);
}
}
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
- setup_frame(sig, ka, oldset, regs);
-
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
+ ret = setup_frame(sig, ka, oldset, regs);
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ if (ret == 0)
+ signal_delivered(sig, info, ka, regs, 0);
}
/*
@@ -536,7 +417,7 @@ handle_signal(int canrestart, unsigned long sig,
* mode below.
*/
-int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+void do_signal(int canrestart, struct pt_regs *regs)
{
siginfo_t info;
int signr;
@@ -549,16 +430,13 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
* if so.
*/
if (!user_mode(regs))
- return 1;
-
- if (!oldset)
- oldset = &current->blocked;
+ return;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
- handle_signal(canrestart, signr, &info, &ka, oldset, regs);
- return 1;
+ handle_signal(canrestart, signr, &info, &ka, regs);
+ return;
}
/* Did we come from a system call? */
@@ -569,10 +447,13 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
regs->r10 == -ERESTARTNOINTR) {
RESTART_CRIS_SYS(regs);
}
- if (regs->r10 == -ERESTART_RESTARTBLOCK){
- regs->r10 = __NR_restart_syscall;
+ if (regs->r10 == -ERESTART_RESTARTBLOCK) {
+ regs->r9 = __NR_restart_syscall;
regs->irp -= 2;
}
}
- return 0;
+
+ /* if there's no signal to deliver, we just put the saved sigmask
+ * back */
+ restore_saved_sigmask();
}
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
index 077e973c33f..b5eb5cd2f60 100644
--- a/arch/cris/arch-v10/kernel/time.c
+++ b/arch/cris/arch-v10/kernel/time.c
@@ -1,5 +1,4 @@
-/* $Id: time.c,v 1.5 2004/09/29 06:12:46 starvik Exp $
- *
+/*
* linux/arch/cris/arch-v10/kernel/time.c
*
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
@@ -14,22 +13,17 @@
#include <linux/swap.h>
#include <linux/sched.h>
#include <linux/init.h>
-#include <asm/arch/svinto.h>
+#include <linux/mm.h>
#include <asm/types.h>
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/delay.h>
-#include <asm/rtc.h>
+#include <asm/irq_regs.h>
/* define this if you need to use print_timestamp */
/* it will make jiffies at 96 hz instead of 100 hz though */
#undef USE_CASCADE_TIMERS
-extern void update_xtime_from_cmos(void);
-extern int set_rtc_mmss(unsigned long nowtime);
-extern int setup_irq(int, struct irqaction *);
-extern int have_rtc;
-
unsigned long get_ns_in_jiffie(void)
{
unsigned char timer_count, t1;
@@ -39,7 +33,7 @@ unsigned long get_ns_in_jiffie(void)
local_irq_save(flags);
timer_count = *R_TIMER0_DATA;
- presc_count = *R_TIM_PRESC_STATUS;
+ presc_count = *R_TIM_PRESC_STATUS;
/* presc_count might be wrapped */
t1 = *R_TIMER0_DATA;
@@ -55,73 +49,23 @@ unsigned long get_ns_in_jiffie(void)
presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
}
- ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) +
+ ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) +
( (presc_count) * (1000000000/PRESCALE_FREQ));
return ns;
}
-unsigned long do_slow_gettimeoffset(void)
+static u32 cris_v10_gettimeoffset(void)
{
- unsigned long count, t1;
- unsigned long usec_count = 0;
- unsigned short presc_count;
-
- static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */
- static unsigned long jiffies_p = 0;
-
- /*
- * cache volatile jiffies temporarily; we have IRQs turned off.
- */
- unsigned long jiffies_t;
+ u32 count;
/* The timer interrupt comes from Etrax timer 0. In order to get
* better precision, we check the current value. It might have
* underflowed already though.
*/
-
-#ifndef CONFIG_SVINTO_SIM
- /* Not available in the xsim simulator. */
count = *R_TIMER0_DATA;
- presc_count = *R_TIM_PRESC_STATUS;
- /* presc_count might be wrapped */
- t1 = *R_TIMER0_DATA;
- if (count != t1){
- /* it wrapped, read prescaler again... */
- presc_count = *R_TIM_PRESC_STATUS;
- count = t1;
- }
-#else
- count = 0;
- presc_count = 0;
-#endif
-
- jiffies_t = jiffies;
- /*
- * avoiding timer inconsistencies (they are rare, but they happen)...
- * there are one problem that must be avoided here:
- * 1. the timer counter underflows
- */
- if( jiffies_t == jiffies_p ) {
- if( count > count_p ) {
- /* Timer wrapped, use new count and prescale
- * increase the time corresponding to one jiffie
- */
- usec_count = 1000000/HZ;
- }
- } else
- jiffies_p = jiffies_t;
- count_p = count;
- if (presc_count >= PRESCALE_VALUE/2 ){
- presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2;
- } else {
- presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
- }
- /* Convert timer value to usec */
- usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) +
- (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000);
-
- return usec_count;
+ /* Convert timer value to nsec */
+ return (TIMER0_DIV - count) * (NSEC_PER_SEC/HZ)/TIMER0_DIV;
}
/* Excerpt from the Etrax100 HSDD about the built-in watchdog:
@@ -135,7 +79,7 @@ unsigned long do_slow_gettimeoffset(void)
* by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit
* and a 3-bit key value. The effect of writing to the R_WATCHDOG register is
* described in the table below:
- *
+ *
* Watchdog Value written:
* state: To enable: To key: Operation:
* -------- ---------- ------- ----------
@@ -144,15 +88,15 @@ unsigned long do_slow_gettimeoffset(void)
* started 0 ~key Stop watchdog
* started 1 ~key Restart watchdog with key = ~key.
* started X new_key_val Change key to new_key_val.
- *
+ *
* Note: '~' is the bitwise NOT operator.
- *
+ *
*/
/* right now, starting the watchdog is the same as resetting it */
#define start_watchdog reset_watchdog
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#ifdef CONFIG_ETRAX_WATCHDOG
static int watchdog_key = 0; /* arbitrary number */
#endif
@@ -162,10 +106,9 @@ static int watchdog_key = 0; /* arbitrary number */
#define WATCHDOG_MIN_FREE_PAGES 8
-void
-reset_watchdog(void)
+void reset_watchdog(void)
{
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
/* only keep watchdog happy as long as we have memory left! */
if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
/* reset the watchdog with the inverse of the old key */
@@ -178,31 +121,25 @@ reset_watchdog(void)
/* stop the watchdog - we still need the correct key */
-void
-stop_watchdog(void)
+void stop_watchdog(void)
{
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#ifdef CONFIG_ETRAX_WATCHDOG
watchdog_key ^= 0x7; /* invert key, which is 3 bits */
*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
IO_STATE(R_WATCHDOG, enable, stop);
-#endif
+#endif
}
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
+
+extern void cris_do_profile(struct pt_regs *regs);
/*
* timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
*/
-
-//static unsigned short myjiff; /* used by our debug routine print_timestamp */
-
-extern void cris_do_profile(struct pt_regs *regs);
-
-static inline irqreturn_t
-timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
{
+ struct pt_regs *regs = get_irq_regs();
/* acknowledge the timer irq */
#ifdef USE_CASCADE_TIMERS
@@ -216,74 +153,41 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
IO_STATE( R_TIMER_CTRL, tm0, run) |
IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
#else
- *R_TIMER_CTRL = r_timer_ctrl_shadow |
- IO_STATE(R_TIMER_CTRL, i0, clr);
+ *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i0, clr);
#endif
/* reset watchdog otherwise it resets us! */
-
reset_watchdog();
-
+
+ /* Update statistics. */
+ update_process_times(user_mode(regs));
+
/* call the real timer interrupt handler */
+ xtime_update(1);
- do_timer(1);
-
cris_do_profile(regs); /* Save profiling information */
-
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- *
- * The division here is not time critical since it will run once in
- * 11 minutes
- */
- if (ntp_synced() &&
- xtime.tv_sec > last_rtc_update + 660 &&
- (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 &&
- (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) {
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
- }
return IRQ_HANDLED;
}
-/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain
- * it needs to be IRQF_DISABLED to make the jiffies update work properly
- */
+/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain */
-static struct irqaction irq2 = { timer_interrupt, IRQF_SHARED | IRQF_DISABLED,
- CPU_MASK_NONE, "timer", NULL, NULL};
-
-void __init
-time_init(void)
-{
- /* probe for the RTC and read it if it exists
- * Before the RTC can be probed the loops_per_usec variable needs
- * to be initialized to make usleep work. A better value for
- * loops_per_usec is calculated by the kernel later once the
- * clock has started.
- */
- loops_per_usec = 50;
+static struct irqaction irq2 = {
+ .handler = timer_interrupt,
+ .flags = IRQF_SHARED,
+ .name = "timer",
+};
- if(RTC_INIT() < 0) {
- /* no RTC, start at 1980 */
- xtime.tv_sec = 0;
- xtime.tv_nsec = 0;
- have_rtc = 0;
- } else {
- /* get the current time */
- have_rtc = 1;
- update_xtime_from_cmos();
- }
+void __init time_init(void)
+{
+ arch_gettimeoffset = cris_v10_gettimeoffset;
- /*
- * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
- * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
+ /* probe for the RTC and read it if it exists
+ * Before the RTC can be probed the loops_per_usec variable needs
+ * to be initialized to make usleep work. A better value for
+ * loops_per_usec is calculated by the kernel later once the
+ * clock has started.
*/
- set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
+ loops_per_usec = 50;
/* Setup the etrax timers
* Base frequency is 25000 hz, divider 250 -> 100 HZ
@@ -292,7 +196,7 @@ time_init(void)
* Remember that linux/timex.h contains #defines that rely on the
* timer settings below (hz and divide factor) !!!
*/
-
+
#ifdef USE_CASCADE_TIMERS
*R_TIMER_CTRL =
IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
@@ -303,8 +207,8 @@ time_init(void)
IO_STATE( R_TIMER_CTRL, i0, nop) |
IO_STATE( R_TIMER_CTRL, tm0, stop_ld) |
IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
-
- *R_TIMER_CTRL = r_timer_ctrl_shadow =
+
+ *R_TIMER_CTRL = r_timer_ctrl_shadow =
IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
IO_STATE( R_TIMER_CTRL, i1, nop) |
@@ -314,18 +218,18 @@ time_init(void)
IO_STATE( R_TIMER_CTRL, tm0, run) |
IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
#else
- *R_TIMER_CTRL =
- IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) |
+ *R_TIMER_CTRL =
+ IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) |
IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) |
- IO_STATE(R_TIMER_CTRL, i1, nop) |
+ IO_STATE(R_TIMER_CTRL, i1, nop) |
IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) |
IO_STATE(R_TIMER_CTRL, i0, nop) |
IO_STATE(R_TIMER_CTRL, tm0, stop_ld) |
IO_STATE(R_TIMER_CTRL, clksel0, flexible);
-
+
*R_TIMER_CTRL = r_timer_ctrl_shadow =
- IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) |
+ IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) |
IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) |
IO_STATE(R_TIMER_CTRL, i1, nop) |
IO_STATE(R_TIMER_CTRL, tm1, run) |
@@ -337,16 +241,14 @@ time_init(void)
*R_TIMER_PRESCALE = PRESCALE_VALUE;
#endif
- *R_IRQ_MASK0_SET =
- IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */
-
- /* now actually register the timer irq handler that calls timer_interrupt() */
-
+ /* unmask the timer irq */
+ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set);
+
+ /* now actually register the irq handler that calls timer_interrupt() */
setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */
/* enable watchdog if we should use one */
-
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
printk("Enabling watchdog...\n");
start_watchdog();
@@ -359,9 +261,7 @@ time_init(void)
driver or infrastructure support yet. */
asm ("setf m");
- *R_IRQ_MASK0_SET =
- IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
- *R_VECT_MASK_SET =
- IO_STATE(R_VECT_MASK_SET, nmi, set);
+ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
+ *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, nmi, set);
#endif
}
diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c
index 4becc1bcced..7001beda716 100644
--- a/arch/cris/arch-v10/kernel/traps.c
+++ b/arch/cris/arch-v10/kernel/traps.c
@@ -1,138 +1,131 @@
-/* $Id: traps.c,v 1.4 2005/04/24 18:47:55 starvik Exp $
+/*
+ * Helper functions for trap handlers
*
- * linux/arch/cris/arch-v10/traps.c
+ * Copyright (C) 2000-2007, Axis Communications AB.
*
- * Heler functions for trap handlers
- *
- * Copyright (C) 2000-2002 Axis Communications AB
- *
- * Authors: Bjorn Wesen
- * Hans-Peter Nilsson
+ * Authors: Bjorn Wesen
+ * Hans-Peter Nilsson
*
*/
#include <linux/ptrace.h>
#include <asm/uaccess.h>
-#include <asm/arch/sv_addr_ag.h>
-
-extern int raw_printk(const char *fmt, ...);
+#include <arch/sv_addr_ag.h>
+#include <arch/system.h>
-void
-show_registers(struct pt_regs * regs)
+void
+show_registers(struct pt_regs *regs)
{
- /* We either use rdusp() - the USP register, which might not
- correspond to the current process for all cases we're called,
- or we use the current->thread.usp, which is not up to date for
- the current process. Experience shows we want the USP
- register. */
+ /*
+ * It's possible to use either the USP register or current->thread.usp.
+ * USP might not correspond to the current process for all cases this
+ * function is called, and current->thread.usp isn't up to date for the
+ * current process. Experience shows that using USP is the way to go.
+ */
unsigned long usp = rdusp();
- raw_printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
- regs->irp, regs->srp, regs->dccr, usp, regs->mof );
- raw_printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
+ printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
+ regs->irp, regs->srp, regs->dccr, usp, regs->mof);
+
+ printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
regs->r0, regs->r1, regs->r2, regs->r3);
- raw_printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
+
+ printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
regs->r4, regs->r5, regs->r6, regs->r7);
- raw_printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
+
+ printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
regs->r8, regs->r9, regs->r10, regs->r11);
- raw_printk("r12: %08lx r13: %08lx oR10: %08lx sp: %08lx\n",
- regs->r12, regs->r13, regs->orig_r10, regs);
- raw_printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
- raw_printk("Process %s (pid: %d, stackpage=%08lx)\n",
+
+ printk("r12: %08lx r13: %08lx oR10: %08lx sp: %08lx\n",
+ regs->r12, regs->r13, regs->orig_r10, (long unsigned)regs);
+
+ printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
+
+ printk("Process %s (pid: %d, stackpage=%08lx)\n",
current->comm, current->pid, (unsigned long)current);
/*
- * When in-kernel, we also print out the stack and code at the
- * time of the fault..
- */
- if (! user_mode(regs)) {
- int i;
+ * When in-kernel, we also print out the stack and code at the
+ * time of the fault..
+ */
+ if (!user_mode(regs)) {
+ int i;
- show_stack(NULL, (unsigned long*)usp);
+ show_stack(NULL, (unsigned long *)usp);
- /* Dump kernel stack if the previous dump wasn't one. */
+ /*
+ * If the previous stack-dump wasn't a kernel one, dump the
+ * kernel stack now.
+ */
if (usp != 0)
- show_stack (NULL, NULL);
-
- raw_printk("\nCode: ");
- if(regs->irp < PAGE_OFFSET)
- goto bad;
-
- /* Often enough the value at regs->irp does not point to
- the interesting instruction, which is most often the
- _previous_ instruction. So we dump at an offset large
- enough that instruction decoding should be in sync at
- the interesting point, but small enough to fit on a row
- (sort of). We point out the regs->irp location in a
- ksymoops-friendly way by wrapping the byte for that
- address in parentheses. */
- for(i = -12; i < 12; i++)
- {
- unsigned char c;
- if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
-bad:
- raw_printk(" Bad IP value.");
- break;
- }
+ show_stack(NULL, NULL);
+
+ printk("\nCode: ");
+
+ if (regs->irp < PAGE_OFFSET)
+ goto bad_value;
+
+ /*
+ * Quite often the value at regs->irp doesn't point to the
+ * interesting instruction, which often is the previous
+ * instruction. So dump at an offset large enough that the
+ * instruction decoding should be in sync at the interesting
+ * point, but small enough to fit on a row. The regs->irp
+ * location is pointed out in a ksymoops-friendly way by
+ * wrapping the byte for that address in parenthesises.
+ */
+ for (i = -12; i < 12; i++) {
+ unsigned char c;
+
+ if (__get_user(c, &((unsigned char *)regs->irp)[i])) {
+bad_value:
+ printk(" Bad IP value.");
+ break;
+ }
if (i == 0)
- raw_printk("(%02x) ", c);
+ printk("(%02x) ", c);
else
- raw_printk("%02x ", c);
- }
- raw_printk("\n");
- }
+ printk("%02x ", c);
+ }
+ printk("\n");
+ }
}
-/* Called from entry.S when the watchdog has bitten
- * We print out something resembling an oops dump, and if
- * we have the nice doggy development flag set, we halt here
- * instead of rebooting.
- */
-
-extern void reset_watchdog(void);
-extern void stop_watchdog(void);
-
-
void
-watchdog_bite_hook(struct pt_regs *regs)
+arch_enable_nmi(void)
{
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
- local_irq_disable();
- stop_watchdog();
- show_registers(regs);
- while(1) /* nothing */;
-#else
- show_registers(regs);
-#endif
+ asm volatile ("setf m");
}
-/* This is normally the 'Oops' routine */
-void
-die_if_kernel(const char * str, struct pt_regs * regs, long err)
+extern void (*nmi_handler)(struct pt_regs *);
+void handle_nmi(struct pt_regs *regs)
{
- if(user_mode(regs))
- return;
-
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
- /* This printout might take too long and trigger the
- * watchdog normally. If we're in the nice doggy
- * development mode, stop the watchdog during printout.
- */
- stop_watchdog();
-#endif
-
- raw_printk("%s: %04lx\n", str, err & 0xffff);
-
- show_registers(regs);
-
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
- reset_watchdog();
-#endif
- do_exit(SIGSEGV);
+ if (nmi_handler)
+ nmi_handler(regs);
+
+ /* Wait until nmi is no longer active. (We enable NMI immediately after
+ returning from this function, and we don't want it happening while
+ exiting from the NMI interrupt handler.) */
+ while (*R_IRQ_MASK0_RD & IO_STATE(R_IRQ_MASK0_RD, nmi_pin, active))
+ ;
}
-void arch_enable_nmi(void)
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void
+handle_BUG(struct pt_regs *regs)
{
- asm volatile("setf m");
+ struct bug_frame f;
+ unsigned char c;
+ unsigned long irp = regs->irp;
+
+ if (__copy_from_user(&f, (const void __user *)(irp - 8), sizeof f))
+ return;
+ if (f.prefix != BUG_PREFIX || f.magic != BUG_MAGIC)
+ return;
+ if (__get_user(c, f.filename))
+ f.filename = "<bad filename>";
+
+ printk("kernel BUG at %s:%d!\n", f.filename, f.line);
}
+#endif