mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +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
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 \
|
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 \
|
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 \
|
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),entry64.o,entry.o)
|
||||||
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
|
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
|
||||||
|
@ -1,137 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* drivers/s390/s390mach.c
|
* Machine check handler
|
||||||
* S/390 machine check handler
|
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2000,2008
|
* Copyright IBM Corp. 2000,2009
|
||||||
* Author(s): Ingo Adlung (adlung@de.ibm.com)
|
* Author(s): Ingo Adlung <adlung@de.ibm.com>,
|
||||||
* Martin Schwidefsky (schwidefsky@de.ibm.com)
|
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
* Cornelia Huck <cornelia.huck@de.ibm.com>,
|
||||||
|
* Heiko Carstens <heiko.carstens@de.ibm.com>,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <linux/device.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <asm/etr.h>
|
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
#include <asm/cio.h>
|
#include <asm/smp.h>
|
||||||
|
#include <asm/etr.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include "s390mach.h"
|
#include <asm/nmi.h>
|
||||||
|
#include <asm/crw.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mcck_struct {
|
struct mcck_struct {
|
||||||
int kill_task;
|
int kill_task;
|
||||||
@ -142,12 +28,18 @@ struct mcck_struct {
|
|||||||
|
|
||||||
static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
|
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
|
* Main machine check handler function. Will be called with interrupts enabled
|
||||||
* or disabled and machine checks enabled or disabled.
|
* or disabled and machine checks enabled or disabled.
|
||||||
*/
|
*/
|
||||||
void
|
void s390_handle_mcck(void)
|
||||||
s390_handle_mcck(void)
|
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct mcck_struct mcck;
|
struct mcck_struct mcck;
|
||||||
@ -166,7 +58,7 @@ s390_handle_mcck(void)
|
|||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
if (mcck.channel_report)
|
if (mcck.channel_report)
|
||||||
up(&m_sem);
|
crw_handle_channel_report();
|
||||||
|
|
||||||
#ifdef CONFIG_MACHCHK_WARNING
|
#ifdef CONFIG_MACHCHK_WARNING
|
||||||
/*
|
/*
|
||||||
@ -204,8 +96,7 @@ EXPORT_SYMBOL_GPL(s390_handle_mcck);
|
|||||||
* returns 0 if all registers could be validated
|
* returns 0 if all registers could be validated
|
||||||
* returns 1 otherwise
|
* returns 1 otherwise
|
||||||
*/
|
*/
|
||||||
static int
|
static int notrace s390_revalidate_registers(struct mci *mci)
|
||||||
s390_revalidate_registers(struct mci *mci)
|
|
||||||
{
|
{
|
||||||
int kill_task;
|
int kill_task;
|
||||||
u64 tmpclock;
|
u64 tmpclock;
|
||||||
@ -214,22 +105,21 @@ s390_revalidate_registers(struct mci *mci)
|
|||||||
|
|
||||||
kill_task = 0;
|
kill_task = 0;
|
||||||
zero = 0;
|
zero = 0;
|
||||||
/* General purpose registers */
|
|
||||||
if (!mci->gr)
|
if (!mci->gr) {
|
||||||
/*
|
/*
|
||||||
* General purpose registers couldn't be restored and have
|
* General purpose registers couldn't be restored and have
|
||||||
* unknown contents. Process needs to be terminated.
|
* unknown contents. Process needs to be terminated.
|
||||||
*/
|
*/
|
||||||
kill_task = 1;
|
kill_task = 1;
|
||||||
|
}
|
||||||
/* Revalidate floating point registers */
|
if (!mci->fp) {
|
||||||
if (!mci->fp)
|
|
||||||
/*
|
/*
|
||||||
* Floating point registers can't be restored and
|
* Floating point registers can't be restored and
|
||||||
* therefore the process needs to be terminated.
|
* therefore the process needs to be terminated.
|
||||||
*/
|
*/
|
||||||
kill_task = 1;
|
kill_task = 1;
|
||||||
|
}
|
||||||
#ifndef CONFIG_64BIT
|
#ifndef CONFIG_64BIT
|
||||||
asm volatile(
|
asm volatile(
|
||||||
" ld 0,0(%0)\n"
|
" 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;
|
fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
|
||||||
#else
|
#else
|
||||||
fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
|
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
|
#endif
|
||||||
/* Floating point control register */
|
|
||||||
if (!mci->fc) {
|
if (!mci->fc) {
|
||||||
/*
|
/*
|
||||||
* Floating point control register can't be restored.
|
* Floating point control register can't be restored.
|
||||||
@ -278,26 +167,25 @@ s390_revalidate_registers(struct mci *mci)
|
|||||||
" ld 15,120(%0)\n"
|
" ld 15,120(%0)\n"
|
||||||
: : "a" (fpt_save_area));
|
: : "a" (fpt_save_area));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Revalidate access registers */
|
/* Revalidate access registers */
|
||||||
asm volatile(
|
asm volatile(
|
||||||
" lam 0,15,0(%0)"
|
" lam 0,15,0(%0)"
|
||||||
: : "a" (&S390_lowcore.access_regs_save_area));
|
: : "a" (&S390_lowcore.access_regs_save_area));
|
||||||
if (!mci->ar)
|
if (!mci->ar) {
|
||||||
/*
|
/*
|
||||||
* Access registers have unknown contents.
|
* Access registers have unknown contents.
|
||||||
* Terminating task.
|
* Terminating task.
|
||||||
*/
|
*/
|
||||||
kill_task = 1;
|
kill_task = 1;
|
||||||
|
}
|
||||||
/* Revalidate control registers */
|
/* Revalidate control registers */
|
||||||
if (!mci->cr)
|
if (!mci->cr) {
|
||||||
/*
|
/*
|
||||||
* Control registers have unknown contents.
|
* Control registers have unknown contents.
|
||||||
* Can't recover and therefore stopping machine.
|
* Can't recover and therefore stopping machine.
|
||||||
*/
|
*/
|
||||||
s390_handle_damage("invalid control registers.");
|
s390_handle_damage("invalid control registers.");
|
||||||
else
|
} else {
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
asm volatile(
|
asm volatile(
|
||||||
" lctlg 0,15,0(%0)"
|
" lctlg 0,15,0(%0)"
|
||||||
@ -307,12 +195,11 @@ s390_revalidate_registers(struct mci *mci)
|
|||||||
" lctl 0,15,0(%0)"
|
" lctl 0,15,0(%0)"
|
||||||
: : "a" (&S390_lowcore.cregs_save_area));
|
: : "a" (&S390_lowcore.cregs_save_area));
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* We don't even try to revalidate the TOD register, since we simply
|
* We don't even try to revalidate the TOD register, since we simply
|
||||||
* can't write something sensible into that register.
|
* can't write something sensible into that register.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
/*
|
/*
|
||||||
* See if we can revalidate the TOD programmable register with its
|
* 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)
|
: : "a" (&S390_lowcore.tod_progreg_save_area)
|
||||||
: "0", "cc");
|
: "0", "cc");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Revalidate clock comparator register */
|
/* Revalidate clock comparator register */
|
||||||
asm volatile(
|
asm volatile(
|
||||||
" stck 0(%1)\n"
|
" stck 0(%1)\n"
|
||||||
@ -354,31 +240,35 @@ s390_revalidate_registers(struct mci *mci)
|
|||||||
#define MAX_IPD_COUNT 29
|
#define MAX_IPD_COUNT 29
|
||||||
#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
|
#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.
|
* machine check handler.
|
||||||
*/
|
*/
|
||||||
void notrace s390_do_machine_check(struct pt_regs *regs)
|
void notrace s390_do_machine_check(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
static int ipd_count;
|
||||||
static DEFINE_SPINLOCK(ipd_lock);
|
static DEFINE_SPINLOCK(ipd_lock);
|
||||||
static unsigned long long last_ipd;
|
static unsigned long long last_ipd;
|
||||||
static int ipd_count;
|
struct mcck_struct *mcck;
|
||||||
unsigned long long tmp;
|
unsigned long long tmp;
|
||||||
struct mci *mci;
|
struct mci *mci;
|
||||||
struct mcck_struct *mcck;
|
|
||||||
int umode;
|
int umode;
|
||||||
|
|
||||||
lockdep_off();
|
lockdep_off();
|
||||||
|
|
||||||
s390_idle_check();
|
s390_idle_check();
|
||||||
|
|
||||||
mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
|
mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
|
||||||
mcck = &__get_cpu_var(cpu_mcck);
|
mcck = &__get_cpu_var(cpu_mcck);
|
||||||
umode = user_mode(regs);
|
umode = user_mode(regs);
|
||||||
|
|
||||||
if (mci->sd)
|
if (mci->sd) {
|
||||||
/* System damage -> stopping machine */
|
/* System damage -> stopping machine */
|
||||||
s390_handle_damage("received system damage machine check.");
|
s390_handle_damage("received system damage machine check.");
|
||||||
|
}
|
||||||
if (mci->pd) {
|
if (mci->pd) {
|
||||||
if (mci->b) {
|
if (mci->b) {
|
||||||
/* Processing backup -> verify if we can survive this */
|
/* 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
|
* Nullifying exigent condition, therefore we might
|
||||||
* retry this instruction.
|
* retry this instruction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spin_lock(&ipd_lock);
|
spin_lock(&ipd_lock);
|
||||||
|
|
||||||
tmp = get_clock();
|
tmp = get_clock();
|
||||||
|
|
||||||
if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
|
if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
|
||||||
ipd_count++;
|
ipd_count++;
|
||||||
else
|
else
|
||||||
ipd_count = 1;
|
ipd_count = 1;
|
||||||
|
|
||||||
last_ipd = tmp;
|
last_ipd = tmp;
|
||||||
|
|
||||||
if (ipd_count == MAX_IPD_COUNT)
|
if (ipd_count == MAX_IPD_COUNT)
|
||||||
s390_handle_damage("too many ipd retries.");
|
s390_handle_damage("too many ipd retries.");
|
||||||
|
|
||||||
spin_unlock(&ipd_lock);
|
spin_unlock(&ipd_lock);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/* Processing damage -> stopping machine */
|
/* Processing damage -> stopping machine */
|
||||||
s390_handle_damage("received instruction processing "
|
s390_handle_damage("received instruction processing "
|
||||||
"damage machine check.");
|
"damage machine check.");
|
||||||
@ -440,20 +323,18 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|||||||
mcck->kill_task = 1;
|
mcck->kill_task = 1;
|
||||||
mcck->mcck_code = *(unsigned long long *) mci;
|
mcck->mcck_code = *(unsigned long long *) mci;
|
||||||
set_thread_flag(TIF_MCCK_PENDING);
|
set_thread_flag(TIF_MCCK_PENDING);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
/*
|
/*
|
||||||
* Couldn't restore all register contents while in
|
* Couldn't restore all register contents while in
|
||||||
* kernel mode -> stopping machine.
|
* kernel mode -> stopping machine.
|
||||||
*/
|
*/
|
||||||
s390_handle_damage("unable to revalidate registers.");
|
s390_handle_damage("unable to revalidate registers.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mci->cd) {
|
if (mci->cd) {
|
||||||
/* Timing facility damage */
|
/* Timing facility damage */
|
||||||
s390_handle_damage("TOD clock damaged");
|
s390_handle_damage("TOD clock damaged");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mci->ed && mci->ec) {
|
if (mci->ed && mci->ec) {
|
||||||
/* External damage */
|
/* External damage */
|
||||||
if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
|
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))
|
if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND))
|
||||||
stp_island_check();
|
stp_island_check();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mci->se)
|
if (mci->se)
|
||||||
/* Storage error uncorrected */
|
/* Storage error uncorrected */
|
||||||
s390_handle_damage("received storage error uncorrected "
|
s390_handle_damage("received storage error uncorrected "
|
||||||
"machine check.");
|
"machine check.");
|
||||||
|
|
||||||
if (mci->ke)
|
if (mci->ke)
|
||||||
/* Storage key-error uncorrected */
|
/* Storage key-error uncorrected */
|
||||||
s390_handle_damage("received storage key-error uncorrected "
|
s390_handle_damage("received storage key-error uncorrected "
|
||||||
"machine check.");
|
"machine check.");
|
||||||
|
|
||||||
if (mci->ds && mci->fa)
|
if (mci->ds && mci->fa)
|
||||||
/* Storage degradation */
|
/* Storage degradation */
|
||||||
s390_handle_damage("received storage degradation machine "
|
s390_handle_damage("received storage degradation machine "
|
||||||
"check.");
|
"check.");
|
||||||
|
|
||||||
if (mci->cp) {
|
if (mci->cp) {
|
||||||
/* Channel report word pending */
|
/* Channel report word pending */
|
||||||
mcck->channel_report = 1;
|
mcck->channel_report = 1;
|
||||||
set_thread_flag(TIF_MCCK_PENDING);
|
set_thread_flag(TIF_MCCK_PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mci->w) {
|
if (mci->w) {
|
||||||
/* Warning pending */
|
/* Warning pending */
|
||||||
mcck->warning = 1;
|
mcck->warning = 1;
|
||||||
@ -495,43 +371,13 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|||||||
lockdep_on();
|
lockdep_on();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int __init machine_check_init(void)
|
||||||
* s390_init_machine_check
|
|
||||||
*
|
|
||||||
* initialize machine check handling
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
machine_check_init(void)
|
|
||||||
{
|
{
|
||||||
init_MUTEX_LOCKED(&m_sem);
|
|
||||||
ctl_set_bit(14, 25); /* enable external damage MCH */
|
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
|
#ifdef CONFIG_MACHCHK_WARNING
|
||||||
ctl_set_bit(14, 24); /* enable warning MCH */
|
ctl_set_bit(14, 24); /* enable warning MCH */
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
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);
|
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/processor.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/timer.h>
|
#include <asm/timer.h>
|
||||||
|
#include <asm/nmi.h>
|
||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
|
|
||||||
asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
|
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];
|
return sf->gprs[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void s390_handle_mcck(void);
|
|
||||||
/*
|
/*
|
||||||
* The idle loop on a S390...
|
* The idle loop on a S390...
|
||||||
*/
|
*/
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
|
#include <asm/nmi.h>
|
||||||
#include "kvm-s390.h"
|
#include "kvm-s390.h"
|
||||||
#include "gaccess.h"
|
#include "gaccess.h"
|
||||||
|
|
||||||
@ -440,8 +440,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
|
|||||||
return -EINVAL; /* not implemented yet */
|
return -EINVAL; /* not implemented yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void s390_handle_mcck(void);
|
|
||||||
|
|
||||||
static void __vcpu_run(struct kvm_vcpu *vcpu)
|
static void __vcpu_run(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
|
memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
# Makefile for the S/390 specific device drivers
|
# Makefile for the S/390 specific device drivers
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-y += s390mach.o
|
|
||||||
obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
|
obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
|
||||||
|
|
||||||
drivers-y += drivers/s390/built-in.o
|
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 \
|
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.o device_fsm.o device_ops.o
|
||||||
ccw_device-objs += device_id.o device_pgid.o device_status.o
|
ccw_device-objs += device_id.o device_pgid.o device_status.o
|
||||||
obj-y += ccw_device.o cmf.o
|
obj-y += ccw_device.o cmf.o
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <asm/chpid.h>
|
#include <asm/chpid.h>
|
||||||
#include <asm/sclp.h>
|
#include <asm/sclp.h>
|
||||||
|
#include <asm/crw.h>
|
||||||
|
|
||||||
#include "../s390mach.h"
|
|
||||||
#include "cio.h"
|
#include "cio.h"
|
||||||
#include "css.h"
|
#include "css.h"
|
||||||
#include "ioasm.h"
|
#include "ioasm.h"
|
||||||
@ -706,12 +706,12 @@ static int __init chp_init(void)
|
|||||||
struct chp_id chpid;
|
struct chp_id chpid;
|
||||||
int ret;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
chp_wq = create_singlethread_workqueue("cio_chp");
|
chp_wq = create_singlethread_workqueue("cio_chp");
|
||||||
if (!chp_wq) {
|
if (!chp_wq) {
|
||||||
s390_unregister_crw_handler(CRW_RSC_CPATH);
|
crw_unregister_handler(CRW_RSC_CPATH);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
INIT_WORK(&cfg_work, cfg_func);
|
INIT_WORK(&cfg_work, cfg_func);
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
#include <asm/cio.h>
|
#include <asm/cio.h>
|
||||||
#include <asm/chpid.h>
|
#include <asm/chpid.h>
|
||||||
#include <asm/chsc.h>
|
#include <asm/chsc.h>
|
||||||
|
#include <asm/crw.h>
|
||||||
|
|
||||||
#include "../s390mach.h"
|
|
||||||
#include "css.h"
|
#include "css.h"
|
||||||
#include "cio.h"
|
#include "cio.h"
|
||||||
#include "cio_debug.h"
|
#include "cio_debug.h"
|
||||||
@ -820,7 +820,7 @@ int __init chsc_alloc_sei_area(void)
|
|||||||
"chsc machine checks!\n");
|
"chsc machine checks!\n");
|
||||||
return -ENOMEM;
|
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)
|
if (ret)
|
||||||
kfree(sei_page);
|
kfree(sei_page);
|
||||||
return ret;
|
return ret;
|
||||||
@ -828,7 +828,7 @@ int __init chsc_alloc_sei_area(void)
|
|||||||
|
|
||||||
void __init chsc_free_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);
|
kfree(sei_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include <asm/isc.h>
|
#include <asm/isc.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/fcx.h>
|
#include <asm/fcx.h>
|
||||||
|
#include <asm/nmi.h>
|
||||||
|
#include <asm/crw.h>
|
||||||
#include "cio.h"
|
#include "cio.h"
|
||||||
#include "css.h"
|
#include "css.h"
|
||||||
#include "chsc.h"
|
#include "chsc.h"
|
||||||
@ -38,7 +40,6 @@
|
|||||||
#include "blacklist.h"
|
#include "blacklist.h"
|
||||||
#include "cio_debug.h"
|
#include "cio_debug.h"
|
||||||
#include "chp.h"
|
#include "chp.h"
|
||||||
#include "../s390mach.h"
|
|
||||||
|
|
||||||
debug_info_t *cio_debug_msg_id;
|
debug_info_t *cio_debug_msg_id;
|
||||||
debug_info_t *cio_debug_trace_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/list.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <asm/isc.h>
|
#include <asm/isc.h>
|
||||||
|
#include <asm/crw.h>
|
||||||
|
|
||||||
#include "../s390mach.h"
|
|
||||||
#include "css.h"
|
#include "css.h"
|
||||||
#include "cio.h"
|
#include "cio.h"
|
||||||
#include "cio_debug.h"
|
#include "cio_debug.h"
|
||||||
@ -765,7 +765,7 @@ init_channel_subsystem (void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
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)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -845,7 +845,7 @@ out_unregister:
|
|||||||
out_bus:
|
out_bus:
|
||||||
bus_unregister(&css_bus_type);
|
bus_unregister(&css_bus_type);
|
||||||
out:
|
out:
|
||||||
s390_unregister_crw_handler(CRW_RSC_CSS);
|
crw_unregister_handler(CRW_RSC_CSS);
|
||||||
chsc_free_sei_area();
|
chsc_free_sei_area();
|
||||||
kfree(slow_subchannel_set);
|
kfree(slow_subchannel_set);
|
||||||
pr_alert("The CSS device driver initialization failed with "
|
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 New Issue
Block a user