patch-1.3.44 linux/arch/sparc/kernel/irq.c
Next file: linux/arch/sparc/kernel/mp.S
Previous file: linux/arch/sparc/kernel/ioport.c
Back to the patch index
Back to the overall index
- Lines: 415
- Date:
Sat Nov 25 02:58:10 1995
- Orig file:
v1.3.43/linux/arch/sparc/kernel/irq.c
- Orig date:
Tue Jun 27 14:11:31 1995
diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
@@ -1,4 +1,5 @@
-/* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
+/* $Id: irq.c,v 1.29 1995/11/25 00:58:08 davem Exp $
+ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
* node trees to find out who's got which IRQ.
@@ -8,19 +9,6 @@
* Copyright (C) 1995 Pete A. Zaitcev (zaitcev@jamica.lab.ipmce.su)
*/
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * The same sigaction struct is used, and with similar semantics (ie there
- * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there
- * are similarities.
- *
- * sa_handler(int irq_NR) is the default function called (0 if no).
- * sa_mask is horribly ugly (I won't even mention it)
- * sa_flags contains various info: SA_INTERRUPT etc
- * sa_restorer is the unused
- */
-
-#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/linkage.h>
@@ -37,38 +25,28 @@
#include <asm/timer.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
+#include <asm/traps.h>
#include <asm/irq.h>
#include <asm/io.h>
/* Pointer to the interrupt enable byte */
-/* XXX Ugh, this is so sun4c specific it's driving me nuts. XXX */
unsigned char *interrupt_enable = 0;
struct sun4m_intregs *sun4m_interrupts;
-/* XXX Needs to handle Sun4m semantics XXX */
void
-disable_irq(unsigned int irq_nr)
+sun4c_disable_irq(unsigned int irq_nr)
{
unsigned long flags;
unsigned char current_mask, new_mask;
- if(sparc_cpu_model != sun4c) return;
-
- save_flags(flags);
- cli();
-
+ if(sparc_cpu_model != sun4c)
+ return;
+ save_flags(flags); cli();
current_mask = *interrupt_enable;
-
switch(irq_nr) {
case 1:
new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
break;
- case 4:
- new_mask = ((current_mask) & (~(SUN4C_INT_E4)));
- break;
- case 6:
- new_mask = ((current_mask) & (~(SUN4C_INT_E6)));
- break;
case 8:
new_mask = ((current_mask) & (~(SUN4C_INT_E8)));
break;
@@ -79,42 +57,49 @@
new_mask = ((current_mask) & (~(SUN4C_INT_E14)));
break;
default:
-#if 0 /* Actually this is safe, as the floppy driver needs this */
- printk("AIEEE, Illegal interrupt disable requested irq=%d\n",
- (int) irq_nr);
- prom_halt();
-#endif
- break;
+ restore_flags(flags);
+ return;
};
+ *interrupt_enable = new_mask;
restore_flags(flags);
- return;
}
-/* XXX Needs to handle sun4m semantics XXX */
void
-enable_irq(unsigned int irq_nr)
+sun4m_disable_irq(unsigned int irq_nr)
{
- unsigned long flags;
- unsigned char current_mask, new_mask;
+ printk("IRQ routines not yet written for the sun4m\n");
+ panic("disable_irq: Unsupported arch.");
+}
- if(sparc_cpu_model != sun4c) return;
+void
+disable_irq(unsigned int irq_nr)
+{
+ switch(sparc_cpu_model) {
+ case sun4c:
+ sun4c_disable_irq(irq_nr);
+ break;
+ case sun4m:
+ sun4m_disable_irq(irq_nr);
+ default:
+ panic("disable_irq: Unsupported arch.");
+ }
+}
- save_flags(flags);
- cli();
+void
+sun4c_enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ unsigned char current_mask, new_mask;
+ if(sparc_cpu_model != sun4c)
+ return;
+ save_flags(flags); cli();
current_mask = *interrupt_enable;
-
switch(irq_nr) {
case 1:
new_mask = ((current_mask) | SUN4C_INT_E1);
break;
- case 4:
- new_mask = ((current_mask) | SUN4C_INT_E4);
- break;
- case 6:
- new_mask = ((current_mask) | SUN4C_INT_E6);
- break;
case 8:
new_mask = ((current_mask) | SUN4C_INT_E8);
break;
@@ -125,19 +110,34 @@
new_mask = ((current_mask) | SUN4C_INT_E14);
break;
default:
-#if 0 /* Floppy driver does this on sun4c's anyhow */
- printk ("Interrupt does not need to enable IE\n");
- return;
-#endif
restore_flags(flags);
return;
};
*interrupt_enable = new_mask;
-
restore_flags(flags);
+}
- return;
+void
+sun4m_enable_irq(unsigned int irq_nr)
+{
+ printk("IRQ routines not written for the sun4m yet.\n");
+ panic("IRQ unsupported arch.");
+}
+
+void
+enable_irq(unsigned int irq_nr)
+{
+ switch(sparc_cpu_model) {
+ case sun4c:
+ sun4c_enable_irq(irq_nr);
+ break;
+ case sun4m:
+ sun4m_enable_irq(irq_nr);
+ break;
+ default:
+ panic("IRQ unsupported arch.");
+ }
}
/*
@@ -193,8 +193,7 @@
printk("Trying to free free IRQ%d\n", irq);
return;
}
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
disable_irq(irq);
action->handler = NULL;
action->flags = 0;
@@ -210,14 +209,14 @@
printk("IO device interrupt, irq = %d\n", irq);
printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc,
- regs->npc, regs->u_regs[14]);
+ regs->npc, regs->u_regs[14]);
printk("Expecting: ");
for (i = 0; i < 16; i++)
if (irq_action[i].handler)
- printk("[%s:%d:0x%x] ", irq_action[i].name, (int) i,
+ prom_printf("[%s:%d:0x%x] ", irq_action[i].name, (int) i,
(unsigned int) irq_action[i].handler);
printk("AIEEE\n");
- prom_halt();
+ panic("bogus interrupt received");
}
void
@@ -225,11 +224,11 @@
{
struct irqaction * action = irq_action + irq;
- if (!action->handler) {
+ kstat.interrupts[irq]++;
+ if (!action->handler)
unexpected_irq(irq, regs);
- return;
- }
- action->handler(irq, regs);
+ else
+ action->handler(irq, regs);
}
/*
@@ -262,6 +261,40 @@
return;
}
+int
+request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
+ unsigned long irqflags, const char *devname)
+{
+ struct irqaction *action;
+ unsigned long flags;
+
+ if(irq > 14)
+ return -EINVAL;
+ action = irq + irq_action;
+ if(action->handler)
+ return -EBUSY;
+ if(!handler)
+ return -EINVAL;
+
+ save_flags(flags); cli();
+
+ /* Dork with trap table if we get this far. */
+ sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one =
+ SPARC_BRANCH((unsigned long) handler,
+ (unsigned long) &sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one);
+ sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_two = SPARC_RD_PSR_L0;
+ sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_three = SPARC_NOP;
+ sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_four = SPARC_NOP;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+
+ restore_flags(flags);
+ return 0;
+}
+
extern void probe_clock(void);
int
@@ -271,44 +304,40 @@
struct irqaction *action;
unsigned long flags;
- if(irq > 14) /* Only levels 1-14 are valid on the Sparc. */
+ if(irq > 14)
return -EINVAL;
- /* i386 keyboard interrupt request, just return */
- if(irq == 1) return 0;
-
- /* sched_init() requesting the timer IRQ */
- if(irq == 0) {
- irq = 10;
- }
-
action = irq + irq_action;
-
if(action->handler)
return -EBUSY;
-
if(!handler)
return -EINVAL;
- save_flags(flags);
-
- cli();
-
+ save_flags(flags); cli();
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
-
enable_irq(irq);
-
- /* Init the timer/clocks if necessary. */
- if(irq == 10) probe_clock();
-
+ if(irq == 10)
+ probe_clock();
restore_flags(flags);
-
return 0;
}
+/* We really don't need these at all on the Sparc. We only have
+ * stubs here because they are exported to modules.
+ */
+unsigned long probe_irq_on(void)
+{
+ return 0;
+}
+
+int probe_irq_off(unsigned long mask)
+{
+ return 0;
+}
+
void
sun4c_init_IRQ(void)
{
@@ -317,10 +346,8 @@
ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
"interrupt-enable");
- if(ie_node == 0) {
- printk("Cannot find /interrupt-enable node\n");
- prom_halt();
- }
+ if(ie_node == 0)
+ panic("Cannot find /interrupt-enable node");
/* Depending on the "address" property is bad news... */
prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
@@ -330,16 +357,14 @@
interrupt_enable = (char *) INTREG_VADDR;
/* Default value, accept interrupts, but no one is actually active */
- /* We also turn on level14 interrupts so PROM can run the console. */
- *interrupt_enable = (SUN4C_INT_ENABLE | SUN4C_INT_E14);
- sti(); /* As of NOW, L1-A works. Turn irq's on full-blast. */
- return;
+ *interrupt_enable = (SUN4C_INT_ENABLE);
+ sti(); /* Turn irq's on full-blast. */
}
void
sun4m_init_IRQ(void)
{
- int ie_node, i;
+ int ie_node;
struct linux_prom_registers int_regs[PROMREG_MAX];
int num_regs;
@@ -349,10 +374,7 @@
if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
(ie_node = prom_getchild (ie_node)) == 0 ||
(ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0)
- {
- printk("Cannot find /obio/interrupt node\n");
- prom_halt();
- }
+ panic("Cannot find /obio/interrupt node\n");
num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
sizeof(int_regs));
num_regs = (num_regs/sizeof(struct linux_prom_registers));
@@ -372,27 +394,7 @@
int_regs[num_regs-1].which_io, 0x0);
sun4m_interrupts = (struct sun4m_intregs *) INTREG_VADDR;
-
-#if 0
- printk("Interrupt register dump...\n");
-
- for(i=0; i<NCPUS; i++)
- printk("cpu%d: tbt %08x\n", i,
- sun4m_interrupts->cpu_intregs[i].tbt);
-
- printk("Master tbt %08x\n", sun4m_interrupts->tbt);
- printk("Master irqs %08x\n", sun4m_interrupts->irqs);
- printk("Master set %08x\n", sun4m_interrupts->set);
- printk("Master clear %08x\n", sun4m_interrupts->clear);
- printk("Undirected ints taken by: %08x\n",
- sun4m_interrupts->undirected_target);
-
- prom_halt();
-#endif
-
sti();
-
- return;
}
void
@@ -406,10 +408,7 @@
sun4m_init_IRQ();
break;
default:
- printk("Cannot initialize IRQ's on this Sun machine...\n");
- halt();
+ panic("Cannot initialize IRQ's on this Sun machine...");
break;
};
-
- return;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this