diff options
Diffstat (limited to 'arch/mips/jmr3927/rbhma3100/irq.c')
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/irq.c | 106 |
1 files changed, 56 insertions, 50 deletions
diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c index 722174481467..39a0243bed9a 100644 --- a/arch/mips/jmr3927/rbhma3100/irq.c +++ b/arch/mips/jmr3927/rbhma3100/irq.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/smp_lock.h> | 46 | #include <linux/smp_lock.h> |
47 | #include <linux/bitops.h> | 47 | #include <linux/bitops.h> |
48 | 48 | ||
49 | #include <asm/irq_regs.h> | ||
49 | #include <asm/io.h> | 50 | #include <asm/io.h> |
50 | #include <asm/mipsregs.h> | 51 | #include <asm/mipsregs.h> |
51 | #include <asm/system.h> | 52 | #include <asm/system.h> |
@@ -239,45 +240,80 @@ struct tb_irq_space jmr3927_ioc_irqspace = { | |||
239 | .space_id = 0, | 240 | .space_id = 0, |
240 | can_share : 1 | 241 | can_share : 1 |
241 | }; | 242 | }; |
243 | |||
242 | struct tb_irq_space jmr3927_irc_irqspace = { | 244 | struct tb_irq_space jmr3927_irc_irqspace = { |
243 | .next = NULL, | 245 | .next = NULL, |
244 | .start_irqno = JMR3927_IRQ_IRC, | 246 | .start_irqno = JMR3927_IRQ_IRC, |
245 | nr_irqs : JMR3927_NR_IRQ_IRC, | 247 | .nr_irqs = JMR3927_NR_IRQ_IRC, |
246 | .mask_func = mask_irq_irc, | 248 | .mask_func = mask_irq_irc, |
247 | .unmask_func = unmask_irq_irc, | 249 | .unmask_func = unmask_irq_irc, |
248 | .name = "on-chip", | 250 | .name = "on-chip", |
249 | .space_id = 0, | 251 | .space_id = 0, |
250 | can_share : 0 | 252 | .can_share = 0 |
251 | }; | 253 | }; |
252 | 254 | ||
253 | void jmr3927_spurious(struct pt_regs *regs) | 255 | |
256 | #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND | ||
257 | static int tx_branch_likely_bug_count = 0; | ||
258 | static int have_tx_branch_likely_bug = 0; | ||
259 | |||
260 | static void tx_branch_likely_bug_fixup(void) | ||
261 | { | ||
262 | struct pt_regs *regs = get_irq_regs(); | ||
263 | |||
264 | /* TX39/49-BUG: Under this condition, the insn in delay slot | ||
265 | of the branch likely insn is executed (not nullified) even | ||
266 | the branch condition is false. */ | ||
267 | if (!have_tx_branch_likely_bug) | ||
268 | return; | ||
269 | if ((regs->cp0_epc & 0xfff) == 0xffc && | ||
270 | KSEGX(regs->cp0_epc) != KSEG0 && | ||
271 | KSEGX(regs->cp0_epc) != KSEG1) { | ||
272 | unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); | ||
273 | /* beql,bnel,blezl,bgtzl */ | ||
274 | /* bltzl,bgezl,blezall,bgezall */ | ||
275 | /* bczfl, bcztl */ | ||
276 | if ((insn & 0xf0000000) == 0x50000000 || | ||
277 | (insn & 0xfc0e0000) == 0x04020000 || | ||
278 | (insn & 0xf3fe0000) == 0x41020000) { | ||
279 | regs->cp0_epc -= 4; | ||
280 | tx_branch_likely_bug_count++; | ||
281 | printk(KERN_INFO | ||
282 | "fix branch-likery bug in %s (insn %08x)\n", | ||
283 | current->comm, insn); | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | #endif | ||
288 | |||
289 | static void jmr3927_spurious(void) | ||
254 | { | 290 | { |
255 | #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND | 291 | #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND |
256 | tx_branch_likely_bug_fixup(regs); | 292 | tx_branch_likely_bug_fixup(); |
257 | #endif | 293 | #endif |
258 | printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n", | 294 | printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n", |
259 | regs->cp0_cause, regs->cp0_epc, regs->regs[31]); | 295 | regs->cp0_cause, regs->cp0_epc, regs->regs[31]); |
260 | } | 296 | } |
261 | 297 | ||
262 | asmlinkage void plat_irq_dispatch(struct pt_regs *regs) | 298 | asmlinkage void plat_irq_dispatch(void) |
263 | { | 299 | { |
264 | int irq; | 300 | int irq; |
265 | 301 | ||
266 | #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND | 302 | #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND |
267 | tx_branch_likely_bug_fixup(regs); | 303 | tx_branch_likely_bug_fixup(); |
268 | #endif | 304 | #endif |
269 | if ((regs->cp0_cause & CAUSEF_IP7) == 0) { | 305 | if ((regs->cp0_cause & CAUSEF_IP7) == 0) { |
270 | #if 0 | 306 | #if 0 |
271 | jmr3927_spurious(regs); | 307 | jmr3927_spurious(); |
272 | #endif | 308 | #endif |
273 | return; | 309 | return; |
274 | } | 310 | } |
275 | irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f; | 311 | irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f; |
276 | 312 | ||
277 | do_IRQ(irq + JMR3927_IRQ_IRC, regs); | 313 | do_IRQ(irq + JMR3927_IRQ_IRC); |
278 | } | 314 | } |
279 | 315 | ||
280 | static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 316 | static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id) |
281 | { | 317 | { |
282 | unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR); | 318 | unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR); |
283 | int i; | 319 | int i; |
@@ -285,7 +321,7 @@ static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs * | |||
285 | for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) { | 321 | for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) { |
286 | if (istat & (1 << i)) { | 322 | if (istat & (1 << i)) { |
287 | irq = JMR3927_IRQ_IOC + i; | 323 | irq = JMR3927_IRQ_IOC + i; |
288 | do_IRQ(irq, regs); | 324 | do_IRQ(irq); |
289 | } | 325 | } |
290 | } | 326 | } |
291 | return IRQ_HANDLED; | 327 | return IRQ_HANDLED; |
@@ -295,7 +331,7 @@ static struct irqaction ioc_action = { | |||
295 | jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL, | 331 | jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL, |
296 | }; | 332 | }; |
297 | 333 | ||
298 | static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 334 | static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id) |
299 | { | 335 | { |
300 | unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR); | 336 | unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR); |
301 | int i; | 337 | int i; |
@@ -303,7 +339,7 @@ static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs | |||
303 | for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) { | 339 | for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) { |
304 | if (istat & (1 << i)) { | 340 | if (istat & (1 << i)) { |
305 | irq = JMR3927_IRQ_ISAC + i; | 341 | irq = JMR3927_IRQ_ISAC + i; |
306 | do_IRQ(irq, regs); | 342 | do_IRQ(irq); |
307 | } | 343 | } |
308 | } | 344 | } |
309 | return IRQ_HANDLED; | 345 | return IRQ_HANDLED; |
@@ -314,7 +350,7 @@ static struct irqaction isac_action = { | |||
314 | }; | 350 | }; |
315 | 351 | ||
316 | 352 | ||
317 | static irqreturn_t jmr3927_isaerr_interrupt(int irq, void * dev_id, struct pt_regs * regs) | 353 | static irqreturn_t jmr3927_isaerr_interrupt(int irq, void *dev_id) |
318 | { | 354 | { |
319 | printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq); | 355 | printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq); |
320 | 356 | ||
@@ -324,7 +360,7 @@ static struct irqaction isaerr_action = { | |||
324 | jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL, | 360 | jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL, |
325 | }; | 361 | }; |
326 | 362 | ||
327 | static irqreturn_t jmr3927_pcierr_interrupt(int irq, void * dev_id, struct pt_regs * regs) | 363 | static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) |
328 | { | 364 | { |
329 | printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); | 365 | printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); |
330 | printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", | 366 | printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", |
@@ -439,33 +475,3 @@ void jmr3927_irq_init(u32 irq_base) | |||
439 | 475 | ||
440 | jmr3927_irq_base = irq_base; | 476 | jmr3927_irq_base = irq_base; |
441 | } | 477 | } |
442 | |||
443 | #ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND | ||
444 | static int tx_branch_likely_bug_count = 0; | ||
445 | static int have_tx_branch_likely_bug = 0; | ||
446 | void tx_branch_likely_bug_fixup(struct pt_regs *regs) | ||
447 | { | ||
448 | /* TX39/49-BUG: Under this condition, the insn in delay slot | ||
449 | of the branch likely insn is executed (not nullified) even | ||
450 | the branch condition is false. */ | ||
451 | if (!have_tx_branch_likely_bug) | ||
452 | return; | ||
453 | if ((regs->cp0_epc & 0xfff) == 0xffc && | ||
454 | KSEGX(regs->cp0_epc) != KSEG0 && | ||
455 | KSEGX(regs->cp0_epc) != KSEG1) { | ||
456 | unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); | ||
457 | /* beql,bnel,blezl,bgtzl */ | ||
458 | /* bltzl,bgezl,blezall,bgezall */ | ||
459 | /* bczfl, bcztl */ | ||
460 | if ((insn & 0xf0000000) == 0x50000000 || | ||
461 | (insn & 0xfc0e0000) == 0x04020000 || | ||
462 | (insn & 0xf3fe0000) == 0x41020000) { | ||
463 | regs->cp0_epc -= 4; | ||
464 | tx_branch_likely_bug_count++; | ||
465 | printk(KERN_INFO | ||
466 | "fix branch-likery bug in %s (insn %08x)\n", | ||
467 | current->comm, insn); | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | #endif | ||