Skip to content

Commit

Permalink
Do not skip interrupt sources in sun4d interrupt handler and acknowle…
Browse files Browse the repository at this point in the history
…dge interrupts correctly

During the introduction of genirq on sparc32 bugs were introduced in
the interrupt handler for sun4d. The interrupts handler checks the status
of the various sbus interfaces in the system and generates a virtual
interrupt, based upon the location of the interrupt source. This lookup
was broken by restructuring the code in such a way that index and shift
operations were performed prior to comparing this against the values
read from the interrupt controllers.

This could cause the handler to loop eternally as the interrupt source
could be skipped before any check was performed. Additionally
sun4d_encode_irq performs shifting internally, so it should not be performed
twice.

In sun4d_unmask interrupts were not correctly acknowledged, as the
corresponding bit it the interrupt mask was not actually cleared.

Signed-off-by: Kjetil Oftedal <oftedal@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
oftedal authored and David S. Miller committed Jun 7, 2011
1 parent 5fba170 commit ea16058
Showing 1 changed file with 5 additions and 9 deletions.
14 changes: 5 additions & 9 deletions arch/sparc/kernel/sun4d_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,9 @@ static void sun4d_sbus_handler_irq(int sbusl)

sbil = (sbusl << 2);
/* Loop for each pending SBI */
for (sbino = 0; bus_mask; sbino++) {
for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
unsigned int idx, mask;

bus_mask >>= 1;
if (!(bus_mask & 1))
continue;
/* XXX This seems to ACK the irq twice. acquire_sbi()
Expand All @@ -118,19 +117,16 @@ static void sun4d_sbus_handler_irq(int sbusl)
mask &= (0xf << sbil);

/* Loop for each pending SBI slot */
idx = 0;
slot = (1 << sbil);
while (mask != 0) {
for (idx = 0; mask != 0; idx++, slot <<= 1) {
unsigned int pil;
struct irq_bucket *p;

idx++;
slot <<= 1;
if (!(mask & slot))
continue;

mask &= ~slot;
pil = sun4d_encode_irq(sbino, sbil, idx);
pil = sun4d_encode_irq(sbino, sbusl, idx);

p = irq_map[pil];
while (p) {
Expand Down Expand Up @@ -218,10 +214,10 @@ static void sun4d_unmask_irq(struct irq_data *data)

#ifdef CONFIG_SMP
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq));
cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
#else
cc_set_imsk(cc_get_imsk() | ~(1 << real_irq));
cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
#endif
}

Expand Down

0 comments on commit ea16058

Please sign in to comment.