mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 03:06:10 +00:00
[S390] split/move machine check handler code
Split machine check handler code and move it to cio and kernel code where it belongs to. No functional change. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
70193af918
commit
f5daba1d41
14 changed files with 340 additions and 339 deletions
68
arch/s390/include/asm/crw.h
Normal file
68
arch/s390/include/asm/crw.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Data definitions for channel report processing
|
||||
* Copyright IBM Corp. 2000,2009
|
||||
* Author(s): Ingo Adlung <adlung@de.ibm.com>,
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>,
|
||||
* Heiko Carstens <heiko.carstens@de.ibm.com>,
|
||||
*/
|
||||
|
||||
#ifndef _ASM_S390_CRW_H
|
||||
#define _ASM_S390_CRW_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Channel Report Word
|
||||
*/
|
||||
struct crw {
|
||||
__u32 res1 : 1; /* reserved zero */
|
||||
__u32 slct : 1; /* solicited */
|
||||
__u32 oflw : 1; /* overflow */
|
||||
__u32 chn : 1; /* chained */
|
||||
__u32 rsc : 4; /* reporting source code */
|
||||
__u32 anc : 1; /* ancillary report */
|
||||
__u32 res2 : 1; /* reserved zero */
|
||||
__u32 erc : 6; /* error-recovery code */
|
||||
__u32 rsid : 16; /* reporting-source ID */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
|
||||
|
||||
extern int crw_register_handler(int rsc, crw_handler_t handler);
|
||||
extern void crw_unregister_handler(int rsc);
|
||||
extern void crw_handle_channel_report(void);
|
||||
|
||||
#define NR_RSCS 16
|
||||
|
||||
#define CRW_RSC_MONITOR 0x2 /* monitoring facility */
|
||||
#define CRW_RSC_SCH 0x3 /* subchannel */
|
||||
#define CRW_RSC_CPATH 0x4 /* channel path */
|
||||
#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */
|
||||
#define CRW_RSC_CSS 0xB /* channel subsystem */
|
||||
|
||||
#define CRW_ERC_EVENT 0x00 /* event information pending */
|
||||
#define CRW_ERC_AVAIL 0x01 /* available */
|
||||
#define CRW_ERC_INIT 0x02 /* initialized */
|
||||
#define CRW_ERC_TERROR 0x03 /* temporary error */
|
||||
#define CRW_ERC_IPARM 0x04 /* installed parm initialized */
|
||||
#define CRW_ERC_TERM 0x05 /* terminal */
|
||||
#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */
|
||||
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
|
||||
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
|
||||
|
||||
static inline int stcrw(struct crw *pcrw)
|
||||
{
|
||||
int ccode;
|
||||
|
||||
asm volatile(
|
||||
" stcrw 0(%2)\n"
|
||||
" ipm %0\n"
|
||||
" srl %0,28\n"
|
||||
: "=d" (ccode), "=m" (*pcrw)
|
||||
: "a" (pcrw)
|
||||
: "cc" );
|
||||
return ccode;
|
||||
}
|
||||
|
||||
#endif /* _ASM_S390_CRW_H */
|
66
arch/s390/include/asm/nmi.h
Normal file
66
arch/s390/include/asm/nmi.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Machine check handler definitions
|
||||
*
|
||||
* Copyright IBM Corp. 2000,2009
|
||||
* Author(s): Ingo Adlung <adlung@de.ibm.com>,
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>,
|
||||
* Heiko Carstens <heiko.carstens@de.ibm.com>,
|
||||
*/
|
||||
|
||||
#ifndef _ASM_S390_NMI_H
|
||||
#define _ASM_S390_NMI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct mci {
|
||||
__u32 sd : 1; /* 00 system damage */
|
||||
__u32 pd : 1; /* 01 instruction-processing damage */
|
||||
__u32 sr : 1; /* 02 system recovery */
|
||||
__u32 : 1; /* 03 */
|
||||
__u32 cd : 1; /* 04 timing-facility damage */
|
||||
__u32 ed : 1; /* 05 external damage */
|
||||
__u32 : 1; /* 06 */
|
||||
__u32 dg : 1; /* 07 degradation */
|
||||
__u32 w : 1; /* 08 warning pending */
|
||||
__u32 cp : 1; /* 09 channel-report pending */
|
||||
__u32 sp : 1; /* 10 service-processor damage */
|
||||
__u32 ck : 1; /* 11 channel-subsystem damage */
|
||||
__u32 : 2; /* 12-13 */
|
||||
__u32 b : 1; /* 14 backed up */
|
||||
__u32 : 1; /* 15 */
|
||||
__u32 se : 1; /* 16 storage error uncorrected */
|
||||
__u32 sc : 1; /* 17 storage error corrected */
|
||||
__u32 ke : 1; /* 18 storage-key error uncorrected */
|
||||
__u32 ds : 1; /* 19 storage degradation */
|
||||
__u32 wp : 1; /* 20 psw mwp validity */
|
||||
__u32 ms : 1; /* 21 psw mask and key validity */
|
||||
__u32 pm : 1; /* 22 psw program mask and cc validity */
|
||||
__u32 ia : 1; /* 23 psw instruction address validity */
|
||||
__u32 fa : 1; /* 24 failing storage address validity */
|
||||
__u32 : 1; /* 25 */
|
||||
__u32 ec : 1; /* 26 external damage code validity */
|
||||
__u32 fp : 1; /* 27 floating point register validity */
|
||||
__u32 gr : 1; /* 28 general register validity */
|
||||
__u32 cr : 1; /* 29 control register validity */
|
||||
__u32 : 1; /* 30 */
|
||||
__u32 st : 1; /* 31 storage logical validity */
|
||||
__u32 ie : 1; /* 32 indirect storage error */
|
||||
__u32 ar : 1; /* 33 access register validity */
|
||||
__u32 da : 1; /* 34 delayed access exception */
|
||||
__u32 : 7; /* 35-41 */
|
||||
__u32 pr : 1; /* 42 tod programmable register validity */
|
||||
__u32 fc : 1; /* 43 fp control register validity */
|
||||
__u32 ap : 1; /* 44 ancillary report */
|
||||
__u32 : 1; /* 45 */
|
||||
__u32 ct : 1; /* 46 cpu timer validity */
|
||||
__u32 cc : 1; /* 47 clock comparator validity */
|
||||
__u32 : 16; /* 47-63 */
|
||||
};
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
extern void s390_handle_mcck(void);
|
||||
extern void s390_do_machine_check(struct pt_regs *regs);
|
||||
|
||||
#endif /* _ASM_S390_NMI_H */
|
|
@ -22,7 +22,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
|
|||
obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \
|
||||
processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
|
||||
s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \
|
||||
vdso.o vtime.o sysinfo.o
|
||||
vdso.o vtime.o sysinfo.o nmi.o
|
||||
|
||||
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
|
||||
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
|
||||
|
|
|
@ -1,137 +1,23 @@
|
|||
/*
|
||||
* drivers/s390/s390mach.c
|
||||
* S/390 machine check handler
|
||||
* Machine check handler
|
||||
*
|
||||
* Copyright IBM Corp. 2000,2008
|
||||
* Author(s): Ingo Adlung (adlung@de.ibm.com)
|
||||
* Martin Schwidefsky (schwidefsky@de.ibm.com)
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
* Copyright IBM Corp. 2000,2009
|
||||
* Author(s): Ingo Adlung <adlung@de.ibm.com>,
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>,
|
||||
* Heiko Carstens <heiko.carstens@de.ibm.com>,
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/etr.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/cio.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/etr.h>
|
||||
#include <asm/cpu.h>
|
||||
#include "s390mach.h"
|
||||
|
||||
static struct semaphore m_sem;
|
||||
|
||||
static NORET_TYPE void
|
||||
s390_handle_damage(char *msg)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
smp_send_stop();
|
||||
#endif
|
||||
disabled_wait((unsigned long) __builtin_return_address(0));
|
||||
for(;;);
|
||||
}
|
||||
|
||||
static crw_handler_t crw_handlers[NR_RSCS];
|
||||
|
||||
/**
|
||||
* s390_register_crw_handler() - register a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
* @handler: handler to be registered
|
||||
*
|
||||
* Returns %0 on success and a negative error value otherwise.
|
||||
*/
|
||||
int s390_register_crw_handler(int rsc, crw_handler_t handler)
|
||||
{
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return -EINVAL;
|
||||
if (!cmpxchg(&crw_handlers[rsc], NULL, handler))
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* s390_unregister_crw_handler() - unregister a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
*/
|
||||
void s390_unregister_crw_handler(int rsc)
|
||||
{
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return;
|
||||
xchg(&crw_handlers[rsc], NULL);
|
||||
synchronize_sched();
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve CRWs and call function to handle event.
|
||||
*/
|
||||
static int s390_collect_crw_info(void *param)
|
||||
{
|
||||
struct crw crw[2];
|
||||
int ccode;
|
||||
struct semaphore *sem;
|
||||
unsigned int chain;
|
||||
int ignore;
|
||||
|
||||
sem = (struct semaphore *)param;
|
||||
repeat:
|
||||
ignore = down_interruptible(sem);
|
||||
chain = 0;
|
||||
while (1) {
|
||||
if (unlikely(chain > 1)) {
|
||||
struct crw tmp_crw;
|
||||
|
||||
printk(KERN_WARNING"%s: Code does not support more "
|
||||
"than two chained crws; please report to "
|
||||
"linux390@de.ibm.com!\n", __func__);
|
||||
ccode = stcrw(&tmp_crw);
|
||||
printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
__func__, tmp_crw.slct, tmp_crw.oflw,
|
||||
tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
|
||||
tmp_crw.erc, tmp_crw.rsid);
|
||||
printk(KERN_WARNING"%s: This was crw number %x in the "
|
||||
"chain\n", __func__, chain);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
chain = tmp_crw.chn ? chain + 1 : 0;
|
||||
continue;
|
||||
}
|
||||
ccode = stcrw(&crw[chain]);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
crw[chain].slct, crw[chain].oflw, crw[chain].chn,
|
||||
crw[chain].rsc, crw[chain].anc, crw[chain].erc,
|
||||
crw[chain].rsid);
|
||||
/* Check for overflows. */
|
||||
if (crw[chain].oflw) {
|
||||
int i;
|
||||
|
||||
pr_debug("%s: crw overflow detected!\n", __func__);
|
||||
for (i = 0; i < NR_RSCS; i++) {
|
||||
if (crw_handlers[i])
|
||||
crw_handlers[i](NULL, NULL, 1);
|
||||
}
|
||||
chain = 0;
|
||||
continue;
|
||||
}
|
||||
if (crw[0].chn && !chain) {
|
||||
chain++;
|
||||
continue;
|
||||
}
|
||||
if (crw_handlers[crw[chain].rsc])
|
||||
crw_handlers[crw[chain].rsc](&crw[0],
|
||||
chain ? &crw[1] : NULL,
|
||||
0);
|
||||
/* chain is always 0 or 1 here. */
|
||||
chain = crw[chain].chn ? chain + 1 : 0;
|
||||
}
|
||||
goto repeat;
|
||||
return 0;
|
||||
}
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
struct mcck_struct {
|
||||
int kill_task;
|
||||
|
@ -142,12 +28,18 @@ struct mcck_struct {
|
|||
|
||||
static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
|
||||
|
||||
static NORET_TYPE void s390_handle_damage(char *msg)
|
||||
{
|
||||
smp_send_stop();
|
||||
disabled_wait((unsigned long) __builtin_return_address(0));
|
||||
while (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main machine check handler function. Will be called with interrupts enabled
|
||||
* or disabled and machine checks enabled or disabled.
|
||||
*/
|
||||
void
|
||||
s390_handle_mcck(void)
|
||||
void s390_handle_mcck(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct mcck_struct mcck;
|
||||
|
@ -166,7 +58,7 @@ s390_handle_mcck(void)
|
|||
local_irq_restore(flags);
|
||||
|
||||
if (mcck.channel_report)
|
||||
up(&m_sem);
|
||||
crw_handle_channel_report();
|
||||
|
||||
#ifdef CONFIG_MACHCHK_WARNING
|
||||
/*
|
||||
|
@ -204,8 +96,7 @@ EXPORT_SYMBOL_GPL(s390_handle_mcck);
|
|||
* returns 0 if all registers could be validated
|
||||
* returns 1 otherwise
|
||||
*/
|
||||
static int
|
||||
s390_revalidate_registers(struct mci *mci)
|
||||
static int notrace s390_revalidate_registers(struct mci *mci)
|
||||
{
|
||||
int kill_task;
|
||||
u64 tmpclock;
|
||||
|
@ -214,22 +105,21 @@ s390_revalidate_registers(struct mci *mci)
|
|||
|
||||
kill_task = 0;
|
||||
zero = 0;
|
||||
/* General purpose registers */
|
||||
if (!mci->gr)
|
||||
|
||||
if (!mci->gr) {
|
||||
/*
|
||||
* General purpose registers couldn't be restored and have
|
||||
* unknown contents. Process needs to be terminated.
|
||||
*/
|
||||
kill_task = 1;
|
||||
|
||||
/* Revalidate floating point registers */
|
||||
if (!mci->fp)
|
||||
}
|
||||
if (!mci->fp) {
|
||||
/*
|
||||
* Floating point registers can't be restored and
|
||||
* therefore the process needs to be terminated.
|
||||
*/
|
||||
kill_task = 1;
|
||||
|
||||
}
|
||||
#ifndef CONFIG_64BIT
|
||||
asm volatile(
|
||||
" ld 0,0(%0)\n"
|
||||
|
@ -245,9 +135,8 @@ s390_revalidate_registers(struct mci *mci)
|
|||
fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
|
||||
#else
|
||||
fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
|
||||
fpt_creg_save_area = fpt_save_area+128;
|
||||
fpt_creg_save_area = fpt_save_area + 128;
|
||||
#endif
|
||||
/* Floating point control register */
|
||||
if (!mci->fc) {
|
||||
/*
|
||||
* Floating point control register can't be restored.
|
||||
|
@ -278,26 +167,25 @@ s390_revalidate_registers(struct mci *mci)
|
|||
" ld 15,120(%0)\n"
|
||||
: : "a" (fpt_save_area));
|
||||
}
|
||||
|
||||
/* Revalidate access registers */
|
||||
asm volatile(
|
||||
" lam 0,15,0(%0)"
|
||||
: : "a" (&S390_lowcore.access_regs_save_area));
|
||||
if (!mci->ar)
|
||||
if (!mci->ar) {
|
||||
/*
|
||||
* Access registers have unknown contents.
|
||||
* Terminating task.
|
||||
*/
|
||||
kill_task = 1;
|
||||
|
||||
}
|
||||
/* Revalidate control registers */
|
||||
if (!mci->cr)
|
||||
if (!mci->cr) {
|
||||
/*
|
||||
* Control registers have unknown contents.
|
||||
* Can't recover and therefore stopping machine.
|
||||
*/
|
||||
s390_handle_damage("invalid control registers.");
|
||||
else
|
||||
} else {
|
||||
#ifdef CONFIG_64BIT
|
||||
asm volatile(
|
||||
" lctlg 0,15,0(%0)"
|
||||
|
@ -307,12 +195,11 @@ s390_revalidate_registers(struct mci *mci)
|
|||
" lctl 0,15,0(%0)"
|
||||
: : "a" (&S390_lowcore.cregs_save_area));
|
||||
#endif
|
||||
|
||||
}
|
||||
/*
|
||||
* We don't even try to revalidate the TOD register, since we simply
|
||||
* can't write something sensible into that register.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/*
|
||||
* See if we can revalidate the TOD programmable register with its
|
||||
|
@ -330,7 +217,6 @@ s390_revalidate_registers(struct mci *mci)
|
|||
: : "a" (&S390_lowcore.tod_progreg_save_area)
|
||||
: "0", "cc");
|
||||
#endif
|
||||
|
||||
/* Revalidate clock comparator register */
|
||||
asm volatile(
|
||||
" stck 0(%1)\n"
|
||||
|
@ -354,31 +240,35 @@ s390_revalidate_registers(struct mci *mci)
|
|||
#define MAX_IPD_COUNT 29
|
||||
#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
|
||||
|
||||
#define ED_STP_ISLAND 6 /* External damage STP island check */
|
||||
#define ED_STP_SYNC 7 /* External damage STP sync check */
|
||||
#define ED_ETR_SYNC 12 /* External damage ETR sync check */
|
||||
#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
|
||||
|
||||
/*
|
||||
* machine check handler.
|
||||
*/
|
||||
void notrace s390_do_machine_check(struct pt_regs *regs)
|
||||
{
|
||||
static int ipd_count;
|
||||
static DEFINE_SPINLOCK(ipd_lock);
|
||||
static unsigned long long last_ipd;
|
||||
static int ipd_count;
|
||||
struct mcck_struct *mcck;
|
||||
unsigned long long tmp;
|
||||
struct mci *mci;
|
||||
struct mcck_struct *mcck;
|
||||
int umode;
|
||||
|
||||
lockdep_off();
|
||||
|
||||
s390_idle_check();
|
||||
|
||||
mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
|
||||
mcck = &__get_cpu_var(cpu_mcck);
|
||||
umode = user_mode(regs);
|
||||
|
||||
if (mci->sd)
|
||||
if (mci->sd) {
|
||||
/* System damage -> stopping machine */
|
||||
s390_handle_damage("received system damage machine check.");
|
||||
|
||||
}
|
||||
if (mci->pd) {
|
||||
if (mci->b) {
|
||||
/* Processing backup -> verify if we can survive this */
|
||||
|
@ -408,24 +298,17 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|||
* 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 {
|
||||
} else {
|
||||
/* Processing damage -> stopping machine */
|
||||
s390_handle_damage("received instruction processing "
|
||||
"damage machine check.");
|
||||
|
@ -440,20 +323,18 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|||
mcck->kill_task = 1;
|
||||
mcck->mcck_code = *(unsigned long long *) mci;
|
||||
set_thread_flag(TIF_MCCK_PENDING);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
/*
|
||||
* Couldn't restore all register contents while in
|
||||
* kernel mode -> stopping machine.
|
||||
*/
|
||||
s390_handle_damage("unable to revalidate registers.");
|
||||
}
|
||||
}
|
||||
|
||||
if (mci->cd) {
|
||||
/* Timing facility damage */
|
||||
s390_handle_damage("TOD clock damaged");
|
||||
}
|
||||
|
||||
if (mci->ed && mci->ec) {
|
||||
/* External damage */
|
||||
if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
|
||||
|
@ -465,28 +346,23 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|||
if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND))
|
||||
stp_island_check();
|
||||
}
|
||||
|
||||
if (mci->se)
|
||||
/* Storage error uncorrected */
|
||||
s390_handle_damage("received storage error uncorrected "
|
||||
"machine check.");
|
||||
|
||||
if (mci->ke)
|
||||
/* Storage key-error uncorrected */
|
||||
s390_handle_damage("received storage key-error uncorrected "
|
||||
"machine check.");
|
||||
|
||||
if (mci->ds && mci->fa)
|
||||
/* Storage degradation */
|
||||
s390_handle_damage("received storage degradation machine "
|
||||
"check.");
|
||||
|
||||
if (mci->cp) {
|
||||
/* Channel report word pending */
|
||||
mcck->channel_report = 1;
|
||||
set_thread_flag(TIF_MCCK_PENDING);
|
||||
}
|
||||
|
||||
if (mci->w) {
|
||||
/* Warning pending */
|
||||
mcck->warning = 1;
|
||||
|
@ -495,43 +371,13 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|||
lockdep_on();
|
||||
}
|
||||
|
||||
/*
|
||||
* s390_init_machine_check
|
||||
*
|
||||
* initialize machine check handling
|
||||
*/
|
||||
static int
|
||||
machine_check_init(void)
|
||||
static int __init machine_check_init(void)
|
||||
{
|
||||
init_MUTEX_LOCKED(&m_sem);
|
||||
ctl_set_bit(14, 25); /* enable external damage MCH */
|
||||
ctl_set_bit(14, 27); /* enable system recovery MCH */
|
||||
ctl_set_bit(14, 27); /* enable system recovery MCH */
|
||||
#ifdef CONFIG_MACHCHK_WARNING
|
||||
ctl_set_bit(14, 24); /* enable warning MCH */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the machine check handler really early to be able to
|
||||
* catch all machine checks that happen during boot
|
||||
*/
|
||||
arch_initcall(machine_check_init);
|
||||
|
||||
/*
|
||||
* Machine checks for the channel subsystem must be enabled
|
||||
* after the channel subsystem is initialized
|
||||
*/
|
||||
static int __init
|
||||
machine_check_crw_init (void)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
ctl_set_bit(14, 28); /* enable channel report MCH */
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_initcall (machine_check_crw_init);
|
|
@ -39,6 +39,7 @@
|
|||
#include <asm/processor.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/nmi.h>
|
||||
#include "entry.h"
|
||||
|
||||
asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
|
||||
|
@ -68,7 +69,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
|
|||
return sf->gprs[8];
|
||||
}
|
||||
|
||||
extern void s390_handle_mcck(void);
|
||||
/*
|
||||
* The idle loop on a S390...
|
||||
*/
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/timer.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#include <asm/nmi.h>
|
||||
#include "kvm-s390.h"
|
||||
#include "gaccess.h"
|
||||
|
||||
|
@ -440,8 +440,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
|
|||
return -EINVAL; /* not implemented yet */
|
||||
}
|
||||
|
||||
extern void s390_handle_mcck(void);
|
||||
|
||||
static void __vcpu_run(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# Makefile for the S/390 specific device drivers
|
||||
#
|
||||
|
||||
obj-y += s390mach.o
|
||||
obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
|
||||
|
||||
drivers-y += drivers/s390/built-in.o
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
|
||||
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \
|
||||
fcx.o itcw.o
|
||||
fcx.o itcw.o crw.o
|
||||
ccw_device-objs += device.o device_fsm.o device_ops.o
|
||||
ccw_device-objs += device_id.o device_pgid.o device_status.o
|
||||
obj-y += ccw_device.o cmf.o
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
#include <linux/errno.h>
|
||||
#include <asm/chpid.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
#include "../s390mach.h"
|
||||
#include "cio.h"
|
||||
#include "css.h"
|
||||
#include "ioasm.h"
|
||||
|
@ -706,12 +706,12 @@ static int __init chp_init(void)
|
|||
struct chp_id chpid;
|
||||
int ret;
|
||||
|
||||
ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw);
|
||||
ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw);
|
||||
if (ret)
|
||||
return ret;
|
||||
chp_wq = create_singlethread_workqueue("cio_chp");
|
||||
if (!chp_wq) {
|
||||
s390_unregister_crw_handler(CRW_RSC_CPATH);
|
||||
crw_unregister_handler(CRW_RSC_CPATH);
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_WORK(&cfg_work, cfg_func);
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <asm/cio.h>
|
||||
#include <asm/chpid.h>
|
||||
#include <asm/chsc.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
#include "../s390mach.h"
|
||||
#include "css.h"
|
||||
#include "cio.h"
|
||||
#include "cio_debug.h"
|
||||
|
@ -820,7 +820,7 @@ int __init chsc_alloc_sei_area(void)
|
|||
"chsc machine checks!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw);
|
||||
ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw);
|
||||
if (ret)
|
||||
kfree(sei_page);
|
||||
return ret;
|
||||
|
@ -828,7 +828,7 @@ int __init chsc_alloc_sei_area(void)
|
|||
|
||||
void __init chsc_free_sei_area(void)
|
||||
{
|
||||
s390_unregister_crw_handler(CRW_RSC_CSS);
|
||||
crw_unregister_handler(CRW_RSC_CSS);
|
||||
kfree(sei_page);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include <asm/isc.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/fcx.h>
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/crw.h>
|
||||
#include "cio.h"
|
||||
#include "css.h"
|
||||
#include "chsc.h"
|
||||
|
@ -38,7 +40,6 @@
|
|||
#include "blacklist.h"
|
||||
#include "cio_debug.h"
|
||||
#include "chp.h"
|
||||
#include "../s390mach.h"
|
||||
|
||||
debug_info_t *cio_debug_msg_id;
|
||||
debug_info_t *cio_debug_trace_id;
|
||||
|
|
145
drivers/s390/cio/crw.c
Normal file
145
drivers/s390/cio/crw.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Channel report handling code
|
||||
*
|
||||
* Copyright IBM Corp. 2000,2009
|
||||
* Author(s): Ingo Adlung <adlung@de.ibm.com>,
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>,
|
||||
* Heiko Carstens <heiko.carstens@de.ibm.com>,
|
||||
*/
|
||||
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
static struct semaphore crw_semaphore;
|
||||
static crw_handler_t crw_handlers[NR_RSCS];
|
||||
|
||||
/**
|
||||
* crw_register_handler() - register a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
* @handler: handler to be registered
|
||||
*
|
||||
* Returns %0 on success and a negative error value otherwise.
|
||||
*/
|
||||
int crw_register_handler(int rsc, crw_handler_t handler)
|
||||
{
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return -EINVAL;
|
||||
if (!cmpxchg(&crw_handlers[rsc], NULL, handler))
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* crw_unregister_handler() - unregister a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
*/
|
||||
void crw_unregister_handler(int rsc)
|
||||
{
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return;
|
||||
xchg(&crw_handlers[rsc], NULL);
|
||||
synchronize_sched();
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve CRWs and call function to handle event.
|
||||
*/
|
||||
static int crw_collect_info(void *unused)
|
||||
{
|
||||
struct crw crw[2];
|
||||
int ccode;
|
||||
unsigned int chain;
|
||||
int ignore;
|
||||
|
||||
repeat:
|
||||
ignore = down_interruptible(&crw_semaphore);
|
||||
chain = 0;
|
||||
while (1) {
|
||||
if (unlikely(chain > 1)) {
|
||||
struct crw tmp_crw;
|
||||
|
||||
printk(KERN_WARNING"%s: Code does not support more "
|
||||
"than two chained crws; please report to "
|
||||
"linux390@de.ibm.com!\n", __func__);
|
||||
ccode = stcrw(&tmp_crw);
|
||||
printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
__func__, tmp_crw.slct, tmp_crw.oflw,
|
||||
tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
|
||||
tmp_crw.erc, tmp_crw.rsid);
|
||||
printk(KERN_WARNING"%s: This was crw number %x in the "
|
||||
"chain\n", __func__, chain);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
chain = tmp_crw.chn ? chain + 1 : 0;
|
||||
continue;
|
||||
}
|
||||
ccode = stcrw(&crw[chain]);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
crw[chain].slct, crw[chain].oflw, crw[chain].chn,
|
||||
crw[chain].rsc, crw[chain].anc, crw[chain].erc,
|
||||
crw[chain].rsid);
|
||||
/* Check for overflows. */
|
||||
if (crw[chain].oflw) {
|
||||
int i;
|
||||
|
||||
pr_debug("%s: crw overflow detected!\n", __func__);
|
||||
for (i = 0; i < NR_RSCS; i++) {
|
||||
if (crw_handlers[i])
|
||||
crw_handlers[i](NULL, NULL, 1);
|
||||
}
|
||||
chain = 0;
|
||||
continue;
|
||||
}
|
||||
if (crw[0].chn && !chain) {
|
||||
chain++;
|
||||
continue;
|
||||
}
|
||||
if (crw_handlers[crw[chain].rsc])
|
||||
crw_handlers[crw[chain].rsc](&crw[0],
|
||||
chain ? &crw[1] : NULL,
|
||||
0);
|
||||
/* chain is always 0 or 1 here. */
|
||||
chain = crw[chain].chn ? chain + 1 : 0;
|
||||
}
|
||||
goto repeat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crw_handle_channel_report(void)
|
||||
{
|
||||
up(&crw_semaphore);
|
||||
}
|
||||
|
||||
/*
|
||||
* Separate initcall needed for semaphore initialization since
|
||||
* crw_handle_channel_report might be called before crw_machine_check_init.
|
||||
*/
|
||||
static int __init crw_init_semaphore(void)
|
||||
{
|
||||
init_MUTEX_LOCKED(&crw_semaphore);
|
||||
return 0;
|
||||
}
|
||||
pure_initcall(crw_init_semaphore);
|
||||
|
||||
/*
|
||||
* Machine checks for the channel subsystem must be enabled
|
||||
* after the channel subsystem is initialized
|
||||
*/
|
||||
static int __init crw_machine_check_init(void)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
task = kthread_run(crw_collect_info, NULL, "kmcheck");
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
ctl_set_bit(14, 28); /* enable channel report MCH */
|
||||
return 0;
|
||||
}
|
||||
device_initcall(crw_machine_check_init);
|
|
@ -18,8 +18,8 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/isc.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
#include "../s390mach.h"
|
||||
#include "css.h"
|
||||
#include "cio.h"
|
||||
#include "cio_debug.h"
|
||||
|
@ -765,7 +765,7 @@ init_channel_subsystem (void)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw);
|
||||
ret = crw_register_handler(CRW_RSC_SCH, css_process_crw);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -845,7 +845,7 @@ out_unregister:
|
|||
out_bus:
|
||||
bus_unregister(&css_bus_type);
|
||||
out:
|
||||
s390_unregister_crw_handler(CRW_RSC_CSS);
|
||||
crw_unregister_handler(CRW_RSC_CSS);
|
||||
chsc_free_sei_area();
|
||||
kfree(slow_subchannel_set);
|
||||
pr_alert("The CSS device driver initialization failed with "
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* drivers/s390/s390mach.h
|
||||
* S/390 data definitions for machine check processing
|
||||
*
|
||||
* S390 version
|
||||
* Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
||||
* Author(s): Ingo Adlung (adlung@de.ibm.com)
|
||||
*/
|
||||
|
||||
#ifndef __s390mach_h
|
||||
#define __s390mach_h
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
struct mci {
|
||||
__u32 sd : 1; /* 00 system damage */
|
||||
__u32 pd : 1; /* 01 instruction-processing damage */
|
||||
__u32 sr : 1; /* 02 system recovery */
|
||||
__u32 to_be_defined_1 : 1; /* 03 */
|
||||
__u32 cd : 1; /* 04 timing-facility damage */
|
||||
__u32 ed : 1; /* 05 external damage */
|
||||
__u32 to_be_defined_2 : 1; /* 06 */
|
||||
__u32 dg : 1; /* 07 degradation */
|
||||
__u32 w : 1; /* 08 warning pending */
|
||||
__u32 cp : 1; /* 09 channel-report pending */
|
||||
__u32 sp : 1; /* 10 service-processor damage */
|
||||
__u32 ck : 1; /* 11 channel-subsystem damage */
|
||||
__u32 to_be_defined_3 : 2; /* 12-13 */
|
||||
__u32 b : 1; /* 14 backed up */
|
||||
__u32 to_be_defined_4 : 1; /* 15 */
|
||||
__u32 se : 1; /* 16 storage error uncorrected */
|
||||
__u32 sc : 1; /* 17 storage error corrected */
|
||||
__u32 ke : 1; /* 18 storage-key error uncorrected */
|
||||
__u32 ds : 1; /* 19 storage degradation */
|
||||
__u32 wp : 1; /* 20 psw mwp validity */
|
||||
__u32 ms : 1; /* 21 psw mask and key validity */
|
||||
__u32 pm : 1; /* 22 psw program mask and cc validity */
|
||||
__u32 ia : 1; /* 23 psw instruction address validity */
|
||||
__u32 fa : 1; /* 24 failing storage address validity */
|
||||
__u32 to_be_defined_5 : 1; /* 25 */
|
||||
__u32 ec : 1; /* 26 external damage code validity */
|
||||
__u32 fp : 1; /* 27 floating point register validity */
|
||||
__u32 gr : 1; /* 28 general register validity */
|
||||
__u32 cr : 1; /* 29 control register validity */
|
||||
__u32 to_be_defined_6 : 1; /* 30 */
|
||||
__u32 st : 1; /* 31 storage logical validity */
|
||||
__u32 ie : 1; /* 32 indirect storage error */
|
||||
__u32 ar : 1; /* 33 access register validity */
|
||||
__u32 da : 1; /* 34 delayed access exception */
|
||||
__u32 to_be_defined_7 : 7; /* 35-41 */
|
||||
__u32 pr : 1; /* 42 tod programmable register validity */
|
||||
__u32 fc : 1; /* 43 fp control register validity */
|
||||
__u32 ap : 1; /* 44 ancillary report */
|
||||
__u32 to_be_defined_8 : 1; /* 45 */
|
||||
__u32 ct : 1; /* 46 cpu timer validity */
|
||||
__u32 cc : 1; /* 47 clock comparator validity */
|
||||
__u32 to_be_defined_9 : 16; /* 47-63 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Channel Report Word
|
||||
*/
|
||||
struct crw {
|
||||
__u32 res1 : 1; /* reserved zero */
|
||||
__u32 slct : 1; /* solicited */
|
||||
__u32 oflw : 1; /* overflow */
|
||||
__u32 chn : 1; /* chained */
|
||||
__u32 rsc : 4; /* reporting source code */
|
||||
__u32 anc : 1; /* ancillary report */
|
||||
__u32 res2 : 1; /* reserved zero */
|
||||
__u32 erc : 6; /* error-recovery code */
|
||||
__u32 rsid : 16; /* reporting-source ID */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
|
||||
|
||||
extern int s390_register_crw_handler(int rsc, crw_handler_t handler);
|
||||
extern void s390_unregister_crw_handler(int rsc);
|
||||
|
||||
#define NR_RSCS 16
|
||||
|
||||
#define CRW_RSC_MONITOR 0x2 /* monitoring facility */
|
||||
#define CRW_RSC_SCH 0x3 /* subchannel */
|
||||
#define CRW_RSC_CPATH 0x4 /* channel path */
|
||||
#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */
|
||||
#define CRW_RSC_CSS 0xB /* channel subsystem */
|
||||
|
||||
#define CRW_ERC_EVENT 0x00 /* event information pending */
|
||||
#define CRW_ERC_AVAIL 0x01 /* available */
|
||||
#define CRW_ERC_INIT 0x02 /* initialized */
|
||||
#define CRW_ERC_TERROR 0x03 /* temporary error */
|
||||
#define CRW_ERC_IPARM 0x04 /* installed parm initialized */
|
||||
#define CRW_ERC_TERM 0x05 /* terminal */
|
||||
#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */
|
||||
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
|
||||
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
|
||||
|
||||
static inline int stcrw(struct crw *pcrw )
|
||||
{
|
||||
int ccode;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"stcrw 0(%2)\n\t"
|
||||
"ipm %0\n\t"
|
||||
"srl %0,28\n\t"
|
||||
: "=d" (ccode), "=m" (*pcrw)
|
||||
: "a" (pcrw)
|
||||
: "cc" );
|
||||
return ccode;
|
||||
}
|
||||
|
||||
#define ED_ETR_SYNC 12 /* External damage ETR sync check */
|
||||
#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
|
||||
|
||||
#define ED_STP_SYNC 7 /* External damage STP sync check */
|
||||
#define ED_STP_ISLAND 6 /* External damage STP island check */
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
void s390_handle_mcck(void);
|
||||
void s390_do_machine_check(struct pt_regs *regs);
|
||||
#endif /* __s390mach */
|
Loading…
Reference in a new issue