patch-2.2.8 linux/arch/ppc/kernel/irq.c
Next file: linux/arch/ppc/kernel/local_irq.h
Previous file: linux/arch/ppc/kernel/indirect_pci.c
Back to the patch index
Back to the overall index
- Lines: 1013
- Date:
Thu Apr 29 12:39:01 1999
- Orig file:
v2.2.7/linux/arch/ppc/kernel/irq.c
- Orig date:
Tue Mar 23 14:35:46 1999
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
@@ -1,5 +1,5 @@
/*
- * $Id: irq.c,v 1.102 1999/02/03 01:36:59 paulus Exp $
+ * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
*
* arch/ppc/kernel/irq.c
*
@@ -58,44 +58,15 @@
#include <asm/amigahw.h>
#include <asm/amigappc.h>
#include <asm/ptrace.h>
-#ifdef CONFIG_8xx
-#include <asm/8xx_immap.h>
-#include <asm/mbx.h>
-#endif
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+#include "local_irq.h"
+
extern volatile unsigned long ipi_count;
-static void dispatch_handler(struct pt_regs *regs, int irq);
void enable_irq(unsigned int irq_nr);
void disable_irq(unsigned int irq_nr);
-static void i8259_mask_and_ack_irq(unsigned int irq_nr);
-static void i8259_mask_irq(unsigned int irq_nr);
-static void i8259_unmask_irq(unsigned int irq_nr);
-#ifdef CONFIG_8xx
-static void mbx_mask_and_ack(unsigned int irq_nr);
-static void mbx_mask_irq(unsigned int irq_nr);
-static void mbx_unmask_irq(unsigned int irq_nr);
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
-#else /* CONFIG_8xx */
-static volatile unsigned char *chrp_int_ack_special;
-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 pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base);
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs);
-static void pmac_mask_irq(unsigned int irq_nr);
-static void pmac_unmask_irq(unsigned int irq_nr);
-static void pmac_mask_and_ack_irq(unsigned int irq_nr);
-static void chrp_mask_and_ack_irq(unsigned int irq_nr);
-static void chrp_unmask_irq(unsigned int irq_nr);
-static void chrp_mask_irq(unsigned int irq_nr);
-#ifdef __SMP__
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_message_recv(void);
-#endif /* __SMP__ */
-#endif /* CONFIG_8xx */
+/* 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. */
@@ -105,39 +76,19 @@
#define VEC_SPUR (24)
#endif
+#define MAXCOUNT 10000000
+
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-unsigned char cached_8259[2] = { 0xff, 0xff };
-#define cached_A1 (cached_8259[0])
-#define cached_21 (cached_8259[1])
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-int max_irqs;
-int max_real_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;
-
-#ifndef CONFIG_8xx
-#define GATWICK_IRQ_POOL_SIZE 10
-static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
-/* pmac */
-struct pmac_irq_hw {
- unsigned int flag;
- unsigned int enable;
- unsigned int ack;
- unsigned int level;
-};
-
-/* these addresses are obtained from the device tree now -- Cort */
-volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmac = {
- (struct pmac_irq_hw *) 0xf3000020,
- (struct pmac_irq_hw *) 0xf3000010,
- (struct pmac_irq_hw *) 0xf4000020,
- (struct pmac_irq_hw *) 0xf4000010,
-};
-#endif /* CONFIG_8xx */
+
+int ppc_spurious_interrupts = 0;
+
+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;
+
/* nasty hack for shared irq's since we need to do kmalloc calls but
* can't very early in the boot when we need to do a request irq.
@@ -174,82 +125,7 @@
kfree(ptr);
}
-struct hw_interrupt_type {
- const char * typename;
- void (*startup)(unsigned int irq);
- void (*shutdown)(unsigned int irq);
- void (*handle)(unsigned int irq, struct pt_regs * regs);
- void (*enable)(unsigned int irq);
- void (*disable)(unsigned int irq);
- void (*mask_and_ack)(unsigned int irq);
- int irq_offset;
-};
-
-#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
-#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
-#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
-
-struct irqdesc {
- struct irqaction *action;
- struct hw_interrupt_type *ctl;
-};
-static struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
-
-static struct hw_interrupt_type i8259_pic = {
- " i8259 ",
- NULL,
- NULL,
- NULL,
- i8259_unmask_irq,
- i8259_mask_irq,
- i8259_mask_and_ack_irq,
- 0
-};
-#ifndef CONFIG_8xx
-static struct hw_interrupt_type pmac_pic = {
- " PMAC-PIC ",
- NULL,
- NULL,
- NULL,
- pmac_unmask_irq,
- pmac_mask_irq,
- pmac_mask_and_ack_irq,
- 0
-};
-
-static struct hw_interrupt_type gatwick_pic = {
- " GATWICK ",
- NULL,
- NULL,
- NULL,
- pmac_unmask_irq,
- pmac_mask_irq,
- pmac_mask_and_ack_irq,
- 0
-};
-
-static struct hw_interrupt_type open_pic = {
- " OpenPIC ",
- NULL,
- NULL,
- NULL,
- chrp_unmask_irq,
- chrp_mask_irq,
- chrp_mask_and_ack_irq,
- 0
-};
-#else
-static struct hw_interrupt_type ppc8xx_pic = {
- " 8xx SIU ",
- NULL,
- NULL,
- NULL,
- mbx_unmask_irq,
- mbx_mask_irq,
- mbx_mask_and_ack,
- 0
-};
-#endif /* CONFIG_8xx */
+struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char * devname, void *dev_id)
@@ -357,19 +233,17 @@
}
#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;
}
-static void dispatch_handler(struct pt_regs *regs, int irq)
+/*
+ * 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;
@@ -390,209 +264,18 @@
__cli();
unmask_irq(irq);
} else {
- spurious_interrupts++;
+ ppc_spurious_interrupts++;
disable_irq( irq );
}
}
-#define MAXCOUNT 100000000
asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
{
- int irq;
- unsigned long bits = 0;
int cpu = smp_processor_id();
- int openpic_eoi_done = 0;
-
- hardirq_enter(cpu);
-#ifndef CONFIG_8xx
-#ifdef __SMP__
- /* IPI's are a hack on the powersurge -- Cort */
- if ( (_machine == _MACH_Pmac) && (cpu != 0) )
- {
- if (!isfake)
- {
-#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;
- }
- 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;
- }
- if (irq == OPENPIC_VEC_SPURIOUS)
- {
- /*
- * Spurious interrupts should never be
- * acknowledged
- */
- spurious_interrupts++;
- openpic_eoi_done = 1;
- }
- bits = 1UL << irq;
- break;
- case _MACH_prep:
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
- {
- outb(0x0C, 0xA0);
- irq = (inb(0xA0) & 7) + 8;
- bits |= 1UL << irq;
-#if 0
- /* It's possible to loose intrs here
- * if we get 2 intrs in the upper 8
- * bits. We eoi irq 2 and handle one of
- * the upper intrs but then ignore it
- * since we've already eoi-d 2. So,
- * we must keep track of lost intrs.
- * -- Cort
- */
- while (1)
- {
- int i;
- outb(0x0C, 0xA0);
- i = inb(0xA0);
- if ( !(i & 128) )
- break;
- irq &= 7;
- irq += 8;
- bits |= 1UL << irq;
- }
-#endif
- }
- else
- 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)
- {
- 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;
- irq += ppc8xx_pic.irq_offset;
- bits = 1UL << irq;
-#endif /* CONFIG_8xx */
-#if 0
- /*
- * this allows for > 1 interrupt at a time so we can
- * clear out any 'double' interrupts on prep and
- * finish up the lost interrupts.
- * It doesn't currently work for irqs > 31 so I'm leaving
- * it commented out for now.
- * -- Cort
- */
- for ( i = 0 ; i < sizeof(bits)*8 ; i++ )
- if ( bits & (1UL<<i) )
- dispatch_handler( regs, i );
-#else
- dispatch_handler( regs, irq );
-#endif
-
-#ifndef CONFIG_8xx
-out:
- if (_machine == _MACH_chrp && !openpic_eoi_done)
- openpic_eoi(0);
-#endif /* CONFIG_8xx */
- hardirq_exit(cpu);
-#ifdef CONFIG_APUS
-out2:
-#endif
+ hardirq_enter(cpu);
+ ppc_md.do_IRQ(regs, cpu, isfake);
+ hardirq_exit(cpu);
}
unsigned long probe_irq_on (void)
@@ -605,461 +288,16 @@
return 0;
}
-static void i8259_mask_and_ack_irq(unsigned int irq_nr)
-{
- if ( irq_nr >= i8259_pic.irq_offset )
- irq_nr -= i8259_pic.irq_offset;
- if (irq_nr > 7) {
- cached_A1 |= 1 << (irq_nr-8);
- 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 {
- cached_21 |= 1 << irq_nr;
- inb(0x21); /* DUMMY */
- outb(cached_21,0x21);
- /*outb(0x20,0x20);*/
- outb(0x60|irq_nr,0x20); /* specific eoi */
- }
-}
-
-static void i8259_set_irq_mask(int irq_nr)
-{
- outb(cached_A1,0xA1);
- outb(cached_21,0x21);
-}
-
-static void i8259_mask_irq(unsigned int irq_nr)
-{
- if ( irq_nr >= i8259_pic.irq_offset )
- irq_nr -= i8259_pic.irq_offset;
- if ( irq_nr < 8 )
- cached_21 |= 1 << irq_nr;
- else
- cached_A1 |= 1 << (irq_nr-8);
- i8259_set_irq_mask(irq_nr);
-}
-
-static void i8259_unmask_irq(unsigned int irq_nr)
-{
-
- if ( irq_nr >= i8259_pic.irq_offset )
- irq_nr -= i8259_pic.irq_offset;
- if ( irq_nr < 8 )
- cached_21 &= ~(1 << irq_nr);
- else
- cached_A1 &= ~(1 << (irq_nr-8));
- i8259_set_irq_mask(irq_nr);
-}
-
-#ifndef CONFIG_8xx
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
- int irq, bits;
-
- 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;
- }
- /* The previous version of this code allowed for this case, we
- * don't. Put this here to check for it.
- * -- Cort
- */
- if ( irq_desc[irq].ctl != &gatwick_pic )
- printk("gatwick irq not from gatwick pic\n");
- else
- dispatch_handler( regs, irq );
-}
-
-void pmac_mask_and_ack_irq(unsigned int irq_nr)
-{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
-
- if ((unsigned)irq_nr >= max_irqs)
- return;
-
- 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);
- do {
- /* make sure ack gets to controller before we enable interrupts */
- mb();
- } while(in_le32(&pmac_irq_hw[i]->flag) & bit);
-
-}
-
-void __openfirmware chrp_mask_and_ack_irq(unsigned int irq_nr)
-{
- if (is_8259_irq(irq_nr))
- i8259_mask_and_ack_irq(irq_nr);
-}
-
-static void 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]);
-
- do {
- /* make sure mask gets to controller before we
- return to user */
- mb();
- } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
- != (cached_irq_mask[i] & bit));
-
- /*
- * 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);
- }
-}
-
-static void pmac_mask_irq(unsigned int irq_nr)
-{
- clear_bit(irq_nr, cached_irq_mask);
- pmac_set_irq_mask(irq_nr);
- mb();
-}
-
-static void 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));
-}
-
-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));
-}
-
-/* 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;
- int count;
-
- memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
- node = gw->child;
- count = 0;
- while(node)
- {
- /* Fix SCC */
- if (strcasecmp(node->name, "escc") == 0)
- if (node->child) {
- if (node->child->n_intrs < 3) {
- node->child->intrs = &gatwick_int_pool[count];
- count += 3;
- }
- node->child->n_intrs = 3;
- node->child->intrs[0].line = 15+irq_base;
- node->child->intrs[1].line = 4+irq_base;
- node->child->intrs[2].line = 5+irq_base;
- printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
- node->child->intrs[0].line,
- node->child->intrs[1].line,
- node->child->intrs[2].line);
- }
- /* Fix media-bay & left SWIM */
- if (strcasecmp(node->name, "media-bay") == 0) {
- struct device_node* ya_node;
-
- if (node->n_intrs == 0)
- node->intrs = &gatwick_int_pool[count++];
- node->n_intrs = 1;
- node->intrs[0].line = 29+irq_base;
- printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
- node->intrs[0].line);
-
- ya_node = node->child;
- while(ya_node)
- {
- if (strcasecmp(ya_node->name, "floppy") == 0) {
- if (ya_node->n_intrs < 2) {
- ya_node->intrs = &gatwick_int_pool[count];
- count += 2;
- }
- ya_node->n_intrs = 2;
- ya_node->intrs[0].line = 19+irq_base;
- ya_node->intrs[1].line = 1+irq_base;
- printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
- ya_node->intrs[0].line, ya_node->intrs[1].line);
- }
- if (strcasecmp(ya_node->name, "ata4") == 0) {
- if (ya_node->n_intrs < 2) {
- ya_node->intrs = &gatwick_int_pool[count];
- count += 2;
- }
- ya_node->n_intrs = 2;
- ya_node->intrs[0].line = 14+irq_base;
- ya_node->intrs[1].line = 3+irq_base;
- printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
- ya_node->intrs[0].line, ya_node->intrs[1].line);
- }
- ya_node = ya_node->sibling;
- }
- }
- node = node->sibling;
- }
- if (count > 10) {
- printk("WARNING !! Gatwick interrupt pool overflow\n");
- printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
- printk(" requested = %d\n", count);
- }
-}
-
-#ifdef __SMP__
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
- smp_message_recv();
-}
-#endif /* __SMP__ */
-
-
-#else /* CONFIG_8xx */
-
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
- int bits, irq;
-
- /* A bug in the QSpan chip causes it to give us 0xff always
- * when doing a character read. So read 32 bits and shift.
- * This doesn't seem to return useful values anyway, but
- * read it to make sure things are acked.
- * -- Cort
- */
- irq = (inl(0x508) >> 24)&0xff;
- if ( irq != 0xff ) printk("iack %d\n", irq);
-
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
- {
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- irq = (irq&7) + 8;
- }
- bits = 1UL << irq;
- irq += i8259_pic.irq_offset;
- dispatch_handler( regs, irq );
-}
-
-static void mbx_mask_and_ack(unsigned int irq_nr)
-{
- /* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
- if ( irq_nr != ISA_BRIDGE_INT )
- mbx_mask_irq(irq_nr);
- if ( irq_nr >= ppc8xx_pic.irq_offset )
- irq_nr -= ppc8xx_pic.irq_offset;
- /* clear the pending bits */
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
-}
-
-static void mbx_mask_irq(unsigned int irq_nr)
-{
- if ( irq_nr == ISA_BRIDGE_INT ) return;
- if ( irq_nr >= ppc8xx_pic.irq_offset )
- irq_nr -= ppc8xx_pic.irq_offset;
- cached_irq_mask[0] &= ~(1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = cached_irq_mask[0];
-}
-
-static void mbx_unmask_irq(unsigned int irq_nr)
-{
- if ( irq_nr >= ppc8xx_pic.irq_offset )
- irq_nr -= ppc8xx_pic.irq_offset;
- cached_irq_mask[0] |= (1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = cached_irq_mask[0];
-}
-#endif /* CONFIG_8xx */
-
-static void __init 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);
- request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT,
- "8259 secondary cascade", NULL );
- enable_irq(i8259_pic.irq_offset + 2); /* Enable cascade interrupt */
-}
-
void __init init_IRQ(void)
{
- extern void xmon_irq(int, void *, struct pt_regs *);
- int i;
static int once = 0;
-#ifndef CONFIG_8xx
- struct device_node *irqctrler;
- unsigned long addr;
- struct device_node *np;
- int second_irq = -999;
-#endif
+
if ( once )
return;
else
once++;
-#ifndef CONFIG_8xx
- switch (_machine)
- {
- case _MACH_Pmac:
- /* 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;
- }
- for ( i = 0; i < max_real_irqs ; i++ )
- irq_desc[i].ctl = &pmac_pic;
-
- /* 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);
- for ( i = max_real_irqs ; i < max_irqs ; i++ )
- irq_desc[i].ctl = &gatwick_pic;
- request_irq( second_irq, gatwick_action, SA_INTERRUPT,
- "gatwick cascade", 0 );
- }
- 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 - XMON", 0);
-#endif /* CONFIG_XMON */
- break;
- case _MACH_chrp:
- 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));
- }
- for ( i = 16 ; i < 36 ; i++ )
- irq_desc[i].ctl = &open_pic;
- /* openpic knows that it's at irq 16 offset
- * so we don't need to set it in the pic structure
- * -- Cort
- */
- openpic_init(1);
- for ( i = 0 ; i < 16 ; i++ )
- irq_desc[i].ctl = &i8259_pic;
- i8259_init();
-#ifdef CONFIG_XMON
- request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
- xmon_irq, 0, "NMI", 0);
-#endif /* CONFIG_XMON */
-#ifdef __SMP__
- request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS),
- openpic_ipi_action, 0, "IPI0", 0);
-#endif /* __SMP__ */
- break;
- case _MACH_prep:
- for ( i = 0 ; i < 16 ; i++ )
- irq_desc[i].ctl = &i8259_pic;
- i8259_init();
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- apus_init_IRQ();
- break;
-#endif
- }
-#else /* CONFIG_8xx */
- ppc8xx_pic.irq_offset = 16;
- for ( i = 16 ; i < 32 ; i++ )
- irq_desc[i].ctl = &ppc8xx_pic;
- unmask_irq(CPM_INTERRUPT);
-
- for ( i = 0 ; i < 16 ; i++ )
- irq_desc[i].ctl = &i8259_pic;
- i8259_init();
- request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
- enable_irq(ISA_BRIDGE_INT);
-#endif /* CONFIG_8xx */
+ ppc_md.init_IRQ();
}
#ifdef __SMP__
@@ -1078,9 +316,13 @@
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;
@@ -1115,7 +357,8 @@
* 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;
}
@@ -1136,7 +379,8 @@
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;
@@ -1226,7 +470,7 @@
if (flags & (1 << 15)) {
int cpu = smp_processor_id();
__cli();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
get_irqlock(cpu);
}
}
@@ -1235,7 +479,7 @@
{
int cpu = smp_processor_id();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
release_irqlock(cpu);
__sti();
}
@@ -1259,7 +503,7 @@
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())
@@ -1268,6 +512,31 @@
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) {
@@ -1284,8 +553,20 @@
__sti();
break;
default:
+ {
+ unsigned long trace[5];
+ int count;
+ int i;
+
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]);
+ }
+ printk("\n");
+ }
}
}
#endif /* __SMP__ */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)