MIPS: Octeon: Fix EOI handling.
authorDavid Daney <ddaney@caviumnetworks.com>
Thu, 7 Jan 2010 19:05:00 +0000 (11:05 -0800)
committerRalf Baechle <ralf@linux-mips.org>
Sat, 27 Feb 2010 11:53:06 +0000 (12:53 +0100)
If an interrupt handler disables interrupts, the EOI function will
just reenable them.  This will put us in an endless loop when the
upcoming Ethernet driver patches are applied.

Only reenable the interrupt on EOI if it is not IRQ_DISABLED.  This
requires that the EOI function be separate from the ENABLE function.
We also rename the ACK functions to correspond with their function.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
To: gregkh@suse.de
Patchwork: http://patchwork.linux-mips.org/patch/840/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/cavium-octeon/octeon-irq.c

index 6f2acf09328dbe00a80215cc84acc6e6739bfe50..1460d0836dc0fffc4594da6b93e8a73f58aad58e 100644 (file)
@@ -193,7 +193,7 @@ static void octeon_irq_ciu0_enable_v2(unsigned int irq)
  * Disable the irq on the current core for chips that have the EN*_W1{S,C}
  * registers.
  */
-static void octeon_irq_ciu0_disable_v2(unsigned int irq)
+static void octeon_irq_ciu0_ack_v2(unsigned int irq)
 {
        int index = cvmx_get_core_num() * 2;
        u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
@@ -201,6 +201,20 @@ static void octeon_irq_ciu0_disable_v2(unsigned int irq)
        cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
 }
 
+/*
+ * Enable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu0_eoi_v2(unsigned int irq)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       int index = cvmx_get_core_num() * 2;
+       u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+
+       if ((desc->status & IRQ_DISABLED) == 0)
+               cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
+}
+
 /*
  * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
  * registers.
@@ -272,8 +286,8 @@ static struct irq_chip octeon_irq_chip_ciu0_v2 = {
        .name = "CIU0",
        .enable = octeon_irq_ciu0_enable_v2,
        .disable = octeon_irq_ciu0_disable_all_v2,
-       .ack = octeon_irq_ciu0_disable_v2,
-       .eoi = octeon_irq_ciu0_enable_v2,
+       .ack = octeon_irq_ciu0_ack_v2,
+       .eoi = octeon_irq_ciu0_eoi_v2,
 #ifdef CONFIG_SMP
        .set_affinity = octeon_irq_ciu0_set_affinity_v2,
 #endif
@@ -374,7 +388,7 @@ static void octeon_irq_ciu1_enable_v2(unsigned int irq)
  * Disable the irq on the current core for chips that have the EN*_W1{S,C}
  * registers.
  */
-static void octeon_irq_ciu1_disable_v2(unsigned int irq)
+static void octeon_irq_ciu1_ack_v2(unsigned int irq)
 {
        int index = cvmx_get_core_num() * 2 + 1;
        u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
@@ -382,6 +396,20 @@ static void octeon_irq_ciu1_disable_v2(unsigned int irq)
        cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
 }
 
+/*
+ * Enable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu1_eoi_v2(unsigned int irq)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       int index = cvmx_get_core_num() * 2 + 1;
+       u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+
+       if ((desc->status & IRQ_DISABLED) == 0)
+               cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+}
+
 /*
  * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
  * registers.
@@ -455,8 +483,8 @@ static struct irq_chip octeon_irq_chip_ciu1_v2 = {
        .name = "CIU0",
        .enable = octeon_irq_ciu1_enable_v2,
        .disable = octeon_irq_ciu1_disable_all_v2,
-       .ack = octeon_irq_ciu1_disable_v2,
-       .eoi = octeon_irq_ciu1_enable_v2,
+       .ack = octeon_irq_ciu1_ack_v2,
+       .eoi = octeon_irq_ciu1_eoi_v2,
 #ifdef CONFIG_SMP
        .set_affinity = octeon_irq_ciu1_set_affinity_v2,
 #endif