summaryrefslogtreecommitdiffstats
path: root/arch/mips/mips-boards/atlas/atlas_int.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/mips-boards/atlas/atlas_int.c')
-rw-r--r--arch/mips/mips-boards/atlas/atlas_int.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
new file mode 100644
index 000000000..ff4e31d07
--- /dev/null
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -0,0 +1,268 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS
+ * Atlas board.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/irq.h>
+#include <asm/mips-boards/atlas.h>
+#include <asm/mips-boards/atlasint.h>
+
+
+struct atlas_ictrl_regs *atlas_hw0_icregs;
+
+extern asmlinkage void mipsIRQ(void);
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+
+static struct irqaction *hw0_irq_action[ATLASINT_END] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+static struct irqaction r4ktimer_action = {
+ NULL, 0, 0, "R4000 timer/counter", NULL, NULL,
+};
+
+static struct irqaction *irq_action[8] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, &r4ktimer_action
+};
+
+#if 0
+#define DEBUG_INT(x...) printk(x)
+#else
+#define DEBUG_INT(x...)
+#endif
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= ATLASINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ atlas_hw0_icregs->intrsten = (1 << irq_nr);
+ restore_flags(flags);
+}
+
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= ATLASINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ atlas_hw0_icregs->intseten = (1 << irq_nr);
+ restore_flags(flags);
+}
+
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ int num = 0;
+ struct irqaction *action;
+
+ for (i = 0; i < 8; i++, num++) {
+ action = irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [on-chip]\n");
+ }
+ for (i = 0; i < ATLASINT_END; i++, num++) {
+ action = hw0_irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [hw0]\n");
+ }
+ return len;
+}
+
+
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ struct irqaction *action;
+
+ DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname);
+
+ if (irq >= ATLASINT_END)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if(!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = 0;
+ hw0_irq_action[irq] = action;
+ enable_irq(irq);
+
+ return 0;
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action;
+
+ if (irq >= ATLASINT_END) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+
+ action = hw0_irq_action[irq];
+ hw0_irq_action[irq] = NULL;
+ disable_irq(irq);
+ kfree(action);
+}
+
+
+int (*irq_cannonicalize)(int irq);
+
+static int atlas_irq_cannonicalize(int irq)
+{
+ return irq; /* Sane hardware, sane code ... */
+}
+
+
+void __init init_IRQ(void)
+{
+ irq_cannonicalize = atlas_irq_cannonicalize;
+ irq_setup();
+}
+
+
+void atlas_hw0_irqdispatch(struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int irq, cpu = smp_processor_id();
+ unsigned long int_status;
+ int i;
+
+ DEBUG_INT("atlas_hw0_irqdispatch\n");
+
+ int_status = atlas_hw0_icregs->intstatus;
+
+ /* if int_status == 0, then the interrupt has already been cleared */
+ if (int_status == 0)
+ return;
+
+ for (i=0; i<ATLASINT_END; i++)
+ if (int_status & 1<<i)
+ break;
+
+ irq = i;
+ action = hw0_irq_action[irq];
+
+ DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq);
+
+ /* if action == NULL, then we don't have a handler for the irq */
+ if ( action == NULL ) {
+ printk("No handler for hw0 irq: %i\n", irq);
+ return;
+ }
+
+ hardirq_enter(cpu);
+ kstat.irqs[0][irq + 8]++;
+ action->handler(irq, action->dev_id, regs);
+ hardirq_exit(cpu);
+
+ return;
+}
+
+
+/* Misc. crap just to keep the kernel linking... */
+unsigned long probe_irq_on (void)
+{
+ return 0;
+}
+
+
+int probe_irq_off (unsigned long irqs)
+{
+ return 0;
+}
+
+
+void __init atlasint_init(void)
+{
+ /*
+ * Mask out all interrupt by writing "1" to all bit position in
+ * the interrupt reset reg.
+ */
+ atlas_hw0_icregs = (struct atlas_ictrl_regs *)ATLAS_ICTRL_REGS_BASE;
+ atlas_hw0_icregs->intrsten = 0xffffffff;
+
+ /* Now safe to set the exception vector. */
+ set_except_vector(0, mipsIRQ);
+}