diff options
Diffstat (limited to 'arch/cris/arch-v32/kernel')
-rw-r--r-- | arch/cris/arch-v32/kernel/Makefile | 5 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/arbiter.c | 296 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/crisksyms.c | 7 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/debugport.c | 342 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/dma.c | 224 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/entry.S | 83 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/fasttimer.c | 535 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/head.S | 204 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/io.c | 153 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/irq.c | 274 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/kgdb.c | 12 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/process.c | 14 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/ptrace.c | 10 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/signal.c | 144 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/smp.c | 31 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/time.c | 237 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/traps.c | 192 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/vcs_hook.c | 96 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/vcs_hook.h | 42 |
19 files changed, 974 insertions, 1927 deletions
diff --git a/arch/cris/arch-v32/kernel/Makefile b/arch/cris/arch-v32/kernel/Makefile index 5d5b613cde8c..993d987b0078 100644 --- a/arch/cris/arch-v32/kernel/Makefile +++ b/arch/cris/arch-v32/kernel/Makefile @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.11 2004/12/17 10:16:13 starvik Exp $ # # Makefile for the linux kernel. # @@ -6,9 +5,9 @@ extra-y := head.o -obj-y := entry.o traps.o irq.o debugport.o dma.o pinmux.o \ +obj-y := entry.o traps.o irq.o debugport.o \ process.o ptrace.o setup.o signal.o traps.o time.o \ - arbiter.o io.o + cache.o cacheflush.o obj-$(CONFIG_ETRAXFS_SIM) += vcs_hook.o diff --git a/arch/cris/arch-v32/kernel/arbiter.c b/arch/cris/arch-v32/kernel/arbiter.c deleted file mode 100644 index 420a5312ed03..000000000000 --- a/arch/cris/arch-v32/kernel/arbiter.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Memory arbiter functions. Allocates bandwidth through the - * arbiter and sets up arbiter breakpoints. - * - * The algorithm first assigns slots to the clients that has specified - * bandwidth (e.g. ethernet) and then the remaining slots are divided - * on all the active clients. - * - * Copyright (c) 2004, 2005 Axis Communications AB. - */ - -#include <asm/arch/hwregs/reg_map.h> -#include <asm/arch/hwregs/reg_rdwr.h> -#include <asm/arch/hwregs/marb_defs.h> -#include <asm/arch/arbiter.h> -#include <asm/arch/hwregs/intr_vect.h> -#include <linux/interrupt.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/spinlock.h> -#include <asm/io.h> - -struct crisv32_watch_entry -{ - unsigned long instance; - watch_callback* cb; - unsigned long start; - unsigned long end; - int used; -}; - -#define NUMBER_OF_BP 4 -#define NBR_OF_CLIENTS 14 -#define NBR_OF_SLOTS 64 -#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */ -#define INTMEM_BANDWIDTH 400000000 -#define NBR_OF_REGIONS 2 - -static struct crisv32_watch_entry watches[NUMBER_OF_BP] = -{ - {regi_marb_bp0}, - {regi_marb_bp1}, - {regi_marb_bp2}, - {regi_marb_bp3} -}; - -static int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; -static int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; -static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH}; - -DEFINE_SPINLOCK(arbiter_lock); - -static irqreturn_t -crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs); - -static void crisv32_arbiter_config(int region) -{ - int slot; - int client; - int interval = 0; - int val[NBR_OF_SLOTS]; - - for (slot = 0; slot < NBR_OF_SLOTS; slot++) - val[slot] = NBR_OF_CLIENTS + 1; - - for (client = 0; client < NBR_OF_CLIENTS; client++) - { - int pos; - if (!requested_slots[region][client]) - continue; - interval = NBR_OF_SLOTS / requested_slots[region][client]; - pos = 0; - while (pos < NBR_OF_SLOTS) - { - if (val[pos] != NBR_OF_CLIENTS + 1) - pos++; - else - { - val[pos] = client; - pos += interval; - } - } - } - - client = 0; - for (slot = 0; slot < NBR_OF_SLOTS; slot++) - { - if (val[slot] == NBR_OF_CLIENTS + 1) - { - int first = client; - while(!active_clients[region][client]) { - client = (client + 1) % NBR_OF_CLIENTS; - if (client == first) - break; - } - val[slot] = client; - client = (client + 1) % NBR_OF_CLIENTS; - } - if (region == EXT_REGION) - REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, val[slot]); - else if (region == INT_REGION) - REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, val[slot]); - } -} - -extern char _stext, _etext; - -static void crisv32_arbiter_init(void) -{ - static int initialized = 0; - - if (initialized) - return; - - initialized = 1; - - /* CPU caches are active. */ - active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1; - crisv32_arbiter_config(EXT_REGION); - crisv32_arbiter_config(INT_REGION); - - if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED, - "arbiter", NULL)) - printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); - -#ifndef CONFIG_ETRAX_KGDB - /* Global watch for writes to kernel text segment. */ - crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext, - arbiter_all_clients, arbiter_all_write, NULL); -#endif -} - - - -int crisv32_arbiter_allocate_bandwidth(int client, int region, - unsigned long bandwidth) -{ - int i; - int total_assigned = 0; - int total_clients = 0; - int req; - - crisv32_arbiter_init(); - - for (i = 0; i < NBR_OF_CLIENTS; i++) - { - total_assigned += requested_slots[region][i]; - total_clients += active_clients[region][i]; - } - req = NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); - - if (total_assigned + total_clients + req + 1 > NBR_OF_SLOTS) - return -ENOMEM; - - active_clients[region][client] = 1; - requested_slots[region][client] = req; - crisv32_arbiter_config(region); - - return 0; -} - -int crisv32_arbiter_watch(unsigned long start, unsigned long size, - unsigned long clients, unsigned long accesses, - watch_callback* cb) -{ - int i; - - crisv32_arbiter_init(); - - if (start > 0x80000000) { - printk("Arbiter: %lX doesn't look like a physical address", start); - return -EFAULT; - } - - spin_lock(&arbiter_lock); - - for (i = 0; i < NUMBER_OF_BP; i++) { - if (!watches[i].used) { - reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); - - watches[i].used = 1; - watches[i].start = start; - watches[i].end = start + size; - watches[i].cb = cb; - - REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, watches[i].start); - REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, watches[i].end); - REG_WR_INT(marb_bp, watches[i].instance, rw_op, accesses); - REG_WR_INT(marb_bp, watches[i].instance, rw_clients, clients); - - if (i == 0) - intr_mask.bp0 = regk_marb_yes; - else if (i == 1) - intr_mask.bp1 = regk_marb_yes; - else if (i == 2) - intr_mask.bp2 = regk_marb_yes; - else if (i == 3) - intr_mask.bp3 = regk_marb_yes; - - REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); - spin_unlock(&arbiter_lock); - - return i; - } - } - spin_unlock(&arbiter_lock); - return -ENOMEM; -} - -int crisv32_arbiter_unwatch(int id) -{ - reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); - - crisv32_arbiter_init(); - - spin_lock(&arbiter_lock); - - if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) { - spin_unlock(&arbiter_lock); - return -EINVAL; - } - - memset(&watches[id], 0, sizeof(struct crisv32_watch_entry)); - - if (id == 0) - intr_mask.bp0 = regk_marb_no; - else if (id == 1) - intr_mask.bp2 = regk_marb_no; - else if (id == 2) - intr_mask.bp2 = regk_marb_no; - else if (id == 3) - intr_mask.bp3 = regk_marb_no; - - REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); - - spin_unlock(&arbiter_lock); - return 0; -} - -extern void show_registers(struct pt_regs *regs); - -static irqreturn_t -crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs) -{ - reg_marb_r_masked_intr masked_intr = REG_RD(marb, regi_marb, r_masked_intr); - reg_marb_bp_r_brk_clients r_clients; - reg_marb_bp_r_brk_addr r_addr; - reg_marb_bp_r_brk_op r_op; - reg_marb_bp_r_brk_first_client r_first; - reg_marb_bp_r_brk_size r_size; - reg_marb_bp_rw_ack ack = {0}; - reg_marb_rw_ack_intr ack_intr = {.bp0=1,.bp1=1,.bp2=1,.bp3=1}; - struct crisv32_watch_entry* watch; - - if (masked_intr.bp0) { - watch = &watches[0]; - ack_intr.bp0 = regk_marb_yes; - } else if (masked_intr.bp1) { - watch = &watches[1]; - ack_intr.bp1 = regk_marb_yes; - } else if (masked_intr.bp2) { - watch = &watches[2]; - ack_intr.bp2 = regk_marb_yes; - } else if (masked_intr.bp3) { - watch = &watches[3]; - ack_intr.bp3 = regk_marb_yes; - } else { - return IRQ_NONE; - } - - /* Retrieve all useful information and print it. */ - r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients); - r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr); - r_op = REG_RD(marb_bp, watch->instance, r_brk_op); - r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client); - r_size = REG_RD(marb_bp, watch->instance, r_brk_size); - - printk("Arbiter IRQ\n"); - printk("Clients %X addr %X op %X first %X size %X\n", - REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size)); - - REG_WR(marb_bp, watch->instance, rw_ack, ack); - REG_WR(marb, regi_marb, rw_ack_intr, ack_intr); - - printk("IRQ occured at %lX\n", regs->erp); - - if (watch->cb) - watch->cb(); - - - return IRQ_HANDLED; -} diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c index e513da711245..77d02c15a7fc 100644 --- a/arch/cris/arch-v32/kernel/crisksyms.c +++ b/arch/cris/arch-v32/kernel/crisksyms.c @@ -2,7 +2,8 @@ #include <linux/irq.h> #include <asm/arch/dma.h> #include <asm/arch/intmem.h> -#include <asm/arch/pinmux.h> +#include <asm/arch/mach/pinmux.h> +#include <asm/arch/io.h> /* Functions for allocating DMA channels */ EXPORT_SYMBOL(crisv32_request_dma); @@ -16,7 +17,11 @@ EXPORT_SYMBOL(crisv32_intmem_virt_to_phys); /* Functions for handling pinmux */ EXPORT_SYMBOL(crisv32_pinmux_alloc); +EXPORT_SYMBOL(crisv32_pinmux_alloc_fixed); EXPORT_SYMBOL(crisv32_pinmux_dealloc); +EXPORT_SYMBOL(crisv32_pinmux_dealloc_fixed); +EXPORT_SYMBOL(crisv32_io_get_name); +EXPORT_SYMBOL(crisv32_io_get); /* Functions masking/unmasking interrupts */ EXPORT_SYMBOL(mask_irq); diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c index d1272ad92153..15af4c293157 100644 --- a/arch/cris/arch-v32/kernel/debugport.c +++ b/arch/cris/arch-v32/kernel/debugport.c @@ -4,17 +4,12 @@ #include <linux/console.h> #include <linux/init.h> -#include <linux/major.h> -#include <linux/delay.h> -#include <linux/tty.h> #include <asm/system.h> -#include <asm/io.h> -#include <asm/arch/hwregs/ser_defs.h> -#include <asm/arch/hwregs/dma_defs.h> -#include <asm/arch/pinmux.h> - -#include <asm/irq.h> -#include <asm/arch/hwregs/intr_vect_defs.h> +#include <hwregs/reg_rdwr.h> +#include <hwregs/reg_map.h> +#include <hwregs/ser_defs.h> +#include <hwregs/dma_defs.h> +#include <asm/arch/mach/pinmux.h> struct dbg_port { @@ -59,45 +54,50 @@ struct dbg_port ports[] = 115200, 'N', 8 - } + }, +#if CONFIG_ETRAX_SERIAL_PORTS == 5 + { + 4, + regi_ser4, + 0, + 115200, + 'N', + 8 + }, +#endif }; static struct dbg_port *port = #if defined(CONFIG_ETRAX_DEBUG_PORT0) -&ports[0]; + &ports[0]; #elif defined(CONFIG_ETRAX_DEBUG_PORT1) -&ports[1]; + &ports[1]; #elif defined(CONFIG_ETRAX_DEBUG_PORT2) -&ports[2]; + &ports[2]; #elif defined(CONFIG_ETRAX_DEBUG_PORT3) -&ports[3]; + &ports[3]; +#elif defined(CONFIG_ETRAX_DEBUG_PORT4) + &ports[4]; #else -NULL; + NULL; #endif #ifdef CONFIG_ETRAX_KGDB static struct dbg_port *kgdb_port = #if defined(CONFIG_ETRAX_KGDB_PORT0) -&ports[0]; + &ports[0]; #elif defined(CONFIG_ETRAX_KGDB_PORT1) -&ports[1]; + &ports[1]; #elif defined(CONFIG_ETRAX_KGDB_PORT2) -&ports[2]; + &ports[2]; #elif defined(CONFIG_ETRAX_KGDB_PORT3) -&ports[3]; + &ports[3]; +#elif defined(CONFIG_ETRAX_KGDB_PORT4) + &ports[4]; #else -NULL; + NULL; #endif #endif -#ifdef CONFIG_ETRAXFS_SIM -extern void print_str( const char *str ); -static char buffer[1024]; -static char msg[] = "Debug: "; -static int buffer_pos = sizeof(msg) - 1; -#endif - -extern struct tty_driver *serial_driver; - static void start_port(struct dbg_port* p) { @@ -114,6 +114,10 @@ start_port(struct dbg_port* p) crisv32_pinmux_alloc_fixed(pinmux_ser2); else if (p->nbr == 3) crisv32_pinmux_alloc_fixed(pinmux_ser3); +#if CONFIG_ETRAX_SERIAL_PORTS == 5 + else if (p->nbr == 4) + crisv32_pinmux_alloc_fixed(pinmux_ser4); +#endif /* Set up serial port registers */ reg_ser_rw_tr_ctrl tr_ctrl = {0}; @@ -156,124 +160,21 @@ start_port(struct dbg_port* p) REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl); } -/* No debug */ -#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL - -static void -console_write(struct console *co, const char *buf, unsigned int len) -{ - return; -} - -/* Target debug */ -#elif !defined(CONFIG_ETRAXFS_SIM) - -static void -console_write_direct(struct console *co, const char *buf, unsigned int len) -{ - int i; - reg_ser_r_stat_din stat; - reg_ser_rw_tr_dma_en tr_dma_en, old; - - /* Switch to manual mode */ - tr_dma_en = old = REG_RD (ser, port->instance, rw_tr_dma_en); - if (tr_dma_en.en == regk_ser_yes) { - tr_dma_en.en = regk_ser_no; - REG_WR(ser, port->instance, rw_tr_dma_en, tr_dma_en); - } - - /* Send data */ - for (i = 0; i < len; i++) { - /* LF -> CRLF */ - if (buf[i] == '\n') { - do { - stat = REG_RD (ser, port->instance, r_stat_din); - } while (!stat.tr_rdy); - REG_WR_INT (ser, port->instance, rw_dout, '\r'); - } - /* Wait until transmitter is ready and send.*/ - do { - stat = REG_RD (ser, port->instance, r_stat_din); - } while (!stat.tr_rdy); - REG_WR_INT (ser, port->instance, rw_dout, buf[i]); - } - - /* Restore mode */ - if (tr_dma_en.en != old.en) - REG_WR(ser, port->instance, rw_tr_dma_en, old); -} - -static void -console_write(struct console *co, const char *buf, unsigned int len) -{ - if (!port) - return; - console_write_direct(co, buf, len); -} - - - -#else - -/* VCS debug */ - -static void -console_write(struct console *co, const char *buf, unsigned int len) -{ - char* pos; - pos = memchr(buf, '\n', len); - if (pos) { - int l = ++pos - buf; - memcpy(buffer + buffer_pos, buf, l); - memcpy(buffer, msg, sizeof(msg) - 1); - buffer[buffer_pos + l] = '\0'; - print_str(buffer); - buffer_pos = sizeof(msg) - 1; - if (pos - buf != len) { - memcpy(buffer + buffer_pos, pos, len - l); - buffer_pos += len - l; - } - } else { - memcpy(buffer + buffer_pos, buf, len); - buffer_pos += len; - } -} - -#endif - -int raw_printk(const char *fmt, ...) -{ - static char buf[1024]; - int printed_len; - va_list args; - va_start(args, fmt); - printed_len = vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - console_write(NULL, buf, strlen(buf)); - return printed_len; -} - -void -stupid_debug(char* buf) -{ - console_write(NULL, buf, strlen(buf)); -} - #ifdef CONFIG_ETRAX_KGDB /* Use polling to get a single character from the kernel debug port */ int getDebugChar(void) { - reg_ser_rs_status_data stat; + reg_ser_rs_stat_din stat; reg_ser_rw_ack_intr ack_intr = { 0 }; do { - stat = REG_RD(ser, kgdb_instance, rs_status_data); - } while (!stat.data_avail); + stat = REG_RD(ser, kgdb_port->instance, rs_stat_din); + } while (!stat.dav); /* Ack the data_avail interrupt. */ - ack_intr.data_avail = 1; - REG_WR(ser, kgdb_instance, rw_ack_intr, ack_intr); + ack_intr.dav = 1; + REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr); return stat.data; } @@ -282,173 +183,18 @@ getDebugChar(void) void putDebugChar(int val) { - reg_ser_r_status_data stat; + reg_ser_r_stat_din stat; do { - stat = REG_RD (ser, kgdb_instance, r_status_data); - } while (!stat.tr_ready); - REG_WR (ser, kgdb_instance, rw_data_out, REG_TYPE_CONV(reg_ser_rw_data_out, int, val)); + stat = REG_RD(ser, kgdb_port->instance, r_stat_din); + } while (!stat.tr_rdy); + REG_WR_INT(ser, kgdb_port->instance, rw_dout, val); } #endif /* CONFIG_ETRAX_KGDB */ -static int __init -console_setup(struct console *co, char *options) -{ - char* s; - - if (options) { - port = &ports[co->index]; - port->baudrate = 115200; - port->parity = 'N'; - port->bits = 8; - port->baudrate = simple_strtoul(options, NULL, 10); - s = options; - while(*s >= '0' && *s <= '9') - s++; - if (*s) port->parity = *s++; - if (*s) port->bits = *s++ - '0'; - port->started = 0; - start_port(port); - } - return 0; -} - -/* This is a dummy serial device that throws away anything written to it. - * This is used when no debug output is wanted. - */ -static struct tty_driver dummy_driver; - -static int dummy_open(struct tty_struct *tty, struct file * filp) -{ - return 0; -} - -static void dummy_close(struct tty_struct *tty, struct file * filp) -{ -} - -static int dummy_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - return count; -} - -static int -dummy_write_room(struct tty_struct *tty) -{ - return 8192; -} - -void __init -init_dummy_console(void) -{ - memset(&dummy_driver, 0, sizeof(struct tty_driver)); - dummy_driver.driver_name = "serial"; - dummy_driver.name = "ttyS"; - dummy_driver.major = TTY_MAJOR; - dummy_driver.minor_start = 68; - dummy_driver.num = 1; /* etrax100 has 4 serial ports */ - dummy_driver.type = TTY_DRIVER_TYPE_SERIAL; - dummy_driver.subtype = SERIAL_TYPE_NORMAL; - dummy_driver.init_termios = tty_std_termios; - dummy_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ - dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - - dummy_driver.open = dummy_open; - dummy_driver.close = dummy_close; - dummy_driver.write = dummy_write; - dummy_driver.write_room = dummy_write_room; - if (tty_register_driver(&dummy_driver)) - panic("Couldn't register dummy serial driver\n"); -} - -static struct tty_driver* -crisv32_console_device(struct console* co, int *index) -{ - if (port) - *index = port->nbr; - return port ? serial_driver : &dummy_driver; -} - -static struct console sercons = { - name : "ttyS", - write: console_write, - read : NULL, - device : crisv32_console_device, - unblank : NULL, - setup : console_setup, - flags : CON_PRINTBUFFER, - index : -1, - cflag : 0, - next : NULL -}; -static struct console sercons0 = { - name : "ttyS", - write: console_write, - read : NULL, - device : crisv32_console_device, - unblank : NULL, - setup : console_setup, - flags : CON_PRINTBUFFER, - index : 0, - cflag : 0, - next : NULL -}; - -static struct console sercons1 = { - name : "ttyS", - write: console_write, - read : NULL, - device : crisv32_console_device, - unblank : NULL, - setup : console_setup, - flags : CON_PRINTBUFFER, - index : 1, - cflag : 0, - next : NULL -}; -static struct console sercons2 = { - name : "ttyS", - write: console_write, - read : NULL, - device : crisv32_console_device, - unblank : NULL, - setup : console_setup, - flags : CON_PRINTBUFFER, - index : 2, - cflag : 0, - next : NULL -}; -static struct console sercons3 = { - name : "ttyS", - write: console_write, - read : NULL, - device : crisv32_console_device, - unblank : NULL, - setup : console_setup, - flags : CON_PRINTBUFFER, - index : 3, - cflag : 0, - next : NULL -}; - /* Register console for printk's, etc. */ int __init init_etrax_debug(void) { - static int first = 1; - - if (!first) { - unregister_console(&sercons); - register_console(&sercons0); - register_console(&sercons1); - register_console(&sercons2); - register_console(&sercons3); - init_dummy_console(); - return 0; - } - first = 0; - register_console(&sercons); start_port(port); #ifdef CONFIG_ETRAX_KGDB @@ -456,5 +202,3 @@ init_etrax_debug(void) #endif /* CONFIG_ETRAX_KGDB */ return 0; } - -__initcall(init_etrax_debug); diff --git a/arch/cris/arch-v32/kernel/dma.c b/arch/cris/arch-v32/kernel/dma.c deleted file mode 100644 index 570e19128ffd..000000000000 --- a/arch/cris/arch-v32/kernel/dma.c +++ /dev/null @@ -1,224 +0,0 @@ -/* Wrapper for DMA channel allocator that starts clocks etc */ - -#include <linux/kernel.h> -#include <linux/spinlock.h> -#include <asm/dma.h> -#include <asm/arch/hwregs/reg_map.h> -#include <asm/arch/hwregs/reg_rdwr.h> -#include <asm/arch/hwregs/marb_defs.h> -#include <asm/arch/hwregs/config_defs.h> -#include <asm/arch/hwregs/strmux_defs.h> -#include <linux/errno.h> -#include <asm/system.h> -#include <asm/arch/arbiter.h> - -static char used_dma_channels[MAX_DMA_CHANNELS]; -static const char * used_dma_channels_users[MAX_DMA_CHANNELS]; - -static DEFINE_SPINLOCK(dma_lock); - -int crisv32_request_dma(unsigned int dmanr, const char * device_id, - unsigned options, unsigned int bandwidth, - enum dma_owner owner) -{ - unsigned long flags; - reg_config_rw_clk_ctrl clk_ctrl; - reg_strmux_rw_cfg strmux_cfg; - - if (crisv32_arbiter_allocate_bandwidth(dmanr, - options & DMA_INT_MEM ? INT_REGION : EXT_REGION, - bandwidth)) - return -ENOMEM; - - spin_lock_irqsave(&dma_lock, flags); - - if (used_dma_channels[dmanr]) { - spin_unlock_irqrestore(&dma_lock, flags); - if (options & DMA_VERBOSE_ON_ERROR) { - printk("Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]); - } - if (options & DMA_PANIC_ON_ERROR) - panic("request_dma error!"); - return -EBUSY; - } - clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); - strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); - - switch(dmanr) - { - case 0: - case 1: - clk_ctrl.dma01_eth0 = 1; - break; - case 2: - case 3: - clk_ctrl.dma23 = 1; - break; - case 4: - case 5: - clk_ctrl.dma45 = 1; - break; - case 6: - case 7: - clk_ctrl.dma67 = 1; - break; - case 8: - case 9: - clk_ctrl.dma89_strcop = 1; - break; -#if MAX_DMA_CHANNELS-1 != 9 -#error Check dma.c -#endif - default: - spin_unlock_irqrestore(&dma_lock, flags); - if (options & DMA_VERBOSE_ON_ERROR) { - printk("Failed to request DMA %i for %s, only 0-%i valid)\n", dmanr, device_id, MAX_DMA_CHANNELS-1); - } - - if (options & DMA_PANIC_ON_ERROR) - panic("request_dma error!"); - return -EINVAL; - } - - switch(owner) - { - case dma_eth0: - if (dmanr == 0) - strmux_cfg.dma0 = regk_strmux_eth0; - else if (dmanr == 1) - strmux_cfg.dma1 = regk_strmux_eth0; - else - panic("Invalid DMA channel for eth0\n"); - break; - case dma_eth1: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_eth1; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_eth1; - else - panic("Invalid DMA channel for eth1\n"); - break; - case dma_iop0: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_iop0; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_iop0; - else - panic("Invalid DMA channel for iop0\n"); - break; - case dma_iop1: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_iop1; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_iop1; - else - panic("Invalid DMA channel for iop1\n"); - break; - case dma_ser0: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_ser0; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_ser0; - else - panic("Invalid DMA channel for ser0\n"); - break; - case dma_ser1: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_ser1; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_ser1; - else - panic("Invalid DMA channel for ser1\n"); - break; - case dma_ser2: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_ser2; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_ser2; - else - panic("Invalid DMA channel for ser2\n"); - break; - case dma_ser3: - if (dmanr == 8) - strmux_cfg.dma8 = regk_strmux_ser3; - else if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_ser3; - else - panic("Invalid DMA channel for ser3\n"); - break; - case dma_sser0: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_sser0; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_sser0; - else - panic("Invalid DMA channel for sser0\n"); - break; - case dma_sser1: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_sser1; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_sser1; - else - panic("Invalid DMA channel for sser1\n"); - break; - case dma_ata: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_ata; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_ata; - else - panic("Invalid DMA channel for ata\n"); - break; - case dma_strp: - if (dmanr == 8) - strmux_cfg.dma8 = regk_strmux_strcop; - else if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_strcop; - else - panic("Invalid DMA channel for strp\n"); - break; - case dma_ext0: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_ext0; - else - panic("Invalid DMA channel for ext0\n"); - break; - case dma_ext1: - if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_ext1; - else - panic("Invalid DMA channel for ext1\n"); - break; - case dma_ext2: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_ext2; - else if (dmanr == 8) - strmux_cfg.dma8 = regk_strmux_ext2; - else - panic("Invalid DMA channel for ext2\n"); - break; - case dma_ext3: - if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_ext3; - else if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_ext2; - else - panic("Invalid DMA channel for ext2\n"); - break; - } - - used_dma_channels[dmanr] = 1; - used_dma_channels_users[dmanr] = device_id; - REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); - REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); - spin_unlock_irqrestore(&dma_lock,flags); - return 0; -} - -void crisv32_free_dma(unsigned int dmanr) -{ - spin_lock(&dma_lock); - used_dma_channels[dmanr] = 0; - spin_unlock(&dma_lock); -} diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index f9d27807b914..eebbaba45430 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -10,7 +10,7 @@ * 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. + * 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 @@ -281,12 +281,10 @@ _work_notifysig: ;; Deal with pending signals and notify-resume requests. addoq +TI_flags, $r0, $acr - move.d [$acr], $r13 ; The thread_info_flags parameter. - 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 [$acr], $r12 ; The thread_info_flags parameter. + move.d $sp, $r11 ; The regs param. jsr do_notify_resume - nop + move.d $r9, $r10 ; do_notify_resume syscall/irq param. ba _Rexit nop @@ -396,7 +394,7 @@ nmi_interrupt: btstq REG_BIT(intr_vect, r_nmi, watchdog), $r0 bpl 1f nop - jsr handle_watchdog_bite ; In time.c. + jsr handle_watchdog_bite ; In time.c. move.d $sp, $r10 ; Pointer to registers 1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0 bpl 1f @@ -515,6 +513,13 @@ _ugdb_handle_exception: ba do_sigtrap ; SIGTRAP the offending process. move.d [$sp+], $r0 ; Restore R0 in delay slot. + .global kernel_execve +kernel_execve: + move.d __NR_execve, $r9 + break 13 + ret + nop + .data .section .rodata,"a" @@ -778,21 +783,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_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 */ @@ -805,6 +810,48 @@ sys_call_table: .long sys_mq_getsetattr .long sys_ni_syscall /* reserved for kexec */ .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 /* * NOTE!! This doesn't have to be exact - we just have diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c index b40551f9f40d..2de9d5849ef0 100644 --- a/arch/cris/arch-v32/kernel/fasttimer.c +++ b/arch/cris/arch-v32/kernel/fasttimer.c @@ -1,110 +1,9 @@ -/* $Id: fasttimer.c,v 1.11 2005/01/04 11:15:46 starvik Exp $ +/* * linux/arch/cris/kernel/fasttimer.c * * Fast timers for ETRAX FS - * This may be useful in other OS than Linux so use 2 space indentation... - * - * $Log: fasttimer.c,v $ - * Revision 1.11 2005/01/04 11:15:46 starvik - * Don't share timer IRQ. - * - * Revision 1.10 2004/12/07 09:19:38 starvik - * Corrected includes. - * Use correct interrupt macros. - * - * Revision 1.9 2004/05/14 10:18:58 starvik - * Export fast_timer_list - * - * Revision 1.8 2004/05/14 07:58:03 starvik - * Merge of changes from 2.4 - * - * Revision 1.7 2003/07/10 12:06:14 starvik - * Return IRQ_NONE if irq wasn't handled - * - * Revision 1.6 2003/07/04 08:27:49 starvik - * Merge of Linux 2.5.74 - * - * Revision 1.5 2003/06/05 10:16:22 johana - * New INTR_VECT macros. - * - * Revision 1.4 2003/06/03 08:49:45 johana - * Fixed typo. - * - * Revision 1.3 2003/06/02 12:51:27 johana - * Now compiles. - * Commented some include files that probably can be removed. - * - * Revision 1.2 2003/06/02 12:09:41 johana - * Ported to ETRAX FS using the trig interrupt instead of timer1. - * - * 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 - * want to use the true time - we want 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, 2003 Axis Communications AB, Lund, Sweden + * Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden */ #include <linux/errno.h> @@ -122,9 +21,9 @@ #include <linux/version.h> -#include <asm/arch/hwregs/reg_map.h> -#include <asm/arch/hwregs/reg_rdwr.h> -#include <asm/arch/hwregs/timer_defs.h> +#include <hwregs/reg_map.h> +#include <hwregs/reg_rdwr.h> +#include <hwregs/timer_defs.h> #include <asm/fasttimer.h> #include <linux/proc_fs.h> @@ -140,30 +39,25 @@ #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; @@ -171,8 +65,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) \ { \ @@ -202,103 +96,92 @@ struct fast_timer timer_expired_log[NUM_TIMER_STATS]; int timer_div_settings[NUM_TIMER_STATS]; int timer_delay_settings[NUM_TIMER_STATS]; +struct work_struct fast_work; static void -timer_trig_handler(void); +timer_trig_handler(struct work_struct *work); /* 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; } /* Called with ints off */ -void __INLINE__ start_timer_trig(unsigned long delay_us) +inline void start_timer_trig(unsigned long delay_us) { reg_timer_rw_ack_intr ack_intr = { 0 }; reg_timer_rw_intr_mask intr_mask; reg_timer_rw_trig trig; reg_timer_rw_trig_cfg trig_cfg = { 0 }; - reg_timer_r_time r_time; + reg_timer_r_time r_time0; + reg_timer_r_time r_time1; + unsigned char trig_wrap; + unsigned char time_wrap; - r_time = REG_RD(timer, regi_timer, r_time); + r_time0 = REG_RD(timer, regi_timer0, r_time); D1(printk("start_timer_trig : %d us freq: %i div: %i\n", delay_us, freq_index, div)); /* Clear trig irq */ - intr_mask = REG_RD(timer, regi_timer, rw_intr_mask); + intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); intr_mask.trig = 0; - REG_WR(timer, regi_timer, rw_intr_mask, intr_mask); + REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); - /* Set timer values */ - /* r_time is 100MHz (10 ns resolution) */ - trig = r_time + delay_us*(1000/10); + /* Set timer values and check if trigger wraps. */ + /* r_time is 100MHz (10 ns resolution) */ + trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0; timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig; timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; /* Ack interrupt */ ack_intr.trig = 1; - REG_WR(timer, regi_timer, rw_ack_intr, ack_intr); + REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); /* Start timer */ - REG_WR(timer, regi_timer, rw_trig, trig); + REG_WR(timer, regi_timer0, rw_trig, trig); trig_cfg.tmr = regk_timer_time; - REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg); + REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); /* Check if we have already passed the trig time */ - r_time = REG_RD(timer, regi_timer, r_time); - if (r_time < trig) { + r_time1 = REG_RD(timer, regi_timer0, r_time); + time_wrap = r_time1 < r_time0; + + if ((trig_wrap && !time_wrap) || (r_time1 < trig)) { /* No, Enable trig irq */ - intr_mask = REG_RD(timer, regi_timer, rw_intr_mask); + intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); intr_mask.trig = 1; - REG_WR(timer, regi_timer, rw_intr_mask, intr_mask); + REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); fast_timers_started++; fast_timer_running = 1; - } - else - { + } else { /* We have passed the time, disable trig point, ack intr */ trig_cfg.tmr = regk_timer_off; - REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg); - REG_WR(timer, regi_timer, rw_ack_intr, ack_intr); - /* call the int routine directly */ - timer_trig_handler(); + REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); + REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); + /* call the int routine */ + INIT_WORK(&fast_work, timer_trig_handler); + schedule_work(&fast_work); } } @@ -320,22 +203,20 @@ 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("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_DEBUG + "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; @@ -343,11 +224,10 @@ 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; - if (t->tv_expires.tv_usec > 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; @@ -355,15 +235,12 @@ 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; t->next = fast_timer_list; if (fast_timer_list) - { fast_timer_list->prev = t; - } fast_timer_list = t; #ifdef FAST_TIMER_LOG timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; @@ -372,10 +249,8 @@ void start_one_shot_timer(struct fast_timer *t, } else { /* Put in correct place in list */ while (tmp->next && - timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) - { + fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) tmp = tmp->next; - } /* Insert t after tmp */ t->prev = tmp; t->next = tmp->next; @@ -388,6 +263,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 */ @@ -431,19 +307,18 @@ int del_fast_timer(struct fast_timer * t) /* Timer interrupt handler for trig interrupts */ static irqreturn_t -timer_trig_interrupt(int irq, void *dev_id, struct pt_regs *regs) +timer_trig_interrupt(int irq, void *dev_id) { reg_timer_r_masked_intr masked_intr; - /* Check if the timer interrupt is for us (a trig int) */ - masked_intr = REG_RD(timer, regi_timer, r_masked_intr); + masked_intr = REG_RD(timer, regi_timer0, r_masked_intr); if (!masked_intr.trig) return IRQ_NONE; - timer_trig_handler(); + timer_trig_handler(NULL); return IRQ_HANDLED; } -static void timer_trig_handler(void) +static void timer_trig_handler(struct work_struct *work) { reg_timer_rw_ack_intr ack_intr = { 0 }; reg_timer_rw_intr_mask intr_mask; @@ -451,38 +326,45 @@ static void timer_trig_handler(void) 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 timer trig interrupt */ - intr_mask = REG_RD(timer, regi_timer, rw_intr_mask); + intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); intr_mask.trig = 0; - REG_WR(timer, regi_timer, rw_intr_mask, intr_mask); + REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); /* First stop timer, then ack interrupt */ /* Stop timer */ trig_cfg.tmr = regk_timer_off; - REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg); + REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); /* Ack interrupt */ ack_intr.trig = 1; - REG_WR(timer, regi_timer, rw_ack_intr, ack_intr); + REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); fast_timer_running = 0; fast_timer_ints++; - local_irq_restore(flags); + fast_timer_function_type *f; + unsigned long d; t = fast_timer_list; - while (t) - { - struct timeval tv; + while (t) { + struct fasttime_t tv; /* 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 timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; @@ -490,84 +372,77 @@ static void timer_trig_handler(void) 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; - } else - { fast_timer_list = t->next; - } if (t->next) - { t->next->prev = t->prev; - } 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 the callback function with interrupts + * enabled. */ + local_irq_restore(flags); + f(d); + local_irq_save(flags); + } else DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints); - } - } - else - { + } else { /* Timer is to early, let's set it again using the normal routines */ D1(printk(".\n")); } - local_irq_save(flags); - if ((t = fast_timer_list) != NULL) - { + t = fast_timer_list; + if (t != 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); - if (us > 0) - { - if (!fast_timer_running) - { + + /* 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) { #ifdef FAST_TIMER_LOG timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; #endif start_timer_trig(us); } - local_irq_restore(flags); break; - } - else - { + } else { /* Timer already expired, let's handle it better late than never. * The normal loop handles it */ D1(printk("e! %d\n", us)); } } - local_irq_restore(flags); } - if (!t) - { + local_irq_restore(flags); + + if (!t) D1(printk("ttrig stop!\n")); - } } 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 wake_up(sleep_wait_p); } @@ -577,28 +452,17 @@ 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 @@ -618,20 +482,22 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len unsigned long flags; int i = 0; int num_to_show; - struct timeval tv; + struct fasttime_t 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) - { + if (!bigbuf) { + bigbuf = vmalloc(BIG_BUF_SIZE); + if (!bigbuf) { + used = 0; + if (buf) + buf[0] = '\0'; + return 0; + } + } + + if (!offset || !used) { do_gettimeofday_fast(&tv); used = 0; @@ -648,7 +514,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len 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_jiff, (unsigned long)tv.tv_usec); #ifdef FAST_TIMER_SANITY_CHECKS used += sprintf(bigbuf + used, "Sanity failed: %i\n", @@ -661,10 +527,8 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len int end_i = debug_log_cnt; i = 0; - if (debug_log_cnt_wrapped) - { + if (debug_log_cnt_wrapped) i = debug_log_cnt; - } while ((i != end_i || (debug_log_cnt_wrapped && !used)) && used+100 < BIG_BUF_SIZE) @@ -697,9 +561,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len "d: %6li us data: 0x%08lX" "\n", t->name, - (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_jiff, (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_jiff, (unsigned long)t->tv_expires.tv_usec, t->delay_us, t->data @@ -719,9 +583,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len "d: %6li us data: 0x%08lX" "\n", t->name, - (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_jiff, (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_jiff, (unsigned long)t->tv_expires.tv_usec, t->delay_us, t->data @@ -739,9 +603,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len "d: %6li us data: 0x%08lX" "\n", t->name, - (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_jiff, (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_jiff, (unsigned long)t->tv_expires.tv_usec, t->delay_us, t->data @@ -752,26 +616,25 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len used += sprintf(bigbuf + used, "Active timers:\n"); local_irq_save(flags); - 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" -/* " 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, + "d: %6li us data: 0x%08lX" +/* " func: 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 /* , t->function */ ); - local_irq_disable(); + local_irq_save(flags); if (t->next != nextt) { printk("timer removed!\n"); @@ -800,7 +663,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) { @@ -838,7 +701,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); @@ -851,21 +714,22 @@ 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++) { - printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); + printk(KERN_DEBUG "%i %i %i %i %i\n", + j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); j += 4; } 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); @@ -892,14 +756,15 @@ static void fast_timer_test(void) while (num_test_timeout < i) { if (num_test_timeout != prev_num) - { prev_num = num_test_timeout; - } } 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_INFO "Timers started %is %06i\n", + tv0.tv_jiff, tv0.tv_usec); + printk(KERN_INFO "Timers started at %is %06i\n", + tv1.tv_jiff, tv1.tv_usec); + printk(KERN_INFO "Timers done %is %06i\n", + tv2.tv_jiff, tv2.tv_usec); DP(printk("buf0:\n"); printk(buf0); printk("buf1:\n"); @@ -921,9 +786,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 @@ -931,10 +796,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"); @@ -944,7 +811,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) @@ -952,18 +819,20 @@ void fast_timer_init(void) printk("fast_timer_init()\n"); #ifdef CONFIG_PROC_FS - if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) - fasttimer_proc_entry->read_proc = proc_fasttimer_read; + fasttimer_proc_entry = create_proc_entry("fasttimer", 0, 0); + if (fasttimer_proc_entry) + fasttimer_proc_entry->read_proc = proc_fasttimer_read; #endif /* PROC_FS */ - if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED, - "fast timer int", NULL)) - { - printk("err: timer1 irq\n"); - } + if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt, + IRQF_SHARED | IRQF_DISABLED, + "fast timer int", &fast_timer_list)) + printk(KERN_ERR "err: fasttimer irq\n"); fast_timer_is_init = 1; #ifdef FAST_TIMER_TEST printk("do test\n"); fast_timer_test(); #endif } + return 0; } +__initcall(fast_timer_init); diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S index 20bd80a84e48..2d66a7c320e1 100644 --- a/arch/cris/arch-v32/kernel/head.S +++ b/arch/cris/arch-v32/kernel/head.S @@ -4,22 +4,25 @@ * Copyright (C) 2003, Axis Communications AB */ - #define ASSEMBLER_MACROS_ONLY /* * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so * -traditional must not be used when assembling this file. */ -#include <asm/arch/hwregs/reg_rdwr.h> -#include <asm/arch/hwregs/asm/mmu_defs_asm.h> -#include <asm/arch/hwregs/asm/reg_map_asm.h> -#include <asm/arch/hwregs/asm/config_defs_asm.h> -#include <asm/arch/hwregs/asm/bif_core_defs_asm.h> +#include <hwregs/reg_rdwr.h> +#include <asm/arch/memmap.h> +#include <hwregs/intr_vect.h> +#include <hwregs/asm/mmu_defs_asm.h> +#include <hwregs/asm/reg_map_asm.h> +#include <asm/arch/mach/startup.inc> #define CRAMFS_MAGIC 0x28cd3d45 +#define JHEAD_MAGIC 0x1FF528A6 +#define JHEAD_SIZE 8 #define RAM_INIT_MAGIC 0x56902387 #define COMMAND_LINE_MAGIC 0x87109563 +#define NAND_BOOT_MAGIC 0x9a9db001 ;; NOTE: R8 and R9 carry information from the decompressor (if the ;; kernel was compressed). They must not be used in the code below @@ -30,12 +33,11 @@ .global romfs_start .global romfs_length .global romfs_in_flash + .global nand_boot .global swapper_pg_dir - .global crisv32_nand_boot - .global crisv32_nand_cramfs_offset ;; Dummy section to make it bootable with current VCS simulator -#ifdef CONFIG_ETRAXFS_SIM +#ifdef CONFIG_ETRAX_VCS_SIM .section ".boot", "ax" ba tstart nop @@ -51,33 +53,15 @@ tstart: ;; di - ;; Start clocks for used blocks. - move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1 - move.d [$r1], $r0 - or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \ - REG_STATE(config, rw_clk_ctrl, bif, yes) | \ - REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0 - move.d $r0, [$r1] - - ;; Set up waitstates etc - move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0 - move.d CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1 - move.d $r1, [$r0] - move.d REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0 - move.d CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1 - move.d $r1, [$r0] - move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0 - move.d CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1 - move.d $r1, [$r0] - move.d REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0 - move.d CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1 - move.d $r1, [$r0] - -#ifdef CONFIG_ETRAXFS_SIM - ;; Set up minimal flash waitstates - move.d 0, $r10 - move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11 - move.d $r10, [$r11] + START_CLOCKS + + SETUP_WAIT_STATES + + GIO_INIT + +#ifdef CONFIG_SMP +secondary_cpu_entry: /* Entry point for secondary CPUs */ + di #endif ;; Setup and enable the MMU. Use same configuration for both the data @@ -85,7 +69,7 @@ tstart: ;; ;; Note; 3 cycles is needed for a bank-select to take effect. Further; ;; bank 1 is the instruction MMU, bank 2 is the data MMU. -#ifndef CONFIG_ETRAXFS_SIM +#ifndef CONFIG_ETRAX_VCS_SIM move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 @@ -93,7 +77,7 @@ tstart: ;; Map the virtual DRAM to the RW eprom area at address 0. ;; Also map 0xa for the hook calls, move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ - | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0) \ + | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) \ | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0 #endif @@ -104,7 +88,7 @@ tstart: ;; Enable certain page protections and setup linear mapping ;; for f,e,c,b,4,0. -#ifndef CONFIG_ETRAXFS_SIM +#ifndef CONFIG_ETRAX_VCS_SIM move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ | REG_STATE(mmu, rw_mm_cfg, acc, on) \ | REG_STATE(mmu, rw_mm_cfg, ex, on) \ @@ -183,17 +167,11 @@ tstart: nop nop nop - move $s10, $r0 + move $s12, $r0 cmpq 0, $r0 beq master_cpu nop slave_cpu: - ; A slave waits for cpu_now_booting to be equal to CPU ID. - move.d cpu_now_booting, $r1 -slave_wait: - cmp.d [$r1], $r0 - bne slave_wait - nop ; Time to boot-up. Get stack location provided by master CPU. move.d smp_init_current_idle_thread, $r1 move.d [$r1], $sp @@ -203,9 +181,16 @@ slave_wait: jsr smp_callin nop master_cpu: + /* Set up entry point for secondary CPUs. The boot ROM has set up + * EBP at start of internal memory. The CPU will get there + * later when we issue an IPI to them... */ + move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0 + move.d secondary_cpu_entry, $r1 + move.d $r1, [$r0] #endif -#ifndef CONFIG_ETRAXFS_SIM - ;; Check if starting from DRAM or flash. +#ifndef CONFIG_ETRAX_VCS_SIM + ; Check if starting from DRAM (network->RAM boot or unpacked + ; compressed kernel), or directly from flash. lapcq ., $r0 and.d 0x7fffffff, $r0 ; Mask off the non-cache bit. cmp.d 0x10000, $r0 ; Arbitrary, something above this code. @@ -232,12 +217,13 @@ _inflash: beq _dram_initialized nop -#include "../lib/dram_init.S" +#include "../mach/dram_init.S" _dram_initialized: ;; Copy the text and data section to DRAM. This depends on that the ;; variables used below are correctly set up by the linker script. ;; The calculated value stored in R4 is used below. + ;; Leave the cramfs file system (piggybacked after the kernel) in flash. moveq 0, $r0 ; Source. move.d text_start, $r1 ; Destination. move.d __vmlinux_end, $r2 @@ -249,7 +235,7 @@ _dram_initialized: blo 1b nop - ;; Keep CRAMFS in flash. + ;; Check for cramfs. moveq 0, $r0 move.d romfs_length, $r1 move.d $r0, [$r1] @@ -258,6 +244,7 @@ _dram_initialized: bne 1f nop + ;; Set length and start of cramfs, set romfs_in_flash flag addoq +4, $r4, $acr move.d [$acr], $r0 move.d romfs_length, $r1 @@ -273,35 +260,32 @@ _dram_initialized: nop _inram: - ;; Check if booting from NAND flash (in that case we just remember the offset - ;; into the flash where cramfs should be). - move.d REG_ADDR(config, regi_config, r_bootsel), $r0 - move.d [$r0], $r0 - and.d REG_MASK(config, r_bootsel, boot_mode), $r0 - cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 - bne move_cramfs - moveq 1,$r0 - move.d crisv32_nand_boot, $r1 - move.d $r0, [$r1] - move.d crisv32_nand_cramfs_offset, $r1 - move.d $r9, [$r1] + ;; Check if booting from NAND flash; if so, set appropriate flags + ;; and move on. + cmp.d NAND_BOOT_MAGIC, $r12 + bne move_cramfs ; not nand, jump moveq 1, $r0 - move.d romfs_in_flash, $r1 + move.d nand_boot, $r1 ; tell axisflashmap we're booting from NAND + move.d $r0, [$r1] + moveq 0, $r0 ; tell axisflashmap romfs is not in + move.d romfs_in_flash, $r1 ; (directly accessed) flash move.d $r0, [$r1] - jump _start_it + jump _start_it ; continue with boot nop move_cramfs: - ;; Move the cramfs after BSS. + ;; kernel is in DRAM. + ;; Must figure out if there is a piggybacked rootfs image or not. + ;; Set romfs_length to 0 => no rootfs image available by default. moveq 0, $r0 move.d romfs_length, $r1 move.d $r0, [$r1] -#ifndef CONFIG_ETRAXFS_SIM +#ifndef CONFIG_ETRAX_VCS_SIM ;; The kernel could have been unpacked to DRAM by the loader, but - ;; the cramfs image could still be inte the flash immediately - ;; following the compressed kernel image. The loaded passes the address - ;; of the bute succeeding the last compressed byte in the flash in + ;; the cramfs image could still be in the flash immediately + ;; following the compressed kernel image. The loader passes the address + ;; of the byte succeeding the last compressed byte in the flash in ;; register R9 when starting the kernel. cmp.d 0x0ffffff8, $r9 bhs _no_romfs_in_flash ; R9 points outside the flash area. @@ -310,11 +294,13 @@ move_cramfs: ba _no_romfs_in_flash nop #endif + ;; cramfs rootfs might to be in flash. Check for it. move.d [$r9], $r0 ; cramfs_super.magic cmp.d CRAMFS_MAGIC, $r0 bne _no_romfs_in_flash nop + ;; found cramfs in flash. set address and size, and romfs_in_flash flag. addoq +4, $r9, $acr move.d [$acr], $r0 move.d romfs_length, $r1 @@ -330,27 +316,43 @@ move_cramfs: nop _no_romfs_in_flash: - ;; Look for cramfs. + ;; No romfs in flash, so look for cramfs, or jffs2 with jhead, + ;; after kernel in RAM, as is the case with network->RAM boot. + ;; For cramfs, partition starts with magic and length. + ;; For jffs2, a jhead is prepended which contains with magic and length. + ;; The jhead is not part of the jffs2 partition however. #ifndef CONFIG_ETRAXFS_SIM move.d __vmlinux_end, $r0 #else move.d __end, $r0 #endif move.d [$r0], $r1 - cmp.d CRAMFS_MAGIC, $r1 - bne 2f + cmp.d CRAMFS_MAGIC, $r1 ; cramfs magic? + beq 2f ; yes, jump + nop + cmp.d JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic? + bne 4f ; no, skip copy nop + addq 4, $r0 ; location of jffs2 size + move.d [$r0+], $r2 ; fetch jffs2 size -> r2 + ; r0 now points to start of jffs2 + ba 3f + nop +2: + addoq +4, $r0, $acr ; location of cramfs size + move.d [$acr], $r2 ; fetch cramfs size -> r2 + ; r0 still points to start of cramfs +3: + ;; Now, move the root fs to after kernel's BSS - addoq +4, $r0, $acr - move.d [$acr], $r2 - move.d _end, $r1 + move.d _end, $r1 ; start of cramfs -> r1 move.d romfs_start, $r3 - move.d $r1, [$r3] + move.d $r1, [$r3] ; store at romfs_start (for axisflashmap) move.d romfs_length, $r3 - move.d $r2, [$r3] + move.d $r2, [$r3] ; store size at romfs_length -#ifndef CONFIG_ETRAXFS_SIM - add.d $r2, $r0 +#ifndef CONFIG_ETRAX_VCS_SIM + add.d $r2, $r0 ; copy from end and downwards add.d $r2, $r1 lsrq 1, $r2 ; Size is in bytes, we copy words. @@ -365,10 +367,17 @@ _no_romfs_in_flash: nop #endif -2: +4: + ;; BSS move done. + ;; Clear romfs_in_flash flag, as we now know romfs is in DRAM + ;; Also clear nand_boot flag; if we got here, we know we've not + ;; booted from NAND flash. moveq 0, $r0 move.d romfs_in_flash, $r1 move.d $r0, [$r1] + moveq 0, $r0 + move.d nand_boot, $r1 + move.d $r0, [$r1] jump _start_it ; Jump to cached code. nop @@ -384,8 +393,8 @@ _start_it: move.d cris_command_line, $r10 or.d 0x80000000, $r11 ; Make it virtual 1: - move.b [$r11+], $r12 - move.b $r12, [$r10+] + move.b [$r11+], $r1 + move.b $r1, [$r10+] subq 1, $r13 bne 1b nop @@ -401,7 +410,7 @@ no_command_line: move.d etrax_irv, $r1 ; Set the exception base register and pointer. move.d $r0, [$r1] -#ifndef CONFIG_ETRAXFS_SIM +#ifndef CONFIG_ETRAX_VCS_SIM ;; Clear the BSS region from _bss_start to _end. move.d __bss_start, $r0 move.d _end, $r1 @@ -411,7 +420,7 @@ no_command_line: nop #endif -#ifdef CONFIG_ETRAXFS_SIM +#ifdef CONFIG_ETRAX_VCS_SIM /* Set the watchdog timeout to something big. Will be removed when */ /* watchdog can be disabled with command line option */ move.d 0x7fffffff, $r10 @@ -423,25 +432,44 @@ no_command_line: move.d __bss_start, $r0 movem [$r0], $r13 +#ifdef CONFIG_ETRAX_L2CACHE + jsr l2cache_init + nop +#endif + jump start_kernel ; Jump to start_kernel() in init/main.c. nop .data etrax_irv: .dword 0 + +; Variables for communication with the Axis flash map driver (axisflashmap), +; and for setting up memory in arch/cris/kernel/setup.c . + +; romfs_start is set to the start of the root file system, if it exists +; in directly accessible memory (i.e. NOR Flash when booting from Flash, +; or RAM when booting directly from a network-downloaded RAM image) romfs_start: .dword 0 + +; romfs_length is set to the size of the root file system image, if it exists +; in directly accessible memory (see romfs_start). Otherwise it is set to 0. romfs_length: .dword 0 + +; romfs_in_flash is set to 1 if the root file system resides in directly +; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot +; or NAND flash boot. romfs_in_flash: .dword 0 -crisv32_nand_boot: - .dword 0 -crisv32_nand_cramfs_offset: + +; nand_boot is set to 1 when the kernel has been booted from NAND flash +nand_boot: .dword 0 swapper_pg_dir = 0xc0002000 .section ".init.data", "aw" -#include "../lib/hw_settings.S" +#include "../mach/hw_settings.S" diff --git a/arch/cris/arch-v32/kernel/io.c b/arch/cris/arch-v32/kernel/io.c deleted file mode 100644 index a22a9e02e093..000000000000 --- a/arch/cris/arch-v32/kernel/io.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Helper functions for I/O pins. - * - * Copyright (c) 2004 Axis Communications AB. - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/ctype.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <asm/io.h> -#include <asm/arch/pinmux.h> -#include <asm/arch/hwregs/gio_defs.h> - -struct crisv32_ioport crisv32_ioports[] = -{ - { - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_oe), - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_dout), - (unsigned long*)REG_ADDR(gio, regi_gio, r_pa_din), - 8 - }, - { - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_oe), - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_dout), - (unsigned long*)REG_ADDR(gio, regi_gio, r_pb_din), - 18 - }, - { - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_oe), - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_dout), - (unsigned long*)REG_ADDR(gio, regi_gio, r_pc_din), - 18 - }, - { - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_oe), - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_dout), - (unsigned long*)REG_ADDR(gio, regi_gio, r_pd_din), - 18 - }, - { - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_oe), - (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_dout), - (unsigned long*)REG_ADDR(gio, regi_gio, r_pe_din), - 18 - } -}; - -#define NBR_OF_PORTS ARRAY_SIZE(crisv32_ioports) - -struct crisv32_iopin crisv32_led1_green; -struct crisv32_iopin crisv32_led1_red; -struct crisv32_iopin crisv32_led2_green; -struct crisv32_iopin crisv32_led2_red; -struct crisv32_iopin crisv32_led3_green; -struct crisv32_iopin crisv32_led3_red; - -/* Dummy port used when green LED and red LED is on the same bit */ -static unsigned long io_dummy; -static struct crisv32_ioport dummy_port = -{ - &io_dummy, - &io_dummy, - &io_dummy, - 18 -}; -static struct crisv32_iopin dummy_led = -{ - &dummy_port, - 0 -}; - -static int __init crisv32_io_init(void) -{ - int ret = 0; - /* Initialize LEDs */ - ret += crisv32_io_get_name(&crisv32_led1_green, CONFIG_ETRAX_LED1G); - ret += crisv32_io_get_name(&crisv32_led1_red, CONFIG_ETRAX_LED1R); - ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_LED2G); - ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_LED2R); - ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_LED3G); - ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_LED3R); - crisv32_io_set_dir(&crisv32_led1_green, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led1_red, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out); - crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out); - - if (!strcmp(CONFIG_ETRAX_LED1G, CONFIG_ETRAX_LED1R)) - crisv32_led1_red = dummy_led; - if (!strcmp(CONFIG_ETRAX_LED2G, CONFIG_ETRAX_LED2R)) - crisv32_led2_red = dummy_led; - - return ret; -} - -__initcall(crisv32_io_init); - -int crisv32_io_get(struct crisv32_iopin* iopin, - unsigned int port, unsigned int pin) -{ - if (port > NBR_OF_PORTS) - return -EINVAL; - if (port > crisv32_ioports[port].pin_count) - return -EINVAL; - - iopin->bit = 1 << pin; - iopin->port = &crisv32_ioports[port]; - - if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) - return -EIO; - - return 0; -} - -int crisv32_io_get_name(struct crisv32_iopin* iopin, - char* name) -{ - int port; - int pin; - - if (toupper(*name) == 'P') - name++; - - if (toupper(*name) < 'A' || toupper(*name) > 'E') - return -EINVAL; - - port = toupper(*name) - 'A'; - name++; - pin = simple_strtoul(name, NULL, 10); - - if (pin < 0 || pin > crisv32_ioports[port].pin_count) - return -EINVAL; - - iopin->bit = 1 << pin; - iopin->port = &crisv32_ioports[port]; - - if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) - return -EIO; - - return 0; -} - -#ifdef CONFIG_PCI -/* PCI I/O access stuff */ -struct cris_io_operations* cris_iops = NULL; -EXPORT_SYMBOL(cris_iops); -#endif - diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index a9acaa270243..173c141ac9ba 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c @@ -15,15 +15,21 @@ #include <linux/threads.h> #include <linux/spinlock.h> #include <linux/kernel_stat.h> -#include <asm/arch/hwregs/reg_map.h> -#include <asm/arch/hwregs/reg_rdwr.h> -#include <asm/arch/hwregs/intr_vect.h> -#include <asm/arch/hwregs/intr_vect_defs.h> +#include <hwregs/reg_map.h> +#include <hwregs/reg_rdwr.h> +#include <hwregs/intr_vect.h> +#include <hwregs/intr_vect_defs.h> #define CPU_FIXED -1 /* IRQ masks (refer to comment for crisv32_do_multiple) */ -#define TIMER_MASK (1 << (TIMER_INTR_VECT - FIRST_IRQ)) +#if TIMER0_INTR_VECT - FIRST_IRQ < 32 +#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ)) +#undef TIMER_VECT1 +#else +#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ - 32)) +#define TIMER_VECT1 +#endif #ifdef CONFIG_ETRAX_KGDB #if defined(CONFIG_ETRAX_KGDB_PORT0) #define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ)) @@ -44,8 +50,8 @@ struct cris_irq_allocation cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */ }; -struct cris_irq_allocation irq_allocations[NR_IRQS] = - {[0 ... NR_IRQS - 1] = {0, CPU_MASK_ALL}}; +struct cris_irq_allocation irq_allocations[NR_REAL_IRQS] = + { [0 ... NR_REAL_IRQS - 1] = {0, CPU_MASK_ALL} }; static unsigned long irq_regs[NR_CPUS] = { @@ -55,6 +61,12 @@ static unsigned long irq_regs[NR_CPUS] = #endif }; +#if NR_REAL_IRQS > 32 +#define NBR_REGS 2 +#else +#define NBR_REGS 1 +#endif + unsigned long cpu_irq_counters[NR_CPUS]; unsigned long irq_counters[NR_REAL_IRQS]; @@ -79,45 +91,81 @@ extern void d_mmu_write(void); extern void kgdb_init(void); extern void breakpoint(void); +/* From traps.c. */ +extern void breakh_BUG(void); + /* - * Build the IRQ handler stubs using macros from irq.h. First argument is the - * IRQ number, the second argument is the corresponding bit in - * intr_rw_vect_mask found in asm/arch/hwregs/intr_vect_defs.h. + * Build the IRQ handler stubs using macros from irq.h. */ -BUILD_IRQ(0x31, (1 << 0)) /* memarb */ -BUILD_IRQ(0x32, (1 << 1)) /* gen_io */ -BUILD_IRQ(0x33, (1 << 2)) /* iop0 */ -BUILD_IRQ(0x34, (1 << 3)) /* iop1 */ -BUILD_IRQ(0x35, (1 << 4)) /* iop2 */ -BUILD_IRQ(0x36, (1 << 5)) /* iop3 */ -BUILD_IRQ(0x37, (1 << 6)) /* dma0 */ -BUILD_IRQ(0x38, (1 << 7)) /* dma1 */ -BUILD_IRQ(0x39, (1 << 8)) /* dma2 */ -BUILD_IRQ(0x3a, (1 << 9)) /* dma3 */ -BUILD_IRQ(0x3b, (1 << 10)) /* dma4 */ -BUILD_IRQ(0x3c, (1 << 11)) /* dma5 */ -BUILD_IRQ(0x3d, (1 << 12)) /* dma6 */ -BUILD_IRQ(0x3e, (1 << 13)) /* dma7 */ -BUILD_IRQ(0x3f, (1 << 14)) /* dma8 */ -BUILD_IRQ(0x40, (1 << 15)) /* dma9 */ -BUILD_IRQ(0x41, (1 << 16)) /* ata */ -BUILD_IRQ(0x42, (1 << 17)) /* sser0 */ -BUILD_IRQ(0x43, (1 << 18)) /* sser1 */ -BUILD_IRQ(0x44, (1 << 19)) /* ser0 */ -BUILD_IRQ(0x45, (1 << 20)) /* ser1 */ -BUILD_IRQ(0x46, (1 << 21)) /* ser2 */ -BUILD_IRQ(0x47, (1 << 22)) /* ser3 */ -BUILD_IRQ(0x48, (1 << 23)) -BUILD_IRQ(0x49, (1 << 24)) /* eth0 */ -BUILD_IRQ(0x4a, (1 << 25)) /* eth1 */ -BUILD_TIMER_IRQ(0x4b, (1 << 26))/* timer */ -BUILD_IRQ(0x4c, (1 << 27)) /* bif_arb */ -BUILD_IRQ(0x4d, (1 << 28)) /* bif_dma */ -BUILD_IRQ(0x4e, (1 << 29)) /* ext */ -BUILD_IRQ(0x4f, (1 << 29)) /* ipi */ +BUILD_IRQ(0x31) +BUILD_IRQ(0x32) +BUILD_IRQ(0x33) +BUILD_IRQ(0x34) +BUILD_IRQ(0x35) +BUILD_IRQ(0x36) +BUILD_IRQ(0x37) +BUILD_IRQ(0x38) +BUILD_IRQ(0x39) +BUILD_IRQ(0x3a) +BUILD_IRQ(0x3b) +BUILD_IRQ(0x3c) +BUILD_IRQ(0x3d) +BUILD_IRQ(0x3e) +BUILD_IRQ(0x3f) +BUILD_IRQ(0x40) +BUILD_IRQ(0x41) +BUILD_IRQ(0x42) +BUILD_IRQ(0x43) +BUILD_IRQ(0x44) +BUILD_IRQ(0x45) +BUILD_IRQ(0x46) +BUILD_IRQ(0x47) +BUILD_IRQ(0x48) +BUILD_IRQ(0x49) +BUILD_IRQ(0x4a) +BUILD_IRQ(0x4b) +BUILD_IRQ(0x4c) +BUILD_IRQ(0x4d) +BUILD_IRQ(0x4e) +BUILD_IRQ(0x4f) +BUILD_IRQ(0x50) +#if MACH_IRQS > 32 +BUILD_IRQ(0x51) +BUILD_IRQ(0x52) +BUILD_IRQ(0x53) +BUILD_IRQ(0x54) +BUILD_IRQ(0x55) +BUILD_IRQ(0x56) +BUILD_IRQ(0x57) +BUILD_IRQ(0x58) +BUILD_IRQ(0x59) +BUILD_IRQ(0x5a) +BUILD_IRQ(0x5b) +BUILD_IRQ(0x5c) +BUILD_IRQ(0x5d) +BUILD_IRQ(0x5e) +BUILD_IRQ(0x5f) +BUILD_IRQ(0x60) +BUILD_IRQ(0x61) +BUILD_IRQ(0x62) +BUILD_IRQ(0x63) +BUILD_IRQ(0x64) +BUILD_IRQ(0x65) +BUILD_IRQ(0x66) +BUILD_IRQ(0x67) +BUILD_IRQ(0x68) +BUILD_IRQ(0x69) +BUILD_IRQ(0x6a) +BUILD_IRQ(0x6b) +BUILD_IRQ(0x6c) +BUILD_IRQ(0x6d) +BUILD_IRQ(0x6e) +BUILD_IRQ(0x6f) +BUILD_IRQ(0x70) +#endif /* Pointers to the low-level handlers. */ -static void (*interrupt[NR_IRQS])(void) = { +static void (*interrupt[MACH_IRQS])(void) = { IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt, IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt, IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt, @@ -128,7 +176,20 @@ static void (*interrupt[NR_IRQS])(void) = { IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt, IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt, IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt, - IRQ0x4f_interrupt + IRQ0x4f_interrupt, IRQ0x50_interrupt, +#if MACH_IRQS > 32 + IRQ0x51_interrupt, IRQ0x52_interrupt, IRQ0x53_interrupt, + IRQ0x54_interrupt, IRQ0x55_interrupt, IRQ0x56_interrupt, + IRQ0x57_interrupt, IRQ0x58_interrupt, IRQ0x59_interrupt, + IRQ0x5a_interrupt, IRQ0x5b_interrupt, IRQ0x5c_interrupt, + IRQ0x5d_interrupt, IRQ0x5e_interrupt, IRQ0x5f_interrupt, + IRQ0x60_interrupt, IRQ0x61_interrupt, IRQ0x62_interrupt, + IRQ0x63_interrupt, IRQ0x64_interrupt, IRQ0x65_interrupt, + IRQ0x66_interrupt, IRQ0x67_interrupt, IRQ0x68_interrupt, + IRQ0x69_interrupt, IRQ0x6a_interrupt, IRQ0x6b_interrupt, + IRQ0x6c_interrupt, IRQ0x6d_interrupt, IRQ0x6e_interrupt, + IRQ0x6f_interrupt, IRQ0x70_interrupt, +#endif }; void @@ -137,13 +198,26 @@ block_irq(int irq, int cpu) int intr_mask; unsigned long flags; - spin_lock_irqsave(&irq_lock, flags); - intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); - - /* Remember; 1 let through, 0 block. */ - intr_mask &= ~(1 << (irq - FIRST_IRQ)); - - REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask); + spin_lock_irqsave(&irq_lock, flags); + if (irq - FIRST_IRQ < 32) + intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], + rw_mask, 0); + else + intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], + rw_mask, 1); + + /* Remember; 1 let thru, 0 block. */ + if (irq - FIRST_IRQ < 32) + intr_mask &= ~(1 << (irq - FIRST_IRQ)); + else + intr_mask &= ~(1 << (irq - FIRST_IRQ - 32)); + + if (irq - FIRST_IRQ < 32) + REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, + 0, intr_mask); + else + REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, + 1, intr_mask); spin_unlock_irqrestore(&irq_lock, flags); } @@ -154,12 +228,26 @@ unblock_irq(int irq, int cpu) unsigned long flags; spin_lock_irqsave(&irq_lock, flags); - intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); - - /* Remember; 1 let through, 0 block. */ - intr_mask |= (1 << (irq - FIRST_IRQ)); + if (irq - FIRST_IRQ < 32) + intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], + rw_mask, 0); + else + intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], + rw_mask, 1); + + /* Remember; 1 let thru, 0 block. */ + if (irq - FIRST_IRQ < 32) + intr_mask |= (1 << (irq - FIRST_IRQ)); + else + intr_mask |= (1 << (irq - FIRST_IRQ - 32)); + + if (irq - FIRST_IRQ < 32) + REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, + 0, intr_mask); + else + REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, + 1, intr_mask); - REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask); spin_unlock_irqrestore(&irq_lock, flags); } @@ -298,8 +386,9 @@ crisv32_do_multiple(struct pt_regs* regs) { int cpu; int mask; - int masked; + int masked[NBR_REGS]; int bit; + int i; cpu = smp_processor_id(); @@ -308,42 +397,59 @@ crisv32_do_multiple(struct pt_regs* regs) */ irq_enter(); - /* Get which IRQs that happened. */ - masked = REG_RD_INT(intr_vect, irq_regs[cpu], r_masked_vect); + for (i = 0; i < NBR_REGS; i++) { + /* Get which IRQs that happend. */ + masked[i] = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], + r_masked_vect, i); - /* Calculate new IRQ mask with these IRQs disabled. */ - mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); - mask &= ~masked; + /* Calculate new IRQ mask with these IRQs disabled. */ + mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i); + mask &= ~masked[i]; /* Timer IRQ is never masked */ - if (masked & TIMER_MASK) - mask |= TIMER_MASK; - - /* Block all the IRQs */ - REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask); +#ifdef TIMER_VECT1 + if ((i == 1) && (masked[0] & TIMER_MASK)) + mask |= TIMER_MASK; +#else + if ((i == 0) && (masked[0] & TIMER_MASK)) + mask |= TIMER_MASK; +#endif + /* Block all the IRQs */ + REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask); /* Check for timer IRQ and handle it special. */ - if (masked & TIMER_MASK) { - masked &= ~TIMER_MASK; - do_IRQ(TIMER_INTR_VECT, regs); +#ifdef TIMER_VECT1 + if ((i == 1) && (masked[i] & TIMER_MASK)) { + masked[i] &= ~TIMER_MASK; + do_IRQ(TIMER0_INTR_VECT, regs); + } +#else + if ((i == 0) && (masked[i] & TIMER_MASK)) { + masked[i] &= ~TIMER_MASK; + do_IRQ(TIMER0_INTR_VECT, regs); + } } +#endif #ifdef IGNORE_MASK /* Remove IRQs that can't be handled as multiple. */ - masked &= ~IGNORE_MASK; + masked[0] &= ~IGNORE_MASK; #endif /* Handle the rest of the IRQs. */ - for (bit = 0; bit < 32; bit++) - { - if (masked & (1 << bit)) - do_IRQ(bit + FIRST_IRQ, regs); + for (i = 0; i < NBR_REGS; i++) { + for (bit = 0; bit < 32; bit++) { + if (masked[i] & (1 << bit)) + do_IRQ(bit + FIRST_IRQ + i*32, regs); + } } /* Unblock all the IRQs. */ - mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); - mask |= masked; - REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask); + for (i = 0; i < NBR_REGS; i++) { + mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i); + mask |= masked[i]; + REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask); + } /* This irq_exit() will trigger the soft IRQs. */ irq_exit(); @@ -361,20 +467,21 @@ init_IRQ(void) reg_intr_vect_rw_mask vect_mask = {0}; /* Clear all interrupts masks. */ - REG_WR(intr_vect, regi_irq, rw_mask, vect_mask); + for (i = 0; i < NBR_REGS; i++) + REG_WR_VECT(intr_vect, regi_irq, rw_mask, i, vect_mask); for (i = 0; i < 256; i++) etrax_irv->v[i] = weird_irq; - /* Point all IRQs to bad handlers. */ + /* Point all IRQ's to bad handlers. */ for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) { irq_desc[j].chip = &crisv32_irq_type; set_exception_vector(i, interrupt[j]); } /* Mark Timer and IPI IRQs as CPU local */ - irq_allocations[TIMER_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; - irq_desc[TIMER_INTR_VECT].status |= IRQ_PER_CPU; + irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; + irq_desc[TIMER0_INTR_VECT].status |= IRQ_PER_CPU; irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU; @@ -391,6 +498,11 @@ init_IRQ(void) set_exception_vector(0x0a, d_mmu_access); set_exception_vector(0x0b, d_mmu_write); +#ifdef CONFIG_BUG + /* Break 14 handler, used to implement cheap BUG(). */ + set_exception_vector(0x1e, breakh_BUG); +#endif + /* The system-call trap is reached by "break 13". */ set_exception_vector(0x1d, system_call); diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c index 480e56348be2..4e2e2e271efb 100644 --- a/arch/cris/arch-v32/kernel/kgdb.c +++ b/arch/cris/arch-v32/kernel/kgdb.c @@ -381,7 +381,7 @@ static int read_register(char regno, unsigned int *valptr); /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */ int getDebugChar(void); -#ifdef CONFIG_ETRAXFS_SIM +#ifdef CONFIG_ETRAX_VCS_SIM int getDebugChar(void) { return socketread(); @@ -391,7 +391,7 @@ int getDebugChar(void) /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ void putDebugChar(int val); -#ifdef CONFIG_ETRAXFS_SIM +#ifdef CONFIG_ETRAX_VCS_SIM void putDebugChar(int val) { socketwrite((char *)&val, 1); @@ -1599,7 +1599,7 @@ kgdb_init(void) REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask); - ser_intr_mask.data_avail = regk_ser_yes; + ser_intr_mask.dav = regk_ser_yes; REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask); #elif defined(CONFIG_ETRAX_KGDB_PORT1) /* Note: no shortcut registered (not handled by multiple_interrupt). @@ -1611,7 +1611,7 @@ kgdb_init(void) REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask); - ser_intr_mask.data_avail = regk_ser_yes; + ser_intr_mask.dav = regk_ser_yes; REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask); #elif defined(CONFIG_ETRAX_KGDB_PORT2) /* Note: no shortcut registered (not handled by multiple_interrupt). @@ -1623,7 +1623,7 @@ kgdb_init(void) REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask); - ser_intr_mask.data_avail = regk_ser_yes; + ser_intr_mask.dav = regk_ser_yes; REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask); #elif defined(CONFIG_ETRAX_KGDB_PORT3) /* Note: no shortcut registered (not handled by multiple_interrupt). @@ -1635,7 +1635,7 @@ kgdb_init(void) REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask); - ser_intr_mask.data_avail = regk_ser_yes; + ser_intr_mask.dav = regk_ser_yes; REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask); #endif diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index b72a15580dc7..ced5b725d9bd 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -12,17 +12,13 @@ #include <linux/err.h> #include <linux/fs.h> #include <linux/slab.h> -#include <asm/arch/hwregs/reg_rdwr.h> -#include <asm/arch/hwregs/reg_map.h> -#include <asm/arch/hwregs/timer_defs.h> -#include <asm/arch/hwregs/intr_vect_defs.h> +#include <hwregs/reg_rdwr.h> +#include <hwregs/reg_map.h> +#include <hwregs/timer_defs.h> +#include <hwregs/intr_vect_defs.h> extern void stop_watchdog(void); -#ifdef CONFIG_ETRAX_GPIO -extern void etrax_gpio_wake_up_check(void); /* Defined in drivers/gpio.c. */ -#endif - extern int cris_hlt_counter; /* We use this if we don't have any better idle routine. */ @@ -82,7 +78,7 @@ hard_reset_now(void) wd_ctrl.cmd = regk_timer_start; arch_enable_nmi(); - REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); + REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); } #endif diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index 2df60529a8af..e27f4670e88e 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2003, Axis Communications AB. + * Copyright (C) 2000-2007, Axis Communications AB. */ #include <linux/kernel.h> @@ -149,7 +149,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = generic_ptrace_pokedata(child, addr, data); break; - /* Write the word at location address in the USER area. */ + /* Write the word at location address in the USER area. */ case PTRACE_POKEUSR: ret = -EIO; if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) @@ -201,7 +201,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; - /* Make the child exit by sending it a sigkill. */ + /* Make the child exit by sending it a sigkill. */ case PTRACE_KILL: ret = 0; @@ -245,9 +245,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } + /* Get all GP registers from the child. */ case PTRACE_GETREGS: { - int i; + int i; unsigned long tmp; for (i = 0; i <= PT_MAX; i++) { @@ -294,6 +295,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } +out_tsk: return ret; } diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 024cc6901974..58c1866804e3 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -50,7 +50,7 @@ struct rt_signal_frame { unsigned char retcode[8]; /* Trampoline code. */ }; -int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs); +void do_signal(int restart, struct pt_regs *regs); void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, struct pt_regs *regs); /* @@ -61,74 +61,16 @@ 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; - + current->saved_sigmask = 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)) { - /* - * This point is reached twice: once to call - * the signal handler, then again to return - * from the sigsuspend system call. When - * calling the signal handler, R10 hold the - * signal number as set by do_signal(). The - * sigsuspend call will always return with - * the restored value above; -EINTR. - */ - return regs->r10; - } - } -} - -/* Define some dummy arguments to be able to reach the regs argument. */ -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; - sigset_t newset; - - 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)) { - /* See comment in function above. */ - return regs->r10; - } - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } int @@ -290,7 +232,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, goto badframe; if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) - goto badframe; + goto badframe; keep_debug_flags(oldccs, oldspc, regs); @@ -347,11 +289,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) /* Grab and setup a signal frame. * * Basically a lot of state-info is stacked, and arranged for the - * user-mode program to return to the kernel using either a trampoline + * user-mode program to return to the kernel using either a trampiline * which performs the syscall sigreturn(), or a provided user-mode * trampoline. */ -static void +static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { @@ -417,16 +359,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, /* Actually move the USP to reflect the stacked frame. */ wrusp((unsigned long)frame); - return; + return 0; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); + return -EFAULT; } -static void +static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { @@ -503,21 +446,24 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* Actually move the usp to reflect the stacked frame. */ wrusp((unsigned long)frame); - return; + return 0; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); + return -EFAULT; } /* Invoke a singal handler to, well, handle the signal. */ -static inline void +static inline int handle_signal(int canrestart, unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) { + int ret; + /* Check if this got called from a system call. */ if (canrestart) { /* If so, check system call restarting. */ @@ -561,19 +507,24 @@ handle_signal(int canrestart, unsigned long sig, /* 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); + ret = setup_frame(sig, ka, oldset, regs); if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - 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) { + 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); + } + + return ret; } /* @@ -587,12 +538,13 @@ handle_signal(int canrestart, unsigned long sig, * we can use user_mode(regs) to see if we came directly from kernel or user * mode below. */ -int -do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) +void +do_signal(int canrestart, struct pt_regs *regs) { int signr; siginfo_t info; struct k_sigaction ka; + sigset_t *oldset; /* * The common case should go fast, which is why this point is @@ -600,17 +552,28 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) * without doing anything. */ if (!user_mode(regs)) - return 1; + return; - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - /* Deliver the signal. */ - handle_signal(canrestart, signr, &info, &ka, oldset, regs); - return 1; + /* Whee! Actually deliver the signal. */ + if (handle_signal(canrestart, signr, &info, &ka, + oldset, regs)) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + + return; } /* Got here from a system call? */ @@ -628,7 +591,12 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) } } - return 0; + /* if there's no signal to deliver, we just put the saved sigmask + * back */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } asmlinkage void @@ -641,7 +609,7 @@ ugdb_trap_user(struct thread_info *ti, int sig) user_regs(ti)->spc = 0; } /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA - not within any configured h/w breakpoint range). Synchronize with + not withing any configured h/w breakpoint range). Synchronize with what already exists for kernel debugging. */ if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) { /* Break 8: subtract 2 from ERP unless in a delay slot. */ diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 171c96e0a5d3..a9c3334e46c9 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c @@ -1,11 +1,12 @@ +#include <linux/types.h> #include <asm/delay.h> -#include <asm/arch/irq.h> -#include <asm/arch/hwregs/intr_vect.h> -#include <asm/arch/hwregs/intr_vect_defs.h> +#include <irq.h> +#include <hwregs/intr_vect.h> +#include <hwregs/intr_vect_defs.h> #include <asm/tlbflush.h> #include <asm/mmu_context.h> -#include <asm/arch/hwregs/mmu_defs_asm.h> -#include <asm/arch/hwregs/supp_reg.h> +#include <hwregs/asm/mmu_defs_asm.h> +#include <hwregs/supp_reg.h> #include <asm/atomic.h> #include <linux/err.h> @@ -20,6 +21,7 @@ #define IPI_SCHEDULE 1 #define IPI_CALL 2 #define IPI_FLUSH_TLB 4 +#define IPI_BOOT 8 #define FLUSH_ALL (void*)0xffffffff @@ -30,6 +32,8 @@ spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED}; cpumask_t cpu_online_map = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); cpumask_t phys_cpu_present_map = CPU_MASK_NONE; +cpumask_t cpu_possible_map; +EXPORT_SYMBOL(cpu_possible_map); EXPORT_SYMBOL(phys_cpu_present_map); /* Variables used during SMP boot */ @@ -55,13 +59,12 @@ static unsigned long flush_addr; extern int setup_irq(int, struct irqaction *); /* Mode registers */ -static unsigned long irq_regs[NR_CPUS] = -{ +static unsigned long irq_regs[NR_CPUS] = { regi_irq, regi_irq2 }; -static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id); static int send_ipi(int vector, int wait, cpumask_t cpu_mask); static struct irqaction irq_ipi = { .handler = crisv32_ipi_interrupt, @@ -101,6 +104,7 @@ void __devinit smp_prepare_boot_cpu(void) cpu_set(0, cpu_online_map); cpu_set(0, phys_cpu_present_map); + cpu_set(0, cpu_possible_map); } void __init smp_cpus_done(unsigned int max_cpus) @@ -113,6 +117,7 @@ smp_boot_one_cpu(int cpuid) { unsigned timeout; struct task_struct *idle; + cpumask_t cpu_mask = CPU_MASK_NONE; idle = fork_idle(cpuid); if (IS_ERR(idle)) @@ -124,6 +129,12 @@ smp_boot_one_cpu(int cpuid) smp_init_current_idle_thread = task_thread_info(idle); cpu_now_booting = cpuid; + /* Kick it */ + cpu_set(cpuid, cpu_online_map); + cpu_set(cpuid, cpu_mask); + send_ipi(IPI_BOOT, 0, cpu_mask); + cpu_clear(cpuid, cpu_online_map); + /* Wait for CPU to come online */ for (timeout = 0; timeout < 10000; timeout++) { if(cpu_online(cpuid)) { @@ -165,7 +176,7 @@ void __init smp_callin(void) /* Enable IRQ and idle */ REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask); unmask_irq(IPI_INTR_VECT); - unmask_irq(TIMER_INTR_VECT); + unmask_irq(TIMER0_INTR_VECT); preempt_disable(); local_irq_enable(); @@ -328,7 +339,7 @@ int smp_call_function(void (*func)(void *info), void *info, return ret; } -irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id) { void (*func) (void *info) = call_data->func; void *info = call_data->info; diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index 2f7e8e200f2c..3a13dd6e0a9a 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -1,8 +1,7 @@ -/* $Id: time.c,v 1.19 2005/04/29 05:40:09 starvik Exp $ - * +/* * linux/arch/cris/arch-v32/kernel/time.c * - * Copyright (C) 2003 Axis Communications AB + * Copyright (C) 2003-2007 Axis Communications AB * */ @@ -14,28 +13,34 @@ #include <linux/sched.h> #include <linux/init.h> #include <linux/threads.h> +#include <linux/cpufreq.h> #include <asm/types.h> #include <asm/signal.h> #include <asm/io.h> #include <asm/delay.h> #include <asm/rtc.h> #include <asm/irq.h> - -#include <asm/arch/hwregs/reg_map.h> -#include <asm/arch/hwregs/reg_rdwr.h> -#include <asm/arch/hwregs/timer_defs.h> -#include <asm/arch/hwregs/intr_vect_defs.h> +#include <asm/irq_regs.h> + +#include <hwregs/reg_map.h> +#include <hwregs/reg_rdwr.h> +#include <hwregs/timer_defs.h> +#include <hwregs/intr_vect_defs.h> +#ifdef CONFIG_CRIS_MACH_ARTPEC3 +#include <hwregs/clkgen_defs.h> +#endif /* Watchdog defines */ -#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */ -#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */ -#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) /* Number of 763 counts before watchdog bites */ +#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */ +#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */ +/* Number of 763 counts before watchdog bites */ +#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) unsigned long timer_regs[NR_CPUS] = { - regi_timer, + regi_timer0, #ifdef CONFIG_SMP - regi_timer2 + regi_timer2 #endif }; @@ -44,12 +49,22 @@ extern int set_rtc_mmss(unsigned long nowtime); extern int setup_irq(int, struct irqaction *); extern int have_rtc; +#ifdef CONFIG_CPU_FREQ +static int +cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, + void *data); + +static struct notifier_block cris_time_freq_notifier_block = { + .notifier_call = cris_time_freq_notifier, +}; +#endif + unsigned long get_ns_in_jiffie(void) { reg_timer_r_tmr0_data data; unsigned long ns; - data = REG_RD(timer, regi_timer, r_tmr0_data); + data = REG_RD(timer, regi_timer0, r_tmr0_data); ns = (TIMER0_DIV - data) * 10; return ns; } @@ -59,31 +74,27 @@ unsigned long do_slow_gettimeoffset(void) unsigned long count; unsigned long usec_count = 0; - static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ + /* For the first call after boot */ + static unsigned long count_p = TIMER0_DIV; static unsigned long jiffies_p = 0; - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ + /* Cache volatile jiffies temporarily; we have IRQs turned off. */ unsigned long jiffies_t; /* 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. - */ + * underflowed already though. */ + count = REG_RD(timer, regi_timer0, r_tmr0_data); + jiffies_t = jiffies; - count = REG_RD(timer, regi_timer, r_tmr0_data); - 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 + /* Avoiding timer inconsistencies (they are rare, but they happen) + * There is 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 + /* Timer wrapped, use new count and prescale. + * Increase the time corresponding to one jiffy. */ usec_count = 1000000/HZ; } @@ -106,17 +117,15 @@ unsigned long do_slow_gettimeoffset(void) */ /* This gives us 1.3 ms to do something useful when the NMI comes */ -/* right now, starting the watchdog is the same as resetting it */ +/* Right now, starting the watchdog is the same as resetting it */ #define start_watchdog reset_watchdog #if defined(CONFIG_ETRAX_WATCHDOG) static short int watchdog_key = 42; /* arbitrary 7 bit number */ #endif -/* number of pages to consider "out of memory". it is normal that the memory - * is used though, so put this really low. - */ - +/* Number of pages to consider "out of memory". It is normal that the memory + * is used though, so set this really low. */ #define WATCHDOG_MIN_FREE_PAGES 8 void @@ -125,14 +134,15 @@ reset_watchdog(void) #if defined(CONFIG_ETRAX_WATCHDOG) reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; - /* only keep watchdog happy as long as we have memory left! */ + /* 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 */ - watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */ + /* Reset the watchdog with the inverse of the old key */ + /* Invert key, which is 7 bits */ + watchdog_key ^= ETRAX_WD_KEY_MASK; wd_ctrl.cnt = ETRAX_WD_CNT; wd_ctrl.cmd = regk_timer_start; wd_ctrl.key = watchdog_key; - REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); + REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); } #endif } @@ -148,7 +158,7 @@ stop_watchdog(void) wd_ctrl.cnt = ETRAX_WD_CNT; wd_ctrl.cmd = regk_timer_stop; wd_ctrl.key = watchdog_key; - REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); + REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); #endif } @@ -160,17 +170,28 @@ handle_watchdog_bite(struct pt_regs* regs) #if defined(CONFIG_ETRAX_WATCHDOG) extern int cause_of_death; - raw_printk("Watchdog bite\n"); + oops_in_progress = 1; + printk(KERN_WARNING "Watchdog bite\n"); /* Check if forced restart or unexpected watchdog */ if (cause_of_death == 0xbedead) { +#ifdef CONFIG_CRIS_MACH_ARTPEC3 + /* There is a bug in Artpec-3 (voodoo TR 78) that requires + * us to go to lower frequency for the reset to be reliable + */ + reg_clkgen_rw_clk_ctrl ctrl = + REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); + ctrl.pll = 0; + REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, ctrl); +#endif while(1); } - /* Unexpected watchdog, stop the watchdog and dump registers*/ + /* Unexpected watchdog, stop the watchdog and dump registers. */ stop_watchdog(); - raw_printk("Oops: bitten by watchdog\n"); - show_registers(regs); + printk(KERN_WARNING "Oops: bitten by watchdog\n"); + show_registers(regs); + oops_in_progress = 0; #ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY reset_watchdog(); #endif @@ -178,21 +199,19 @@ handle_watchdog_bite(struct pt_regs* regs) #endif } -/* last time the cmos clock got updated */ +/* Last time the cmos clock got updated. */ static long last_rtc_update = 0; /* * 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 "do_timer()" 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) +timer_interrupt(int irq, void *dev_id) { + struct pt_regs *regs = get_irq_regs(); int cpu = smp_processor_id(); reg_timer_r_masked_intr masked_intr; reg_timer_rw_ack_intr ack_intr = { 0 }; @@ -202,11 +221,11 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!masked_intr.tmr0) return IRQ_NONE; - /* acknowledge the timer irq */ + /* Acknowledge the timer irq. */ ack_intr.tmr0 = 1; REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr); - /* reset watchdog otherwise it resets us! */ + /* Reset watchdog otherwise it resets us! */ reset_watchdog(); /* Update statistics. */ @@ -218,7 +237,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (cpu != 0) return IRQ_HANDLED; - /* call the real timer interrupt handler */ + /* Call the real timer interrupt handler */ do_timer(1); /* @@ -236,17 +255,17 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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 */ + /* Do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; } 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. + * It needs to be IRQF_DISABLED to make the jiffies update work properly. */ - -static struct irqaction irq_timer = { - .mask = timer_interrupt, +static struct irqaction irq_timer = { + .handler = timer_interrupt, .flags = IRQF_SHARED | IRQF_DISABLED, .mask = CPU_MASK_NONE, .name = "timer" @@ -256,27 +275,27 @@ void __init cris_timer_init(void) { int cpu = smp_processor_id(); - reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; - reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV; + reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; + reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV; reg_timer_rw_intr_mask timer_intr_mask; - /* Setup the etrax timers + /* Setup the etrax timers. * Base frequency is 100MHz, divider 1000000 -> 100 HZ * We use timer0, so timer1 is free. * The trig timer is used by the fasttimer API if enabled. */ - tmr0_ctrl.op = regk_timer_ld; + tmr0_ctrl.op = regk_timer_ld; tmr0_ctrl.freq = regk_timer_f100; - REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div); - REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */ - tmr0_ctrl.op = regk_timer_run; - REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */ - - /* enable the timer irq */ - timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask); - timer_intr_mask.tmr0 = 1; - REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); + REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div); + REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */ + tmr0_ctrl.op = regk_timer_run; + REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */ + + /* Enable the timer irq. */ + timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask); + timer_intr_mask.tmr0 = 1; + REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); } void __init @@ -284,7 +303,7 @@ time_init(void) { reg_intr_vect_rw_mask intr_mask; - /* probe for the RTC and read it if it exists + /* 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 @@ -293,52 +312,74 @@ time_init(void) loops_per_usec = 50; if(RTC_INIT() < 0) { - /* no RTC, start at 1980 */ + /* No RTC, start at 1980 */ xtime.tv_sec = 0; xtime.tv_nsec = 0; have_rtc = 0; } else { - /* get the current time */ + /* Get the current time */ have_rtc = 1; update_xtime_from_cmos(); } /* - * 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). + * 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). */ set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - /* Start CPU local timer */ + /* Start CPU local timer. */ cris_timer_init(); - /* enable the timer irq in global config */ - intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); - intr_mask.timer = 1; - REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); - - /* now actually register the timer irq handler that calls timer_interrupt() */ + /* Enable the timer irq in global config. */ + intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1); + intr_mask.timer0 = 1; + REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask); - setup_irq(TIMER_INTR_VECT, &irq_timer); + /* Now actually register the timer irq handler that calls + * timer_interrupt(). */ + setup_irq(TIMER0_INTR_VECT, &irq_timer); - /* enable watchdog if we should use one */ + /* Enable watchdog if we should use one. */ #if defined(CONFIG_ETRAX_WATCHDOG) - printk("Enabling watchdog...\n"); + printk(KERN_INFO "Enabling watchdog...\n"); start_watchdog(); /* If we use the hardware watchdog, we want to trap it as an NMI - and dump registers before it resets us. For this to happen, we - must set the "m" NMI enable flag (which once set, is unset only - when an NMI is taken). - - The same goes for the external NMI, but that doesn't have any - driver or infrastructure support yet. */ - { - unsigned long flags; - local_save_flags(flags); - flags |= (1<<30); /* NMI M flag is at bit 30 */ - local_irq_restore(flags); - } + * and dump registers before it resets us. For this to happen, we + * must set the "m" NMI enable flag (which once set, is unset only + * when an NMI is taken). */ + { + unsigned long flags; + local_save_flags(flags); + flags |= (1<<30); /* NMI M flag is at bit 30 */ + local_irq_restore(flags); + } +#endif + +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&cris_time_freq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); #endif } + +#ifdef CONFIG_CPU_FREQ +static int +cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freqs = data; + if (val == CPUFREQ_POSTCHANGE) { + reg_timer_r_tmr0_data data; + reg_timer_rw_tmr0_div div = (freqs->new * 500) / HZ; + do { + data = REG_RD(timer, timer_regs[freqs->cpu], + r_tmr0_data); + } while (data > 20); + REG_WR(timer, timer_regs[freqs->cpu], rw_tmr0_div, div); + } + return 0; +} +#endif diff --git a/arch/cris/arch-v32/kernel/traps.c b/arch/cris/arch-v32/kernel/traps.c index 17fd3dbd1c80..9003e382cada 100644 --- a/arch/cris/arch-v32/kernel/traps.c +++ b/arch/cris/arch-v32/kernel/traps.c @@ -1,50 +1,45 @@ /* - * Copyright (C) 2003, Axis Communications AB. + * Copyright (C) 2003-2006, Axis Communications AB. */ #include <linux/ptrace.h> +#include <linux/module.h> #include <asm/uaccess.h> - -#include <asm/arch/hwregs/supp_reg.h> - -extern void reset_watchdog(void); -extern void stop_watchdog(void); - -extern int raw_printk(const char *fmt, ...); +#include <hwregs/supp_reg.h> +#include <hwregs/intr_vect_defs.h> +#include <asm/irq.h> void show_registers(struct pt_regs *regs) { /* * It's possible to use either the USP register or current->thread.usp. - * USP might not correspond to the current proccess for all cases this + * 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 proccess. Experience shows that using USP is the way to go. + * current process. Experience shows that using USP is the way to go. */ - unsigned long usp; + unsigned long usp = rdusp(); unsigned long d_mmu_cause; unsigned long i_mmu_cause; - usp = rdusp(); + printk("CPU: %d\n", smp_processor_id()); - raw_printk("CPU: %d\n", smp_processor_id()); + printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", + regs->erp, regs->srp, regs->ccs, usp, regs->mof); - raw_printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", - regs->erp, regs->srp, regs->ccs, usp, regs->mof); + printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", + regs->r0, regs->r1, regs->r2, regs->r3); - raw_printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", - regs->r0, regs->r1, regs->r2, regs->r3); + printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", + regs->r4, regs->r5, regs->r6, regs->r7); - raw_printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", - regs->r4, regs->r5, regs->r6, regs->r7); + printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", + regs->r8, regs->r9, regs->r10, regs->r11); - raw_printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", - regs->r8, regs->r9, regs->r10, regs->r11); + printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", + regs->r12, regs->r13, regs->orig_r10, regs->acr); - raw_printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", - regs->r12, regs->r13, regs->orig_r10, regs->acr); - - raw_printk("sp: %08lx\n", regs); + printk(" sp: %08lx\n", (unsigned long)regs); SUPP_BANK_SEL(BANK_IM); SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause); @@ -52,18 +47,20 @@ show_registers(struct pt_regs *regs) SUPP_BANK_SEL(BANK_DM); SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause); - raw_printk(" Data MMU Cause: %08lx\n", d_mmu_cause); - raw_printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); + printk(" Data MMU Cause: %08lx\n", d_mmu_cause); + printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); - raw_printk("Process %s (pid: %d, stackpage: %08lx)\n", - current->comm, current->pid, (unsigned long) current); + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, (unsigned long)current); - /* Show additional info if in kernel-mode. */ + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ if (!user_mode(regs)) { int i; - unsigned char c; - show_stack(NULL, (unsigned long *) usp); + show_stack(NULL, (unsigned long *)usp); /* * If the previous stack-dump wasn't a kernel one, dump the @@ -72,7 +69,7 @@ show_registers(struct pt_regs *regs) if (usp != 0) show_stack(NULL, NULL); - raw_printk("\nCode: "); + printk("\nCode: "); if (regs->erp < PAGE_OFFSET) goto bad_value; @@ -84,76 +81,115 @@ show_registers(struct pt_regs *regs) * instruction decoding should be in sync at the interesting * point, but small enough to fit on a row. The regs->erp * location is pointed out in a ksymoops-friendly way by - * wrapping the byte for that address in parenthesis. + * wrapping the byte for that address in parenthesises. */ for (i = -12; i < 12; i++) { - if (__get_user(c, &((unsigned char *) regs->erp)[i])) { + unsigned char c; + + if (__get_user(c, &((unsigned char *)regs->erp)[i])) { bad_value: - raw_printk(" Bad IP value."); + printk(" Bad IP value."); break; } if (i == 0) - raw_printk("(%02x) ", c); + printk("(%02x) ", c); else - raw_printk("%02x ", c); + printk("%02x ", c); } - - raw_printk("\n"); + printk("\n"); } } -/* - * This gets called from entry.S when the watchdog has bitten. Show something - * similar to an Oops dump, and if the kernel is configured to be a nice doggy; - * halt instead of reboot. - */ 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); + unsigned long flags; - while (1) - ; /* Do nothing. */ -#else - show_registers(regs); -#endif + local_save_flags(flags); + flags |= (1 << 30); /* NMI M flag is at bit 30 */ + local_irq_restore(flags); } -/* This is normally the Oops function. */ -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_ETRAXFS + reg_intr_vect_r_nmi r; +#endif -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - /* - * This printout might take too long and could trigger - * the watchdog normally. If NICE_DOGGY is set, simply - * stop the watchdog during the printout. - */ - stop_watchdog(); + if (nmi_handler) + nmi_handler(regs); + +#ifdef CONFIG_ETRAXFS + /* Wait until nmi is no longer active. */ + do { + r = REG_RD(intr_vect, regi_irq, r_nmi); + } while (r.ext == regk_intr_vect_on); #endif +} - raw_printk("%s: %04lx\n", str, err & 0xffff); - show_registers(regs); +#ifdef CONFIG_BUG +extern void die_if_kernel(const char *str, struct pt_regs *regs, long err); -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - reset_watchdog(); -#endif +/* Copy of the regs at BUG() time. */ +struct pt_regs BUG_regs; - do_exit(SIGSEGV); +void do_BUG(char *file, unsigned int line) +{ + printk("kernel BUG at %s:%d!\n", file, line); + die_if_kernel("Oops", &BUG_regs, 0); } +EXPORT_SYMBOL(do_BUG); -void arch_enable_nmi(void) +void fixup_BUG(struct pt_regs *regs) { - unsigned long flags; - local_save_flags(flags); - flags |= (1<<30); /* NMI M flag is at bit 30 */ - local_irq_restore(flags); + BUG_regs = *regs; + +#ifdef CONFIG_DEBUG_BUGVERBOSE + /* + * Fixup the BUG arguments through exception handlers. + */ + { + const struct exception_table_entry *fixup; + + /* + * ERP points at the "break 14" + 2, compensate for the 2 + * bytes. + */ + fixup = search_exception_tables(instruction_pointer(regs) - 2); + if (fixup) { + /* Adjust the instruction pointer in the stackframe. */ + instruction_pointer(regs) = fixup->fixup; + arch_fixup(regs); + } + } +#else + /* Dont try to lookup the filename + line, just dump regs. */ + do_BUG("unknown", 0); +#endif } + +/* + * Break 14 handler. Save regs and jump into the fixup_BUG. + */ +__asm__ ( ".text\n\t" + ".global breakh_BUG\n\t" + "breakh_BUG:\n\t" + SAVE_ALL + KGDB_FIXUP + "move.d $sp, $r10\n\t" + "jsr fixup_BUG\n\t" + "nop\n\t" + "jump ret_from_intr\n\t" + "nop\n\t"); + + +#ifdef CONFIG_DEBUG_BUGVERBOSE +void +handle_BUG(struct pt_regs *regs) +{ +} +#endif +#endif diff --git a/arch/cris/arch-v32/kernel/vcs_hook.c b/arch/cris/arch-v32/kernel/vcs_hook.c deleted file mode 100644 index 64d71c54c22c..000000000000 --- a/arch/cris/arch-v32/kernel/vcs_hook.c +++ /dev/null @@ -1,96 +0,0 @@ -// $Id: vcs_hook.c,v 1.2 2003/08/12 12:01:06 starvik Exp $ -// -// Call simulator hook. This is the part running in the -// simulated program. -// - -#include "vcs_hook.h" -#include <stdarg.h> -#include <asm/arch-v32/hwregs/reg_map.h> -#include <asm/arch-v32/hwregs/intr_vect_defs.h> - -#define HOOK_TRIG_ADDR 0xb7000000 /* hook cvlog model reg address */ -#define HOOK_MEM_BASE_ADDR 0xa0000000 /* csp4 (shared mem) base addr */ - -#define HOOK_DATA(offset) ((unsigned*) HOOK_MEM_BASE_ADDR)[offset] -#define VHOOK_DATA(offset) ((volatile unsigned*) HOOK_MEM_BASE_ADDR)[offset] -#define HOOK_TRIG(funcid) do { *((unsigned *) HOOK_TRIG_ADDR) = funcid; } while(0) -#define HOOK_DATA_BYTE(offset) ((unsigned char*) HOOK_MEM_BASE_ADDR)[offset] - - -// ------------------------------------------------------------------ hook_call -int hook_call( unsigned id, unsigned pcnt, ...) { - va_list ap; - unsigned i; - unsigned ret; -#ifdef USING_SOS - PREEMPT_OFF_SAVE(); -#endif - - // pass parameters - HOOK_DATA(0) = id; - - /* Have to make hook_print_str a special case since we call with a - parameter of byte type. Should perhaps be a separate - hook_call. */ - - if (id == hook_print_str) { - int i; - char *str; - - HOOK_DATA(1) = pcnt; - - va_start(ap, pcnt); - str = (char*)va_arg(ap,unsigned); - - for (i=0; i!=pcnt; i++) { - HOOK_DATA_BYTE(8+i) = str[i]; - } - HOOK_DATA_BYTE(8+i) = 0; /* null byte */ - } - else { - va_start(ap, pcnt); - for( i = 1; i <= pcnt; i++ ) HOOK_DATA(i) = va_arg(ap,unsigned); - va_end(ap); - } - - // read from mem to make sure data has propagated to memory before trigging - *((volatile unsigned*) HOOK_MEM_BASE_ADDR); - - // trigger hook - HOOK_TRIG(id); - - // wait for call to finish - while( VHOOK_DATA(0) > 0 ) {} - - // extract return value - - ret = VHOOK_DATA(1); - -#ifdef USING_SOS - PREEMPT_RESTORE(); -#endif - return ret; -} - -unsigned -hook_buf(unsigned i) -{ - return (HOOK_DATA(i)); -} - -void print_str( const char *str ) { - int i; - for (i=1; str[i]; i++); /* find null at end of string */ - hook_call(hook_print_str, i, str); -} - -// --------------------------------------------------------------- CPU_KICK_DOG -void CPU_KICK_DOG(void) { - (void) hook_call( hook_kick_dog, 0 ); -} - -// ------------------------------------------------------- CPU_WATCHDOG_TIMEOUT -void CPU_WATCHDOG_TIMEOUT( unsigned t ) { - (void) hook_call( hook_dog_timeout, 1, t ); -} diff --git a/arch/cris/arch-v32/kernel/vcs_hook.h b/arch/cris/arch-v32/kernel/vcs_hook.h deleted file mode 100644 index 7d73709e3cc6..000000000000 --- a/arch/cris/arch-v32/kernel/vcs_hook.h +++ /dev/null @@ -1,42 +0,0 @@ -// $Id: vcs_hook.h,v 1.1 2003/08/12 12:01:06 starvik Exp $ -// -// Call simulator hook functions - -#ifndef HOOK_H -#define HOOK_H - -int hook_call( unsigned id, unsigned pcnt, ...); - -enum hook_ids { - hook_debug_on = 1, - hook_debug_off, - hook_stop_sim_ok, - hook_stop_sim_fail, - hook_alloc_shared, - hook_ptr_shared, - hook_free_shared, - hook_file2shared, - hook_cmp_shared, - hook_print_params, - hook_sim_time, - hook_stop_sim, - hook_kick_dog, - hook_dog_timeout, - hook_rand, - hook_srand, - hook_rand_range, - hook_print_str, - hook_print_hex, - hook_cmp_offset_shared, - hook_fill_random_shared, - hook_alloc_random_data, - hook_calloc_random_data, - hook_print_int, - hook_print_uint, - hook_fputc, - hook_init_fd, - hook_sbrk - -}; - -#endif |