X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fmips%2Fjmr3927%2Frbhma3100%2Firq.c;h=3da49c5aaf4947bcda20511d94419faca8d03b5d;hb=refs%2Fheads%2Fvserver;hp=b9799b86fc79a9b319852948c43663c4b167d8ac;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c index b9799b86f..3da49c5aa 100644 --- a/arch/mips/jmr3927/rbhma3100/irq.c +++ b/arch/mips/jmr3927/rbhma3100/irq.c @@ -29,7 +29,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include @@ -47,6 +46,7 @@ #include #include +#include #include #include #include @@ -77,8 +77,6 @@ static int jmr3927_gen_iack(void) } #endif -extern asmlinkage void jmr3927_IRQ(void); - #define irc_dlevel 0 #define irc_elevel 1 @@ -92,17 +90,6 @@ static unsigned char irc_level[TX3927_NUM_IR] = { static void jmr3927_irq_disable(unsigned int irq_nr); static void jmr3927_irq_enable(unsigned int irq_nr); -static DEFINE_SPINLOCK(jmr3927_irq_lock); - -static unsigned int jmr3927_irq_startup(unsigned int irq) -{ - jmr3927_irq_enable(irq); - - return 0; -} - -#define jmr3927_irq_shutdown jmr3927_irq_disable - static void jmr3927_irq_ack(unsigned int irq) { if (irq == JMR3927_IRQ_IRC_TMR0) @@ -113,15 +100,14 @@ static void jmr3927_irq_ack(unsigned int irq) static void jmr3927_irq_end(unsigned int irq) { - jmr3927_irq_enable(irq); + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + jmr3927_irq_enable(irq); } static void jmr3927_irq_disable(unsigned int irq_nr) { struct tb_irq_space* sp; - unsigned long flags; - spinlock_irqsave(&jmr3927_irq_lock, flags); for (sp = tb_irq_spaces; sp; sp = sp->next) { if (sp->start_irqno <= irq_nr && irq_nr < sp->start_irqno + sp->nr_irqs) { @@ -131,15 +117,12 @@ static void jmr3927_irq_disable(unsigned int irq_nr) break; } } - spinlock_irqrestore(&jmr3927_irq_lock, flags); } static void jmr3927_irq_enable(unsigned int irq_nr) { struct tb_irq_space* sp; - unsigned long flags; - spinlock_irqsave(&jmr3927_irq_lock, flags); for (sp = tb_irq_spaces; sp; sp = sp->next) { if (sp->start_irqno <= irq_nr && irq_nr < sp->start_irqno + sp->nr_irqs) { @@ -149,7 +132,6 @@ static void jmr3927_irq_enable(unsigned int irq_nr) break; } } - spinlock_irqrestore(&jmr3927_irq_lock, flags); } /* @@ -205,7 +187,10 @@ static void mask_irq_irc(int irq_nr, int space_id) /* update IRCSR */ tx3927_ircptr->imr = 0; tx3927_ircptr->imr = irc_elevel; + /* flush write buffer */ + (void)tx3927_ircptr->ssr; } + static void unmask_irq_irc(int irq_nr, int space_id) { volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2]; @@ -238,45 +223,83 @@ struct tb_irq_space jmr3927_ioc_irqspace = { .space_id = 0, can_share : 1 }; + struct tb_irq_space jmr3927_irc_irqspace = { - .next = NULL, - .start_irqno = JMR3927_IRQ_IRC, - nr_irqs : JMR3927_NR_IRQ_IRC, - .mask_func = mask_irq_irc, - .unmask_func = unmask_irq_irc, - .name = "on-chip", - .space_id = 0, - can_share : 0 + .next = NULL, + .start_irqno = JMR3927_IRQ_IRC, + .nr_irqs = JMR3927_NR_IRQ_IRC, + .mask_func = mask_irq_irc, + .unmask_func = unmask_irq_irc, + .name = "on-chip", + .space_id = 0, + .can_share = 0 }; -void jmr3927_spurious(struct pt_regs *regs) + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND +static int tx_branch_likely_bug_count = 0; +static int have_tx_branch_likely_bug = 0; + +static void tx_branch_likely_bug_fixup(void) { + struct pt_regs *regs = get_irq_regs(); + + /* TX39/49-BUG: Under this condition, the insn in delay slot + of the branch likely insn is executed (not nullified) even + the branch condition is false. */ + if (!have_tx_branch_likely_bug) + return; + if ((regs->cp0_epc & 0xfff) == 0xffc && + KSEGX(regs->cp0_epc) != KSEG0 && + KSEGX(regs->cp0_epc) != KSEG1) { + unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); + /* beql,bnel,blezl,bgtzl */ + /* bltzl,bgezl,blezall,bgezall */ + /* bczfl, bcztl */ + if ((insn & 0xf0000000) == 0x50000000 || + (insn & 0xfc0e0000) == 0x04020000 || + (insn & 0xf3fe0000) == 0x41020000) { + regs->cp0_epc -= 4; + tx_branch_likely_bug_count++; + printk(KERN_INFO + "fix branch-likery bug in %s (insn %08x)\n", + current->comm, insn); + } + } +} +#endif + +static void jmr3927_spurious(void) +{ + struct pt_regs * regs = get_irq_regs(); + #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND - tx_branch_likely_bug_fixup(regs); + tx_branch_likely_bug_fixup(); #endif printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n", regs->cp0_cause, regs->cp0_epc, regs->regs[31]); } -void jmr3927_irc_irqdispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { + struct pt_regs * regs = get_irq_regs(); int irq; #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND - tx_branch_likely_bug_fixup(regs); + tx_branch_likely_bug_fixup(); #endif if ((regs->cp0_cause & CAUSEF_IP7) == 0) { #if 0 - jmr3927_spurious(regs); + jmr3927_spurious(); #endif return; } irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f; - do_IRQ(irq + JMR3927_IRQ_IRC, regs); + do_IRQ(irq + JMR3927_IRQ_IRC); } -static void jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id) { unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR); int i; @@ -284,16 +307,17 @@ static void jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs) for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) { if (istat & (1 << i)) { irq = JMR3927_IRQ_IOC + i; - do_IRQ(irq, regs); + do_IRQ(irq); } } + return IRQ_HANDLED; } static struct irqaction ioc_action = { jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL, }; -static void jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id) { unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR); int i; @@ -301,9 +325,10 @@ static void jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs) for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) { if (istat & (1 << i)) { irq = JMR3927_IRQ_ISAC + i; - do_IRQ(irq, regs); + do_IRQ(irq); } } + return IRQ_HANDLED; } static struct irqaction isac_action = { @@ -311,19 +336,23 @@ static struct irqaction isac_action = { }; -static void jmr3927_isaerr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static irqreturn_t jmr3927_isaerr_interrupt(int irq, void *dev_id) { printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq); + + return IRQ_HANDLED; } static struct irqaction isaerr_action = { jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL, }; -static void jmr3927_pcierr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) { printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat); + + return IRQ_HANDLED; } static struct irqaction pcierr_action = { jmr3927_pcierr_interrupt, 0, CPU_MASK_NONE, "PCI error", NULL, NULL, @@ -388,8 +417,6 @@ void __init arch_init_irq(void) jmr3927_irq_init(NR_ISA_IRQS); - set_except_vector(0, jmr3927_IRQ); - /* setup irq space */ add_tb_irq_space(&jmr3927_isac_irqspace); add_tb_irq_space(&jmr3927_ioc_irqspace); @@ -411,56 +438,21 @@ void __init arch_init_irq(void) set_c0_status(ST0_IM); /* IE bit is still 0. */ } -static hw_irq_controller jmr3927_irq_controller = { - "jmr3927_irq", - jmr3927_irq_startup, - jmr3927_irq_shutdown, - jmr3927_irq_enable, - jmr3927_irq_disable, - jmr3927_irq_ack, - jmr3927_irq_end, +static struct irq_chip jmr3927_irq_controller = { + .typename = "jmr3927_irq", + .ack = jmr3927_irq_ack, + .mask = jmr3927_irq_disable, + .mask_ack = jmr3927_irq_ack, + .unmask = jmr3927_irq_enable, + .end = jmr3927_irq_end, }; void jmr3927_irq_init(u32 irq_base) { u32 i; - for (i= irq_base; i< irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &jmr3927_irq_controller; - } + for (i= irq_base; i< irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC; i++) + set_irq_chip(i, &jmr3927_irq_controller); jmr3927_irq_base = irq_base; } - -#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND -static int tx_branch_likely_bug_count = 0; -static int have_tx_branch_likely_bug = 0; -void tx_branch_likely_bug_fixup(struct pt_regs *regs) -{ - /* TX39/49-BUG: Under this condition, the insn in delay slot - of the branch likely insn is executed (not nullified) even - the branch condition is false. */ - if (!have_tx_branch_likely_bug) - return; - if ((regs->cp0_epc & 0xfff) == 0xffc && - KSEGX(regs->cp0_epc) != KSEG0 && - KSEGX(regs->cp0_epc) != KSEG1) { - unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); - /* beql,bnel,blezl,bgtzl */ - /* bltzl,bgezl,blezall,bgezall */ - /* bczfl, bcztl */ - if ((insn & 0xf0000000) == 0x50000000 || - (insn & 0xfc0e0000) == 0x04020000 || - (insn & 0xf3fe0000) == 0x41020000) { - regs->cp0_epc -= 4; - tx_branch_likely_bug_count++; - printk(KERN_INFO - "fix branch-likery bug in %s (insn %08x)\n", - current->comm, insn); - } - } -} -#endif