Commit f5daba1d4116d964435ddd99f32b6c80448a496b

Authored by Heiko Carstens
Committed by Martin Schwidefsky
1 parent 70193af918

[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>

Showing 15 changed files with 677 additions and 676 deletions Side-by-side Diff

arch/s390/include/asm/crw.h
  1 +/*
  2 + * Data definitions for channel report processing
  3 + * Copyright IBM Corp. 2000,2009
  4 + * Author(s): Ingo Adlung <adlung@de.ibm.com>,
  5 + * Martin Schwidefsky <schwidefsky@de.ibm.com>,
  6 + * Cornelia Huck <cornelia.huck@de.ibm.com>,
  7 + * Heiko Carstens <heiko.carstens@de.ibm.com>,
  8 + */
  9 +
  10 +#ifndef _ASM_S390_CRW_H
  11 +#define _ASM_S390_CRW_H
  12 +
  13 +#include <linux/types.h>
  14 +
  15 +/*
  16 + * Channel Report Word
  17 + */
  18 +struct crw {
  19 + __u32 res1 : 1; /* reserved zero */
  20 + __u32 slct : 1; /* solicited */
  21 + __u32 oflw : 1; /* overflow */
  22 + __u32 chn : 1; /* chained */
  23 + __u32 rsc : 4; /* reporting source code */
  24 + __u32 anc : 1; /* ancillary report */
  25 + __u32 res2 : 1; /* reserved zero */
  26 + __u32 erc : 6; /* error-recovery code */
  27 + __u32 rsid : 16; /* reporting-source ID */
  28 +} __attribute__ ((packed));
  29 +
  30 +typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
  31 +
  32 +extern int crw_register_handler(int rsc, crw_handler_t handler);
  33 +extern void crw_unregister_handler(int rsc);
  34 +extern void crw_handle_channel_report(void);
  35 +
  36 +#define NR_RSCS 16
  37 +
  38 +#define CRW_RSC_MONITOR 0x2 /* monitoring facility */
  39 +#define CRW_RSC_SCH 0x3 /* subchannel */
  40 +#define CRW_RSC_CPATH 0x4 /* channel path */
  41 +#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */
  42 +#define CRW_RSC_CSS 0xB /* channel subsystem */
  43 +
  44 +#define CRW_ERC_EVENT 0x00 /* event information pending */
  45 +#define CRW_ERC_AVAIL 0x01 /* available */
  46 +#define CRW_ERC_INIT 0x02 /* initialized */
  47 +#define CRW_ERC_TERROR 0x03 /* temporary error */
  48 +#define CRW_ERC_IPARM 0x04 /* installed parm initialized */
  49 +#define CRW_ERC_TERM 0x05 /* terminal */
  50 +#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */
  51 +#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
  52 +#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
  53 +
  54 +static inline int stcrw(struct crw *pcrw)
  55 +{
  56 + int ccode;
  57 +
  58 + asm volatile(
  59 + " stcrw 0(%2)\n"
  60 + " ipm %0\n"
  61 + " srl %0,28\n"
  62 + : "=d" (ccode), "=m" (*pcrw)
  63 + : "a" (pcrw)
  64 + : "cc" );
  65 + return ccode;
  66 +}
  67 +
  68 +#endif /* _ASM_S390_CRW_H */
arch/s390/include/asm/nmi.h
  1 +/*
  2 + * Machine check handler definitions
  3 + *
  4 + * Copyright IBM Corp. 2000,2009
  5 + * Author(s): Ingo Adlung <adlung@de.ibm.com>,
  6 + * Martin Schwidefsky <schwidefsky@de.ibm.com>,
  7 + * Cornelia Huck <cornelia.huck@de.ibm.com>,
  8 + * Heiko Carstens <heiko.carstens@de.ibm.com>,
  9 + */
  10 +
  11 +#ifndef _ASM_S390_NMI_H
  12 +#define _ASM_S390_NMI_H
  13 +
  14 +#include <linux/types.h>
  15 +
  16 +struct mci {
  17 + __u32 sd : 1; /* 00 system damage */
  18 + __u32 pd : 1; /* 01 instruction-processing damage */
  19 + __u32 sr : 1; /* 02 system recovery */
  20 + __u32 : 1; /* 03 */
  21 + __u32 cd : 1; /* 04 timing-facility damage */
  22 + __u32 ed : 1; /* 05 external damage */
  23 + __u32 : 1; /* 06 */
  24 + __u32 dg : 1; /* 07 degradation */
  25 + __u32 w : 1; /* 08 warning pending */
  26 + __u32 cp : 1; /* 09 channel-report pending */
  27 + __u32 sp : 1; /* 10 service-processor damage */
  28 + __u32 ck : 1; /* 11 channel-subsystem damage */
  29 + __u32 : 2; /* 12-13 */
  30 + __u32 b : 1; /* 14 backed up */
  31 + __u32 : 1; /* 15 */
  32 + __u32 se : 1; /* 16 storage error uncorrected */
  33 + __u32 sc : 1; /* 17 storage error corrected */
  34 + __u32 ke : 1; /* 18 storage-key error uncorrected */
  35 + __u32 ds : 1; /* 19 storage degradation */
  36 + __u32 wp : 1; /* 20 psw mwp validity */
  37 + __u32 ms : 1; /* 21 psw mask and key validity */
  38 + __u32 pm : 1; /* 22 psw program mask and cc validity */
  39 + __u32 ia : 1; /* 23 psw instruction address validity */
  40 + __u32 fa : 1; /* 24 failing storage address validity */
  41 + __u32 : 1; /* 25 */
  42 + __u32 ec : 1; /* 26 external damage code validity */
  43 + __u32 fp : 1; /* 27 floating point register validity */
  44 + __u32 gr : 1; /* 28 general register validity */
  45 + __u32 cr : 1; /* 29 control register validity */
  46 + __u32 : 1; /* 30 */
  47 + __u32 st : 1; /* 31 storage logical validity */
  48 + __u32 ie : 1; /* 32 indirect storage error */
  49 + __u32 ar : 1; /* 33 access register validity */
  50 + __u32 da : 1; /* 34 delayed access exception */
  51 + __u32 : 7; /* 35-41 */
  52 + __u32 pr : 1; /* 42 tod programmable register validity */
  53 + __u32 fc : 1; /* 43 fp control register validity */
  54 + __u32 ap : 1; /* 44 ancillary report */
  55 + __u32 : 1; /* 45 */
  56 + __u32 ct : 1; /* 46 cpu timer validity */
  57 + __u32 cc : 1; /* 47 clock comparator validity */
  58 + __u32 : 16; /* 47-63 */
  59 +};
  60 +
  61 +struct pt_regs;
  62 +
  63 +extern void s390_handle_mcck(void);
  64 +extern void s390_do_machine_check(struct pt_regs *regs);
  65 +
  66 +#endif /* _ASM_S390_NMI_H */
arch/s390/kernel/Makefile
... ... @@ -22,7 +22,7 @@
22 22 obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \
23 23 processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
24 24 s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \
25   - vdso.o vtime.o sysinfo.o
  25 + vdso.o vtime.o sysinfo.o nmi.o
26 26  
27 27 obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
28 28 obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
arch/s390/kernel/nmi.c
  1 +/*
  2 + * Machine check handler
  3 + *
  4 + * Copyright IBM Corp. 2000,2009
  5 + * Author(s): Ingo Adlung <adlung@de.ibm.com>,
  6 + * Martin Schwidefsky <schwidefsky@de.ibm.com>,
  7 + * Cornelia Huck <cornelia.huck@de.ibm.com>,
  8 + * Heiko Carstens <heiko.carstens@de.ibm.com>,
  9 + */
  10 +
  11 +#include <linux/init.h>
  12 +#include <linux/errno.h>
  13 +#include <linux/time.h>
  14 +#include <linux/module.h>
  15 +#include <asm/lowcore.h>
  16 +#include <asm/smp.h>
  17 +#include <asm/etr.h>
  18 +#include <asm/cpu.h>
  19 +#include <asm/nmi.h>
  20 +#include <asm/crw.h>
  21 +
  22 +struct mcck_struct {
  23 + int kill_task;
  24 + int channel_report;
  25 + int warning;
  26 + unsigned long long mcck_code;
  27 +};
  28 +
  29 +static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
  30 +
  31 +static NORET_TYPE void s390_handle_damage(char *msg)
  32 +{
  33 + smp_send_stop();
  34 + disabled_wait((unsigned long) __builtin_return_address(0));
  35 + while (1);
  36 +}
  37 +
  38 +/*
  39 + * Main machine check handler function. Will be called with interrupts enabled
  40 + * or disabled and machine checks enabled or disabled.
  41 + */
  42 +void s390_handle_mcck(void)
  43 +{
  44 + unsigned long flags;
  45 + struct mcck_struct mcck;
  46 +
  47 + /*
  48 + * Disable machine checks and get the current state of accumulated
  49 + * machine checks. Afterwards delete the old state and enable machine
  50 + * checks again.
  51 + */
  52 + local_irq_save(flags);
  53 + local_mcck_disable();
  54 + mcck = __get_cpu_var(cpu_mcck);
  55 + memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct));
  56 + clear_thread_flag(TIF_MCCK_PENDING);
  57 + local_mcck_enable();
  58 + local_irq_restore(flags);
  59 +
  60 + if (mcck.channel_report)
  61 + crw_handle_channel_report();
  62 +
  63 +#ifdef CONFIG_MACHCHK_WARNING
  64 +/*
  65 + * The warning may remain for a prolonged period on the bare iron.
  66 + * (actually till the machine is powered off, or until the problem is gone)
  67 + * So we just stop listening for the WARNING MCH and prevent continuously
  68 + * being interrupted. One caveat is however, that we must do this per
  69 + * processor and cannot use the smp version of ctl_clear_bit().
  70 + * On VM we only get one interrupt per virtally presented machinecheck.
  71 + * Though one suffices, we may get one interrupt per (virtual) processor.
  72 + */
  73 + if (mcck.warning) { /* WARNING pending ? */
  74 + static int mchchk_wng_posted = 0;
  75 + /*
  76 + * Use single machine clear, as we cannot handle smp right now
  77 + */
  78 + __ctl_clear_bit(14, 24); /* Disable WARNING MCH */
  79 + if (xchg(&mchchk_wng_posted, 1) == 0)
  80 + kill_cad_pid(SIGPWR, 1);
  81 + }
  82 +#endif
  83 +
  84 + if (mcck.kill_task) {
  85 + local_irq_enable();
  86 + printk(KERN_EMERG "mcck: Terminating task because of machine "
  87 + "malfunction (code 0x%016llx).\n", mcck.mcck_code);
  88 + printk(KERN_EMERG "mcck: task: %s, pid: %d.\n",
  89 + current->comm, current->pid);
  90 + do_exit(SIGSEGV);
  91 + }
  92 +}
  93 +EXPORT_SYMBOL_GPL(s390_handle_mcck);
  94 +
  95 +/*
  96 + * returns 0 if all registers could be validated
  97 + * returns 1 otherwise
  98 + */
  99 +static int notrace s390_revalidate_registers(struct mci *mci)
  100 +{
  101 + int kill_task;
  102 + u64 tmpclock;
  103 + u64 zero;
  104 + void *fpt_save_area, *fpt_creg_save_area;
  105 +
  106 + kill_task = 0;
  107 + zero = 0;
  108 +
  109 + if (!mci->gr) {
  110 + /*
  111 + * General purpose registers couldn't be restored and have
  112 + * unknown contents. Process needs to be terminated.
  113 + */
  114 + kill_task = 1;
  115 + }
  116 + if (!mci->fp) {
  117 + /*
  118 + * Floating point registers can't be restored and
  119 + * therefore the process needs to be terminated.
  120 + */
  121 + kill_task = 1;
  122 + }
  123 +#ifndef CONFIG_64BIT
  124 + asm volatile(
  125 + " ld 0,0(%0)\n"
  126 + " ld 2,8(%0)\n"
  127 + " ld 4,16(%0)\n"
  128 + " ld 6,24(%0)"
  129 + : : "a" (&S390_lowcore.floating_pt_save_area));
  130 +#endif
  131 +
  132 + if (MACHINE_HAS_IEEE) {
  133 +#ifdef CONFIG_64BIT
  134 + fpt_save_area = &S390_lowcore.floating_pt_save_area;
  135 + fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
  136 +#else
  137 + fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
  138 + fpt_creg_save_area = fpt_save_area + 128;
  139 +#endif
  140 + if (!mci->fc) {
  141 + /*
  142 + * Floating point control register can't be restored.
  143 + * Task will be terminated.
  144 + */
  145 + asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
  146 + kill_task = 1;
  147 +
  148 + } else
  149 + asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area));
  150 +
  151 + asm volatile(
  152 + " ld 0,0(%0)\n"
  153 + " ld 1,8(%0)\n"
  154 + " ld 2,16(%0)\n"
  155 + " ld 3,24(%0)\n"
  156 + " ld 4,32(%0)\n"
  157 + " ld 5,40(%0)\n"
  158 + " ld 6,48(%0)\n"
  159 + " ld 7,56(%0)\n"
  160 + " ld 8,64(%0)\n"
  161 + " ld 9,72(%0)\n"
  162 + " ld 10,80(%0)\n"
  163 + " ld 11,88(%0)\n"
  164 + " ld 12,96(%0)\n"
  165 + " ld 13,104(%0)\n"
  166 + " ld 14,112(%0)\n"
  167 + " ld 15,120(%0)\n"
  168 + : : "a" (fpt_save_area));
  169 + }
  170 + /* Revalidate access registers */
  171 + asm volatile(
  172 + " lam 0,15,0(%0)"
  173 + : : "a" (&S390_lowcore.access_regs_save_area));
  174 + if (!mci->ar) {
  175 + /*
  176 + * Access registers have unknown contents.
  177 + * Terminating task.
  178 + */
  179 + kill_task = 1;
  180 + }
  181 + /* Revalidate control registers */
  182 + if (!mci->cr) {
  183 + /*
  184 + * Control registers have unknown contents.
  185 + * Can't recover and therefore stopping machine.
  186 + */
  187 + s390_handle_damage("invalid control registers.");
  188 + } else {
  189 +#ifdef CONFIG_64BIT
  190 + asm volatile(
  191 + " lctlg 0,15,0(%0)"
  192 + : : "a" (&S390_lowcore.cregs_save_area));
  193 +#else
  194 + asm volatile(
  195 + " lctl 0,15,0(%0)"
  196 + : : "a" (&S390_lowcore.cregs_save_area));
  197 +#endif
  198 + }
  199 + /*
  200 + * We don't even try to revalidate the TOD register, since we simply
  201 + * can't write something sensible into that register.
  202 + */
  203 +#ifdef CONFIG_64BIT
  204 + /*
  205 + * See if we can revalidate the TOD programmable register with its
  206 + * old contents (should be zero) otherwise set it to zero.
  207 + */
  208 + if (!mci->pr)
  209 + asm volatile(
  210 + " sr 0,0\n"
  211 + " sckpf"
  212 + : : : "0", "cc");
  213 + else
  214 + asm volatile(
  215 + " l 0,0(%0)\n"
  216 + " sckpf"
  217 + : : "a" (&S390_lowcore.tod_progreg_save_area)
  218 + : "0", "cc");
  219 +#endif
  220 + /* Revalidate clock comparator register */
  221 + asm volatile(
  222 + " stck 0(%1)\n"
  223 + " sckc 0(%1)"
  224 + : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
  225 +
  226 + /* Check if old PSW is valid */
  227 + if (!mci->wp)
  228 + /*
  229 + * Can't tell if we come from user or kernel mode
  230 + * -> stopping machine.
  231 + */
  232 + s390_handle_damage("old psw invalid.");
  233 +
  234 + if (!mci->ms || !mci->pm || !mci->ia)
  235 + kill_task = 1;
  236 +
  237 + return kill_task;
  238 +}
  239 +
  240 +#define MAX_IPD_COUNT 29
  241 +#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
  242 +
  243 +#define ED_STP_ISLAND 6 /* External damage STP island check */
  244 +#define ED_STP_SYNC 7 /* External damage STP sync check */
  245 +#define ED_ETR_SYNC 12 /* External damage ETR sync check */
  246 +#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
  247 +
  248 +/*
  249 + * machine check handler.
  250 + */
  251 +void notrace s390_do_machine_check(struct pt_regs *regs)
  252 +{
  253 + static int ipd_count;
  254 + static DEFINE_SPINLOCK(ipd_lock);
  255 + static unsigned long long last_ipd;
  256 + struct mcck_struct *mcck;
  257 + unsigned long long tmp;
  258 + struct mci *mci;
  259 + int umode;
  260 +
  261 + lockdep_off();
  262 + s390_idle_check();
  263 +
  264 + mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
  265 + mcck = &__get_cpu_var(cpu_mcck);
  266 + umode = user_mode(regs);
  267 +
  268 + if (mci->sd) {
  269 + /* System damage -> stopping machine */
  270 + s390_handle_damage("received system damage machine check.");
  271 + }
  272 + if (mci->pd) {
  273 + if (mci->b) {
  274 + /* Processing backup -> verify if we can survive this */
  275 + u64 z_mcic, o_mcic, t_mcic;
  276 +#ifdef CONFIG_64BIT
  277 + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29);
  278 + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
  279 + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
  280 + 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 |
  281 + 1ULL<<16);
  282 +#else
  283 + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 |
  284 + 1ULL<<29);
  285 + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
  286 + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
  287 + 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16);
  288 +#endif
  289 + t_mcic = *(u64 *)mci;
  290 +
  291 + if (((t_mcic & z_mcic) != 0) ||
  292 + ((t_mcic & o_mcic) != o_mcic)) {
  293 + s390_handle_damage("processing backup machine "
  294 + "check with damage.");
  295 + }
  296 +
  297 + /*
  298 + * Nullifying exigent condition, therefore we might
  299 + * retry this instruction.
  300 + */
  301 + spin_lock(&ipd_lock);
  302 + tmp = get_clock();
  303 + if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
  304 + ipd_count++;
  305 + else
  306 + ipd_count = 1;
  307 + last_ipd = tmp;
  308 + if (ipd_count == MAX_IPD_COUNT)
  309 + s390_handle_damage("too many ipd retries.");
  310 + spin_unlock(&ipd_lock);
  311 + } else {
  312 + /* Processing damage -> stopping machine */
  313 + s390_handle_damage("received instruction processing "
  314 + "damage machine check.");
  315 + }
  316 + }
  317 + if (s390_revalidate_registers(mci)) {
  318 + if (umode) {
  319 + /*
  320 + * Couldn't restore all register contents while in
  321 + * user mode -> mark task for termination.
  322 + */
  323 + mcck->kill_task = 1;
  324 + mcck->mcck_code = *(unsigned long long *) mci;
  325 + set_thread_flag(TIF_MCCK_PENDING);
  326 + } else {
  327 + /*
  328 + * Couldn't restore all register contents while in
  329 + * kernel mode -> stopping machine.
  330 + */
  331 + s390_handle_damage("unable to revalidate registers.");
  332 + }
  333 + }
  334 + if (mci->cd) {
  335 + /* Timing facility damage */
  336 + s390_handle_damage("TOD clock damaged");
  337 + }
  338 + if (mci->ed && mci->ec) {
  339 + /* External damage */
  340 + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
  341 + etr_sync_check();
  342 + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
  343 + etr_switch_to_local();
  344 + if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC))
  345 + stp_sync_check();
  346 + if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND))
  347 + stp_island_check();
  348 + }
  349 + if (mci->se)
  350 + /* Storage error uncorrected */
  351 + s390_handle_damage("received storage error uncorrected "
  352 + "machine check.");
  353 + if (mci->ke)
  354 + /* Storage key-error uncorrected */
  355 + s390_handle_damage("received storage key-error uncorrected "
  356 + "machine check.");
  357 + if (mci->ds && mci->fa)
  358 + /* Storage degradation */
  359 + s390_handle_damage("received storage degradation machine "
  360 + "check.");
  361 + if (mci->cp) {
  362 + /* Channel report word pending */
  363 + mcck->channel_report = 1;
  364 + set_thread_flag(TIF_MCCK_PENDING);
  365 + }
  366 + if (mci->w) {
  367 + /* Warning pending */
  368 + mcck->warning = 1;
  369 + set_thread_flag(TIF_MCCK_PENDING);
  370 + }
  371 + lockdep_on();
  372 +}
  373 +
  374 +static int __init machine_check_init(void)
  375 +{
  376 + ctl_set_bit(14, 25); /* enable external damage MCH */
  377 + ctl_set_bit(14, 27); /* enable system recovery MCH */
  378 +#ifdef CONFIG_MACHCHK_WARNING
  379 + ctl_set_bit(14, 24); /* enable warning MCH */
  380 +#endif
  381 + return 0;
  382 +}
  383 +arch_initcall(machine_check_init);
arch/s390/kernel/process.c
... ... @@ -39,6 +39,7 @@
39 39 #include <asm/processor.h>
40 40 #include <asm/irq.h>
41 41 #include <asm/timer.h>
  42 +#include <asm/nmi.h>
42 43 #include "entry.h"
43 44  
44 45 asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
... ... @@ -68,7 +69,6 @@
68 69 return sf->gprs[8];
69 70 }
70 71  
71   -extern void s390_handle_mcck(void);
72 72 /*
73 73 * The idle loop on a S390...
74 74 */
arch/s390/kvm/kvm-s390.c
... ... @@ -23,7 +23,7 @@
23 23 #include <linux/timer.h>
24 24 #include <asm/lowcore.h>
25 25 #include <asm/pgtable.h>
26   -
  26 +#include <asm/nmi.h>
27 27 #include "kvm-s390.h"
28 28 #include "gaccess.h"
29 29  
... ... @@ -439,8 +439,6 @@
439 439 {
440 440 return -EINVAL; /* not implemented yet */
441 441 }
442   -
443   -extern void s390_handle_mcck(void);
444 442  
445 443 static void __vcpu_run(struct kvm_vcpu *vcpu)
446 444 {
drivers/s390/Makefile
... ... @@ -2,7 +2,6 @@
2 2 # Makefile for the S/390 specific device drivers
3 3 #
4 4  
5   -obj-y += s390mach.o
6 5 obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
7 6  
8 7 drivers-y += drivers/s390/built-in.o
drivers/s390/cio/Makefile
... ... @@ -3,7 +3,7 @@
3 3 #
4 4  
5 5 obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \
6   - fcx.o itcw.o
  6 + fcx.o itcw.o crw.o
7 7 ccw_device-objs += device.o device_fsm.o device_ops.o
8 8 ccw_device-objs += device_id.o device_pgid.o device_status.o
9 9 obj-y += ccw_device.o cmf.o
drivers/s390/cio/chp.c
... ... @@ -17,8 +17,8 @@
17 17 #include <linux/errno.h>
18 18 #include <asm/chpid.h>
19 19 #include <asm/sclp.h>
  20 +#include <asm/crw.h>
20 21  
21   -#include "../s390mach.h"
22 22 #include "cio.h"
23 23 #include "css.h"
24 24 #include "ioasm.h"
25 25  
... ... @@ -706,12 +706,12 @@
706 706 struct chp_id chpid;
707 707 int ret;
708 708  
709   - ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw);
  709 + ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw);
710 710 if (ret)
711 711 return ret;
712 712 chp_wq = create_singlethread_workqueue("cio_chp");
713 713 if (!chp_wq) {
714   - s390_unregister_crw_handler(CRW_RSC_CPATH);
  714 + crw_unregister_handler(CRW_RSC_CPATH);
715 715 return -ENOMEM;
716 716 }
717 717 INIT_WORK(&cfg_work, cfg_func);
drivers/s390/cio/chsc.c
... ... @@ -19,8 +19,8 @@
19 19 #include <asm/cio.h>
20 20 #include <asm/chpid.h>
21 21 #include <asm/chsc.h>
  22 +#include <asm/crw.h>
22 23  
23   -#include "../s390mach.h"
24 24 #include "css.h"
25 25 #include "cio.h"
26 26 #include "cio_debug.h"
... ... @@ -820,7 +820,7 @@
820 820 "chsc machine checks!\n");
821 821 return -ENOMEM;
822 822 }
823   - ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw);
  823 + ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw);
824 824 if (ret)
825 825 kfree(sei_page);
826 826 return ret;
... ... @@ -828,7 +828,7 @@
828 828  
829 829 void __init chsc_free_sei_area(void)
830 830 {
831   - s390_unregister_crw_handler(CRW_RSC_CSS);
  831 + crw_unregister_handler(CRW_RSC_CSS);
832 832 kfree(sei_page);
833 833 }
834 834  
drivers/s390/cio/cio.c
... ... @@ -30,6 +30,8 @@
30 30 #include <asm/isc.h>
31 31 #include <asm/cpu.h>
32 32 #include <asm/fcx.h>
  33 +#include <asm/nmi.h>
  34 +#include <asm/crw.h>
33 35 #include "cio.h"
34 36 #include "css.h"
35 37 #include "chsc.h"
... ... @@ -38,7 +40,6 @@
38 40 #include "blacklist.h"
39 41 #include "cio_debug.h"
40 42 #include "chp.h"
41   -#include "../s390mach.h"
42 43  
43 44 debug_info_t *cio_debug_msg_id;
44 45 debug_info_t *cio_debug_trace_id;
drivers/s390/cio/crw.c
  1 +/*
  2 + * Channel report handling code
  3 + *
  4 + * Copyright IBM Corp. 2000,2009
  5 + * Author(s): Ingo Adlung <adlung@de.ibm.com>,
  6 + * Martin Schwidefsky <schwidefsky@de.ibm.com>,
  7 + * Cornelia Huck <cornelia.huck@de.ibm.com>,
  8 + * Heiko Carstens <heiko.carstens@de.ibm.com>,
  9 + */
  10 +
  11 +#include <linux/semaphore.h>
  12 +#include <linux/kthread.h>
  13 +#include <linux/init.h>
  14 +#include <asm/crw.h>
  15 +
  16 +static struct semaphore crw_semaphore;
  17 +static crw_handler_t crw_handlers[NR_RSCS];
  18 +
  19 +/**
  20 + * crw_register_handler() - register a channel report word handler
  21 + * @rsc: reporting source code to handle
  22 + * @handler: handler to be registered
  23 + *
  24 + * Returns %0 on success and a negative error value otherwise.
  25 + */
  26 +int crw_register_handler(int rsc, crw_handler_t handler)
  27 +{
  28 + if ((rsc < 0) || (rsc >= NR_RSCS))
  29 + return -EINVAL;
  30 + if (!cmpxchg(&crw_handlers[rsc], NULL, handler))
  31 + return 0;
  32 + return -EBUSY;
  33 +}
  34 +
  35 +/**
  36 + * crw_unregister_handler() - unregister a channel report word handler
  37 + * @rsc: reporting source code to handle
  38 + */
  39 +void crw_unregister_handler(int rsc)
  40 +{
  41 + if ((rsc < 0) || (rsc >= NR_RSCS))
  42 + return;
  43 + xchg(&crw_handlers[rsc], NULL);
  44 + synchronize_sched();
  45 +}
  46 +
  47 +/*
  48 + * Retrieve CRWs and call function to handle event.
  49 + */
  50 +static int crw_collect_info(void *unused)
  51 +{
  52 + struct crw crw[2];
  53 + int ccode;
  54 + unsigned int chain;
  55 + int ignore;
  56 +
  57 +repeat:
  58 + ignore = down_interruptible(&crw_semaphore);
  59 + chain = 0;
  60 + while (1) {
  61 + if (unlikely(chain > 1)) {
  62 + struct crw tmp_crw;
  63 +
  64 + printk(KERN_WARNING"%s: Code does not support more "
  65 + "than two chained crws; please report to "
  66 + "linux390@de.ibm.com!\n", __func__);
  67 + ccode = stcrw(&tmp_crw);
  68 + printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
  69 + "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
  70 + __func__, tmp_crw.slct, tmp_crw.oflw,
  71 + tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
  72 + tmp_crw.erc, tmp_crw.rsid);
  73 + printk(KERN_WARNING"%s: This was crw number %x in the "
  74 + "chain\n", __func__, chain);
  75 + if (ccode != 0)
  76 + break;
  77 + chain = tmp_crw.chn ? chain + 1 : 0;
  78 + continue;
  79 + }
  80 + ccode = stcrw(&crw[chain]);
  81 + if (ccode != 0)
  82 + break;
  83 + printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
  84 + "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
  85 + crw[chain].slct, crw[chain].oflw, crw[chain].chn,
  86 + crw[chain].rsc, crw[chain].anc, crw[chain].erc,
  87 + crw[chain].rsid);
  88 + /* Check for overflows. */
  89 + if (crw[chain].oflw) {
  90 + int i;
  91 +
  92 + pr_debug("%s: crw overflow detected!\n", __func__);
  93 + for (i = 0; i < NR_RSCS; i++) {
  94 + if (crw_handlers[i])
  95 + crw_handlers[i](NULL, NULL, 1);
  96 + }
  97 + chain = 0;
  98 + continue;
  99 + }
  100 + if (crw[0].chn && !chain) {
  101 + chain++;
  102 + continue;
  103 + }
  104 + if (crw_handlers[crw[chain].rsc])
  105 + crw_handlers[crw[chain].rsc](&crw[0],
  106 + chain ? &crw[1] : NULL,
  107 + 0);
  108 + /* chain is always 0 or 1 here. */
  109 + chain = crw[chain].chn ? chain + 1 : 0;
  110 + }
  111 + goto repeat;
  112 + return 0;
  113 +}
  114 +
  115 +void crw_handle_channel_report(void)
  116 +{
  117 + up(&crw_semaphore);
  118 +}
  119 +
  120 +/*
  121 + * Separate initcall needed for semaphore initialization since
  122 + * crw_handle_channel_report might be called before crw_machine_check_init.
  123 + */
  124 +static int __init crw_init_semaphore(void)
  125 +{
  126 + init_MUTEX_LOCKED(&crw_semaphore);
  127 + return 0;
  128 +}
  129 +pure_initcall(crw_init_semaphore);
  130 +
  131 +/*
  132 + * Machine checks for the channel subsystem must be enabled
  133 + * after the channel subsystem is initialized
  134 + */
  135 +static int __init crw_machine_check_init(void)
  136 +{
  137 + struct task_struct *task;
  138 +
  139 + task = kthread_run(crw_collect_info, NULL, "kmcheck");
  140 + if (IS_ERR(task))
  141 + return PTR_ERR(task);
  142 + ctl_set_bit(14, 28); /* enable channel report MCH */
  143 + return 0;
  144 +}
  145 +device_initcall(crw_machine_check_init);
drivers/s390/cio/css.c
... ... @@ -18,8 +18,8 @@
18 18 #include <linux/list.h>
19 19 #include <linux/reboot.h>
20 20 #include <asm/isc.h>
  21 +#include <asm/crw.h>
21 22  
22   -#include "../s390mach.h"
23 23 #include "css.h"
24 24 #include "cio.h"
25 25 #include "cio_debug.h"
... ... @@ -765,7 +765,7 @@
765 765 if (ret)
766 766 goto out;
767 767  
768   - ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw);
  768 + ret = crw_register_handler(CRW_RSC_SCH, css_process_crw);
769 769 if (ret)
770 770 goto out;
771 771  
... ... @@ -845,7 +845,7 @@
845 845 out_bus:
846 846 bus_unregister(&css_bus_type);
847 847 out:
848   - s390_unregister_crw_handler(CRW_RSC_CSS);
  848 + crw_unregister_handler(CRW_RSC_CSS);
849 849 chsc_free_sei_area();
850 850 kfree(slow_subchannel_set);
851 851 pr_alert("The CSS device driver initialization failed with "
drivers/s390/s390mach.c
1   -/*
2   - * drivers/s390/s390mach.c
3   - * S/390 machine check handler
4   - *
5   - * Copyright IBM Corp. 2000,2008
6   - * Author(s): Ingo Adlung (adlung@de.ibm.com)
7   - * Martin Schwidefsky (schwidefsky@de.ibm.com)
8   - * Cornelia Huck <cornelia.huck@de.ibm.com>
9   - */
10   -
11   -#include <linux/init.h>
12   -#include <linux/sched.h>
13   -#include <linux/errno.h>
14   -#include <linux/workqueue.h>
15   -#include <linux/time.h>
16   -#include <linux/device.h>
17   -#include <linux/kthread.h>
18   -#include <asm/etr.h>
19   -#include <asm/lowcore.h>
20   -#include <asm/cio.h>
21   -#include <asm/cpu.h>
22   -#include "s390mach.h"
23   -
24   -static struct semaphore m_sem;
25   -
26   -static NORET_TYPE void
27   -s390_handle_damage(char *msg)
28   -{
29   -#ifdef CONFIG_SMP
30   - smp_send_stop();
31   -#endif
32   - disabled_wait((unsigned long) __builtin_return_address(0));
33   - for(;;);
34   -}
35   -
36   -static crw_handler_t crw_handlers[NR_RSCS];
37   -
38   -/**
39   - * s390_register_crw_handler() - register a channel report word handler
40   - * @rsc: reporting source code to handle
41   - * @handler: handler to be registered
42   - *
43   - * Returns %0 on success and a negative error value otherwise.
44   - */
45   -int s390_register_crw_handler(int rsc, crw_handler_t handler)
46   -{
47   - if ((rsc < 0) || (rsc >= NR_RSCS))
48   - return -EINVAL;
49   - if (!cmpxchg(&crw_handlers[rsc], NULL, handler))
50   - return 0;
51   - return -EBUSY;
52   -}
53   -
54   -/**
55   - * s390_unregister_crw_handler() - unregister a channel report word handler
56   - * @rsc: reporting source code to handle
57   - */
58   -void s390_unregister_crw_handler(int rsc)
59   -{
60   - if ((rsc < 0) || (rsc >= NR_RSCS))
61   - return;
62   - xchg(&crw_handlers[rsc], NULL);
63   - synchronize_sched();
64   -}
65   -
66   -/*
67   - * Retrieve CRWs and call function to handle event.
68   - */
69   -static int s390_collect_crw_info(void *param)
70   -{
71   - struct crw crw[2];
72   - int ccode;
73   - struct semaphore *sem;
74   - unsigned int chain;
75   - int ignore;
76   -
77   - sem = (struct semaphore *)param;
78   -repeat:
79   - ignore = down_interruptible(sem);
80   - chain = 0;
81   - while (1) {
82   - if (unlikely(chain > 1)) {
83   - struct crw tmp_crw;
84   -
85   - printk(KERN_WARNING"%s: Code does not support more "
86   - "than two chained crws; please report to "
87   - "linux390@de.ibm.com!\n", __func__);
88   - ccode = stcrw(&tmp_crw);
89   - printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
90   - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
91   - __func__, tmp_crw.slct, tmp_crw.oflw,
92   - tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
93   - tmp_crw.erc, tmp_crw.rsid);
94   - printk(KERN_WARNING"%s: This was crw number %x in the "
95   - "chain\n", __func__, chain);
96   - if (ccode != 0)
97   - break;
98   - chain = tmp_crw.chn ? chain + 1 : 0;
99   - continue;
100   - }
101   - ccode = stcrw(&crw[chain]);
102   - if (ccode != 0)
103   - break;
104   - printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
105   - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
106   - crw[chain].slct, crw[chain].oflw, crw[chain].chn,
107   - crw[chain].rsc, crw[chain].anc, crw[chain].erc,
108   - crw[chain].rsid);
109   - /* Check for overflows. */
110   - if (crw[chain].oflw) {
111   - int i;
112   -
113   - pr_debug("%s: crw overflow detected!\n", __func__);
114   - for (i = 0; i < NR_RSCS; i++) {
115   - if (crw_handlers[i])
116   - crw_handlers[i](NULL, NULL, 1);
117   - }
118   - chain = 0;
119   - continue;
120   - }
121   - if (crw[0].chn && !chain) {
122   - chain++;
123   - continue;
124   - }
125   - if (crw_handlers[crw[chain].rsc])
126   - crw_handlers[crw[chain].rsc](&crw[0],
127   - chain ? &crw[1] : NULL,
128   - 0);
129   - /* chain is always 0 or 1 here. */
130   - chain = crw[chain].chn ? chain + 1 : 0;
131   - }
132   - goto repeat;
133   - return 0;
134   -}
135   -
136   -struct mcck_struct {
137   - int kill_task;
138   - int channel_report;
139   - int warning;
140   - unsigned long long mcck_code;
141   -};
142   -
143   -static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
144   -
145   -/*
146   - * Main machine check handler function. Will be called with interrupts enabled
147   - * or disabled and machine checks enabled or disabled.
148   - */
149   -void
150   -s390_handle_mcck(void)
151   -{
152   - unsigned long flags;
153   - struct mcck_struct mcck;
154   -
155   - /*
156   - * Disable machine checks and get the current state of accumulated
157   - * machine checks. Afterwards delete the old state and enable machine
158   - * checks again.
159   - */
160   - local_irq_save(flags);
161   - local_mcck_disable();
162   - mcck = __get_cpu_var(cpu_mcck);
163   - memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct));
164   - clear_thread_flag(TIF_MCCK_PENDING);
165   - local_mcck_enable();
166   - local_irq_restore(flags);
167   -
168   - if (mcck.channel_report)
169   - up(&m_sem);
170   -
171   -#ifdef CONFIG_MACHCHK_WARNING
172   -/*
173   - * The warning may remain for a prolonged period on the bare iron.
174   - * (actually till the machine is powered off, or until the problem is gone)
175   - * So we just stop listening for the WARNING MCH and prevent continuously
176   - * being interrupted. One caveat is however, that we must do this per
177   - * processor and cannot use the smp version of ctl_clear_bit().
178   - * On VM we only get one interrupt per virtally presented machinecheck.
179   - * Though one suffices, we may get one interrupt per (virtual) processor.
180   - */
181   - if (mcck.warning) { /* WARNING pending ? */
182   - static int mchchk_wng_posted = 0;
183   - /*
184   - * Use single machine clear, as we cannot handle smp right now
185   - */
186   - __ctl_clear_bit(14, 24); /* Disable WARNING MCH */
187   - if (xchg(&mchchk_wng_posted, 1) == 0)
188   - kill_cad_pid(SIGPWR, 1);
189   - }
190   -#endif
191   -
192   - if (mcck.kill_task) {
193   - local_irq_enable();
194   - printk(KERN_EMERG "mcck: Terminating task because of machine "
195   - "malfunction (code 0x%016llx).\n", mcck.mcck_code);
196   - printk(KERN_EMERG "mcck: task: %s, pid: %d.\n",
197   - current->comm, current->pid);
198   - do_exit(SIGSEGV);
199   - }
200   -}
201   -EXPORT_SYMBOL_GPL(s390_handle_mcck);
202   -
203   -/*
204   - * returns 0 if all registers could be validated
205   - * returns 1 otherwise
206   - */
207   -static int
208   -s390_revalidate_registers(struct mci *mci)
209   -{
210   - int kill_task;
211   - u64 tmpclock;
212   - u64 zero;
213   - void *fpt_save_area, *fpt_creg_save_area;
214   -
215   - kill_task = 0;
216   - zero = 0;
217   - /* General purpose registers */
218   - if (!mci->gr)
219   - /*
220   - * General purpose registers couldn't be restored and have
221   - * unknown contents. Process needs to be terminated.
222   - */
223   - kill_task = 1;
224   -
225   - /* Revalidate floating point registers */
226   - if (!mci->fp)
227   - /*
228   - * Floating point registers can't be restored and
229   - * therefore the process needs to be terminated.
230   - */
231   - kill_task = 1;
232   -
233   -#ifndef CONFIG_64BIT
234   - asm volatile(
235   - " ld 0,0(%0)\n"
236   - " ld 2,8(%0)\n"
237   - " ld 4,16(%0)\n"
238   - " ld 6,24(%0)"
239   - : : "a" (&S390_lowcore.floating_pt_save_area));
240   -#endif
241   -
242   - if (MACHINE_HAS_IEEE) {
243   -#ifdef CONFIG_64BIT
244   - fpt_save_area = &S390_lowcore.floating_pt_save_area;
245   - fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
246   -#else
247   - fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
248   - fpt_creg_save_area = fpt_save_area+128;
249   -#endif
250   - /* Floating point control register */
251   - if (!mci->fc) {
252   - /*
253   - * Floating point control register can't be restored.
254   - * Task will be terminated.
255   - */
256   - asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
257   - kill_task = 1;
258   -
259   - } else
260   - asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area));
261   -
262   - asm volatile(
263   - " ld 0,0(%0)\n"
264   - " ld 1,8(%0)\n"
265   - " ld 2,16(%0)\n"
266   - " ld 3,24(%0)\n"
267   - " ld 4,32(%0)\n"
268   - " ld 5,40(%0)\n"
269   - " ld 6,48(%0)\n"
270   - " ld 7,56(%0)\n"
271   - " ld 8,64(%0)\n"
272   - " ld 9,72(%0)\n"
273   - " ld 10,80(%0)\n"
274   - " ld 11,88(%0)\n"
275   - " ld 12,96(%0)\n"
276   - " ld 13,104(%0)\n"
277   - " ld 14,112(%0)\n"
278   - " ld 15,120(%0)\n"
279   - : : "a" (fpt_save_area));
280   - }
281   -
282   - /* Revalidate access registers */
283   - asm volatile(
284   - " lam 0,15,0(%0)"
285   - : : "a" (&S390_lowcore.access_regs_save_area));
286   - if (!mci->ar)
287   - /*
288   - * Access registers have unknown contents.
289   - * Terminating task.
290   - */
291   - kill_task = 1;
292   -
293   - /* Revalidate control registers */
294   - if (!mci->cr)
295   - /*
296   - * Control registers have unknown contents.
297   - * Can't recover and therefore stopping machine.
298   - */
299   - s390_handle_damage("invalid control registers.");
300   - else
301   -#ifdef CONFIG_64BIT
302   - asm volatile(
303   - " lctlg 0,15,0(%0)"
304   - : : "a" (&S390_lowcore.cregs_save_area));
305   -#else
306   - asm volatile(
307   - " lctl 0,15,0(%0)"
308   - : : "a" (&S390_lowcore.cregs_save_area));
309   -#endif
310   -
311   - /*
312   - * We don't even try to revalidate the TOD register, since we simply
313   - * can't write something sensible into that register.
314   - */
315   -
316   -#ifdef CONFIG_64BIT
317   - /*
318   - * See if we can revalidate the TOD programmable register with its
319   - * old contents (should be zero) otherwise set it to zero.
320   - */
321   - if (!mci->pr)
322   - asm volatile(
323   - " sr 0,0\n"
324   - " sckpf"
325   - : : : "0", "cc");
326   - else
327   - asm volatile(
328   - " l 0,0(%0)\n"
329   - " sckpf"
330   - : : "a" (&S390_lowcore.tod_progreg_save_area)
331   - : "0", "cc");
332   -#endif
333   -
334   - /* Revalidate clock comparator register */
335   - asm volatile(
336   - " stck 0(%1)\n"
337   - " sckc 0(%1)"
338   - : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
339   -
340   - /* Check if old PSW is valid */
341   - if (!mci->wp)
342   - /*
343   - * Can't tell if we come from user or kernel mode
344   - * -> stopping machine.
345   - */
346   - s390_handle_damage("old psw invalid.");
347   -
348   - if (!mci->ms || !mci->pm || !mci->ia)
349   - kill_task = 1;
350   -
351   - return kill_task;
352   -}
353   -
354   -#define MAX_IPD_COUNT 29
355   -#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
356   -
357   -/*
358   - * machine check handler.
359   - */
360   -void notrace s390_do_machine_check(struct pt_regs *regs)
361   -{
362   - static DEFINE_SPINLOCK(ipd_lock);
363   - static unsigned long long last_ipd;
364   - static int ipd_count;
365   - unsigned long long tmp;
366   - struct mci *mci;
367   - struct mcck_struct *mcck;
368   - int umode;
369   -
370   - lockdep_off();
371   -
372   - s390_idle_check();
373   -
374   - mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
375   - mcck = &__get_cpu_var(cpu_mcck);
376   - umode = user_mode(regs);
377   -
378   - if (mci->sd)
379   - /* System damage -> stopping machine */
380   - s390_handle_damage("received system damage machine check.");
381   -
382   - if (mci->pd) {
383   - if (mci->b) {
384   - /* Processing backup -> verify if we can survive this */
385   - u64 z_mcic, o_mcic, t_mcic;
386   -#ifdef CONFIG_64BIT
387   - z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29);
388   - o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
389   - 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
390   - 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 |
391   - 1ULL<<16);
392   -#else
393   - z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 |
394   - 1ULL<<29);
395   - o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
396   - 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
397   - 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16);
398   -#endif
399   - t_mcic = *(u64 *)mci;
400   -
401   - if (((t_mcic & z_mcic) != 0) ||
402   - ((t_mcic & o_mcic) != o_mcic)) {
403   - s390_handle_damage("processing backup machine "
404   - "check with damage.");
405   - }
406   -
407   - /*
408   - * Nullifying exigent condition, therefore we might
409   - * retry this instruction.
410   - */
411   -
412   - spin_lock(&ipd_lock);
413   -
414   - tmp = get_clock();
415   -
416   - if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
417   - ipd_count++;
418   - else
419   - ipd_count = 1;
420   -
421   - last_ipd = tmp;
422   -
423   - if (ipd_count == MAX_IPD_COUNT)
424   - s390_handle_damage("too many ipd retries.");
425   -
426   - spin_unlock(&ipd_lock);
427   - }
428   - else {
429   - /* Processing damage -> stopping machine */
430   - s390_handle_damage("received instruction processing "
431   - "damage machine check.");
432   - }
433   - }
434   - if (s390_revalidate_registers(mci)) {
435   - if (umode) {
436   - /*
437   - * Couldn't restore all register contents while in
438   - * user mode -> mark task for termination.
439   - */
440   - mcck->kill_task = 1;
441   - mcck->mcck_code = *(unsigned long long *) mci;
442   - set_thread_flag(TIF_MCCK_PENDING);
443   - }
444   - else
445   - /*
446   - * Couldn't restore all register contents while in
447   - * kernel mode -> stopping machine.
448   - */
449   - s390_handle_damage("unable to revalidate registers.");
450   - }
451   -
452   - if (mci->cd) {
453   - /* Timing facility damage */
454   - s390_handle_damage("TOD clock damaged");
455   - }
456   -
457   - if (mci->ed && mci->ec) {
458   - /* External damage */
459   - if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
460   - etr_sync_check();
461   - if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
462   - etr_switch_to_local();
463   - if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC))
464   - stp_sync_check();
465   - if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND))
466   - stp_island_check();
467   - }
468   -
469   - if (mci->se)
470   - /* Storage error uncorrected */
471   - s390_handle_damage("received storage error uncorrected "
472   - "machine check.");
473   -
474   - if (mci->ke)
475   - /* Storage key-error uncorrected */
476   - s390_handle_damage("received storage key-error uncorrected "
477   - "machine check.");
478   -
479   - if (mci->ds && mci->fa)
480   - /* Storage degradation */
481   - s390_handle_damage("received storage degradation machine "
482   - "check.");
483   -
484   - if (mci->cp) {
485   - /* Channel report word pending */
486   - mcck->channel_report = 1;
487   - set_thread_flag(TIF_MCCK_PENDING);
488   - }
489   -
490   - if (mci->w) {
491   - /* Warning pending */
492   - mcck->warning = 1;
493   - set_thread_flag(TIF_MCCK_PENDING);
494   - }
495   - lockdep_on();
496   -}
497   -
498   -/*
499   - * s390_init_machine_check
500   - *
501   - * initialize machine check handling
502   - */
503   -static int
504   -machine_check_init(void)
505   -{
506   - init_MUTEX_LOCKED(&m_sem);
507   - ctl_set_bit(14, 25); /* enable external damage MCH */
508   - ctl_set_bit(14, 27); /* enable system recovery MCH */
509   -#ifdef CONFIG_MACHCHK_WARNING
510   - ctl_set_bit(14, 24); /* enable warning MCH */
511   -#endif
512   - return 0;
513   -}
514   -
515   -/*
516   - * Initialize the machine check handler really early to be able to
517   - * catch all machine checks that happen during boot
518   - */
519   -arch_initcall(machine_check_init);
520   -
521   -/*
522   - * Machine checks for the channel subsystem must be enabled
523   - * after the channel subsystem is initialized
524   - */
525   -static int __init
526   -machine_check_crw_init (void)
527   -{
528   - struct task_struct *task;
529   -
530   - task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
531   - if (IS_ERR(task))
532   - return PTR_ERR(task);
533   - ctl_set_bit(14, 28); /* enable channel report MCH */
534   - return 0;
535   -}
536   -
537   -device_initcall (machine_check_crw_init);
drivers/s390/s390mach.h
1   -/*
2   - * drivers/s390/s390mach.h
3   - * S/390 data definitions for machine check processing
4   - *
5   - * S390 version
6   - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
7   - * Author(s): Ingo Adlung (adlung@de.ibm.com)
8   - */
9   -
10   -#ifndef __s390mach_h
11   -#define __s390mach_h
12   -
13   -#include <asm/types.h>
14   -
15   -struct mci {
16   - __u32 sd : 1; /* 00 system damage */
17   - __u32 pd : 1; /* 01 instruction-processing damage */
18   - __u32 sr : 1; /* 02 system recovery */
19   - __u32 to_be_defined_1 : 1; /* 03 */
20   - __u32 cd : 1; /* 04 timing-facility damage */
21   - __u32 ed : 1; /* 05 external damage */
22   - __u32 to_be_defined_2 : 1; /* 06 */
23   - __u32 dg : 1; /* 07 degradation */
24   - __u32 w : 1; /* 08 warning pending */
25   - __u32 cp : 1; /* 09 channel-report pending */
26   - __u32 sp : 1; /* 10 service-processor damage */
27   - __u32 ck : 1; /* 11 channel-subsystem damage */
28   - __u32 to_be_defined_3 : 2; /* 12-13 */
29   - __u32 b : 1; /* 14 backed up */
30   - __u32 to_be_defined_4 : 1; /* 15 */
31   - __u32 se : 1; /* 16 storage error uncorrected */
32   - __u32 sc : 1; /* 17 storage error corrected */
33   - __u32 ke : 1; /* 18 storage-key error uncorrected */
34   - __u32 ds : 1; /* 19 storage degradation */
35   - __u32 wp : 1; /* 20 psw mwp validity */
36   - __u32 ms : 1; /* 21 psw mask and key validity */
37   - __u32 pm : 1; /* 22 psw program mask and cc validity */
38   - __u32 ia : 1; /* 23 psw instruction address validity */
39   - __u32 fa : 1; /* 24 failing storage address validity */
40   - __u32 to_be_defined_5 : 1; /* 25 */
41   - __u32 ec : 1; /* 26 external damage code validity */
42   - __u32 fp : 1; /* 27 floating point register validity */
43   - __u32 gr : 1; /* 28 general register validity */
44   - __u32 cr : 1; /* 29 control register validity */
45   - __u32 to_be_defined_6 : 1; /* 30 */
46   - __u32 st : 1; /* 31 storage logical validity */
47   - __u32 ie : 1; /* 32 indirect storage error */
48   - __u32 ar : 1; /* 33 access register validity */
49   - __u32 da : 1; /* 34 delayed access exception */
50   - __u32 to_be_defined_7 : 7; /* 35-41 */
51   - __u32 pr : 1; /* 42 tod programmable register validity */
52   - __u32 fc : 1; /* 43 fp control register validity */
53   - __u32 ap : 1; /* 44 ancillary report */
54   - __u32 to_be_defined_8 : 1; /* 45 */
55   - __u32 ct : 1; /* 46 cpu timer validity */
56   - __u32 cc : 1; /* 47 clock comparator validity */
57   - __u32 to_be_defined_9 : 16; /* 47-63 */
58   -};
59   -
60   -/*
61   - * Channel Report Word
62   - */
63   -struct crw {
64   - __u32 res1 : 1; /* reserved zero */
65   - __u32 slct : 1; /* solicited */
66   - __u32 oflw : 1; /* overflow */
67   - __u32 chn : 1; /* chained */
68   - __u32 rsc : 4; /* reporting source code */
69   - __u32 anc : 1; /* ancillary report */
70   - __u32 res2 : 1; /* reserved zero */
71   - __u32 erc : 6; /* error-recovery code */
72   - __u32 rsid : 16; /* reporting-source ID */
73   -} __attribute__ ((packed));
74   -
75   -typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
76   -
77   -extern int s390_register_crw_handler(int rsc, crw_handler_t handler);
78   -extern void s390_unregister_crw_handler(int rsc);
79   -
80   -#define NR_RSCS 16
81   -
82   -#define CRW_RSC_MONITOR 0x2 /* monitoring facility */
83   -#define CRW_RSC_SCH 0x3 /* subchannel */
84   -#define CRW_RSC_CPATH 0x4 /* channel path */
85   -#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */
86   -#define CRW_RSC_CSS 0xB /* channel subsystem */
87   -
88   -#define CRW_ERC_EVENT 0x00 /* event information pending */
89   -#define CRW_ERC_AVAIL 0x01 /* available */
90   -#define CRW_ERC_INIT 0x02 /* initialized */
91   -#define CRW_ERC_TERROR 0x03 /* temporary error */
92   -#define CRW_ERC_IPARM 0x04 /* installed parm initialized */
93   -#define CRW_ERC_TERM 0x05 /* terminal */
94   -#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */
95   -#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
96   -#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
97   -
98   -static inline int stcrw(struct crw *pcrw )
99   -{
100   - int ccode;
101   -
102   - __asm__ __volatile__(
103   - "stcrw 0(%2)\n\t"
104   - "ipm %0\n\t"
105   - "srl %0,28\n\t"
106   - : "=d" (ccode), "=m" (*pcrw)
107   - : "a" (pcrw)
108   - : "cc" );
109   - return ccode;
110   -}
111   -
112   -#define ED_ETR_SYNC 12 /* External damage ETR sync check */
113   -#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
114   -
115   -#define ED_STP_SYNC 7 /* External damage STP sync check */
116   -#define ED_STP_ISLAND 6 /* External damage STP island check */
117   -
118   -struct pt_regs;
119   -
120   -void s390_handle_mcck(void);
121   -void s390_do_machine_check(struct pt_regs *regs);
122   -#endif /* __s390mach */