patch-2.4.10 linux/arch/mips/philips/nino/irq.c
Next file: linux/arch/mips/philips/nino/kgdb.c
Previous file: linux/arch/mips/philips/nino/int-handler.S
Back to the patch index
Back to the overall index
- Lines: 315
- Date:
Sun Sep 9 10:43:02 2001
- Orig file:
v2.4.9/linux/arch/mips/philips/nino/irq.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.9/linux/arch/mips/philips/nino/irq.c linux/arch/mips/philips/nino/irq.c
@@ -0,0 +1,314 @@
+/*
+ * linux/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.
+ */
+#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;
+
+irq_cpustat_t irq_stat [NR_CPUS];
+
+static inline void mask_irq(unsigned int irq_nr)
+{
+ switch (irq_nr) {
+ case 0: /* Periodic Timer Interrupt */
+ IntClear5 = INT5_PERIODICINT;
+ IntClear6 = INT6_PERIODICINT;
+ IntEnable6 &= ~INT6_PERIODICINT;
+ break;
+
+ case 3:
+ /* Serial port receive interrupt */
+ break;
+
+ case 2:
+ /* Serial port transmit interrupt */
+ break;
+
+ default:
+ printk( "Attempt to mask unknown IRQ %d?\n", irq_nr );
+ }
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+ switch (irq_nr) {
+ case 0:
+ IntEnable6 |= INT6_PERIODICINT;
+ break;
+
+ case 3:
+ /* Serial port receive interrupt */
+ break;
+
+ case 2:
+ /* Serial port transmit interrupt */
+ break;
+
+ default:
+ printk( "Attempt to unmask unknown IRQ %d?\n", irq_nr );
+ }
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ mask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ unmask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+/*
+ * 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] =
+{
+ 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
+};
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ struct irqaction *action;
+
+ 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;
+}
+
+atomic_t __mips_bh_counter;
+
+/*
+ * 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)
+{
+ struct irqaction *action;
+ int do_random, cpu;
+
+ 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);
+
+ /* unmasking and bottom half handling is done magically for us. */
+}
+
+/*
+ * 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;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action, **p;
+ unsigned long flags;
+
+ 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);
+}
+
+unsigned long probe_irq_on(void)
+{
+ /* TODO */
+ return 0;
+}
+
+int probe_irq_off(unsigned long irqs)
+{
+ /* TODO */
+ return 0;
+}
+
+void __init init_IRQ(void)
+{
+ irq_setup();
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)