diff options
Diffstat (limited to 'arch/powerpc/platforms/85xx/mpc85xx_cds.c')
-rw-r--r-- | arch/powerpc/platforms/85xx/mpc85xx_cds.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 71200bdce05a..81b70628df75 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -24,6 +24,7 @@ #include <linux/seq_file.h> #include <linux/initrd.h> #include <linux/module.h> +#include <linux/interrupt.h> #include <linux/fsl_devices.h> #include <asm/system.h> @@ -119,16 +120,30 @@ DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge); DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge); #ifdef CONFIG_PPC_I8259 -#warning The i8259 PIC support is currently broken -static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc) +static void mpc85xx_8259_cascade_handler(unsigned int irq, + struct irq_desc *desc) { unsigned int cascade_irq = i8259_irq(); if (cascade_irq != NO_IRQ) + /* handle an interrupt from the 8259 */ generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + /* check for any interrupts from the shared IRQ line */ + handle_fasteoi_irq(irq, desc); } + +static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static struct irqaction mpc85xxcds_8259_irqaction = { + .handler = mpc85xx_8259_cascade_action, + .flags = IRQF_SHARED, + .mask = CPU_MASK_NONE, + .name = "8259 cascade", +}; #endif /* PPC_I8259 */ #endif /* CONFIG_PCI */ @@ -137,7 +152,7 @@ static void __init mpc85xx_cds_pic_init(void) struct mpic *mpic; struct resource r; struct device_node *np = NULL; -#ifdef CONFIG_PPC_I8259 +#if defined(CONFIG_PPC_I8259) && defined(CONFIG_PCI) struct device_node *cascade_node = NULL; int cascade_irq; #endif @@ -165,7 +180,7 @@ static void __init mpc85xx_cds_pic_init(void) mpic_init(mpic); -#ifdef CONFIG_PPC_I8259 +#if defined(CONFIG_PPC_I8259) && defined(CONFIG_PCI) /* Initialize the i8259 controller */ for_each_node_by_type(np, "interrupt-controller") if (of_device_is_compatible(np, "chrp,iic")) { @@ -187,7 +202,17 @@ static void __init mpc85xx_cds_pic_init(void) i8259_init(cascade_node, 0); of_node_put(cascade_node); - set_irq_chained_handler(cascade_irq, mpc85xx_8259_cascade); + /* + * Hook the interrupt to make sure desc->action is never NULL. + * This is required to ensure that the interrupt does not get + * disabled when the last user of the shared IRQ line frees their + * interrupt. + */ + if (setup_irq(cascade_irq, &mpc85xxcds_8259_irqaction)) + printk(KERN_ERR "Failed to setup cascade interrupt\n"); + else + /* Success. Connect our low-level cascade handler. */ + set_irq_handler(cascade_irq, mpc85xx_8259_cascade_handler); #endif /* CONFIG_PPC_I8259 */ } |