mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
[ARM] 5308/1: Fix Viper ISA IRQ handling
The ISA IRQ renumbering broke the Viper ISA code in interesting ways. It originally assumed that ISA interrupt were numbered in the order that is defined by the CPLD registers. Unfortunately, this is no longer the case. Furthermore, the viper_irq_handler() function being a chained IRQ handler, it must ACK the interrupt by itself, or the handler will be immediately reentered, with the expected damages. This fix was made possible thanks to the help of David Raeman, who provided debug information and tested each version of this patch. Tested-by: David Raeman <david.raeman@gmail.com> Signed-off-by: Marc Zyngier <maz@misterjones.org> Acked-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
af2010daf7
commit
a9ff8f6462
@ -204,25 +204,54 @@ static void viper_set_core_cpu_voltage(unsigned long khz, int force)
|
||||
|
||||
/* Interrupt handling */
|
||||
static unsigned long viper_irq_enabled_mask;
|
||||
static const int viper_isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 };
|
||||
static const int viper_isa_irq_map[] = {
|
||||
0, /* ISA irq #0, invalid */
|
||||
0, /* ISA irq #1, invalid */
|
||||
0, /* ISA irq #2, invalid */
|
||||
1 << 0, /* ISA irq #3 */
|
||||
1 << 1, /* ISA irq #4 */
|
||||
1 << 2, /* ISA irq #5 */
|
||||
1 << 3, /* ISA irq #6 */
|
||||
1 << 4, /* ISA irq #7 */
|
||||
0, /* ISA irq #8, invalid */
|
||||
1 << 8, /* ISA irq #9 */
|
||||
1 << 5, /* ISA irq #10 */
|
||||
1 << 6, /* ISA irq #11 */
|
||||
1 << 7, /* ISA irq #12 */
|
||||
0, /* ISA irq #13, invalid */
|
||||
1 << 9, /* ISA irq #14 */
|
||||
1 << 10, /* ISA irq #15 */
|
||||
};
|
||||
|
||||
static inline int viper_irq_to_bitmask(unsigned int irq)
|
||||
{
|
||||
return viper_isa_irq_map[irq - PXA_ISA_IRQ(0)];
|
||||
}
|
||||
|
||||
static inline int viper_bit_to_irq(int bit)
|
||||
{
|
||||
return viper_isa_irqs[bit] + PXA_ISA_IRQ(0);
|
||||
}
|
||||
|
||||
static void viper_ack_irq(unsigned int irq)
|
||||
{
|
||||
int viper_irq = irq - PXA_ISA_IRQ(0);
|
||||
int viper_irq = viper_irq_to_bitmask(irq);
|
||||
|
||||
if (viper_irq < 8)
|
||||
VIPER_LO_IRQ_STATUS = 1 << viper_irq;
|
||||
if (viper_irq & 0xff)
|
||||
VIPER_LO_IRQ_STATUS = viper_irq;
|
||||
else
|
||||
VIPER_HI_IRQ_STATUS = 1 << (viper_irq - 8);
|
||||
VIPER_HI_IRQ_STATUS = (viper_irq >> 8);
|
||||
}
|
||||
|
||||
static void viper_mask_irq(unsigned int irq)
|
||||
{
|
||||
viper_irq_enabled_mask &= ~(1 << (irq - PXA_ISA_IRQ(0)));
|
||||
viper_irq_enabled_mask &= ~(viper_irq_to_bitmask(irq));
|
||||
}
|
||||
|
||||
static void viper_unmask_irq(unsigned int irq)
|
||||
{
|
||||
viper_irq_enabled_mask |= (1 << (irq - PXA_ISA_IRQ(0)));
|
||||
viper_irq_enabled_mask |= viper_irq_to_bitmask(irq);
|
||||
}
|
||||
|
||||
static inline unsigned long viper_irq_pending(void)
|
||||
@ -237,8 +266,12 @@ static void viper_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
|
||||
pending = viper_irq_pending();
|
||||
do {
|
||||
/* we're in a chained irq handler,
|
||||
* so ack the interrupt by hand */
|
||||
GEDR(VIPER_CPLD_GPIO) = GPIO_bit(VIPER_CPLD_GPIO);
|
||||
|
||||
if (likely(pending)) {
|
||||
irq = PXA_ISA_IRQ(0) + __ffs(pending);
|
||||
irq = viper_bit_to_irq(__ffs(pending));
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
pending = viper_irq_pending();
|
||||
@ -254,15 +287,14 @@ static struct irq_chip viper_irq_chip = {
|
||||
|
||||
static void __init viper_init_irq(void)
|
||||
{
|
||||
const int isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 };
|
||||
int irq;
|
||||
int level;
|
||||
int isa_irq;
|
||||
|
||||
pxa25x_init_irq();
|
||||
|
||||
/* setup ISA IRQs */
|
||||
for (irq = 0; irq < ARRAY_SIZE(isa_irqs); irq++) {
|
||||
isa_irq = isa_irqs[irq];
|
||||
for (level = 0; level < ARRAY_SIZE(viper_isa_irqs); level++) {
|
||||
isa_irq = viper_bit_to_irq(level);
|
||||
set_irq_chip(isa_irq, &viper_irq_chip);
|
||||
set_irq_handler(isa_irq, handle_edge_irq);
|
||||
set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE);
|
||||
|
Loading…
Reference in New Issue
Block a user