aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2006-04-27 18:40:23 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-28 08:33:48 -0700
commitb73d40c6178f2c8b2d574db566b47f36e3d12072 (patch)
tree5f0f10ee010f06d359dbbf33dd2160f34d770ea2
parent9b5dec1aa08b77c4217cd5fcaf1e4e177f659b2e (diff)
[PATCH] s390: instruction processing damage handling
In case of an instruction processing damage (IPD) machine check in kernel mode the resulting action is always to stop the kernel. This is not necessarily the best solution since a retry of the failing instruction might succeed. Add logic to retry the instruction if no more than 30 instruction processing damage checks occured in the last 5 minutes. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/s390/s390mach.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 3bf46660351..5ae14803091 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -362,12 +362,19 @@ s390_revalidate_registers(struct mci *mci)
return kill_task;
}
+#define MAX_IPD_COUNT 29
+#define MAX_IPD_TIME (5 * 60 * 100 * 1000) /* 5 minutes */
+
/*
* machine check handler.
*/
void
s390_do_machine_check(struct pt_regs *regs)
{
+ static DEFINE_SPINLOCK(ipd_lock);
+ static unsigned long long last_ipd;
+ static int ipd_count;
+ unsigned long long tmp;
struct mci *mci;
struct mcck_struct *mcck;
int umode;
@@ -404,11 +411,27 @@ s390_do_machine_check(struct pt_regs *regs)
s390_handle_damage("processing backup machine "
"check with damage.");
}
- if (!umode)
- s390_handle_damage("processing backup machine "
- "check in kernel mode.");
- mcck->kill_task = 1;
- mcck->mcck_code = *(unsigned long long *) mci;
+
+ /*
+ * Nullifying exigent condition, therefore we might
+ * retry this instruction.
+ */
+
+ spin_lock(&ipd_lock);
+
+ tmp = get_clock();
+
+ if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
+ ipd_count++;
+ else
+ ipd_count = 1;
+
+ last_ipd = tmp;
+
+ if (ipd_count == MAX_IPD_COUNT)
+ s390_handle_damage("too many ipd retries.");
+
+ spin_unlock(&ipd_lock);
}
else {
/* Processing damage -> stopping machine */