patch-2.1.45 linux/arch/sparc64/kernel/irq.c
Next file: linux/arch/sparc64/kernel/process.c
Previous file: linux/arch/sparc64/kernel/ioctl32.c
Back to the patch index
Back to the overall index
- Lines: 191
- Date:
Wed Jul 16 19:22:50 1997
- Orig file:
v2.1.44/linux/arch/sparc64/kernel/irq.c
- Orig date:
Mon Jul 7 08:18:54 1997
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.14 1997/06/24 17:30:26 davem Exp $
+/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -47,7 +47,8 @@
static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
static int static_irq_count = 0;
-static struct irqaction *irq_action[NR_IRQS+1] = {
+/* XXX Must be exported so that fast IRQ handlers can get at it... -DaveM */
+struct irqaction *irq_action[NR_IRQS+1] = {
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
};
@@ -279,13 +280,13 @@
/* If this is flagged as statically allocated then we use our
* private struct which is never freed.
*/
- if(irqflags & SA_STATIC_ALLOC)
+ if(irqflags & SA_STATIC_ALLOC) {
if(static_irq_count < MAX_STATIC_ALLOC)
action = &static_irqaction[static_irq_count++];
else
printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
"using kmalloc\n", irq, name);
-
+ }
if(action == NULL)
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
GFP_KERNEL);
@@ -464,14 +465,101 @@
}
#endif
-/* XXX This needs to be written for floppy driver, and soon will be necessary
- * XXX for serial driver as well.
+/* The following assumes that the branch lies before the place we
+ * are branching to. This is the case for a trap vector...
+ * You have been warned.
*/
+#define SPARC_BRANCH(dest_addr, inst_addr) \
+ (0x10800000 | ((((dest_addr)-(inst_addr))>>2)&0x3fffff))
+
+#define SPARC_NOP (0x01000000)
+
+static void install_fast_irq(unsigned int cpu_irq,
+ void (*handler)(int, void *, struct pt_regs *))
+{
+ extern unsigned long sparc64_ttable_tl0;
+ unsigned long ttent = (unsigned long) &sparc64_ttable_tl0;
+ unsigned int *insns;
+
+ ttent += 0x820;
+ ttent += (cpu_irq - 1) << 5;
+ insns = (unsigned int *) ttent;
+ insns[0] = SPARC_BRANCH(((unsigned long) handler),
+ ((unsigned long)&insns[0]));
+ insns[1] = SPARC_NOP;
+ __asm__ __volatile__("flush %0" : : "r" (ttent));
+}
+
int request_fast_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char *name)
{
- return -1;
+ struct irqaction *action;
+ unsigned long flags;
+ unsigned int cpu_irq, *imap, *iclr;
+
+ /* XXX This really is not the way to do it, the "right way"
+ * XXX is to have drivers set SA_SBUS or something like that
+ * XXX in irqflags and we base our decision here on whether
+ * XXX that flag bit is set or not.
+ *
+ * In this case nobody can have a fast interrupt at the level
+ * where TICK interrupts live.
+ */
+ if(irq == 14)
+ return -EINVAL;
+ cpu_irq = ino_to_pil[irq];
+
+ if(!handler)
+ return -EINVAL;
+ imap = irq_to_imap(irq);
+ action = *(cpu_irq + irq_action);
+ if(action) {
+ if(action->flags & SA_SHIRQ)
+ panic("Trying to register fast irq when already shared.\n");
+ if(irqflags & SA_SHIRQ)
+ panic("Trying to register fast irq as shared.\n");
+ printk("request_fast_irq: Trying to register yet already owned.\n");
+ return -EBUSY;
+ }
+ save_and_cli(flags);
+ if(irqflags & SA_STATIC_ALLOC) {
+ if(static_irq_count < MAX_STATIC_ALLOC)
+ action = &static_irqaction[static_irq_count++];
+ else
+ printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
+ "using kmalloc\n", irq, name);
+ }
+ if(action == NULL)
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ GFP_KERNEL);
+ if(!action) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+ install_fast_irq(cpu_irq, handler);
+
+ if(imap) {
+ int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+
+ ivector_to_mask[ivindex] = (1 << cpu_irq);
+ iclr = imap_to_iclr(imap);
+ action->mask = (unsigned long) iclr;
+ irqflags |= SA_SYSIO_MASKED;
+ } else
+ action->mask = 0;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->dev_id = NULL;
+ action->name = name;
+ action->next = NULL;
+
+ *(cpu_irq + irq_action) = action;
+
+ enable_irq(irq);
+ restore_flags(flags);
+ return 0;
}
/* We really don't need these at all on the Sparc. We only have
@@ -496,27 +584,31 @@
/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- extern void timer_interrupt(int, void *, struct pt_regs *);
- unsigned long compare;
-
if (!(get_softint () & 1)) {
/* Just to be sure... */
clear_softint(1 << 14);
printk("Spurious level14 at %016lx\n", regs->tpc);
return;
- }
+ } else {
+ unsigned long compare, tick;
- timer_interrupt(irq, dev_id, regs);
+ do {
+ extern void timer_interrupt(int, void *, struct pt_regs *);
- /* Acknowledge INT_TIMER */
- clear_softint(1 << 0);
+ timer_interrupt(irq, dev_id, regs);
- /* Set up for next timer tick. */
- __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
- "add %0, %1, %0\n\t"
- "wr %0, 0x0, %%tick_cmpr"
- : "=r" (compare)
- : "r" (tick_offset));
+ /* Acknowledge INT_TIMER */
+ clear_softint(1 << 0);
+
+ /* Set up for next timer tick. */
+ __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
+ "add %0, %2, %0\n\t"
+ "wr %0, 0x0, %%tick_cmpr\n\t"
+ "rd %%tick, %1"
+ : "=&r" (compare), "=r" (tick)
+ : "r" (tick_offset));
+ } while(tick >= compare);
+ }
}
/* This is called from time_init() to get the jiffies timer going. */
@@ -584,7 +676,7 @@
prom_timers = (struct sun5_timer *) 0;
return;
}
- prom_timers = (struct sun5_timer *) addr[0];
+ prom_timers = (struct sun5_timer *) ((unsigned long)addr[0]);
}
static void kill_prom_timer(void)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov