From 64484296abf5a6419e9c31d7b394f92e541d73d3 Mon Sep 17 00:00:00 2001
From: Gavin Shan <gwshan@linux.vnet.ibm.com>
Date: Tue, 28 Jul 2015 10:58:29 +1000
Subject: [PATCH] powerpc/powernv: Reenable EEH IRQ if necessary
pnv_eeh_next_error() is called to handle EEH special event. The
function can be called for multiple times for one EEH special
event. So we can't enable the EEH IRQ without limitation. Otherwise,
the following warning would be seen because of attempt to enable
IRQ, which has been enabled.
The patch introduces another flag to track the EEH IRQ enablement
state and doesn't enable it if it's already enabled.
EEH: Notify device driver to resume
Unbalanced enable for IRQ 17
------------[ cut here ]------------
WARNING: at /scratch/dja/linux-capi/kernel/irq/manage.c:511
Modules linked in: cxl
:
NIP [c0000000000f1760] .__enable_irq+0x30/0xd0
LR [c0000000000f175c] .__enable_irq+0x2c/0xd0
Call Trace:
[c000000751b97990] [c0000000000f175c] .__enable_irq+0x2c/0xd0 (unreliable)
[c000000751b97a20] [c0000000000f1848] .enable_irq+0x48/0x90
[c000000751b97ab0] [c00000000006ab00] .pnv_eeh_next_error+0x1f0/0x6f0
[c000000751b97ba0] [c000000000035908] .eeh_handle_event+0xb8/0x2f0
[c000000751b97c70] [c000000000035cf8] .eeh_event_handler+0x1b8/0x1c0
[c000000751b97d30] [c0000000000bb564] .kthread+0x104/0x130
[c000000751b97e30] [c0000000000095a4] .ret_from_kernel_thread+0x58/0xb4
Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-powernv.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
@@ -41,6 +41,7 @@
#include "pci.h"
static bool pnv_eeh_nb_init = false;
+static bool pnv_eeh_irq_enabled = false;
static int eeh_event_irq = -EINVAL;
/**
@@ -98,7 +99,10 @@ static irqreturn_t pnv_eeh_event(int irq, void *data)
* finished processing the outstanding ones. Event processing
* gets unmasked in next_error() if EEH is enabled.
*/
- disable_irq_nosync(irq);
+ if (pnv_eeh_irq_enabled) {
+ disable_irq_nosync(irq);
+ pnv_eeh_irq_enabled = false;
+ }
if (eeh_enabled())
eeh_send_failure_event(NULL);
@@ -243,11 +247,14 @@ static int pnv_eeh_post_init(void)
return ret;
}
+ pnv_eeh_irq_enabled = true;
pnv_eeh_nb_init = true;
}
- if (!eeh_enabled())
+ if (!eeh_enabled() && pnv_eeh_irq_enabled) {
disable_irq(eeh_event_irq);
+ pnv_eeh_irq_enabled = false;
+ }
list_for_each_entry(hose, &hose_list, list_node) {
phb = hose->private_data;
@@ -1478,8 +1485,10 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
}
/* Unmask the event */
- if (eeh_enabled())
+ if (eeh_enabled() && !pnv_eeh_irq_enabled) {
enable_irq(eeh_event_irq);
+ pnv_eeh_irq_enabled = true;
+ }
return ret;
}
--
2.1.0