aboutsummaryrefslogtreecommitdiff
path: root/arch/cris/arch-v10/kernel
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-07-30 18:14:15 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-07-30 18:14:15 -0400
commita670fcb43f01a67ef56176afc76e5d43d128b25c (patch)
tree09c9411c78a33ff980e9ea871bc7686e7589abbf /arch/cris/arch-v10/kernel
parent327309e899662b482c58cf25f574513d38b5788c (diff)
parentb0825488a642cadcf39709961dde61440cb0731c (diff)
/spare/repo/netdev-2.6 branch 'master'
Diffstat (limited to 'arch/cris/arch-v10/kernel')
-rw-r--r--arch/cris/arch-v10/kernel/Makefile5
-rw-r--r--arch/cris/arch-v10/kernel/debugport.c273
-rw-r--r--arch/cris/arch-v10/kernel/dma.c287
-rw-r--r--arch/cris/arch-v10/kernel/entry.S54
-rw-r--r--arch/cris/arch-v10/kernel/fasttimer.c55
-rw-r--r--arch/cris/arch-v10/kernel/head.S126
-rw-r--r--arch/cris/arch-v10/kernel/io_interface_mux.c879
-rw-r--r--arch/cris/arch-v10/kernel/irq.c76
-rw-r--r--arch/cris/arch-v10/kernel/kgdb.c17
-rw-r--r--arch/cris/arch-v10/kernel/process.c3
-rw-r--r--arch/cris/arch-v10/kernel/ptrace.c9
-rw-r--r--arch/cris/arch-v10/kernel/shadows.c3
-rw-r--r--arch/cris/arch-v10/kernel/traps.c37
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, &regs, 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");
+}