patch-2.3.9 linux/arch/mips/kernel/irq.c
Next file: linux/arch/mips/kernel/mips_ksyms.c
Previous file: linux/arch/mips/kernel/irixsig.c
Back to the patch index
Back to the overall index
- Lines: 307
- Date:
Fri Jun 25 17:40:12 1999
- Orig file:
v2.3.8/linux/arch/mips/kernel/irq.c
- Orig date:
Wed Dec 23 09:44:40 1998
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.13 1998/05/28 03:17:55 ralf Exp $
+/* $Id: irq.c,v 1.15 1999/02/25 21:50:49 tsbogend Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
+#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -27,9 +28,21 @@
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
+#include <asm/sni.h>
-unsigned char cache_21 = 0xff;
-unsigned char cache_A1 = 0xff;
+/*
+ * This contains the irq mask for both 8259A irq controllers, it's an
+ * int so we can deal with the third PIC in some systems like the RM300.
+ * (XXX This is broken for big endian.)
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define __byte(x,y) (((unsigned char *)&(y))[x])
+#define __word(x,y) (((unsigned short *)&(y))[x])
+#define __long(x,y) (((unsigned int *)&(y))[x])
+
+#define cached_21 (__byte(0,cached_irq_mask))
+#define cached_A1 (__byte(1,cached_irq_mask))
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
@@ -39,31 +52,23 @@
* (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and
* PCI devices. Other onboard hardware needs specific routines.
*/
-static inline void mask_irq(unsigned int irq_nr)
+static inline void mask_irq(unsigned int irq)
{
- unsigned char mask;
-
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8) {
- cache_21 |= mask;
- outb(cache_21,0x21);
+ cached_irq_mask |= 1 << irq;
+ if (irq & 8) {
+ outb(cached_A1, 0xa1);
} else {
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
+ outb(cached_21, 0x21);
}
}
-static inline void unmask_irq(unsigned int irq_nr)
+static inline void unmask_irq(unsigned int irq)
{
- unsigned char mask;
-
- mask = ~(1 << (irq_nr & 7));
- if (irq_nr < 8) {
- cache_21 &= mask;
- outb(cache_21,0x21);
+ cached_irq_mask &= ~(1 << irq);
+ if (irq & 8) {
+ outb(cached_A1, 0xa1);
} else {
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
+ outb(cached_21, 0x21);
}
}
@@ -84,13 +89,11 @@
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[32] = {
+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,
@@ -122,6 +125,59 @@
atomic_t __mips_bh_counter;
+static inline void i8259_mask_and_ack_irq(int irq)
+{
+ cached_irq_mask |= 1 << irq;
+
+ if (irq & 8) {
+ inb(0xa1);
+ outb(cached_A1, 0xa1);
+ outb(0x62, 0x20); /* Specific EOI to cascade */
+ outb(0x20, 0xa0);
+ } else {
+ inb(0x21);
+ outb(cached_21, 0x21);
+ outb(0x20, 0x20);
+ }
+}
+
+asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int do_random, cpu;
+
+ cpu = smp_processor_id();
+ hardirq_enter(cpu);
+
+ if (irq >= 16)
+ goto out;
+
+ i8259_mask_and_ack_irq(irq);
+
+ kstat.irqs[cpu][irq]++;
+
+ action = *(irq + irq_action);
+ if (!action)
+ goto out;
+
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ action = *(irq + irq_action);
+ 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);
+ __cli();
+ unmask_irq (irq);
+
+out:
+ hardirq_exit(cpu);
+}
+
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
@@ -135,23 +191,9 @@
int do_random, cpu;
cpu = smp_processor_id();
- irq_enter(cpu, irq);
+ hardirq_enter(cpu);
kstat.irqs[cpu][irq]++;
- /*
- * mask and ack quickly, we don't want the irq controller
- * thinking we're snobs just because some other CPU has
- * disabled global interrupts (we have already done the
- * INT_ACK cycles, it's too late to try to pretend to the
- * controller that we aren't taking the interrupt).
- *
- * Commented out because we've already done this in the
- * machinespecific part of the handler. It's reasonable to
- * do this here in a highlevel language though because that way
- * we could get rid of a good part of duplicated code ...
- */
- /* mask_and_ack_irq(irq); */
-
action = *(irq + irq_action);
if (action) {
if (!(action->flags & SA_INTERRUPT))
@@ -165,21 +207,14 @@
} while (action);
if (do_random & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
- unmask_irq (irq);
__cli();
}
- irq_exit(cpu, irq);
+ hardirq_exit(cpu);
/* unmasking and bottom half handling is done magically for us. */
}
-/*
- * Used only for setup of PC style interrupts and therefore still
- * called setup_x86_irq. Later on I'll provide a machine specific
- * function with similar purpose. Idea is to put all interrupts
- * in a single table and differenciate them just by number.
- */
-int setup_x86_irq(int irq, struct irqaction * new)
+int i8259_setup_irq(int irq, struct irqaction * new)
{
int shared = 0;
struct irqaction *old, **p;
@@ -216,11 +251,15 @@
return 0;
}
+/*
+ * Request_interrupt and free_interrupt ``sort of'' handle interrupts of
+ * non i8259 devices. They will have to be replaced by architecture
+ * specific variants. For now we still use this as broken as it is because
+ * it used to work ...
+ */
int request_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char * devname,
- void *dev_id)
+ unsigned long irqflags, const char * devname, void *dev_id)
{
int retval;
struct irqaction * action;
@@ -241,7 +280,7 @@
action->next = NULL;
action->dev_id = dev_id;
- retval = setup_x86_irq(irq, action);
+ retval = i8259_setup_irq(irq, action);
if (retval)
kfree(action);
@@ -275,7 +314,7 @@
unsigned long probe_irq_on (void)
{
- unsigned int i, irqs = 0, irqmask;
+ unsigned int i, irqs = 0;
unsigned long delay;
/* first, enable any unassigned (E)ISA irqs */
@@ -291,19 +330,17 @@
/* about 100ms delay */;
/* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
- return irqs & ~irqmask;
+ return irqs & ~cached_irq_mask;
}
int probe_irq_off (unsigned long irqs)
{
- unsigned int i, irqmask;
+ unsigned int i;
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
#ifdef DEBUG
printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
#endif
- irqs &= irqmask;
+ irqs &= cached_irq_mask;
if (!irqs)
return 0;
i = ffz(~irqs);
@@ -314,13 +351,36 @@
int (*irq_cannonicalize)(int irq);
-static int i8259a_irq_cannonicalize(int irq)
+static int i8259_irq_cannonicalize(int irq)
{
return ((irq == 2) ? 9 : irq);
}
+__initfunc(static void i8259_init(void))
+{
+ /* Init master interrupt controller */
+ outb(0x11, 0x20); /* Start init sequence */
+ outb(0x00, 0x21); /* Vector base */
+ outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0x21); /* Select 8086 mode */
+ outb(0xff, 0x21); /* Mask all */
+
+ /* Init slave interrupt controller */
+ outb(0x11, 0xa0); /* Start init sequence */
+ outb(0x08, 0xa1); /* Vector base */
+ outb(0x02, 0xa1); /* edge triggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0xa1); /* Select 8086 mode */
+ outb(0xff, 0xa1); /* Mask all */
+
+ outb(cached_A1, 0xa1);
+ outb(cached_21, 0x21);
+}
+
__initfunc(void init_IRQ(void))
{
- irq_cannonicalize = i8259a_irq_cannonicalize;
+ irq_cannonicalize = i8259_irq_cannonicalize;
+ /* i8259_init(); */
irq_setup();
}
+
+EXPORT_SYMBOL(irq_cannonicalize);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)