]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
[SPARC64]: Do not ACK an INO if it is disabled or inprogress.
authorDavid S. Miller <davem@sunset.davemloft.net>
Tue, 10 Jul 2007 05:40:36 +0000 (22:40 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 16 Jul 2007 11:04:05 +0000 (04:04 -0700)
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>
arch/sparc64/kernel/irq.c

index 6b6165d36fd8aae7789faef3e7cf9e64019cb464..634194e7d2d6cbd5cb5ed6f074d4f90bedcfe4fe 100644 (file)
@@ -309,6 +309,10 @@ static void sun4u_irq_disable(unsigned int virt_irq)
 static void sun4u_irq_end(unsigned int virt_irq)
 {
        struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+       struct irq_desc *desc = irq_desc + virt_irq;
+
+       if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+               return;
 
        if (likely(data))
                upa_writeq(ICLR_IDLE, data->iclr);
@@ -373,6 +377,10 @@ static void sun4v_irq_end(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
        unsigned int ino = bucket - &ivector_table[0];
+       struct irq_desc *desc = irq_desc + virt_irq;
+
+       if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+               return;
 
        if (likely(bucket)) {
                int err;
@@ -443,6 +451,10 @@ static void sun4v_virq_end(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
        unsigned int ino = bucket - &ivector_table[0];
+       struct irq_desc *desc = irq_desc + virt_irq;
+
+       if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+               return;
 
        if (likely(bucket)) {
                unsigned long dev_handle, dev_ino;