[S390] split/move machine check handler code
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Thu, 26 Mar 2009 14:24:01 +0000 (15:24 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 26 Mar 2009 14:24:10 +0000 (15:24 +0100)
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>
14 files changed:
arch/s390/include/asm/crw.h [new file with mode: 0644]
arch/s390/include/asm/nmi.h [new file with mode: 0644]
arch/s390/kernel/Makefile
arch/s390/kernel/nmi.c [moved from drivers/s390/s390mach.c with 67% similarity]
arch/s390/kernel/process.c
arch/s390/kvm/kvm-s390.c
drivers/s390/Makefile
drivers/s390/cio/Makefile
drivers/s390/cio/chp.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cio.c
drivers/s390/cio/crw.c [new file with mode: 0644]
drivers/s390/cio/css.c
drivers/s390/s390mach.h [deleted file]

diff --git a/arch/s390/include/asm/crw.h b/arch/s390/include/asm/crw.h
new file mode 100644 (file)
index 0000000..2185a6d
--- /dev/null
@@ -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 */
diff --git a/arch/s390/include/asm/nmi.h b/arch/s390/include/asm/nmi.h
new file mode 100644 (file)
index 0000000..f4b6044
--- /dev/null
@@ -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 */
index 33e7aee..228e310 100644 (file)
@@ -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)
similarity index 67%
rename from drivers/s390/s390mach.c
rename to arch/s390/kernel/nmi.c
index 8e43705..8d50eaf 100644 (file)
 /*
- *  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);
index e6b4806..bd616fb 100644 (file)
@@ -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...
  */
index c55a4b9..caa4d28 100644 (file)
@@ -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);
index 0828dc8..95bccfd 100644 (file)
@@ -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
index bd79bd1..adb3dd3 100644 (file)
@@ -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
index 1246f61..3e5f304 100644 (file)
@@ -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);
index ebab6ea..7399b07 100644 (file)
@@ -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);
 }
 
index 659f8a7..73135c5 100644 (file)
@@ -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;
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
new file mode 100644 (file)
index 0000000..508f88f
--- /dev/null
@@ -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);
index 8019288..a5fc563 100644 (file)
@@ -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 "
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
deleted file mode 100644 (file)
index d39f8b6..0000000
+++ /dev/null
@@ -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 */