aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-10 01:40:36 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-16 07:04:05 -0400
commit5a606b72a4309a656cd1a19ad137dc5557c4b8ea (patch)
tree2ca87c1915a2232d1629a56dd9762195bdddf2e6
parent667ef3c3968e4e2ddc3f3f84f05e11fb2453d5b6 (diff)
[SPARC64]: Do not ACK an INO if it is disabled or inprogress.
This is also a partial workaround for a bug in the LDOM firmware which double-transmits RX inos during high load. Without this, such an event causes the kernel to loop forever in the interrupt call chain ACK'ing but never actually running the IRQ handler (and thus clearing the interrupt condition in the device). There is still a bad potential effect when double INOs occur, not covered by this changeset. Namely, if the INO is already on the per-cpu INO vector list, we still blindly re-insert it and thus we can end up losing interrupts already linked in after it. We could deal with that by traversing the list before insertion, but that's too expensive for this edge case. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc64/kernel/irq.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 6b6165d36fd8..634194e7d2d6 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -309,6 +309,10 @@ static void sun4u_irq_disable(unsigned int virt_irq)
309static void sun4u_irq_end(unsigned int virt_irq) 309static void sun4u_irq_end(unsigned int virt_irq)
310{ 310{
311 struct irq_handler_data *data = get_irq_chip_data(virt_irq); 311 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
312 struct irq_desc *desc = irq_desc + virt_irq;
313
314 if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
315 return;
312 316
313 if (likely(data)) 317 if (likely(data))
314 upa_writeq(ICLR_IDLE, data->iclr); 318 upa_writeq(ICLR_IDLE, data->iclr);
@@ -373,6 +377,10 @@ static void sun4v_irq_end(unsigned int virt_irq)
373{ 377{
374 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 378 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
375 unsigned int ino = bucket - &ivector_table[0]; 379 unsigned int ino = bucket - &ivector_table[0];
380 struct irq_desc *desc = irq_desc + virt_irq;
381
382 if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
383 return;
376 384
377 if (likely(bucket)) { 385 if (likely(bucket)) {
378 int err; 386 int err;
@@ -443,6 +451,10 @@ static void sun4v_virq_end(unsigned int virt_irq)
443{ 451{
444 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 452 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
445 unsigned int ino = bucket - &ivector_table[0]; 453 unsigned int ino = bucket - &ivector_table[0];
454 struct irq_desc *desc = irq_desc + virt_irq;
455
456 if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
457 return;
446 458
447 if (likely(bucket)) { 459 if (likely(bucket)) {
448 unsigned long dev_handle, dev_ino; 460 unsigned long dev_handle, dev_ino;