diff options
Diffstat (limited to 'arch/cris/arch-v10/kernel')
-rw-r--r-- | arch/cris/arch-v10/kernel/Makefile | 5 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/debugport.c | 273 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/dma.c | 287 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/entry.S | 54 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/fasttimer.c | 55 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/head.S | 126 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/io_interface_mux.c | 879 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/irq.c | 76 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/kgdb.c | 17 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/process.c | 3 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/ptrace.c | 9 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/shadows.c | 3 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/traps.c | 37 |
13 files changed, 1574 insertions, 250 deletions
diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile index 52761603b6a..dcfec41d353 100644 --- a/arch/cris/arch-v10/kernel/Makefile +++ b/arch/cris/arch-v10/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $ +# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $ # # Makefile for the linux kernel. # @@ -7,7 +7,8 @@ extra-y := head.o obj-y := entry.o traps.o shadows.o debugport.o irq.o \ - process.o setup.o signal.o traps.o time.o ptrace.o + process.o setup.o signal.o traps.o time.o ptrace.o \ + dma.o io_interface_mux.o obj-$(CONFIG_ETRAX_KGDB) += kgdb.o obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index 6cf069e5e7b..f3a85b77c17 100644 --- a/arch/cris/arch-v10/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -12,6 +12,31 @@ * init_etrax_debug() * * $Log: debugport.c,v $ + * Revision 1.27 2005/06/10 10:34:14 starvik + * Real console support + * + * Revision 1.26 2005/06/07 07:06:07 starvik + * Added LF->CR translation to make ETRAX customers happy. + * + * Revision 1.25 2005/03/08 08:56:47 mikaelam + * Do only set index as port->index if port is defined, otherwise use the index from the command line + * + * Revision 1.24 2005/01/19 10:26:33 mikaelam + * Return the cris serial driver in console device driver callback function + * + * Revision 1.23 2005/01/14 10:12:17 starvik + * KGDB on separate port. + * Console fixes from 2.4. + * + * Revision 1.22 2005/01/11 16:06:13 starvik + * typo + * + * Revision 1.21 2005/01/11 13:49:14 starvik + * Added raw_printk to be used where we don't trust the console. + * + * Revision 1.20 2004/12/27 11:18:32 starvik + * Merge of Linux 2.6.10 (not functional yet). + * * Revision 1.19 2004/10/21 07:26:16 starvik * Made it possible to specify console settings on kernel command line. * @@ -114,7 +139,11 @@ struct dbg_port ports[]= R_SERIAL0_BAUD, R_SERIAL0_TR_CTRL, R_SERIAL0_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser0_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser0_data, set), + 0, + 115200, + 'N', + 8 }, { 1, @@ -124,7 +153,11 @@ struct dbg_port ports[]= R_SERIAL1_BAUD, R_SERIAL1_TR_CTRL, R_SERIAL1_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser1_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser1_data, set), + 0, + 115200, + 'N', + 8 }, { 2, @@ -134,7 +167,11 @@ struct dbg_port ports[]= R_SERIAL2_BAUD, R_SERIAL2_TR_CTRL, R_SERIAL2_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser2_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser2_data, set), + 0, + 115200, + 'N', + 8 }, { 3, @@ -144,11 +181,15 @@ struct dbg_port ports[]= R_SERIAL3_BAUD, R_SERIAL3_TR_CTRL, R_SERIAL3_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser3_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser3_data, set), + 0, + 115200, + 'N', + 8 } }; -static struct tty_driver *serial_driver; +extern struct tty_driver *serial_driver; struct dbg_port* port = #if defined(CONFIG_ETRAX_DEBUG_PORT0) @@ -162,37 +203,44 @@ struct dbg_port* port = #else NULL; #endif -/* Used by serial.c to register a debug_write_function so that the normal - * serial driver is used for kernel debug output - */ -typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len); -debugport_write_function debug_write_function = NULL; +static struct dbg_port* kgdb_port = +#if defined(CONFIG_ETRAX_KGDB_PORT0) + &ports[0]; +#elif defined(CONFIG_ETRAX_KGDB_PORT1) + &ports[1]; +#elif defined(CONFIG_ETRAX_KGDB_PORT2) + &ports[2]; +#elif defined(CONFIG_ETRAX_KGDB_PORT3) + &ports[3]; +#else + NULL; +#endif static void -start_port(void) +start_port(struct dbg_port* p) { unsigned long rec_ctrl = 0; unsigned long tr_ctrl = 0; - if (!port) + if (!p) return; - if (port->started) + if (p->started) return; - port->started = 1; + p->started = 1; - if (port->index == 0) + if (p->index == 0) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); } - else if (port->index == 1) + else if (p->index == 1) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); } - else if (port->index == 2) + else if (p->index == 2) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); @@ -211,69 +259,69 @@ start_port(void) *R_GEN_CONFIG = genconfig_shadow; - *port->xoff = + *p->xoff = IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) | IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) | IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0); - switch (port->baudrate) + switch (p->baudrate) { case 0: case 115200: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); break; case 1200: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz); break; case 2400: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz); break; case 4800: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz); break; case 9600: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz); break; case 19200: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz); break; case 38400: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz); break; case 57600: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz); break; default: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); break; } - if (port->parity == 'E') { + if (p->parity == 'E') { rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); tr_ctrl = IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); - } else if (port->parity == 'O') { + } else if (p->parity == 'O') { rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); @@ -288,8 +336,7 @@ start_port(void) IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable); } - - if (port->bits == 7) + if (p->bits == 7) { rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); @@ -300,7 +347,7 @@ start_port(void) tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit); } - *port->rec_ctrl = + *p->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) | IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) | IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) | @@ -308,7 +355,7 @@ start_port(void) IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) | rec_ctrl; - *port->tr_ctrl = + *p->tr_ctrl = IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) | IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) | IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) | @@ -323,8 +370,18 @@ console_write_direct(struct console *co, const char *buf, unsigned int len) int i; unsigned long flags; local_irq_save(flags); + + if (!port) + return; + /* Send data */ for (i = 0; i < len; i++) { + /* LF -> CRLF */ + if (buf[i] == '\n') { + while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) + ; + *port->write = '\r'; + } /* Wait until transmitter is ready and send.*/ while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) ; @@ -333,6 +390,25 @@ console_write_direct(struct console *co, const char *buf, unsigned int len) local_irq_restore(flags); } +int raw_printk(const char *fmt, ...) +{ + static char buf[1024]; + int printed_len; + static int first = 1; + if (first) { + /* Force reinitialization of the port to get manual mode. */ + port->started = 0; + start_port(port); + first = 0; + } + va_list args; + va_start(args, fmt); + printed_len = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + console_write_direct(NULL, buf, strlen(buf)); + return printed_len; +} + static void console_write(struct console *co, const char *buf, unsigned int len) { @@ -345,18 +421,7 @@ console_write(struct console *co, const char *buf, unsigned int len) return; #endif - start_port(); - -#ifdef CONFIG_ETRAX_KGDB - /* kgdb needs to output debug info using the gdb protocol */ - putDebugString(buf, len); - return; -#endif - - if (debug_write_function) - debug_write_function(co->index, buf, len); - else - console_write_direct(co, buf, len); + console_write_direct(co, buf, len); } /* legacy function */ @@ -374,8 +439,11 @@ getDebugChar(void) { unsigned long readval; + if (!kgdb_port) + return 0; + do { - readval = *port->read; + readval = *kgdb_port->read; } while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail))); return (readval & IO_MASK(R_SERIAL0_READ, data_in)); @@ -386,9 +454,12 @@ getDebugChar(void) void putDebugChar(int val) { - while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) + if (!kgdb_port) + return; + + while (!(*kgdb_port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) ; - *port->write = val; + *kgdb_port->write = val; } /* Enable irq for receiving chars on the debug port, used by kgdb */ @@ -396,19 +467,16 @@ putDebugChar(int val) void enableDebugIRQ(void) { - *R_IRQ_MASK1_SET = port->irq; + if (!kgdb_port) + return; + + *R_IRQ_MASK1_SET = kgdb_port->irq; /* use R_VECT_MASK directly, since we really bypass Linux normal * IRQ handling in kgdb anyway, we don't need to use enable_irq */ *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); - *port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); -} - -static struct tty_driver* -etrax_console_device(struct console* co, int *index) -{ - return serial_driver; + *kgdb_port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); } static int __init @@ -428,11 +496,69 @@ console_setup(struct console *co, char *options) if (*s) port->parity = *s++; if (*s) port->bits = *s++ - '0'; port->started = 0; - start_port(); + start_port(0); } 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_NO_DEVFS; + + 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* +etrax_console_device(struct console* co, int *index) +{ + if (port) + *index = port->index; + return port ? serial_driver : &dummy_driver; +} + static struct console sercons = { name : "ttyS", write: console_write, @@ -504,28 +630,21 @@ init_etrax_debug(void) static int first = 1; if (!first) { - if (!port) { - register_console(&sercons0); - register_console(&sercons1); - register_console(&sercons2); - register_console(&sercons3); - unregister_console(&sercons); - } + unregister_console(&sercons); + register_console(&sercons0); + register_console(&sercons1); + register_console(&sercons2); + register_console(&sercons3); + init_dummy_console(); return 0; } - first = 0; - if (port) - register_console(&sercons); - return 0; -} -int __init -init_console(void) -{ - serial_driver = alloc_tty_driver(1); - if (!serial_driver) - return -ENOMEM; + first = 0; + register_console(&sercons); + start_port(port); +#ifdef CONFIG_ETRAX_KGDB + start_port(kgdb_port); +#endif return 0; } - __initcall(init_etrax_debug); diff --git a/arch/cris/arch-v10/kernel/dma.c b/arch/cris/arch-v10/kernel/dma.c new file mode 100644 index 00000000000..e9a0311b141 --- /dev/null +++ b/arch/cris/arch-v10/kernel/dma.c @@ -0,0 +1,287 @@ +/* Wrapper for DMA channel allocator that updates DMA client muxing. + * Copyright 2004, Axis Communications AB + * $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $ + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> + +#include <asm/dma.h> +#include <asm/arch/svinto.h> + +/* Macro to access ETRAX 100 registers */ +#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_STATE_(reg##_, field##_, _##val) + + +static char used_dma_channels[MAX_DMA_CHANNELS]; +static const char * used_dma_channels_users[MAX_DMA_CHANNELS]; + +int cris_request_dma(unsigned int dmanr, const char * device_id, + unsigned options, enum dma_owner owner) +{ + unsigned long flags; + unsigned long int gens; + int fail = -EINVAL; + + if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) { + printk(KERN_CRIT "cris_request_dma: invalid DMA channel %u\n", dmanr); + return -EINVAL; + } + + local_irq_save(flags); + if (used_dma_channels[dmanr]) { + local_irq_restore(flags); + if (options & DMA_VERBOSE_ON_ERROR) { + printk(KERN_CRIT "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; + } + + gens = genconfig_shadow; + + switch(owner) + { + case dma_eth: + if ((dmanr != NETWORK_TX_DMA_NBR) && + (dmanr != NETWORK_RX_DMA_NBR)) { + printk(KERN_CRIT "Invalid DMA channel for eth\n"); + goto bail; + } + break; + case dma_ser0: + if (dmanr == SER0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma6, serial0); + } else if (dmanr == SER0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma7, serial0); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser0\n"); + goto bail; + } + break; + case dma_ser1: + if (dmanr == SER1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma8, serial1); + } else if (dmanr == SER1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma9, serial1); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser1\n"); + goto bail; + } + break; + case dma_ser2: + if (dmanr == SER2_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, serial2); + } else if (dmanr == SER2_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, serial2); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser2\n"); + goto bail; + } + break; + case dma_ser3: + if (dmanr == SER3_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, serial3); + } else if (dmanr == SER3_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, serial3); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser3\n"); + goto bail; + } + break; + case dma_ata: + if (dmanr == ATA_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, ata); + } else if (dmanr == ATA_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, ata); + } else { + printk(KERN_CRIT "Invalid DMA channel for ata\n"); + goto bail; + } + break; + case dma_ext0: + if (dmanr == EXTDMA0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, extdma0); + } else if (dmanr == EXTDMA0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, extdma0); + } else { + printk(KERN_CRIT "Invalid DMA channel for ext0\n"); + goto bail; + } + break; + case dma_ext1: + if (dmanr == EXTDMA1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma6, extdma1); + } else if (dmanr == EXTDMA1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma7, extdma1); + } else { + printk(KERN_CRIT "Invalid DMA channel for ext1\n"); + goto bail; + } + break; + case dma_int6: + if (dmanr == MEM2MEM_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma7, intdma6); + } else { + printk(KERN_CRIT "Invalid DMA channel for int6\n"); + goto bail; + } + break; + case dma_int7: + if (dmanr == MEM2MEM_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma6, intdma7); + } else { + printk(KERN_CRIT "Invalid DMA channel for int7\n"); + goto bail; + } + break; + case dma_usb: + if (dmanr == USB_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma8, usb); + } else if (dmanr == USB_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma9, usb); + } else { + printk(KERN_CRIT "Invalid DMA channel for usb\n"); + goto bail; + } + break; + case dma_scsi0: + if (dmanr == SCSI0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, scsi0); + } else if (dmanr == SCSI0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, scsi0); + } else { + printk(KERN_CRIT "Invalid DMA channel for scsi0\n"); + goto bail; + } + break; + case dma_scsi1: + if (dmanr == SCSI1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, scsi1); + } else if (dmanr == SCSI1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, scsi1); + } else { + printk(KERN_CRIT "Invalid DMA channel for scsi1\n"); + goto bail; + } + break; + case dma_par0: + if (dmanr == PAR0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, par0); + } else if (dmanr == PAR0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, par0); + } else { + printk(KERN_CRIT "Invalid DMA channel for par0\n"); + goto bail; + } + break; + case dma_par1: + if (dmanr == PAR1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, par1); + } else if (dmanr == PAR1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, par1); + } else { + printk(KERN_CRIT "Invalid DMA channel for par1\n"); + goto bail; + } + break; + default: + printk(KERN_CRIT "Invalid DMA owner.\n"); + goto bail; + } + + used_dma_channels[dmanr] = 1; + used_dma_channels_users[dmanr] = device_id; + + { + volatile int i; + genconfig_shadow = gens; + *R_GEN_CONFIG = genconfig_shadow; + /* Wait 12 cycles before doing any DMA command */ + for(i = 6; i > 0; i--) + nop(); + } + fail = 0; + bail: + local_irq_restore(flags); + return fail; +} + +void cris_free_dma(unsigned int dmanr, const char * device_id) +{ + unsigned long flags; + if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) { + printk(KERN_CRIT "cris_free_dma: invalid DMA channel %u\n", dmanr); + return; + } + + local_irq_save(flags); + if (!used_dma_channels[dmanr]) { + printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated\n", dmanr); + } else if (device_id != used_dma_channels_users[dmanr]) { + printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated by device\n", dmanr); + } else { + switch(dmanr) + { + case 0: + *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH0_CMD, cmd, *R_DMA_CH0_CMD) == + IO_STATE_VALUE(R_DMA_CH0_CMD, cmd, reset)); + break; + case 1: + *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH1_CMD, cmd, *R_DMA_CH1_CMD) == + IO_STATE_VALUE(R_DMA_CH1_CMD, cmd, reset)); + break; + case 2: + *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH2_CMD, cmd, *R_DMA_CH2_CMD) == + IO_STATE_VALUE(R_DMA_CH2_CMD, cmd, reset)); + break; + case 3: + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH3_CMD, cmd, *R_DMA_CH3_CMD) == + IO_STATE_VALUE(R_DMA_CH3_CMD, cmd, reset)); + break; + case 4: + *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH4_CMD, cmd, *R_DMA_CH4_CMD) == + IO_STATE_VALUE(R_DMA_CH4_CMD, cmd, reset)); + break; + case 5: + *R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH5_CMD, cmd, *R_DMA_CH5_CMD) == + IO_STATE_VALUE(R_DMA_CH5_CMD, cmd, reset)); + break; + case 6: + *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *R_DMA_CH6_CMD) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + break; + case 7: + *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH7_CMD, cmd, *R_DMA_CH7_CMD) == + IO_STATE_VALUE(R_DMA_CH7_CMD, cmd, reset)); + break; + case 8: + *R_DMA_CH8_CMD = IO_STATE(R_DMA_CH8_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH8_CMD, cmd, *R_DMA_CH8_CMD) == + IO_STATE_VALUE(R_DMA_CH8_CMD, cmd, reset)); + break; + case 9: + *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH9_CMD, cmd, *R_DMA_CH9_CMD) == + IO_STATE_VALUE(R_DMA_CH9_CMD, cmd, reset)); + break; + } + used_dma_channels[dmanr] = 0; + } + local_irq_restore(flags); +} + +EXPORT_SYMBOL(cris_request_dma); +EXPORT_SYMBOL(cris_free_dma); diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 1bc44f481c3..c0163bf94a5 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $ +/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 starvik Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,22 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.28 2005/06/20 05:06:30 starvik + * Remove unnecessary diff to kernel.org tree + * + * Revision 1.27 2005/03/04 08:16:16 starvik + * Merge of Linux 2.6.11. + * + * Revision 1.26 2005/01/11 13:49:47 starvik + * Added NMI handler. + * + * Revision 1.25 2004/12/27 11:18:32 starvik + * Merge of Linux 2.6.10 (not functional yet). + * + * Revision 1.24 2004/12/22 10:41:23 starvik + * Updates to make v10 compile with the latest SMP aware generic code (even + * though v10 will never have SMP). + * * Revision 1.23 2004/10/19 13:07:37 starvik * Merge of Linux 2.6.9 * @@ -279,6 +295,7 @@ #ifdef CONFIG_PREEMPT ; Check if preemptive kernel scheduling should be done _resume_kernel: + di ; Load current task struct movs.w -8192, $r0 ; THREAD_SIZE = 8192 and.d $sp, $r0 @@ -291,12 +308,7 @@ _need_resched: bpl _Rexit nop ; Ok, lets's do some preemptive kernel scheduling - move.d PREEMPT_ACTIVE, $r10 - move.d $r10, [$r0+TI_preempt_count] ; Mark as active - ei - jsr schedule - clear.d [$r0+TI_preempt_count] ; Mark as inactive - di + jsr preempt_schedule_irq ; Load new task struct movs.w -8192, $r0 ; THREAD_SIZE = 8192 and.d $sp, $r0 @@ -590,15 +602,15 @@ mmu_bus_fault: move.d $r0, [$sp+16] 1: btstq 12, $r1 ; Refill? bpl 2f - lsrq PMD_SHIFT, $r1 ; Get PMD index into PGD (bit 24-31) - move.d [current_pgd], $r0 ; PGD for the current process + lsrq 24, $r1 ; Get PGD index (bit 24-31) + move.d [per_cpu__current_pgd], $r0 ; PGD for the current process move.d [$r0+$r1.d], $r0 ; Get PMD beq 2f nop and.w PAGE_MASK, $r0 ; Remove PMD flags move.d [R_MMU_CAUSE], $r1 lsrq PAGE_SHIFT, $r1 - and.d 0x7ff, $r1 ; Get PTE index into PMD (bit 13-24) + and.d 0x7ff, $r1 ; Get PTE index into PGD (bit 13-23) move.d [$r0+$r1.d], $r1 ; Get PTE beq 2f nop @@ -656,11 +668,6 @@ hwbreakpoint: nop IRQ1_interrupt: - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) -;; If we receive a watchdog interrupt while it is not expected, then set -;; up a canonical frame and dump register contents before dying. - ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame push $srp @@ -672,9 +679,16 @@ IRQ1_interrupt: push $r10 ; push orig_r10 clear.d [$sp=$sp-4] ; frametype == 0, normal frame -;; We don't check that we actually were bit by the watchdog as opposed to -;; an external NMI, since there is currently no handler for external NMI. - + move.d [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog? + and.d 0x80000000, $r1 + beq wdog + move.d $sp, $r10 + jsr handle_nmi + setf m ; Enable NMI again + retb ; Return from NMI + nop +wdog: +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) ;; Check if we're waiting for reset to happen, as signalled by ;; hard_reset_now setting cause_of_death to a magic value. If so, just ;; get stuck until reset happens. @@ -1118,6 +1132,10 @@ 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 /* * NOTE!! This doesn't have to be exact - we just have diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c index 4717f7ae8e5..094ff45ae85 100644 --- a/arch/cris/arch-v10/kernel/fasttimer.c +++ b/arch/cris/arch-v10/kernel/fasttimer.c @@ -1,10 +1,20 @@ -/* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $ +/* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 starvik Exp $ * linux/arch/cris/kernel/fasttimer.c * * Fast timers for ETRAX100/ETRAX100LX * This may be useful in other OS than Linux so use 2 space indentation... * * $Log: fasttimer.c,v $ + * Revision 1.9 2005/03/04 08:16:16 starvik + * Merge of Linux 2.6.11. + * + * Revision 1.8 2005/01/05 06:09:29 starvik + * cli()/sti() will be obsolete in 2.6.11. + * + * Revision 1.7 2005/01/03 13:35:46 starvik + * Removed obsolete stuff. + * Mark fast timer IRQ as not shared. + * * Revision 1.6 2004/05/14 10:18:39 starvik * Export fast_timer_list * @@ -148,8 +158,7 @@ static int debug_log_cnt_wrapped = 0; #define DEBUG_LOG(string, value) \ { \ unsigned long log_flags; \ - save_flags(log_flags); \ - cli(); \ + local_irq_save(log_flags); \ debug_log_string[debug_log_cnt] = (string); \ debug_log_value[debug_log_cnt] = (unsigned long)(value); \ if (++debug_log_cnt >= DEBUG_LOG_MAX) \ @@ -157,7 +166,7 @@ static int debug_log_cnt_wrapped = 0; debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ debug_log_cnt_wrapped = 1; \ } \ - restore_flags(log_flags); \ + local_irq_restore(log_flags); \ } #else #define DEBUG_LOG(string, value) @@ -320,8 +329,7 @@ void start_one_shot_timer(struct fast_timer *t, D1(printk("sft %s %d us\n", name, delay_us)); - save_flags(flags); - cli(); + local_irq_save(flags); do_gettimeofday_fast(&t->tv_set); tmp = fast_timer_list; @@ -395,7 +403,7 @@ void start_one_shot_timer(struct fast_timer *t, D2(printk("start_one_shot_timer: %d us done\n", delay_us)); - restore_flags(flags); + local_irq_restore(flags); } /* start_one_shot_timer */ static inline int fast_timer_pending (const struct fast_timer * t) @@ -425,11 +433,10 @@ int del_fast_timer(struct fast_timer * t) unsigned long flags; int ret; - save_flags(flags); - cli(); + local_irq_save(flags); ret = detach_fast_timer(t); t->next = t->prev = NULL; - restore_flags(flags); + local_irq_restore(flags); return ret; } /* del_fast_timer */ @@ -444,8 +451,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) struct fast_timer *t; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* Clear timer1 irq */ *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); @@ -462,7 +468,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timer_running = 0; fast_timer_ints++; - restore_flags(flags); + local_irq_restore(flags); t = fast_timer_list; while (t) @@ -482,8 +488,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timers_expired++; /* Remove this timer before call, since it may reuse the timer */ - save_flags(flags); - cli(); + local_irq_save(flags); if (t->prev) { t->prev->next = t->next; @@ -498,7 +503,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) } t->prev = NULL; t->next = NULL; - restore_flags(flags); + local_irq_restore(flags); if (t->function != NULL) { @@ -515,8 +520,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk(".\n")); } - save_flags(flags); - cli(); + local_irq_save(flags); if ((t = fast_timer_list) != NULL) { /* Start next timer.. */ @@ -535,7 +539,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) #endif start_timer1(us); } - restore_flags(flags); + local_irq_restore(flags); break; } else @@ -546,7 +550,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk("e! %d\n", us)); } } - restore_flags(flags); + local_irq_restore(flags); } if (!t) @@ -748,13 +752,12 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len #endif used += sprintf(bigbuf + used, "Active timers:\n"); - save_flags(flags); - cli(); + local_irq_save(flags); t = fast_timer_list; while (t != NULL && (used+100 < BIG_BUF_SIZE)) { nextt = t->next; - restore_flags(flags); + local_irq_restore(flags); used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " "d: %6li us data: 0x%08lX" /* " func: 0x%08lX" */ @@ -768,14 +771,14 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len t->data /* , t->function */ ); - cli(); + local_irq_disable(); if (t->next != nextt) { printk(KERN_WARNING "timer removed!\n"); } t = nextt; } - restore_flags(flags); + local_irq_restore(flags); } if (used - offset < len) @@ -963,7 +966,7 @@ void fast_timer_init(void) if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) fasttimer_proc_entry->read_proc = proc_fasttimer_read; #endif /* PROC_FS */ - if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, + if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0, "fast timer int", NULL)) { printk("err: timer1 irq\n"); diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S index 2c1dd1184a8..f00c145b43f 100644 --- a/arch/cris/arch-v10/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $ +/* $Id: head.S,v 1.10 2005/06/20 05:12:54 starvik Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,16 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.10 2005/06/20 05:12:54 starvik + * Remove unnecessary diff to kernel.org tree + * + * Revision 1.9 2004/12/13 12:21:51 starvik + * Added I/O and DMA allocators from Linux 2.4 + * + * Revision 1.8 2004/11/22 11:41:14 starvik + * Kernel command line may be supplied to kernel. Not used by Axis but may + * be used by customers. + * * Revision 1.7 2004/05/14 07:58:01 starvik * Merge of changes from 2.4 * @@ -181,6 +191,7 @@ #define CRAMFS_MAGIC 0x28cd3d45 #define RAM_INIT_MAGIC 0x56902387 +#define COMMAND_LINE_MAGIC 0x87109563 #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) @@ -490,6 +501,23 @@ _no_romfs_in_flash: _start_it: + ;; Check if kernel command line is supplied + cmp.d COMMAND_LINE_MAGIC, $r10 + bne no_command_line + nop + + move.d 256, $r13 + move.d cris_command_line, $r10 + or.d 0x80000000, $r11 ; Make it virtual +1: + move.b [$r11+], $r12 + move.b $r12, [$r10+] + subq 1, $r13 + bne 1b + nop + +no_command_line: + ;; the kernel stack is overlayed with the task structure for each ;; task. thus the initial kernel stack is in the same page as the ;; init_task (but starts in the top of the page, size 8192) @@ -567,76 +595,32 @@ _start_it: ;; Etrax product HW genconfig setup moveq 0,$r0 -#if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \ - && !defined(CONFIG_DMA_MEMCPY) - ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ - | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0 -#endif -#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) - ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \ - | IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0 -#endif -#ifdef CONFIG_DMA_MEMCPY - ; 6/7 memory-memory DMA - or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \ - | IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0 -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT2 - ; Enable serial port 2 - or.w IO_STATE (R_GEN_CONFIG, ser2, select),$r0 -#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2) - ; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \ - | IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0 -#endif -#endif -#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) - ; Enable serial port 3 - or.w IO_STATE (R_GEN_CONFIG, ser3, select),$r0 -#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3) - ; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \ - | IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0 -#endif -#endif -#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) - ; parport 0 enabled using DMA 2/3 - or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0 -#endif -#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) - ; parport 1 enabled using DMA 4/5 - or.w IO_STATE (R_GEN_CONFIG, par1, select),$r0 -#endif -#ifdef CONFIG_ETRAX_IDE - ; DMA channels 2 and 3 to ATA, ATA enabled - or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \ - | IO_STATE (R_GEN_CONFIG, dma2, ata) \ - | IO_STATE (R_GEN_CONFIG, ata, select),$r0 -#endif - -#ifdef CONFIG_ETRAX_USB_HOST_PORT1 - ; Set the USB port 1 enable bit - or.d IO_STATE (R_GEN_CONFIG, usb1, select),$r0 -#endif -#ifdef CONFIG_ETRAX_USB_HOST_PORT2 - ; Set the USB port 2 enable bit - or.d IO_STATE (R_GEN_CONFIG, usb2, select),$r0 -#endif -#ifdef CONFIG_ETRAX_USB_HOST - ; Connect DMA channels 8 and 9 to USB - and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \ - | IO_MASK (R_GEN_CONFIG, dma8))) \ - | IO_STATE (R_GEN_CONFIG, dma9, usb) \ - | IO_STATE (R_GEN_CONFIG, dma8, usb),$r0 -#endif - -#ifdef CONFIG_JULIETTE - ; DMA channels 4 and 5 to EXTDMA0, for Juliette - or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \ - | IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0 -#endif + + ;; Init interfaces (disable them). + or.d IO_STATE (R_GEN_CONFIG, scsi0, disable) \ + | IO_STATE (R_GEN_CONFIG, ata, disable) \ + | IO_STATE (R_GEN_CONFIG, par0, disable) \ + | IO_STATE (R_GEN_CONFIG, ser2, disable) \ + | IO_STATE (R_GEN_CONFIG, mio, disable) \ + | IO_STATE (R_GEN_CONFIG, scsi1, disable) \ + | IO_STATE (R_GEN_CONFIG, scsi0w, disable) \ + | IO_STATE (R_GEN_CONFIG, par1, disable) \ + | IO_STATE (R_GEN_CONFIG, ser3, disable) \ + | IO_STATE (R_GEN_CONFIG, mio_w, disable) \ + | IO_STATE (R_GEN_CONFIG, usb1, disable) \ + | IO_STATE (R_GEN_CONFIG, usb2, disable) \ + | IO_STATE (R_GEN_CONFIG, par_w, disable),$r0 + + ;; Init DMA channel muxing (set to unused clients). + or.d IO_STATE (R_GEN_CONFIG, dma2, ata) \ + | IO_STATE (R_GEN_CONFIG, dma3, ata) \ + | IO_STATE (R_GEN_CONFIG, dma4, scsi1) \ + | IO_STATE (R_GEN_CONFIG, dma5, scsi1) \ + | IO_STATE (R_GEN_CONFIG, dma6, unused) \ + | IO_STATE (R_GEN_CONFIG, dma7, unused) \ + | IO_STATE (R_GEN_CONFIG, dma8, usb) \ + | IO_STATE (R_GEN_CONFIG, dma9, usb),$r0 + #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT) or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0 diff --git a/arch/cris/arch-v10/kernel/io_interface_mux.c b/arch/cris/arch-v10/kernel/io_interface_mux.c new file mode 100644 index 00000000000..29d48ad00df --- /dev/null +++ b/arch/cris/arch-v10/kernel/io_interface_mux.c @@ -0,0 +1,879 @@ +/* IO interface mux allocator for ETRAX100LX. + * Copyright 2004, Axis Communications AB + * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $ + */ + + +/* C.f. ETRAX100LX Designer's Reference 20.9 */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/init.h> + +#include <asm/arch/svinto.h> +#include <asm/io.h> +#include <asm/arch/io_interface_mux.h> + + +#define DBG(s) + +/* Macro to access ETRAX 100 registers */ +#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_STATE_(reg##_, field##_, _##val) + +enum io_if_group { + group_a = (1<<0), + group_b = (1<<1), + group_c = (1<<2), + group_d = (1<<3), + group_e = (1<<4), + group_f = (1<<5) +}; + +struct watcher +{ + void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available); + struct watcher *next; +}; + + +struct if_group +{ + enum io_if_group group; + unsigned char used; + enum cris_io_interface owner; +}; + + +struct interface +{ + enum cris_io_interface ioif; + unsigned char groups; + unsigned char used; + char *owner; + unsigned int gpio_g_in; + unsigned int gpio_g_out; + unsigned char gpio_b; +}; + +static struct if_group if_groups[6] = { + { + .group = group_a, + .used = 0, + }, + { + .group = group_b, + .used = 0, + }, + { + .group = group_c, + .used = 0, + }, + { + .group = group_d, + .used = 0, + }, + { + .group = group_e, + .used = 0, + }, + { + .group = group_f, + .used = 0, + } +}; + +/* The order in the array must match the order of enum + * cris_io_interface in io_interface_mux.h */ +static struct interface interfaces[] = { + /* Begin Non-multiplexed interfaces */ + { + .ioif = if_eth, + .groups = 0, + .gpio_g_in = 0, + .gpio_g_out = 0, + .gpio_b = 0 + }, + { + .ioif = if_serial_0, + .groups = 0, + .gpio_g_in = 0, + .gpio_g_out = 0, + .gpio_b = 0 + }, + /* End Non-multiplexed interfaces */ + { + .ioif = if_serial_1, + .groups = group_e, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x00 + }, + { + .ioif = if_serial_2, + .groups = group_b, + .gpio_g_in = 0x000000c0, + .gpio_g_out = 0x000000c0, + .gpio_b = 0x00 + }, + { + .ioif = if_serial_3, + .groups = group_c, + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x00 + }, + { + .ioif = if_sync_serial_1, + .groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3 + can be used simultaneously */ + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x10 + }, + { + .ioif = if_sync_serial_3, + .groups = group_c | group_f, + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x80 + }, + { + .ioif = if_shared_ram, + .groups = group_a, + .gpio_g_in = 0x0000ff3e, + .gpio_g_out = 0x0000ff38, + .gpio_b = 0x00 + }, + { + .ioif = if_shared_ram_w, + .groups = group_a | group_d, + .gpio_g_in = 0x00ffff3e, + .gpio_g_out = 0x00ffff38, + .gpio_b = 0x00 + }, + { + .ioif = if_par_0, + .groups = group_a, + .gpio_g_in = 0x0000ff3e, + .gpio_g_out = 0x0000ff3e, + .gpio_b = 0x00 + }, + { + .ioif = if_par_1, + .groups = group_d, + .gpio_g_in = 0x3eff0000, + .gpio_g_out = 0x3eff0000, + .gpio_b = 0x00 + }, + { + .ioif = if_par_w, + .groups = group_a | group_d, + .gpio_g_in = 0x00ffff3e, + .gpio_g_out = 0x00ffff3e, + .gpio_b = 0x00 + }, + { + .ioif = if_scsi8_0, + .groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1 + can be used simultaneously */ + .gpio_g_in = 0x0000ffff, + .gpio_g_out = 0x0000ffff, + .gpio_b = 0x10 + }, + { + .ioif = if_scsi8_1, + .groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1 + can be used simultaneously */ + .gpio_g_in = 0xffff0000, + .gpio_g_out = 0xffff0000, + .gpio_b = 0x80 + }, + { + .ioif = if_scsi_w, + .groups = group_a | group_b | group_d | group_f, + .gpio_g_in = 0x01ffffff, + .gpio_g_out = 0x07ffffff, + .gpio_b = 0x80 + }, + { + .ioif = if_ata, + .groups = group_a | group_b | group_c | group_d, + .gpio_g_in = 0xf9ffffff, + .gpio_g_out = 0xffffffff, + .gpio_b = 0x80 + }, + { + .ioif = if_csp, + .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0xfc + }, + { + .ioif = if_i2c, + .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x03 + }, + { + .ioif = if_usb_1, + .groups = group_e | group_f, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x2c + }, + { + .ioif = if_usb_2, + .groups = group_d, + .gpio_g_in = 0x0e000000, + .gpio_g_out = 0x3c000000, + .gpio_b = 0x00 + }, + /* GPIO pins */ + { + .ioif = if_gpio_grp_a, + .groups = group_a, + .gpio_g_in = 0x0000ff3f, + .gpio_g_out = 0x0000ff3f, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_b, + .groups = group_b, + .gpio_g_in = 0x000000c0, + .gpio_g_out = 0x000000c0, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_c, + .groups = group_c, + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_d, + .groups = group_d, + .gpio_g_in = 0x3fff0000, + .gpio_g_out = 0x3fff0000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_e, + .groups = group_e, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_f, + .groups = group_f, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0xff + } + /* Array end */ +}; + +static struct watcher *watchers = NULL; + +static unsigned int gpio_in_pins = 0xffffffff; +static unsigned int gpio_out_pins = 0xffffffff; +static unsigned char gpio_pb_pins = 0xff; +static unsigned char gpio_pa_pins = 0xff; + +static enum cris_io_interface gpio_pa_owners[8]; +static enum cris_io_interface gpio_pb_owners[8]; +static enum cris_io_interface gpio_pg_owners[32]; + +static int cris_io_interface_init(void); + +static unsigned char clear_group_from_set(const unsigned char groups, struct if_group *group) +{ + return (groups & ~group->group); +} + + +static struct if_group *get_group(const unsigned char groups) +{ + int i; + for (i = 0; i < sizeof(if_groups)/sizeof(struct if_group); i++) { + if (groups & if_groups[i].group) { + return &if_groups[i]; + } + } + return NULL; +} + + +static void notify_watchers(void) +{ + struct watcher *w = watchers; + + DBG(printk("io_interface_mux: notifying watchers\n")); + + while (NULL != w) { + w->notify((const unsigned int)gpio_in_pins, + (const unsigned int)gpio_out_pins, + (const unsigned char)gpio_pa_pins, + (const unsigned char)gpio_pb_pins); + w = w->next; + } +} + + +int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id) +{ + int set_gen_config = 0; + int set_gen_config_ii = 0; + unsigned long int gens; + unsigned long int gens_ii; + struct if_group *grp; + unsigned char group_set; + unsigned long flags; + + (void)cris_io_interface_init(); + + DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id)); + + if ((ioif >= if_max_interfaces) || (ioif < 0)) { + printk(KERN_CRIT "cris_request_io_interface: Bad interface %u submitted for %s\n", + ioif, + device_id); + return -EINVAL; + } + + local_irq_save(flags); + + if (interfaces[ioif].used) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n", + device_id, + interfaces[ioif].owner); + return -EBUSY; + } + + /* Check that all required groups are free before allocating, */ + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + if (grp->used) { + if (grp->group == group_f) { + if ((if_sync_serial_1 == ioif) || + (if_sync_serial_3 == ioif)) { + if ((grp->owner != if_sync_serial_1) && + (grp->owner != if_sync_serial_3)) { + local_irq_restore(flags); + return -EBUSY; + } + } else if ((if_scsi8_0 == ioif) || + (if_scsi8_1 == ioif)) { + if ((grp->owner != if_scsi8_0) && + (grp->owner != if_scsi8_1)) { + local_irq_restore(flags); + return -EBUSY; + } + } + } else { + local_irq_restore(flags); + return -EBUSY; + } + } + group_set = clear_group_from_set(group_set, grp); + } + + /* Are the required GPIO pins available too? */ + if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) || + ((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) || + ((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) { + printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n", + ioif); + return -EBUSY; + } + + /* All needed I/O pins and pin groups are free, allocate. */ + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + grp->used = 1; + grp->owner = ioif; + group_set = clear_group_from_set(group_set, grp); + } + + gens = genconfig_shadow; + gens_ii = gen_config_ii_shadow; + + set_gen_config = 1; + switch (ioif) + { + /* Begin Non-multiplexed interfaces */ + case if_eth: + /* fall through */ + case if_serial_0: + set_gen_config = 0; + break; + /* End Non-multiplexed interfaces */ + case if_serial_1: + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode1, async); + break; + case if_serial_2: + SETS(gens, R_GEN_CONFIG, ser2, select); + break; + case if_serial_3: + SETS(gens, R_GEN_CONFIG, ser3, select); + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode3, async); + break; + case if_sync_serial_1: + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode1, sync); + break; + case if_sync_serial_3: + SETS(gens, R_GEN_CONFIG, ser3, select); + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode3, sync); + break; + case if_shared_ram: + SETS(gens, R_GEN_CONFIG, mio, select); + break; + case if_shared_ram_w: + SETS(gens, R_GEN_CONFIG, mio_w, select); + break; + case if_par_0: + SETS(gens, R_GEN_CONFIG, par0, select); + break; + case if_par_1: + SETS(gens, R_GEN_CONFIG, par1, select); + break; + case if_par_w: + SETS(gens, R_GEN_CONFIG, par0, select); + SETS(gens, R_GEN_CONFIG, par_w, select); + break; + case if_scsi8_0: + SETS(gens, R_GEN_CONFIG, scsi0, select); + break; + case if_scsi8_1: + SETS(gens, R_GEN_CONFIG, scsi1, select); + break; + case if_scsi_w: + SETS(gens, R_GEN_CONFIG, scsi0, select); + SETS(gens, R_GEN_CONFIG, scsi0w, select); + break; + case if_ata: + SETS(gens, R_GEN_CONFIG, ata, select); + break; + case if_csp: + /* fall through */ + case if_i2c: + set_gen_config = 0; + break; + case if_usb_1: + SETS(gens, R_GEN_CONFIG, usb1, select); + break; + case if_usb_2: + SETS(gens, R_GEN_CONFIG, usb2, select); + break; + case if_gpio_grp_a: + /* GPIO groups are only accounted, don't do configuration changes. */ + /* fall through */ + case if_gpio_grp_b: + /* fall through */ + case if_gpio_grp_c: + /* fall through */ + case if_gpio_grp_d: + /* fall through */ + case if_gpio_grp_e: + /* fall through */ + case if_gpio_grp_f: + set_gen_config = 0; + break; + default: + panic("cris_request_io_interface: Bad interface %u submitted for %s\n", + ioif, + device_id); + } + + interfaces[ioif].used = 1; + interfaces[ioif].owner = (char*)device_id; + + if (set_gen_config) { + volatile int i; + genconfig_shadow = gens; + *R_GEN_CONFIG = genconfig_shadow; + /* Wait 12 cycles before doing any DMA command */ + for(i = 6; i > 0; i--) + nop(); + } + if (set_gen_config_ii) { + gen_config_ii_shadow = gens_ii; + *R_GEN_CONFIG_II = gen_config_ii_shadow; + } + + DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + interfaces[ioif].gpio_g_in, + interfaces[ioif].gpio_g_out, + interfaces[ioif].gpio_b)); + + gpio_in_pins &= ~interfaces[ioif].gpio_g_in; + gpio_out_pins &= ~interfaces[ioif].gpio_g_out; + gpio_pb_pins &= ~interfaces[ioif].gpio_b; + + DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + + local_irq_restore(flags); + + notify_watchers(); + + return 0; +} + + +void cris_free_io_interface(enum cris_io_interface ioif) +{ + struct if_group *grp; + unsigned char group_set; + unsigned long flags; + + (void)cris_io_interface_init(); + + if ((ioif >= if_max_interfaces) || (ioif < 0)) { + printk(KERN_CRIT "cris_free_io_interface: Bad interface %u\n", + ioif); + return; + } + local_irq_save(flags); + if (!interfaces[ioif].used) { + printk(KERN_CRIT "cris_free_io_interface: Freeing free interface %u\n", + ioif); + local_irq_restore(flags); + return; + } + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + if (grp->group == group_f) { + switch (ioif) + { + case if_sync_serial_1: + if ((grp->owner == if_sync_serial_1) && + interfaces[if_sync_serial_3].used) { + grp->owner = if_sync_serial_3; + } else + grp->used = 0; + break; + case if_sync_serial_3: + if ((grp->owner == if_sync_serial_3) && + interfaces[if_sync_serial_1].used) { + grp->owner = if_sync_serial_1; + } else + grp->used = 0; + break; + case if_scsi8_0: + if ((grp->owner == if_scsi8_0) && + interfaces[if_scsi8_1].used) { + grp->owner = if_scsi8_1; + } else + grp->used = 0; + break; + case if_scsi8_1: + if ((grp->owner == if_scsi8_1) && + interfaces[if_scsi8_0].used) { + grp->owner = if_scsi8_0; + } else + grp->used = 0; + break; + default: + grp->used = 0; + } + } else { + grp->used = 0; + } + group_set = clear_group_from_set(group_set, grp); + } + interfaces[ioif].used = 0; + interfaces[ioif].owner = NULL; + + DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + DBG(printk("freeing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + interfaces[ioif].gpio_g_in, + interfaces[ioif].gpio_g_out, + interfaces[ioif].gpio_b)); + + gpio_in_pins |= interfaces[ioif].gpio_g_in; + gpio_out_pins |= interfaces[ioif].gpio_g_out; + gpio_pb_pins |= interfaces[ioif].gpio_b; + + DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + + local_irq_restore(flags); + + notify_watchers(); +} + +/* Create a bitmask from bit 0 (inclusive) to bit stop_bit + (non-inclusive). stop_bit == 0 returns 0x0 */ +static inline unsigned int create_mask(const unsigned stop_bit) +{ + /* Avoid overflow */ + if (stop_bit >= 32) { + return 0xffffffff; + } + return (1<<stop_bit)-1; +} + + +/* port can be 'a', 'b' or 'g' */ +int cris_io_interface_allocate_pins(const enum cris_io_interface ioif, + const char port, + const unsigned start_bit, + const unsigned stop_bit) +{ + unsigned int i; + unsigned int mask = 0; + unsigned int tmp_mask; + unsigned long int flags; + enum cris_io_interface *owners; + + (void)cris_io_interface_init(); + + DBG(printk("cris_io_interface_allocate_pins: if=%d port=%c start=%u stop=%u\n", + ioif, port, start_bit, stop_bit)); + + if (!((start_bit <= stop_bit) && + ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) || + ((port == 'g') && (stop_bit < 32))))) { + return -EINVAL; + } + + mask = create_mask(stop_bit + 1); + tmp_mask = create_mask(start_bit); + mask &= ~tmp_mask; + + DBG(printk("cris_io_interface_allocate_pins: port=%c start=%u stop=%u mask=0x%08x\n", + port, start_bit, stop_bit, mask)); + + local_irq_save(flags); + + switch (port) { + case 'a': + if ((gpio_pa_pins & mask) != mask) { + local_irq_restore(flags); + return -EBUSY; + } + owners = gpio_pa_owners; + gpio_pa_pins &= ~mask; + break; + case 'b': + if ((gpio_pb_pins & mask) != mask) { + local_irq_restore(flags); + return -EBUSY; + } + owners = gpio_pb_owners; + gpio_pb_pins &= ~mask; + break; + case 'g': + if (((gpio_in_pins & mask) != mask) || + ((gpio_out_pins & mask) != mask)) { + local_irq_restore(flags); + return -EBUSY; + } + owners = gpio_pg_owners; + gpio_in_pins &= ~mask; + gpio_out_pins &= ~mask; + break; + default: + local_irq_restore(flags); + return -EINVAL; + } + + for (i = start_bit; i <= stop_bit; i++) { + owners[i] = ioif; + } + local_irq_restore(flags); + + notify_watchers(); + return 0; +} + + +/* port can be 'a', 'b' or 'g' */ +int cris_io_interface_free_pins(const enum cris_io_interface ioif, + const char port, + const unsigned start_bit, + const unsigned stop_bit) +{ + unsigned int i; + unsigned int mask = 0; + unsigned int tmp_mask; + unsigned long int flags; + enum cris_io_interface *owners; + + (void)cris_io_interface_init(); + + if (!((start_bit <= stop_bit) && + ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) || + ((port == 'g') && (stop_bit < 32))))) { + return -EINVAL; + } + + mask = create_mask(stop_bit + 1); + tmp_mask = create_mask(start_bit); + mask &= ~tmp_mask; + + DBG(printk("cris_io_interface_free_pins: port=%c start=%u stop=%u mask=0x%08x\n", + port, start_bit, stop_bit, mask)); + + local_irq_save(flags); + + switch (port) { + case 'a': + if ((~gpio_pa_pins & mask) != mask) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); + } + owners = gpio_pa_owners; + break; + case 'b': + if ((~gpio_pb_pins & mask) != mask) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); + } + owners = gpio_pb_owners; + break; + case 'g': + if (((~gpio_in_pins & mask) != mask) || + ((~gpio_out_pins & mask) != mask)) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); + } + owners = gpio_pg_owners; + break; + default: + owners = NULL; /* Cannot happen. Shut up, gcc! */ + } + + for (i = start_bit; i <= stop_bit; i++) { + if (owners[i] != ioif) { + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing unowned pins"); + } + } + + /* All was ok, change data. */ + switch (port) { + case 'a': + gpio_pa_pins |= mask; + break; + case 'b': + gpio_pb_pins |= mask; + break; + case 'g': + gpio_in_pins |= mask; + gpio_out_pins |= mask; + break; + } + + for (i = start_bit; i <= stop_bit; i++) { + owners[i] = if_unclaimed; + } + local_irq_restore(flags); + notify_watchers(); + + return 0; +} + + +int cris_io_interface_register_watcher(void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available)) +{ + struct watcher *w; + + (void)cris_io_interface_init(); + + if (NULL == notify) { + return -EINVAL; + } + w = kmalloc(sizeof(*w), GFP_KERNEL); + if (!w) { + return -ENOMEM; + } + w->notify = notify; + w->next = watchers; + watchers = w; + + w->notify((const unsigned int)gpio_in_pins, + (const unsigned int)gpio_out_pins, + (const unsigned char)gpio_pa_pins, + (const unsigned char)gpio_pb_pins); + + return 0; +} + +void cris_io_interface_delete_watcher(void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available)) +{ + struct watcher *w = watchers, *prev = NULL; + + (void)cris_io_interface_init(); + + while ((NULL != w) && (w->notify != notify)){ + prev = w; + w = w->next; + } + if (NULL != w) { + if (NULL != prev) { + prev->next = w->next; + } else { + watchers = w->next; + } + kfree(w); + return; + } + printk(KERN_WARNING "cris_io_interface_delete_watcher: Deleting unknown watcher 0x%p\n", notify); +} + + +static int cris_io_interface_init(void) +{ + static int first = 1; + int i; + + if (!first) { + return 0; + } + first = 0; + + for (i = 0; i<8; i++) { + gpio_pa_owners[i] = if_unclaimed; + gpio_pb_owners[i] = if_unclaimed; + gpio_pg_owners[i] = if_unclaimed; + } + for (; i<32; i++) { + gpio_pg_owners[i] = if_unclaimed; + } + return 0; +} + + +module_init(cris_io_interface_init); + + +EXPORT_SYMBOL(cris_request_io_interface); +EXPORT_SYMBOL(cris_free_io_interface); +EXPORT_SYMBOL(cris_io_interface_allocate_pins); +EXPORT_SYMBOL(cris_io_interface_free_pins); +EXPORT_SYMBOL(cris_io_interface_register_watcher); +EXPORT_SYMBOL(cris_io_interface_delete_watcher); diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c index b2f16d6fc87..4b368a12201 100644 --- a/arch/cris/arch-v10/kernel/irq.c +++ b/arch/cris/arch-v10/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $ +/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $ * * linux/arch/cris/kernel/irq.c * @@ -12,11 +12,13 @@ */ #include <asm/irq.h> +#include <linux/irq.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/config.h> -irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ +#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); +#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is * global just so that the kernel gdb can use it. @@ -102,41 +104,52 @@ static void (*interrupt[NR_IRQS])(void) = { IRQ31_interrupt }; -static void (*bad_interrupt[NR_IRQS])(void) = { - NULL, NULL, - NULL, bad_IRQ3_interrupt, - bad_IRQ4_interrupt, bad_IRQ5_interrupt, - bad_IRQ6_interrupt, bad_IRQ7_interrupt, - bad_IRQ8_interrupt, bad_IRQ9_interrupt, - bad_IRQ10_interrupt, bad_IRQ11_interrupt, - bad_IRQ12_interrupt, bad_IRQ13_interrupt, - NULL, NULL, - bad_IRQ16_interrupt, bad_IRQ17_interrupt, - bad_IRQ18_interrupt, bad_IRQ19_interrupt, - bad_IRQ20_interrupt, bad_IRQ21_interrupt, - bad_IRQ22_interrupt, bad_IRQ23_interrupt, - bad_IRQ24_interrupt, bad_IRQ25_interrupt, - NULL, NULL, NULL, NULL, NULL, - bad_IRQ31_interrupt -}; +static void enable_crisv10_irq(unsigned int irq); + +static unsigned int startup_crisv10_irq(unsigned int irq) +{ + enable_crisv10_irq(irq); + return 0; +} + +#define shutdown_crisv10_irq disable_crisv10_irq -void arch_setup_irq(int irq) +static void enable_crisv10_irq(unsigned int irq) { - set_int_vector(irq, interrupt[irq]); + unmask_irq(irq); } -void arch_free_irq(int irq) +static void disable_crisv10_irq(unsigned int irq) { - set_int_vector(irq, bad_interrupt[irq]); + mask_irq(irq); } +static void ack_crisv10_irq(unsigned int irq) +{ +} + +static void end_crisv10_irq(unsigned int irq) +{ +} + +static struct hw_interrupt_type crisv10_irq_type = { + .typename = "CRISv10", + .startup = startup_crisv10_irq, + .shutdown = shutdown_crisv10_irq, + .enable = enable_crisv10_irq, + .disable = disable_crisv10_irq, + .ack = ack_crisv10_irq, + .end = end_crisv10_irq, + .set_affinity = NULL +}; + void weird_irq(void); void system_call(void); /* from entry.S */ void do_sigtrap(void); /* from entry.S */ void gdb_handle_breakpoint(void); /* from entry.S */ /* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and - setting the irq vector table to point to bad_interrupt ptrs. + setting the irq vector table. */ void __init @@ -154,14 +167,15 @@ init_IRQ(void) *R_VECT_MASK_CLR = 0xffffffff; - /* clear the shortcut entry points */ - - for(i = 0; i < NR_IRQS; i++) - irq_shortcuts[i] = NULL; - for (i = 0; i < 256; i++) etrax_irv->v[i] = weird_irq; + /* Initialize IRQ handler descriptiors. */ + for(i = 2; i < NR_IRQS; i++) { + irq_desc[i].handler = &crisv10_irq_type; + set_int_vector(i, interrupt[i]); + } + /* the entries in the break vector contain actual code to be executed by the associated break handler, rather than just a jump address. therefore we need to setup a default breakpoint handler @@ -170,10 +184,6 @@ init_IRQ(void) for (i = 0; i < 16; i++) set_break_vector(i, do_sigtrap); - /* set all etrax irq's to the bad handlers */ - for (i = 2; i < NR_IRQS; i++) - set_int_vector(i, bad_interrupt[i]); - /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ set_int_vector(15, multiple_interrupt); diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c index 7d368c877ee..b72e6a91a63 100644 --- a/arch/cris/arch-v10/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -18,6 +18,10 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.6 2005/01/14 10:12:17 starvik +*! KGDB on separate port. +*! Console fixes from 2.4. +*! *! Revision 1.5 2004/10/07 13:59:08 starvik *! Corrected call to set_int_vector *! @@ -71,7 +75,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $ +*! $Id: kgdb.c,v 1.6 2005/01/14 10:12:17 starvik Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -225,6 +229,7 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/linkage.h> +#include <linux/reboot.h> #include <asm/setup.h> #include <asm/ptrace.h> @@ -1344,12 +1349,11 @@ handle_exception (int sigval) } } -/* The jump is to the address 0x00000002. Performs a complete re-start - from scratch. */ +/* Performs a complete re-start from scratch. */ static void kill_restart () { - __asm__ volatile ("jump 2"); + machine_restart(""); } /********************************** Breakpoint *******************************/ @@ -1506,6 +1510,11 @@ kgdb_handle_serial: bne goback nop + move.d [reg+0x5E], $r10 ; Get DCCR + btstq 8, $r10 ; Test the U-flag. + bmi goback + nop + ;; ;; Handle the communication ;; diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 87ff3779082..69e28b4057e 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $ +/* $Id: process.c,v 1.12 2004/12/27 11:18:32 starvik Exp $ * * linux/arch/cris/kernel/process.c * @@ -101,6 +101,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) regs.r11 = (unsigned long)fn; regs.r12 = (unsigned long)arg; regs.irp = (unsigned long)kernel_thread_helper; + regs.dccr = 1 << I_DCCR_BITNR; /* Ok, create the new process.. */ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c index 581ecabaae5..130dd214e41 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -11,6 +11,7 @@ #include <linux/ptrace.h> #include <linux/user.h> #include <linux/signal.h> +#include <linux/security.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -86,9 +87,13 @@ sys_ptrace(long request, long pid, long addr, long data) ret = -EPERM; if (request == PTRACE_TRACEME) { + /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - + ret = security_ptrace(current->parent, current); + if (ret) + goto out; + /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; ret = 0; goto out; @@ -207,7 +212,7 @@ sys_ptrace(long request, long pid, long addr, long data) case PTRACE_KILL: ret = 0; - if (child->state == TASK_ZOMBIE) + if (child->exit_state == EXIT_ZOMBIE) break; child->exit_code = SIGKILL; diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c index 561a890a8e4..38fd44dfbc5 100644 --- a/arch/cris/arch-v10/kernel/shadows.c +++ b/arch/cris/arch-v10/kernel/shadows.c @@ -1,4 +1,4 @@ -/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $ * * Various shadow registers. Defines for these are in include/asm-etrax100/io.h */ @@ -6,6 +6,7 @@ /* Shadows for internal Etrax-registers */ unsigned long genconfig_shadow; +unsigned long gen_config_ii_shadow; unsigned long port_g_data_shadow; unsigned char port_pa_dir_shadow; unsigned char port_pa_data_shadow; diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c index da491f438a6..34a27ea2052 100644 --- a/arch/cris/arch-v10/kernel/traps.c +++ b/arch/cris/arch-v10/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ +/* $Id: traps.c,v 1.4 2005/04/24 18:47:55 starvik Exp $ * * linux/arch/cris/arch-v10/traps.c * @@ -16,6 +16,8 @@ #include <asm/uaccess.h> #include <asm/arch/sv_addr_ag.h> +extern int raw_printk(const char *fmt, ...); + void show_registers(struct pt_regs * regs) { @@ -26,18 +28,18 @@ show_registers(struct pt_regs * regs) register. */ unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", + raw_printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", regs->irp, regs->srp, regs->dccr, usp, regs->mof ); - printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", + 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", + 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", + 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\n", - regs->r12, regs->r13, regs->orig_r10); - printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); - printk("Process %s (pid: %d, stackpage=%08lx)\n", + raw_printk("r12: %08lx r13: %08lx oR10: %08lx sp: %08lx\n", + regs->r12, regs->r13, regs->orig_r10, regs); + raw_printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); + raw_printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); /* @@ -53,7 +55,7 @@ show_registers(struct pt_regs * regs) if (usp != 0) show_stack (NULL, NULL); - printk("\nCode: "); + raw_printk("\nCode: "); if(regs->irp < PAGE_OFFSET) goto bad; @@ -70,16 +72,16 @@ show_registers(struct pt_regs * regs) unsigned char c; if(__get_user(c, &((unsigned char*)regs->irp)[i])) { bad: - printk(" Bad IP value."); + raw_printk(" Bad IP value."); break; } if (i == 0) - printk("(%02x) ", c); + raw_printk("(%02x) ", c); else - printk("%02x ", c); + raw_printk("%02x ", c); } - printk("\n"); + raw_printk("\n"); } } @@ -121,7 +123,7 @@ die_if_kernel(const char * str, struct pt_regs * regs, long err) stop_watchdog(); #endif - printk("%s: %04lx\n", str, err & 0xffff); + raw_printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); @@ -130,3 +132,8 @@ die_if_kernel(const char * str, struct pt_regs * regs, long err) #endif do_exit(SIGSEGV); } + +void arch_enable_nmi(void) +{ + asm volatile("setf m"); +} |