summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/irq.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /arch/ppc/kernel/irq.c
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'arch/ppc/kernel/irq.c')
-rw-r--r--arch/ppc/kernel/irq.c1012
1 files changed, 194 insertions, 818 deletions
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index f4a7c7143..461e51aa1 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,5 +1,5 @@
/*
- * $Id: irq.c,v 1.91 1998/12/28 10:28:47 paulus Exp $
+ * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
*
* arch/ppc/kernel/irq.c
*
@@ -42,6 +42,7 @@
#include <linux/malloc.h>
#include <linux/openpic.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/hydra.h>
@@ -56,101 +57,46 @@
#include <asm/amigaints.h>
#include <asm/amigahw.h>
#include <asm/amigappc.h>
-#ifdef CONFIG_8xx
-#include <asm/8xx_immap.h>
-#include <asm/mbx.h>
-#endif
+#include <asm/ptrace.h>
+
+#include "local_irq.h"
-extern void process_int(unsigned long vec, struct pt_regs *fp);
-extern void apus_init_IRQ(void);
-extern void amiga_disable_irq(unsigned int irq);
-extern void amiga_enable_irq(unsigned int irq);
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-static volatile unsigned char *chrp_int_ack_special;
extern volatile unsigned long ipi_count;
-static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base);
+void enable_irq(unsigned int irq_nr);
+void disable_irq(unsigned int irq_nr);
+
+/* Fixme - Need to figure out a way to get rid of this - Corey */
+volatile unsigned char *chrp_int_ack_special;
#ifdef CONFIG_APUS
/* Rename a few functions. Requires the CONFIG_APUS protection. */
#define request_irq nop_ppc_request_irq
#define free_irq nop_ppc_free_irq
#define get_irq_list nop_get_irq_list
-#endif
-#ifndef CONFIG_8xx
-void (*mask_and_ack_irq)(int irq_nr);
-void (*mask_irq)(unsigned int irq_nr);
-void (*unmask_irq)(unsigned int irq_nr);
-#else /* CONFIG_8xx */
-/* init_IRQ() happens too late for the MBX because we initialize the
- * CPM early and it calls request_irq() before we have these function
- * pointers initialized.
- */
-#define mask_and_ack_irq(irq) mbx_mask_irq(irq)
-#define mask_irq(irq) mbx_mask_irq(irq)
-#define unmask_irq(irq) mbx_unmask_irq(irq)
-#endif /* CONFIG_8xx */
-
#define VEC_SPUR (24)
-#undef SHOW_IRQ
-#undef SHOW_GATWICK_IRQS
-#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-#define cached_21 (((char *)(cached_irq_mask))[3])
-#define cached_A1 (((char *)(cached_irq_mask))[2])
-#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-int max_irqs;
-int max_real_irqs;
-static struct irqaction *irq_action[NR_IRQS];
-static int spurious_interrupts = 0;
-static unsigned int cached_irq_mask[NR_MASK_WORDS];
-unsigned int lost_interrupts[NR_MASK_WORDS];
-atomic_t n_lost_interrupts;
-
-/* pmac */
-struct pmac_irq_hw {
- unsigned int flag;
- unsigned int enable;
- unsigned int ack;
- unsigned int level;
-};
+#endif
-/* XXX these addresses should be obtained from the device tree */
-volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
- (struct pmac_irq_hw *) 0xf3000020,
- (struct pmac_irq_hw *) 0xf3000010,
- (struct pmac_irq_hw *) 0xf4000020,
- (struct pmac_irq_hw *) 0xf4000010,
-};
+#define MAXCOUNT 10000000
-/* This is the interrupt used on the main controller for the secondary
- controller. Happens on PowerBooks G3 Series (a second mac-io)
- -- BenH
- */
-static int second_irq = -999;
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-/* Returns the number of 0's to the left of the most significant 1 bit */
-static inline int cntlzw(int bits)
-{
- int lz;
+int ppc_spurious_interrupts = 0;
- asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits));
- return lz;
-}
+unsigned int ppc_local_bh_count[NR_CPUS];
+unsigned int ppc_local_irq_count[NR_CPUS];
+struct irqaction *ppc_irq_action[NR_IRQS];
+unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+atomic_t ppc_n_lost_interrupts;
-static inline void sync(void)
-{
- asm volatile ("sync");
-}
/* nasty hack for shared irq's since we need to do kmalloc calls but
- * can't very very early in the boot when we need to do a request irq.
+ * can't very early in the boot when we need to do a request irq.
* this needs to be removed.
* -- Cort
*/
static char cache_bitmask = 0;
-static struct irqaction malloc_cache[4];
+static struct irqaction malloc_cache[8];
extern int mem_init_done;
void *irq_kmalloc(size_t size, int pri)
@@ -179,168 +125,80 @@ void irq_kfree(void *ptr)
kfree(ptr);
}
-#ifndef CONFIG_8xx
-void i8259_mask_and_ack_irq(int irq_nr)
-{
- /* spin_lock(&irq_controller_lock);*/
- cached_irq_mask[0] |= 1 << irq_nr;
- if (irq_nr > 7) {
- inb(0xA1); /* DUMMY */
- outb(cached_A1,0xA1);
- outb(0x62,0x20); /* Specific EOI to cascade */
- /*outb(0x20,0xA0);*/
- outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
- } else {
- inb(0x21); /* DUMMY */
- outb(cached_21,0x21);
- /*outb(0x20,0x20);*/
- outb(0x60|irq_nr,0x20); /* specific eoi */
-
- }
- /* spin_unlock(&irq_controller_lock);*/
-}
-
-void __pmac pmac_mask_and_ack_irq(int irq_nr)
-{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
-
- if ((unsigned)irq_nr >= max_irqs)
- return;
- /*spin_lock(&irq_controller_lock);*/
-
- clear_bit(irq_nr, cached_irq_mask);
- if (test_and_clear_bit(irq_nr, lost_interrupts))
- atomic_dec(&n_lost_interrupts);
- out_le32(&pmac_irq_hw[i]->ack, bit);
- out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
- out_le32(&pmac_irq_hw[i]->ack, bit);
- /* make sure ack gets to controller before we enable interrupts */
- sync();
-
- /*spin_unlock(&irq_controller_lock);*/
- /*if ( irq_controller_lock.lock )
- panic("irq controller lock still held in mask and ack\n");*/
-}
+struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
-void __openfirmware chrp_mask_and_ack_irq(int irq_nr)
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
{
- /* spinlocks are done by i8259_mask_and_ack() - Cort */
- if (is_8259_irq(irq_nr))
- i8259_mask_and_ack_irq(irq_nr);
-}
-
+ struct irqaction *old, **p, *action;
+ unsigned long flags;
-static void i8259_set_irq_mask(int irq_nr)
-{
- if (irq_nr > 7) {
- outb(cached_A1,0xA1);
- } else {
- outb(cached_21,0x21);
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+ if (!handler)
+ {
+ /* Free */
+ for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
+ {
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ restore_flags(flags);
+ irq_kfree(action);
+ return 0;
+ }
+ return -ENOENT;
}
-}
-
-static void __pmac pmac_set_irq_mask(int irq_nr)
-{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
-
- if ((unsigned)irq_nr >= max_irqs)
- return;
-
- /* enable unmasked interrupts */
- out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
-
- /*
- * Unfortunately, setting the bit in the enable register
- * when the device interrupt is already on *doesn't* set
- * the bit in the flag register or request another interrupt.
- */
- if ((bit & cached_irq_mask[i])
- && (ld_le32(&pmac_irq_hw[i]->level) & bit)
- && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
- if (!test_and_set_bit(irq_nr, lost_interrupts))
- atomic_inc(&n_lost_interrupts);
+
+ action = (struct irqaction *)
+ irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ save_flags(flags);
+ cli();
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = NULL;
+ enable_irq(irq);
+
+ p = &irq_desc[irq].action;
+
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & action->flags & SA_SHIRQ))
+ return -EBUSY;
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
}
-}
-
-/*
- * These have to be protected by the spinlock
- * before being called.
- */
-static void i8259_mask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] |= 1 << irq_nr;
- i8259_set_irq_mask(irq_nr);
-}
-
-static void i8259_unmask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] &= ~(1 << irq_nr);
- i8259_set_irq_mask(irq_nr);
-}
-
-static void __pmac pmac_mask_irq(unsigned int irq_nr)
-{
- clear_bit(irq_nr, cached_irq_mask);
- pmac_set_irq_mask(irq_nr);
- sync();
-}
-
-static void __pmac pmac_unmask_irq(unsigned int irq_nr)
-{
- set_bit(irq_nr, cached_irq_mask);
- pmac_set_irq_mask(irq_nr);
-}
-
-static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
-{
- if (is_8259_irq(irq_nr))
- i8259_mask_irq(irq_nr);
- else
- openpic_disable_irq(irq_to_openpic(irq_nr));
-}
+ *p = action;
-static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
-{
- if (is_8259_irq(irq_nr))
- i8259_unmask_irq(irq_nr);
- else
- openpic_enable_irq(irq_to_openpic(irq_nr));
-}
-#else /* CONFIG_8xx */
-static void mbx_mask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] &= ~(1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
- cached_irq_mask[0];
+ restore_flags(flags);
+ return 0;
}
-static void mbx_unmask_irq(unsigned int irq_nr)
+void free_irq(unsigned int irq, void *dev_id)
{
- cached_irq_mask[0] |= (1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
- cached_irq_mask[0];
+ request_irq(irq, NULL, 0, NULL, dev_id);
}
-#endif /* CONFIG_8xx */
void disable_irq(unsigned int irq_nr)
{
- /*unsigned long flags;*/
-
- /* spin_lock_irqsave(&irq_controller_lock, flags);*/
mask_irq(irq_nr);
- /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
synchronize_irq();
}
void enable_irq(unsigned int irq_nr)
{
- /*unsigned long flags;*/
-
- /* spin_lock_irqsave(&irq_controller_lock, flags);*/
unmask_irq(irq_nr);
- /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
}
int get_irq_list(char *buf)
@@ -354,8 +212,8 @@ int get_irq_list(char *buf)
*(char *)(buf+len++) = '\n';
for (i = 0 ; i < NR_IRQS ; i++) {
- action = irq_action[i];
- if ((!action || !action->handler) && (i != second_irq))
+ action = irq_desc[i].action;
+ if ( !action || !action->handler )
continue;
len += sprintf(buf+len, "%3d: ", i);
#ifdef __SMP__
@@ -365,56 +223,83 @@ int get_irq_list(char *buf)
#else
len += sprintf(buf+len, "%10u ", kstat_irqs(i));
#endif /* __SMP__ */
- switch( _machine )
- {
- case _MACH_prep:
- len += sprintf(buf+len, " 82c59 ");
- break;
- case _MACH_Pmac:
- if (i < 64)
- len += sprintf(buf+len, " PMAC-PIC ");
- else
- len += sprintf(buf+len, " GATWICK ");
- break;
- case _MACH_chrp:
- if ( is_8259_irq(i) )
- len += sprintf(buf+len, " 82c59 ");
- else
- len += sprintf(buf+len, " OpenPIC ");
- break;
- case _MACH_mbx:
- len += sprintf(buf+len, " MPC8xx ");
- break;
+ if ( irq_desc[i].ctl )
+ len += sprintf(buf+len, " %s ", irq_desc[i].ctl->typename );
+ len += sprintf(buf+len, " %s",action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ", %s", action->name);
}
-
- if (i != second_irq) {
- len += sprintf(buf+len, " %s",action->name);
- for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ", %s", action->name);
- }
- len += sprintf(buf+len, "\n");
- } else
- len += sprintf(buf+len, " Gatwick secondary IRQ controller\n");
+ len += sprintf(buf+len, "\n");
}
#ifdef __SMP__
/* should this be per processor send/receive? */
- len += sprintf(buf+len, "IPI: %10lu", ipi_count);
- for ( i = 0 ; i <= smp_num_cpus-1; i++ )
- len += sprintf(buf+len," ");
- len += sprintf(buf+len, " interprocessor messages received\n");
+ len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
#endif
- len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
- for ( i = 0 ; i <= smp_num_cpus-1; i++ )
- len += sprintf(buf+len," ");
- len += sprintf(buf+len, " spurious or short\n");
+ len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
return len;
}
-
/*
- * Global interrupt locks for SMP. Allow interrupts to come in on any
- * CPU, yet make cli/sti act globally to protect critical regions..
+ * Eventually, this should take an array of interrupts and an array size
+ * so it can dispatch multiple interrupts.
*/
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
+{
+ int status;
+ struct irqaction *action;
+ int cpu = smp_processor_id();
+
+ mask_and_ack_irq(irq);
+ status = 0;
+ action = irq_desc[irq].action;
+ kstat.irqs[cpu][irq]++;
+ if (action && action->handler) {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while ( action );
+ __cli();
+ unmask_irq(irq);
+ } else {
+ ppc_spurious_interrupts++;
+ disable_irq( irq );
+ }
+}
+
+asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
+{
+ int cpu = smp_processor_id();
+
+ hardirq_enter(cpu);
+ ppc_md.do_IRQ(regs, cpu, isfake);
+ hardirq_exit(cpu);
+}
+
+unsigned long probe_irq_on (void)
+{
+ return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+ return 0;
+}
+
+void __init init_IRQ(void)
+{
+ static int once = 0;
+
+ if ( once )
+ return;
+ else
+ once++;
+
+ ppc_md.init_IRQ();
+}
+
#ifdef __SMP__
unsigned char global_irq_holder = NO_PROC_ID;
unsigned volatile int global_irq_lock;
@@ -431,9 +316,13 @@ static void show(char * str)
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d %d]\n",
- atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
+ atomic_read(&global_irq_count),
+ ppc_local_irq_count[0],
+ ppc_local_irq_count[1]);
printk("bh: %d [%d %d]\n",
- atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
+ atomic_read(&global_bh_count),
+ ppc_local_bh_count[0],
+ ppc_local_bh_count[1]);
stack = (unsigned long *) &str;
for (i = 40; i ; i--) {
unsigned long x = *++stack;
@@ -443,7 +332,6 @@ static void show(char * str)
}
}
-#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
{
int count = MAXCOUNT;
@@ -469,7 +357,8 @@ static inline void wait_on_irq(int cpu)
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
- if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+ if (ppc_local_bh_count[cpu]
+ || !atomic_read(&global_bh_count))
break;
}
@@ -490,7 +379,8 @@ static inline void wait_on_irq(int cpu)
continue;
if (global_irq_lock)
continue;
- if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+ if (!ppc_local_bh_count[cpu]
+ && atomic_read(&global_bh_count))
continue;
if (!test_and_set_bit(0,&global_irq_lock))
break;
@@ -512,7 +402,6 @@ void synchronize_bh(void)
wait_on_bh();
}
-
/*
* This is called when we want to synchronize with
* interrupts. We may for example tell a device to
@@ -581,7 +470,7 @@ void __global_cli(void)
if (flags & (1 << 15)) {
int cpu = smp_processor_id();
__cli();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
get_irqlock(cpu);
}
}
@@ -590,7 +479,7 @@ void __global_sti(void)
{
int cpu = smp_processor_id();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
release_irqlock(cpu);
__sti();
}
@@ -614,7 +503,7 @@ unsigned long __global_save_flags(void)
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
- if (!local_irq_count[smp_processor_id()]) {
+ if (!ppc_local_irq_count[smp_processor_id()]) {
if (local_enabled)
retval = 1;
if (global_irq_holder == (unsigned char) smp_processor_id())
@@ -623,6 +512,31 @@ unsigned long __global_save_flags(void)
return retval;
}
+int
+tb(long vals[],
+ int max_size)
+{
+ register unsigned long *orig_sp __asm__ ("r1");
+ register unsigned long lr __asm__ ("r3");
+ unsigned long *sp;
+ int i;
+
+ asm volatile ("mflr 3");
+ vals[0] = lr;
+ sp = (unsigned long *) *orig_sp;
+ sp = (unsigned long *) *sp;
+ for (i=1; i<max_size; i++) {
+ if (sp == 0) {
+ break;
+ }
+
+ vals[i] = *(sp+1);
+ sp = (unsigned long *) *sp;
+ }
+
+ return i;
+}
+
void __global_restore_flags(unsigned long flags)
{
switch (flags) {
@@ -639,559 +553,21 @@ void __global_restore_flags(unsigned long flags)
__sti();
break;
default:
- printk("global_restore_flags: %08lx (%08lx)\n",
- flags, (&flags)[-1]);
- }
-}
-
-#endif /* __SMP__ */
-
-asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
-{
- int irq;
- unsigned long bits;
- struct irqaction *action;
- int cpu = smp_processor_id();
- int status;
- int openpic_eoi_done = 0;
-
- /* save the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- unsigned dcache_locked;
-
- dcache_locked = unlock_dcache();
- hardirq_enter(cpu);
-#ifndef CONFIG_8xx
-#ifdef __SMP__
- if ( cpu != 0 )
- {
- if (!isfake)
- {
- extern void smp_message_recv(void);
-#ifdef CONFIG_XMON
- static int xmon_2nd;
- if (xmon_2nd)
- xmon(regs);
-#endif
- smp_message_recv();
- goto out;
- }
- /* could be here due to a do_fake_interrupt call but we don't
- mess with the controller from the second cpu -- Cort */
- goto out;
- }
-
- {
- unsigned int loops = MAXCOUNT;
- while (test_bit(0, &global_irq_lock)) {
- if (smp_processor_id() == global_irq_holder) {
- printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- break;
- }
- if (loops-- == 0) {
- printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- }
- }
- }
-#endif /* __SMP__ */
-
- switch ( _machine )
- {
- case _MACH_Pmac:
- for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
-
- /* Here, we handle interrupts coming from Gatwick,
- * normal interrupt code will take care of acking and
- * masking the irq on Gatwick itself but we ack&mask
- * the Gatwick main interrupt on Heathrow now. It's
- * unmasked later, after interrupt handling. -- BenH
- */
- if (irq == second_irq) {
- mask_and_ack_irq(second_irq);
- for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
- /* If not found, on exit, irq is 63 (128-1-32-32).
- * We set it to -1 and revalidate second controller
- */
- if (irq < max_real_irqs) {
- irq = -1;
- unmask_irq(second_irq);
- }
-#ifdef SHOW_GATWICK_IRQS
- printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits);
-#endif
- }
-
- break;
- case _MACH_chrp:
- irq = openpic_irq(0);
- if (irq == IRQ_8259_CASCADE)
- {
- /*
- * This magic address generates a PCI IACK cycle.
- *
- * This should go in the above mask/ack code soon. -- Cort
- */
- irq = *chrp_int_ack_special;
- /*
- * Acknowledge as soon as possible to allow i8259
- * interrupt nesting
- */
- openpic_eoi(0);
- openpic_eoi_done = 1;
- }
- else if (irq >= OPENPIC_VEC_TIMER)
- {
- /*
- * OpenPIC interrupts >64 will be used for other purposes
- * like interprocessor interrupts and hardware errors
- */
- if (irq == OPENPIC_VEC_SPURIOUS) {
- /*
- * Spurious interrupts should never be
- * acknowledged
- */
- spurious_interrupts++;
- openpic_eoi_done = 1;
- } else {
- /*
- * Here we should process IPI timer
- * for now the interrupt is dismissed.
- */
- }
- goto out;
- }
- break;
- case _MACH_prep:
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
- {
-retry_cascade:
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- /* if no intr left */
- if ( !(irq & 128 ) )
- goto out;
- irq = (irq&7) + 8;
- }
- bits = 1UL << irq;
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
{
- int old_level, new_level;
-
- old_level = ~(regs->mq) & IPLEMU_IPLMASK;
- new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
-
- if (new_level == 0)
- {
- goto apus_out;
- }
-
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
- | (~(new_level) & IPLEMU_IPLMASK)));
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-
- process_int (VEC_SPUR+new_level, regs);
-
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
- | (~(old_level) & IPLEMU_IPLMASK)));
-
-apus_out:
- hardirq_exit(cpu);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
- goto out2;
- }
-#endif
- }
-
- if (irq < 0) {
- /* we get here with Gatwick but the 'bogus' isn't correct in that case -- Cort */
- if ( irq != second_irq )
- {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- spurious_interrupts++;
- }
- goto out;
- }
-
-#else /* CONFIG_8xx */
- /* For MPC8xx, read the SIVEC register and shift the bits down
- * to get the irq number.
- */
- bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
- irq = bits >> 26;
-#endif /* CONFIG_8xx */
- mask_and_ack_irq(irq);
- status = 0;
- action = irq_action[irq];
- kstat.irqs[cpu][irq]++;
- if (action && action->handler) {
- if (!(action->flags & SA_INTERRUPT))
- __sti();
- do {
- status |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while ( action );
- __cli();
- unmask_irq(irq);
- } else {
-#ifndef CONFIG_8xx
- if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
-#endif
- spurious_interrupts++;
- disable_irq( irq );
- }
-
- /* This was a gatwick sub-interrupt, we re-enable them on Heathrow
- now */
- if (_machine == _MACH_Pmac && irq >= max_real_irqs)
- unmask_irq(second_irq);
-
- /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
-#ifndef CONFIG_8xx
- if ( is_prep && (irq > 7) )
- goto retry_cascade;
- /* do_bottom_half is called if necessary from int_return in head.S */
-out:
- if (_machine == _MACH_chrp && !openpic_eoi_done)
- openpic_eoi(0);
-#endif /* CONFIG_8xx */
- hardirq_exit(cpu);
-
-#ifdef CONFIG_APUS
-out2:
-#endif
- /* restore the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- lock_dcache(dcache_locked);
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
-{
- struct irqaction *old, **p, *action;
- unsigned long flags;
-
-#ifdef SHOW_IRQ
- printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
- irq,(int)handler,devname,(int)dev_id);
-#endif /* SHOW_IRQ */
-
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- /* Cannot allocate second controller IRQ */
- if (irq == second_irq)
- return -EBUSY;
+ unsigned long trace[5];
+ int count;
+ int i;
- if (!handler)
- {
- /* Free */
- for (p = irq + irq_action; (action = *p) != NULL; p = &action->next)
- {
- /* Found it - now free it */
- save_flags(flags);
- cli();
- *p = action->next;
- restore_flags(flags);
- irq_kfree(action);
- return 0;
- }
- return -ENOENT;
- }
-
- action = (struct irqaction *)
- irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- if (!action)
- return -ENOMEM;
- save_flags(flags);
- cli();
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->dev_id = dev_id;
- action->next = NULL;
- enable_irq(irq);
- p = irq_action + irq;
-
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & action->flags & SA_SHIRQ))
- return -EBUSY;
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- }
- *p = action;
-
- restore_flags(flags);
- return 0;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- request_irq(irq, NULL, 0, NULL, dev_id);
-}
-
-unsigned long probe_irq_on (void)
-{
- return 0;
-}
-
-int probe_irq_off (unsigned long irqs)
-{
- return 0;
-}
-
-#ifndef CONFIG_8xx
-__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);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
- panic("Could not allocate cascade IRQ!");
- enable_irq(2); /* Enable cascade interrupt */
-}
-#endif /* CONFIG_8xx */
-
-/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External
- * interrupts can be either edge or level triggered, but there is no
- * reason for us to change the EPPC-bug values (it would not work if we did).
- */
-__initfunc(void init_IRQ(void))
-{
- extern void xmon_irq(int, void *, struct pt_regs *);
- int i;
- struct device_node *irqctrler;
- unsigned long addr;
- struct device_node *np;
-
-#ifndef CONFIG_8xx
- switch (_machine)
- {
- case _MACH_Pmac:
- mask_and_ack_irq = pmac_mask_and_ack_irq;
- mask_irq = pmac_mask_irq;
- unmask_irq = pmac_unmask_irq;
-
- /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128,
- others have 32 */
- max_irqs = max_real_irqs = 32;
- irqctrler = find_devices("mac-io");
- if (irqctrler)
- {
- max_real_irqs = 64;
- if (irqctrler->next)
- max_irqs = 128;
- else
- max_irqs = 64;
- }
-
- /* get addresses of first controller */
- if (irqctrler) {
- if (irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 0; i < 2; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (2 - i) * 0x10);
- }
-
- /* get addresses of second controller */
- irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
- if (irqctrler && irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 2; i < 4; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (4 - i) * 0x10);
- }
- }
-
- /* disable all interrupts in all controllers */
- for (i = 0; i * 32 < max_irqs; ++i)
- out_le32(&pmac_irq_hw[i]->enable, 0);
-
-
- /* get interrupt line of secondary interrupt controller */
- if (irqctrler) {
- second_irq = irqctrler->intrs[0].line;
- printk(KERN_INFO "irq: secondary controller on irq %d\n",
- (int)second_irq);
- if (device_is_compatible(irqctrler, "gatwick"))
- pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
- enable_irq(second_irq);
- }
- printk("System has %d possible interrupts\n", max_irqs);
- if (max_irqs != max_real_irqs)
- printk(KERN_DEBUG "%d interrupts on main controller\n",
- max_real_irqs);
-
-#ifdef CONFIG_XMON
- request_irq(20, xmon_irq, 0, "NMI", 0);
-#endif /* CONFIG_XMON */
- break;
- case _MACH_chrp:
- mask_and_ack_irq = chrp_mask_and_ack_irq;
- mask_irq = chrp_mask_irq;
- unmask_irq = chrp_unmask_irq;
-
- if ( !(np = find_devices("pci") ) )
- printk("Cannot find pci to get ack address\n");
- else
- {
- chrp_int_ack_special = (volatile unsigned char *)
- (*(unsigned long *)get_property(np,
- "8259-interrupt-acknowledge", NULL));
- }
- openpic_init(1);
- i8259_init();
- cached_irq_mask[0] = cached_irq_mask[1] = ~0UL;
-#ifdef CONFIG_XMON
- request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
- xmon_irq, 0, "NMI", 0);
-#endif /* CONFIG_XMON */
- break;
- case _MACH_prep:
- mask_and_ack_irq = i8259_mask_and_ack_irq;
- mask_irq = i8259_mask_irq;
- unmask_irq = i8259_unmask_irq;
- cached_irq_mask[0] = ~0UL;
-
- i8259_init();
- /*
- * According to the Carolina spec from ibm irqs 0,1,2, and 8
- * must be edge triggered. Also, the pci intrs must be level
- * triggered and _only_ isa intrs can be level sensitive
- * which are 3-7,9-12,14-15. 13 is special - it can be level.
- *
- * power on default is 0's in both regs - all edge.
- *
- * These edge/level control regs allow edge/level status
- * to be decided on a irq basis instead of on a PIC basis.
- * It's still pretty ugly.
- * - Cort
- */
- {
- unsigned char irq_mode1 = 0, irq_mode2 = 0;
- irq_mode1 = 0; /* to get rid of compiler warnings */
- /*
- * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
- */
- if ( _prep_type == _PREP_IBM )
- irq_mode2 |= 0xa0;
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
+ count = tb(trace, 5);
+ printk("tb:");
+ for(i=0; i<count; i++) {
+ printk(" %8.8lx", trace[i]);
}
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- mask_irq = amiga_disable_irq;
- unmask_irq = amiga_enable_irq;
- apus_init_IRQ();
- break;
-#endif
+ printk("\n");
}
-#endif /* CONFIG_8xx */
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
- struct device_node *node;
- static struct interrupt_info int_pool[4];
-
- memset(int_pool, 0, sizeof(int_pool));
- node = gw->child;
- while(node)
- {
- /* Fix SCC */
- if (strcasecmp(node->name, "escc") == 0)
- if (node->child && node->child->n_intrs == 0)
- {
- node->child->n_intrs = 1;
- node->child->intrs = &int_pool[0];
- int_pool[0].line = 15+irq_base;
- printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n",
- int_pool[0].line);
- }
- /* Fix media-bay & left SWIM */
- if (strcasecmp(node->name, "media-bay") == 0)
- {
- struct device_node* ya_node;
-
- if (node->n_intrs == 0)
- {
- node->n_intrs = 1;
- node->intrs = &int_pool[1];
- int_pool[1].line = 29+irq_base;
- printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
- int_pool[1].line);
- }
- ya_node = node->child;
- while(ya_node)
- {
- if ((strcasecmp(ya_node->name, "floppy") == 0) &&
- ya_node->n_intrs == 0)
- {
- ya_node->n_intrs = 2;
- ya_node->intrs = &int_pool[2];
- int_pool[2].line = 19+irq_base;
- int_pool[3].line = 1+irq_base;
- printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
- int_pool[2].line, int_pool[3].line);
- }
- ya_node = ya_node->sibling;
- }
- }
- node = node->sibling;
}
-
}
+#endif /* __SMP__ */