diff -urN linux.orig/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- linux.orig/arch/ppc/kernel/chrp_setup.c Sun Mar 25 18:31:49 2001 +++ linux/arch/ppc/kernel/chrp_setup.c Tue Aug 27 15:46:50 2002 @@ -4,6 +4,7 @@ * Copyright (C) 1995 Linus Torvalds * Adapted from 'alpha' version by Gary Thomas * Modified by Cort Dougan (cort@cs.nmt.edu) + * Fixed IRQ time out problem by Krzysztof Taraszka (dzimi@pld.org.pl) */ /* @@ -359,6 +360,81 @@ } } +void +chrp_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake) +{ + int irq; + unsigned long bits = 0; + int openpic_eoi_done = 0; + +#ifdef __SMP__ + { + unsigned int loops = 1000000; + 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__ */ + + irq = openpic_irq(smp_processor_id()); + if (irq == IRQ_8259_CASCADE) + { + /* + * This magic address generates a PCI IACK cycle. + * + * This should go in the above mask/ack code soon. -- Cort + */ + if ( chrp_int_ack_special ) + irq = *chrp_int_ack_special; + else + irq = i8259_irq(0); + /* + * Acknowledge as soon as possible to allow i8259 + * interrupt nesting */ + openpic_eoi(smp_processor_id()); + openpic_eoi_done = 1; + } + if (irq == OPENPIC_VEC_SPURIOUS) + { + /* + * Spurious interrupts should never be + * acknowledged + */ + ppc_spurious_interrupts++; + openpic_eoi_done = 1; + goto out; + } + bits = 1UL << irq; + + if (irq < 0) + { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } + else + { + ppc_irq_dispatch_handler( regs, irq ); + } +out: + if (!openpic_eoi_done) + openpic_eoi(smp_processor_id()); +} + __initfunc(void chrp_init_IRQ(void)) { @@ -570,7 +646,7 @@ ppc_md.get_cpuinfo = chrp_get_cpuinfo; ppc_md.irq_cannonicalize = chrp_irq_cannonicalize; ppc_md.init_IRQ = chrp_init_IRQ; - ppc_md.do_IRQ = open_pic_do_IRQ; + ppc_md.do_IRQ = chrp_do_IRQ; ppc_md.init = chrp_init2; diff -urN linux.orig/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- linux.orig/arch/ppc/kernel/open_pic.c Sun Mar 25 18:31:49 2001 +++ linux/arch/ppc/kernel/open_pic.c Tue Aug 27 15:46:50 2002 @@ -11,116 +11,45 @@ #include #include #include -#include #include "open_pic.h" #include "i8259.h" -extern volatile unsigned char *chrp_int_ack_special; - -void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake) -{ - int irq; - int openpic_eoi_done = 0; - #ifdef __SMP__ - { - unsigned int loops = 1000000; - 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 - } - } - } +void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + smp_message_recv(cpl-OPENPIC_VEC_IPI); +} #endif /* __SMP__ */ - - irq = openpic_irq(smp_processor_id()); - /* make sure open_pic.irq_offset is set to something! - * do we really need the _MACH_Pmac test?? - */ - if (!(_machine == _MACH_Pmac) && (irq == open_pic.irq_offset)) - { - /* - * This magic address generates a PCI IACK cycle. - * - * This should go in the above mask/ack code soon. -- Cort - */ - if ( chrp_int_ack_special ) - irq = *chrp_int_ack_special; -#ifndef CONFIG_PMAC - else - irq = i8259_irq(0); -#endif - /* - * Acknowledge as soon as possible to allow i8259 - * interrupt nesting */ - openpic_eoi(smp_processor_id()); - openpic_eoi_done = 1; - } - if (irq == OPENPIC_VEC_SPURIOUS) - { - /* - * Spurious interrupts should never be - * acknowledged - */ - ppc_spurious_interrupts++; - openpic_eoi_done = 1; - goto out; - } - if (irq < 0) - { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - } - else - { - ppc_irq_dispatch_handler( regs, irq ); - } -out: - if (!openpic_eoi_done) - openpic_eoi(smp_processor_id()); +void chrp_mask_and_ack_irq(unsigned int irq_nr) +{ + if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) + i8259_pic.mask_and_ack(irq_nr); } -#ifdef __SMP__ -void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) +static void chrp_mask_irq(unsigned int irq_nr) { - smp_message_recv(cpl-OPENPIC_VEC_IPI); + if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) + i8259_pic.disable(irq_nr); + else + openpic_disable_irq(irq_nr-open_pic.irq_offset); } -#endif /* __SMP__ */ +static void chrp_unmask_irq(unsigned int irq_nr) +{ + if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) + i8259_pic.enable(irq_nr); + else + openpic_enable_irq(irq_nr-open_pic.irq_offset); +} struct hw_interrupt_type open_pic = { " OpenPIC ", NULL, NULL, NULL, - openpic_enable_irq, - openpic_disable_irq, - /* Theorically, the mask&ack should be NULL for OpenPIC. However, doing - * so shows tons of bogus interrupts coming in. - * This problem is apparently due to the common code always calling - * unmask(). I apparently (need more test) fixed it in the 2.4 new IRQ - * management by cleanly implementing the handler's end() function, so - * neither mask nor unmask are needed. In the meantime, the fix below will - * work for 2.2 -Benh - * - * Hopefully this will fix my bogus interrups on MTX - * I merged everthing together so we don't have the same code in three - * places. This might cause stability problems, but I'd rather - * get it right once than three different times because someone forgot - * to make the same change to PReP or something --Troy - */ - openpic_disable_irq, + chrp_unmask_irq, + chrp_mask_irq, + chrp_mask_and_ack_irq, 0 }; diff -urN linux.orig/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h --- linux.orig/arch/ppc/kernel/open_pic.h Sun Mar 25 18:31:49 2001 +++ linux/arch/ppc/kernel/open_pic.h Tue Aug 27 15:46:50 2002 @@ -6,7 +6,6 @@ extern struct hw_interrupt_type open_pic; -void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake); void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); void openpic_enable_IPI(u_int ipi); void do_openpic_setup_cpu(void); diff -urN linux.orig/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c --- linux.orig/arch/ppc/kernel/openpic.c Fri Nov 2 17:39:05 2001 +++ linux/arch/ppc/kernel/openpic.c Tue Aug 27 15:46:50 2002 @@ -10,6 +10,9 @@ * to avoid bogus interrupts and to make sure the disable function exits with * the interrupt actually masked. --BenH * Todo: map interrupts to all available CPUs after the ack round + * + * Fixed IRQ time out problem by + * Krzysztof Taraszka (dzimi@pld.org.pl) * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive @@ -33,6 +36,8 @@ #define REGISTER_DEBUG #undef REGISTER_DEBUG +#define OPENPIC_SENSE_POLARITY 0x00800000 /* Undoc'd */ + #ifdef __powerpc__ extern int use_of_interrupt_tree; #endif @@ -173,7 +178,6 @@ * other ones are just masked out. * Note: We might want to adjust priorities too. */ - /* Not an init func, called on pbook wakeup --BenH */ void __init @@ -229,7 +233,7 @@ /* Initialize IPI interrupts */ for (i = 0; i < OPENPIC_NUM_IPI; i++) { - openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i); + openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i); } if (_machine != _MACH_Pmac) { @@ -266,7 +270,7 @@ openpic_initirq( np->intrs[j].line, pri, np->intrs[j].line, - 0, + np->intrs[j].sense, np->intrs[j].sense); irq_desc[np->intrs[j].line].level = np->intrs[j].sense; } @@ -276,8 +280,8 @@ /* Fixme: read level value from controller */ printk("openpic: WARNING, openpic running without interrupt tree\n"); } - } - + } + /* Initialize the spurious interrupt */ openpic_set_spurious(OPENPIC_VEC_SPURIOUS); @@ -311,10 +315,6 @@ { openpic_setfield(&OpenPIC->Global.Global_Configuration0, OPENPIC_CONFIG_RESET); - /* Wait for reset to complete */ - while(openpic_readfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_RESET)) - ; } @@ -465,12 +465,12 @@ for ( i = 0; i < OPENPIC_NUM_IPI ; i++ ) openpic_enable_IPI(i); - +#if 0 /* let the openpic know we want intrs */ for ( i = 0; i < NumSources ; i++ ) openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination) | (1<= NumSources) - return; + check_arg_irq(irq); openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { @@ -519,30 +515,15 @@ OPENPIC_MASK)); } -u_int openpic_get_enable(u_int irq) -{ - if (irq < 0 || irq >= NumSources) - return 0; - return !openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_MASK); -} - void openpic_disable_irq(u_int irq) { - u32 vp; - - /* on SMP, we get IPI vector numbers here, we should handle them - * or at least ignore them. - */ - if (irq < 0 || irq >= NumSources) - return; + check_arg_irq(irq); openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { - mb(); /* sync is probably useless here */ - vp = openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_MASK | OPENPIC_ACTIVITY); - } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); + mb(); + } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_MASK)); } /* @@ -561,11 +542,10 @@ check_arg_vec(vec); openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | - OPENPIC_POLARITY_MASK | OPENPIC_SENSE_MASK, + OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL, (pri << OPENPIC_PRIORITY_SHIFT) | vec | - (pol ? OPENPIC_POLARITY_POSITIVE : - OPENPIC_POLARITY_NEGATIVE) | - (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE)); + (pol ? OPENPIC_SENSE_POLARITY : 0) | + (sense ? OPENPIC_SENSE_LEVEL : 0)); } /* @@ -608,7 +588,7 @@ save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority); save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination); } - for (i=0; iProcessor[i].Current_Task_Priority); openpic_set_priority(i, 0xf); } @@ -626,7 +606,7 @@ } for (i=0; iGlobal.IPI_Vector_Priority(i), save_ipi_vp[i]); - for (i=0; iSource[i].Vector_Priority, save_irq_src_vp[i]); openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]); } diff -urN linux.orig/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- linux.orig/arch/ppc/kernel/pmac_pic.c Sun Mar 25 18:31:49 2001 +++ linux/arch/ppc/kernel/pmac_pic.c Tue Aug 27 15:47:42 2002 @@ -32,6 +32,8 @@ extern u_int openpic_read(volatile u_int *addr); +extern void chrp_do_IRQ(struct pt_regs *,int , int); + #define MAXCOUNT 10000000 #define GATWICK_IRQ_POOL_SIZE 10 @@ -385,7 +387,7 @@ irq_desc[i].ctl = &open_pic; irq_desc[i].level = 0; } - ppc_md.do_IRQ = open_pic_do_IRQ; + ppc_md.do_IRQ = chrp_do_IRQ; open_pic.irq_offset = 0; openpic_init(1); #ifdef CONFIG_XMON diff -urN linux.orig/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- linux.orig/arch/ppc/kernel/prep_pci.c Sun Mar 25 18:31:49 2001 +++ linux/arch/ppc/kernel/prep_pci.c Tue Aug 27 15:46:50 2002 @@ -5,6 +5,9 @@ * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) * * The motherboard routes/maps will disappear shortly. -- Cort + * + * Add chrp_do_IRQ into ppc_md.do_IRQ -- Krzysztof Taraszka (dzimi@pld.org.pl) + * */ #include @@ -43,6 +46,8 @@ /* Used for Motorola to store system config register */ static unsigned long *ProcInfo; +extern void chrp_do_IRQ(struct pt_regs *,int , int); + /* Tables for known hardware */ /* Motorola PowerStackII - Utah */ @@ -783,7 +788,7 @@ OpenPIC_InitSenses = mvme2600_openpic_initsenses; OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses); - ppc_md.do_IRQ = open_pic_do_IRQ; + ppc_md.do_IRQ = chrp_do_IRQ; /* If raven is present on Motorola store the system config register * for later use.