patch-2.4.19 linux-2.4.19/arch/mips/philips/nino/irq.c
Next file: linux-2.4.19/arch/mips/philips/nino/kgdb.c
Previous file: linux-2.4.19/arch/mips/philips/nino/int-handler.S
Back to the patch index
Back to the overall index
- Lines: 521
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/arch/mips/philips/nino/irq.c
- Orig date:
Sun Sep 9 10:43:02 2001
diff -urN linux-2.4.18/arch/mips/philips/nino/irq.c linux-2.4.19/arch/mips/philips/nino/irq.c
@@ -1,314 +1,264 @@
/*
- * linux/arch/mips/philips/nino/irq.c
+ * arch/mips/philips/nino/irq.c
*
- * Copyright (C) 1992 Linus Torvalds
- * Copyright (C) 1999 Harald Koerfgen
- * Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
* Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * Generic interrupt handler for Philips Nino.
+ *
+ * Interrupt service routines for Philips Nino
*/
-#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
#include <linux/sched.h>
-#include <linux/types.h>
#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/tx3912.h>
-unsigned long spurious_count = 0;
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
-irq_cpustat_t irq_stat [NR_CPUS];
+extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
-static inline void mask_irq(unsigned int irq_nr)
+static void enable_irq6(unsigned int irq)
{
- switch (irq_nr) {
- case 0: /* Periodic Timer Interrupt */
- IntClear5 = INT5_PERIODICINT;
- IntClear6 = INT6_PERIODICINT;
- IntEnable6 &= ~INT6_PERIODICINT;
- break;
+ if(irq == 0) {
+ outl(inl(TX3912_INT6_ENABLE) |
+ TX3912_INT6_ENABLE_PRIORITYMASK_PERINT,
+ TX3912_INT6_ENABLE);
+ outl(inl(TX3912_INT5_ENABLE) | TX3912_INT5_PERINT,
+ TX3912_INT5_ENABLE);
+ }
+ if(irq == 3) {
+ outl(inl(TX3912_INT6_ENABLE) |
+ TX3912_INT6_ENABLE_PRIORITYMASK_UARTARXINT,
+ TX3912_INT6_ENABLE);
+ outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_RX_BITS,
+ TX3912_INT2_ENABLE);
+ }
+}
- case 3:
- /* Serial port receive interrupt */
- break;
+static unsigned int startup_irq6(unsigned int irq)
+{
+ enable_irq6(irq);
- case 2:
- /* Serial port transmit interrupt */
- break;
+ return 0; /* Never anything pending */
+}
- default:
- printk( "Attempt to mask unknown IRQ %d?\n", irq_nr );
+static void disable_irq6(unsigned int irq)
+{
+ if(irq == 0) {
+ outl(inl(TX3912_INT6_ENABLE) &
+ ~TX3912_INT6_ENABLE_PRIORITYMASK_PERINT,
+ TX3912_INT6_ENABLE);
+ outl(inl(TX3912_INT5_ENABLE) & ~TX3912_INT5_PERINT,
+ TX3912_INT5_ENABLE);
+ outl(inl(TX3912_INT5_CLEAR) | TX3912_INT5_PERINT,
+ TX3912_INT5_CLEAR);
+ }
+ if(irq == 3) {
+ outl(inl(TX3912_INT6_ENABLE) &
+ ~TX3912_INT6_ENABLE_PRIORITYMASK_UARTARXINT,
+ TX3912_INT6_ENABLE);
+ outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_RX_BITS,
+ TX3912_INT2_ENABLE);
}
}
-static inline void unmask_irq(unsigned int irq_nr)
+#define shutdown_irq6 disable_irq6
+#define mask_and_ack_irq6 disable_irq6
+
+static void end_irq6(unsigned int irq)
{
- switch (irq_nr) {
- case 0:
- IntEnable6 |= INT6_PERIODICINT;
- break;
+ if(!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_irq6(irq);
+}
- case 3:
- /* Serial port receive interrupt */
- break;
+static struct hw_interrupt_type irq6_type = {
+ "MIPS",
+ startup_irq6,
+ shutdown_irq6,
+ enable_irq6,
+ disable_irq6,
+ mask_and_ack_irq6,
+ end_irq6,
+ NULL
+};
+
+void irq6_dispatch(struct pt_regs *regs)
+{
+ int irq = -1;
- case 2:
- /* Serial port transmit interrupt */
- break;
+ if((inl(TX3912_INT6_STATUS) & TX3912_INT6_STATUS_INTVEC_UARTARXINT) ==
+ TX3912_INT6_STATUS_INTVEC_UARTARXINT) {
+ irq = 3;
+ goto done;
+ }
+ if ((inl(TX3912_INT6_STATUS) & TX3912_INT6_STATUS_INTVEC_PERINT) ==
+ TX3912_INT6_STATUS_INTVEC_PERINT) {
+ irq = 0;
+ goto done;
+ }
- default:
- printk( "Attempt to unmask unknown IRQ %d?\n", irq_nr );
+ /* if irq == -1, then interrupt was cleared or is invalid */
+ if (irq == -1) {
+ panic("Unhandled High Priority PR31700 Interrupt = 0x%08x",
+ inl(TX3912_INT6_STATUS));
}
+
+done:
+ do_IRQ(irq, regs);
}
-void disable_irq(unsigned int irq_nr)
+static void enable_irq4(unsigned int irq)
{
- unsigned long flags;
-
- save_and_cli(flags);
- mask_irq(irq_nr);
- restore_flags(flags);
+ set_cp0_status(STATUSF_IP4);
+ if (irq == 2) {
+ outl(inl(TX3912_INT2_CLEAR) | TX3912_INT2_UARTA_TX_BITS,
+ TX3912_INT2_CLEAR);
+ outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_TX_BITS,
+ TX3912_INT2_ENABLE);
+ }
}
-void enable_irq(unsigned int irq_nr)
+static unsigned int startup_irq4(unsigned int irq)
{
- unsigned long flags;
+ enable_irq4(irq);
- save_and_cli(flags);
- unmask_irq(irq_nr);
- restore_flags(flags);
+ return 0; /* Never anything pending */
}
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
-extern void interrupt(void);
-
-static struct irqaction *irq_action[NR_IRQS] =
+static void disable_irq4(unsigned int irq)
{
- 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,
- 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
-};
+ clear_cp0_status(STATUSF_IP4);
+}
-int get_irq_list(char *buf)
-{
- int i, len = 0;
- struct irqaction *action;
+#define shutdown_irq4 disable_irq4
+#define mask_and_ack_irq4 disable_irq4
- for (i = 0; i < NR_IRQS; i++) {
- action = irq_action[i];
- if (!action)
- continue;
- len += sprintf(buf + len, "%2d: %8d %c %s",
- i, kstat.irqs[0][i],
- (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, "\n");
- }
- return len;
+static void end_irq4(unsigned int irq)
+{
+ if(!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_irq4(irq);
}
-atomic_t __mips_bh_counter;
+static struct hw_interrupt_type irq4_type = {
+ "MIPS",
+ startup_irq4,
+ shutdown_irq4,
+ enable_irq4,
+ disable_irq4,
+ mask_and_ack_irq4,
+ end_irq4,
+ NULL
+};
-/*
- * do_IRQ handles IRQ's that have been installed without the
- * SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts enabled. All relatively slow
- * IRQ's should use this format: notably the keyboard/timer
- * routines.
- */
-asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+void irq4_dispatch(struct pt_regs *regs)
{
- struct irqaction *action;
- int do_random, cpu;
+ int irq = -1;
- if (irq == 20) {
- if (IntStatus2 & 0xfffff00) {
- if (IntStatus2 & 0x0f000000)
- return do_IRQ(2, regs);
- }
- }
-
- cpu = smp_processor_id();
- irq_enter(cpu, irq);
- kstat.irqs[cpu][irq]++;
-
- if (irq == 20) {
- printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n",
- IntStatus1, IntStatus2, IntStatus3,
- IntStatus4, IntStatus5 );
- printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n",
- IntEnable1, IntEnable2, IntEnable3,
- IntEnable4, IntEnable5 );
-
- }
-
- mask_irq(irq);
- action = *(irq + irq_action);
- if (action) {
- if (!(action->flags & SA_INTERRUPT))
- __sti();
- do_random = 0;
- do {
- do_random |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while (action);
- if (do_random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- unmask_irq(irq);
- __cli();
- } else {
- IntClear1 = ~0;
- IntClear3 = ~0;
- IntClear4 = ~0;
- IntClear5 = ~0;
- unmask_irq(irq);
- }
- irq_exit(cpu, irq);
+ if(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTA_TX_BITS) {
+ irq = 2;
+ goto done;
+ }
- /* unmasking and bottom half handling is done magically for us. */
-}
+ /* if irq == -1, then interrupt was cleared or is invalid */
+ if (irq == -1) {
+ printk("PR31700 Interrupt Status Register 1 = 0x%08x\n",
+ inl(TX3912_INT1_STATUS));
+ printk("PR31700 Interrupt Status Register 2 = 0x%08x\n",
+ inl(TX3912_INT2_STATUS));
+ printk("PR31700 Interrupt Status Register 3 = 0x%08x\n",
+ inl(TX3912_INT3_STATUS));
+ printk("PR31700 Interrupt Status Register 4 = 0x%08x\n",
+ inl(TX3912_INT4_STATUS));
+ printk("PR31700 Interrupt Status Register 5 = 0x%08x\n",
+ inl(TX3912_INT5_STATUS));
+ panic("Unhandled Low Priority PR31700 Interrupt");
+ }
-/*
- * Idea is to put all interrupts
- * in a single table and differenciate them just by number.
- */
-int setup_nino_irq(int irq, struct irqaction *new)
-{
- int shared = 0;
- struct irqaction *old, **p;
- unsigned long flags;
-
- p = irq_action + irq;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ))
- return -EBUSY;
-
- /* Can't share interrupts unless both are same type */
- if ((old->flags ^ new->flags) & SA_INTERRUPT)
- return -EBUSY;
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
- if (new->flags & SA_SAMPLE_RANDOM)
- rand_initialize_irq(irq);
-
- save_and_cli(flags);
- *p = new;
-
- if (!shared) {
- unmask_irq(irq);
- }
- restore_flags(flags);
- return 0;
-}
-
-int request_irq(unsigned int irq,
- void (*handler) (int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
-{
- int retval;
- struct irqaction *action;
-
- if (irq >= NR_IRQS)
- 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->next = NULL;
- action->dev_id = dev_id;
-
- retval = setup_nino_irq(irq, action);
-
- if (retval)
- kfree(action);
- return retval;
+done:
+ do_IRQ(irq, regs);
+ return;
}
-void free_irq(unsigned int irq, void *dev_id)
+void irq_bad(struct pt_regs *regs)
{
- struct irqaction *action, **p;
- unsigned long flags;
+ /* This should never happen */
+ printk(" CAUSE register = 0x%08lx\n", regs->cp0_cause);
+ printk("STATUS register = 0x%08lx\n", regs->cp0_status);
+ printk(" EPC register = 0x%08lx\n", regs->cp0_epc);
+ panic("Stray interrupt, spinning...");
+}
+
+void __init nino_irq_setup(void)
+{
+ extern asmlinkage void ninoIRQ(void);
+
+ unsigned int i;
+
+ /* Disable all hardware interrupts */
+ change_cp0_status(ST0_IM, 0x00);
+
+ /* Clear interrupts */
+ outl(0xffffffff, TX3912_INT1_CLEAR);
+ outl(0xffffffff, TX3912_INT2_CLEAR);
+ outl(0xffffffff, TX3912_INT3_CLEAR);
+ outl(0xffffffff, TX3912_INT4_CLEAR);
+ outl(0xffffffff, TX3912_INT5_CLEAR);
+
+ /*
+ * Disable all PR31700 interrupts. We let the various
+ * device drivers in the system register themselves
+ * and set the proper hardware bits.
+ */
+ outl(0x00000000, TX3912_INT1_ENABLE);
+ outl(0x00000000, TX3912_INT2_ENABLE);
+ outl(0x00000000, TX3912_INT3_ENABLE);
+ outl(0x00000000, TX3912_INT4_ENABLE);
+ outl(0x00000000, TX3912_INT5_ENABLE);
+
+ /* Initialize IRQ vector table */
+ init_generic_irq();
+
+ /* Initialize IRQ action handlers */
+ for (i = 0; i < 16; i++) {
+ hw_irq_controller *handler = NULL;
+ if (i == 0 || i == 3)
+ handler = &irq6_type;
+ else
+ handler = &irq4_type;
+
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = handler;
+ }
- if (irq >= NR_IRQS) {
- printk(KERN_CRIT __FUNCTION__ ": trying to free IRQ%d\n", irq);
- return;
- }
- for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now free it */
- save_and_cli(flags);
- *p = action->next;
- if (!irq[irq_action])
- mask_irq(irq);
- restore_flags(flags);
- kfree(action);
- return;
- }
- printk(KERN_CRIT __FUNCTION__ ": trying to free free IRQ%d\n", irq);
-}
+ /* Set up the external interrupt exception vector */
+ set_except_vector(0, ninoIRQ);
-unsigned long probe_irq_on(void)
-{
- /* TODO */
- return 0;
-}
+ /* Enable high priority interrupts */
+ outl(TX3912_INT6_ENABLE_GLOBALEN | TX3912_INT6_ENABLE_HIGH_PRIORITY,
+ TX3912_INT6_ENABLE);
-int probe_irq_off(unsigned long irqs)
-{
- /* TODO */
- return 0;
+ /* Enable all interrupts */
+ change_cp0_status(ST0_IM, ALLINTS);
}
+void (*irq_setup)(void);
+
void __init init_IRQ(void)
{
- irq_setup();
+#ifdef CONFIG_REMOTE_DEBUG
+ extern void breakpoint(void);
+ extern void set_debug_traps(void);
+
+ printk("Wait for gdb client connection ...\n");
+ set_debug_traps();
+ breakpoint();
+#endif
+
+ /* Invoke board-specific irq setup */
+ irq_setup();
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)