forked from Minki/linux
d6478fad43
Fix the IRQ handling on the MN10300 arch. This patch makes a number of significant changes: (1) It separates the irq_chip definition for edge-triggered interrupts from the one for level-triggered interrupts. This is necessary because the MN10300 PIC latches the IRQ channel's interrupt request bit (GxICR_REQUEST), even after the device has ceased to assert its interrupt line and the interrupt channel has been disabled in the PIC. So for level-triggered interrupts we need to clear this bit when we re-enable - which is achieved by setting GxICR_DETECT but not GxICR_REQUEST when writing to the register. Not doing this results in spurious interrupts occurring because calling mask_ack() at the start of handle_level_irq() is insufficient - it fails to clear the REQUEST latch because the device that caused the interrupt is still asserting its interrupt line at this point. (2) IRQ disablement [irq_chip::disable_irq()] shouldn't clear the interrupt request flag for edge-triggered interrupts lest it lose an interrupt. (3) IRQ unmasking [irq_chip::unmask_irq()] also shouldn't clear the interrupt request flag for edge-triggered interrupts lest it lose an interrupt. (4) The end() operation is now left to the default (no-operation) as __do_IRQ() is compiled out. This may affect misrouted_irq(), but according to Thomas Gleixner it's the correct thing to do. (5) handle_level_irq() is used for edge-triggered interrupts rather than handle_edge_irq() as the MN10300 PIC latches interrupt events even on masked IRQ channels, thus rendering IRQ_PENDING unnecessary. It is sufficient to call mask_ack() at the start and unmask() at the end. (6) For level-triggered interrupts, ack() is now NULL as it's not used, and there is no effective ACK function on the PIC. mask_ack() is now the same as mask() as the latch continues to latch, even when the channel is masked. Further, the patch discards the disable() op implementation as its now the same as the mask() op implementation, which is used instead. It also discards the enable() op implementations as they're now the same as the unmask() op implementations, which are used instead. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
61 lines
1.4 KiB
C
61 lines
1.4 KiB
C
/* ASB2303 initialisation
|
|
*
|
|
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public Licence
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the Licence, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/param.h>
|
|
#include <linux/init.h>
|
|
#include <linux/device.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/intctl-regs.h>
|
|
|
|
/*
|
|
* initialise some of the unit hardware before gdbstub is set up
|
|
*/
|
|
asmlinkage void __init unit_init(void)
|
|
{
|
|
/* set up the external interrupts */
|
|
SET_XIRQ_TRIGGER(0, XIRQ_TRIGGER_HILEVEL);
|
|
SET_XIRQ_TRIGGER(2, XIRQ_TRIGGER_LOWLEVEL);
|
|
SET_XIRQ_TRIGGER(3, XIRQ_TRIGGER_HILEVEL);
|
|
SET_XIRQ_TRIGGER(4, XIRQ_TRIGGER_LOWLEVEL);
|
|
SET_XIRQ_TRIGGER(5, XIRQ_TRIGGER_LOWLEVEL);
|
|
}
|
|
|
|
/*
|
|
* initialise the rest of the unit hardware after gdbstub is ready
|
|
*/
|
|
void __init unit_setup(void)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* initialise the external interrupts used by a unit of this type
|
|
*/
|
|
void __init unit_init_IRQ(void)
|
|
{
|
|
unsigned int extnum;
|
|
|
|
for (extnum = 0; extnum < NR_XIRQS; extnum++) {
|
|
switch (GET_XIRQ_TRIGGER(extnum)) {
|
|
case XIRQ_TRIGGER_HILEVEL:
|
|
case XIRQ_TRIGGER_LOWLEVEL:
|
|
set_intr_postackable(XIRQ2IRQ(extnum));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|