diff options
Diffstat (limited to 'arch/cris/arch-v10/kernel')
| -rw-r--r-- | arch/cris/arch-v10/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/asm-offsets.c | 47 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/crisksyms.c | 2 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/debugport.c | 164 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/dma.c | 10 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/entry.S | 536 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/fasttimer.c | 649 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/head.S | 352 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/io_interface_mux.c | 521 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/irq.c | 128 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/kgdb.c | 985 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/process.c | 141 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/ptrace.c | 99 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/setup.c | 6 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/shadows.c | 5 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/signal.c | 294 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/time.c | 219 | ||||
| -rw-r--r-- | arch/cris/arch-v10/kernel/traps.c | 201 |
18 files changed, 1643 insertions, 2717 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 34528da9881..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 prefered 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 = ® - - 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 = ® - - 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, ®_cont); if (status == SUCCESS) { - - *ptr++ = highhex (regno); - *ptr++ = lowhex (regno); + ptr = hex_byte_pack(ptr, regno); *ptr++ = ':'; ptr = mem2hex(ptr, (unsigned char *)®_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 (®_g, ®, 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 (®_g, ®, sizeof(registers)); - /* Replace the content available on the stack. */ - if (current_thread_g != executing_task) { - copy_registers_from_stack (current_thread_g, ®_g); - } - mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)®_g, sizeof(registers)); -#else - mem2hex(remcomOutBuffer, (char *)®, 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 *)®_g, &remcomInBuffer[1], sizeof(registers)); - if (current_thread_g == executing_task) { - copy_registers (®, ®_g, sizeof(registers)); - } - else { - copy_registers_to_stack(current_thread_g, ®_g); - } -#else - hex2mem((char *)®, &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(®s, 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, ®s, 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 961c0d58ded..bfddfb99401 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -6,7 +6,6 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> @@ -16,7 +15,6 @@ #include <asm/uaccess.h> #include <asm/page.h> #include <asm/pgtable.h> -#include <asm/system.h> #include <asm/processor.h> /* @@ -66,6 +64,7 @@ void ptrace_disable(struct task_struct *child) { /* Todo - pending singlesteps? */ + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } /* @@ -76,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; } @@ -114,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; @@ -211,7 +140,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - data += sizeof(long); + datap++; } break; @@ -235,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 19bcad05716..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) * @@ -16,7 +16,6 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> @@ -28,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 */ @@ -41,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(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->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(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->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. @@ -206,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; @@ -215,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; @@ -239,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(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - + set_current_blocked(&set); + if (restore_sigcontext(regs, &frame->sc)) goto badframe; @@ -255,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; @@ -278,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(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->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; @@ -295,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(); @@ -325,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(); @@ -346,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; @@ -402,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; @@ -433,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; @@ -444,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) @@ -456,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(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + if (ret == 0) + signal_delivered(sig, info, ka, regs, 0); } /* @@ -537,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; @@ -550,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 = ¤t->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? */ @@ -570,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 9c22b76e129..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; @@ -38,9 +32,8 @@ unsigned long get_ns_in_jiffie(void) unsigned long flags; local_irq_save(flags); - local_irq_disable(); 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; @@ -56,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: @@ -136,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: * -------- ---------- ------- ---------- @@ -145,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 @@ -163,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 */ @@ -179,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 @@ -217,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(regs); - 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 @@ -293,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) | @@ -304,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) | @@ -315,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) | @@ -338,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(); @@ -360,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 |
