0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/mutex.h>
0012 #include <linux/kthread.h>
0013 #include <linux/init.h>
0014 #include <linux/wait.h>
0015 #include <asm/crw.h>
0016 #include <asm/ctl_reg.h>
0017 #include "ioasm.h"
0018
0019 static DEFINE_MUTEX(crw_handler_mutex);
0020 static crw_handler_t crw_handlers[NR_RSCS];
0021 static atomic_t crw_nr_req = ATOMIC_INIT(0);
0022 static DECLARE_WAIT_QUEUE_HEAD(crw_handler_wait_q);
0023
0024
0025
0026
0027
0028
0029
0030
0031 int crw_register_handler(int rsc, crw_handler_t handler)
0032 {
0033 int rc = 0;
0034
0035 if ((rsc < 0) || (rsc >= NR_RSCS))
0036 return -EINVAL;
0037 mutex_lock(&crw_handler_mutex);
0038 if (crw_handlers[rsc])
0039 rc = -EBUSY;
0040 else
0041 crw_handlers[rsc] = handler;
0042 mutex_unlock(&crw_handler_mutex);
0043 return rc;
0044 }
0045
0046
0047
0048
0049
0050 void crw_unregister_handler(int rsc)
0051 {
0052 if ((rsc < 0) || (rsc >= NR_RSCS))
0053 return;
0054 mutex_lock(&crw_handler_mutex);
0055 crw_handlers[rsc] = NULL;
0056 mutex_unlock(&crw_handler_mutex);
0057 }
0058
0059
0060
0061
0062 static int crw_collect_info(void *unused)
0063 {
0064 struct crw crw[2];
0065 int ccode, signal;
0066 unsigned int chain;
0067
0068 repeat:
0069 signal = wait_event_interruptible(crw_handler_wait_q,
0070 atomic_read(&crw_nr_req) > 0);
0071 if (unlikely(signal))
0072 atomic_inc(&crw_nr_req);
0073 chain = 0;
0074 while (1) {
0075 crw_handler_t handler;
0076
0077 if (unlikely(chain > 1)) {
0078 struct crw tmp_crw;
0079
0080 printk(KERN_WARNING"%s: Code does not support more "
0081 "than two chained crws; please report to "
0082 "linux390@de.ibm.com!\n", __func__);
0083 ccode = stcrw(&tmp_crw);
0084 printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
0085 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
0086 __func__, tmp_crw.slct, tmp_crw.oflw,
0087 tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
0088 tmp_crw.erc, tmp_crw.rsid);
0089 printk(KERN_WARNING"%s: This was crw number %x in the "
0090 "chain\n", __func__, chain);
0091 if (ccode != 0)
0092 break;
0093 chain = tmp_crw.chn ? chain + 1 : 0;
0094 continue;
0095 }
0096 ccode = stcrw(&crw[chain]);
0097 if (ccode != 0)
0098 break;
0099 printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
0100 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
0101 crw[chain].slct, crw[chain].oflw, crw[chain].chn,
0102 crw[chain].rsc, crw[chain].anc, crw[chain].erc,
0103 crw[chain].rsid);
0104
0105 if (crw[chain].oflw) {
0106 int i;
0107
0108 pr_debug("%s: crw overflow detected!\n", __func__);
0109 mutex_lock(&crw_handler_mutex);
0110 for (i = 0; i < NR_RSCS; i++) {
0111 if (crw_handlers[i])
0112 crw_handlers[i](NULL, NULL, 1);
0113 }
0114 mutex_unlock(&crw_handler_mutex);
0115 chain = 0;
0116 continue;
0117 }
0118 if (crw[0].chn && !chain) {
0119 chain++;
0120 continue;
0121 }
0122 mutex_lock(&crw_handler_mutex);
0123 handler = crw_handlers[crw[chain].rsc];
0124 if (handler)
0125 handler(&crw[0], chain ? &crw[1] : NULL, 0);
0126 mutex_unlock(&crw_handler_mutex);
0127
0128 chain = crw[chain].chn ? chain + 1 : 0;
0129 }
0130 if (atomic_dec_and_test(&crw_nr_req))
0131 wake_up(&crw_handler_wait_q);
0132 goto repeat;
0133 return 0;
0134 }
0135
0136 void crw_handle_channel_report(void)
0137 {
0138 atomic_inc(&crw_nr_req);
0139 wake_up(&crw_handler_wait_q);
0140 }
0141
0142 void crw_wait_for_channel_report(void)
0143 {
0144 crw_handle_channel_report();
0145 wait_event(crw_handler_wait_q, atomic_read(&crw_nr_req) == 0);
0146 }
0147
0148
0149
0150
0151
0152 static int __init crw_machine_check_init(void)
0153 {
0154 struct task_struct *task;
0155
0156 task = kthread_run(crw_collect_info, NULL, "kmcheck");
0157 if (IS_ERR(task))
0158 return PTR_ERR(task);
0159 ctl_set_bit(14, 28);
0160 return 0;
0161 }
0162 device_initcall(crw_machine_check_init);