root/drivers/s390/cio/crw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. crw_register_handler
  2. crw_unregister_handler
  3. crw_collect_info
  4. crw_handle_channel_report
  5. crw_wait_for_channel_report
  6. crw_machine_check_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *   Channel report handling code
   4  *
   5  *    Copyright IBM Corp. 2000, 2009
   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  *               Heiko Carstens <heiko.carstens@de.ibm.com>,
  10  */
  11 
  12 #include <linux/mutex.h>
  13 #include <linux/kthread.h>
  14 #include <linux/init.h>
  15 #include <linux/wait.h>
  16 #include <asm/crw.h>
  17 #include <asm/ctl_reg.h>
  18 #include "ioasm.h"
  19 
  20 static DEFINE_MUTEX(crw_handler_mutex);
  21 static crw_handler_t crw_handlers[NR_RSCS];
  22 static atomic_t crw_nr_req = ATOMIC_INIT(0);
  23 static DECLARE_WAIT_QUEUE_HEAD(crw_handler_wait_q);
  24 
  25 /**
  26  * crw_register_handler() - register a channel report word handler
  27  * @rsc: reporting source code to handle
  28  * @handler: handler to be registered
  29  *
  30  * Returns %0 on success and a negative error value otherwise.
  31  */
  32 int crw_register_handler(int rsc, crw_handler_t handler)
  33 {
  34         int rc = 0;
  35 
  36         if ((rsc < 0) || (rsc >= NR_RSCS))
  37                 return -EINVAL;
  38         mutex_lock(&crw_handler_mutex);
  39         if (crw_handlers[rsc])
  40                 rc = -EBUSY;
  41         else
  42                 crw_handlers[rsc] = handler;
  43         mutex_unlock(&crw_handler_mutex);
  44         return rc;
  45 }
  46 
  47 /**
  48  * crw_unregister_handler() - unregister a channel report word handler
  49  * @rsc: reporting source code to handle
  50  */
  51 void crw_unregister_handler(int rsc)
  52 {
  53         if ((rsc < 0) || (rsc >= NR_RSCS))
  54                 return;
  55         mutex_lock(&crw_handler_mutex);
  56         crw_handlers[rsc] = NULL;
  57         mutex_unlock(&crw_handler_mutex);
  58 }
  59 
  60 /*
  61  * Retrieve CRWs and call function to handle event.
  62  */
  63 static int crw_collect_info(void *unused)
  64 {
  65         struct crw crw[2];
  66         int ccode, signal;
  67         unsigned int chain;
  68 
  69 repeat:
  70         signal = wait_event_interruptible(crw_handler_wait_q,
  71                                           atomic_read(&crw_nr_req) > 0);
  72         if (unlikely(signal))
  73                 atomic_inc(&crw_nr_req);
  74         chain = 0;
  75         while (1) {
  76                 crw_handler_t handler;
  77 
  78                 if (unlikely(chain > 1)) {
  79                         struct crw tmp_crw;
  80 
  81                         printk(KERN_WARNING"%s: Code does not support more "
  82                                "than two chained crws; please report to "
  83                                "linux390@de.ibm.com!\n", __func__);
  84                         ccode = stcrw(&tmp_crw);
  85                         printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
  86                                "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
  87                                __func__, tmp_crw.slct, tmp_crw.oflw,
  88                                tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
  89                                tmp_crw.erc, tmp_crw.rsid);
  90                         printk(KERN_WARNING"%s: This was crw number %x in the "
  91                                "chain\n", __func__, chain);
  92                         if (ccode != 0)
  93                                 break;
  94                         chain = tmp_crw.chn ? chain + 1 : 0;
  95                         continue;
  96                 }
  97                 ccode = stcrw(&crw[chain]);
  98                 if (ccode != 0)
  99                         break;
 100                 printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
 101                        "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
 102                        crw[chain].slct, crw[chain].oflw, crw[chain].chn,
 103                        crw[chain].rsc, crw[chain].anc, crw[chain].erc,
 104                        crw[chain].rsid);
 105                 /* Check for overflows. */
 106                 if (crw[chain].oflw) {
 107                         int i;
 108 
 109                         pr_debug("%s: crw overflow detected!\n", __func__);
 110                         mutex_lock(&crw_handler_mutex);
 111                         for (i = 0; i < NR_RSCS; i++) {
 112                                 if (crw_handlers[i])
 113                                         crw_handlers[i](NULL, NULL, 1);
 114                         }
 115                         mutex_unlock(&crw_handler_mutex);
 116                         chain = 0;
 117                         continue;
 118                 }
 119                 if (crw[0].chn && !chain) {
 120                         chain++;
 121                         continue;
 122                 }
 123                 mutex_lock(&crw_handler_mutex);
 124                 handler = crw_handlers[crw[chain].rsc];
 125                 if (handler)
 126                         handler(&crw[0], chain ? &crw[1] : NULL, 0);
 127                 mutex_unlock(&crw_handler_mutex);
 128                 /* chain is always 0 or 1 here. */
 129                 chain = crw[chain].chn ? chain + 1 : 0;
 130         }
 131         if (atomic_dec_and_test(&crw_nr_req))
 132                 wake_up(&crw_handler_wait_q);
 133         goto repeat;
 134         return 0;
 135 }
 136 
 137 void crw_handle_channel_report(void)
 138 {
 139         atomic_inc(&crw_nr_req);
 140         wake_up(&crw_handler_wait_q);
 141 }
 142 
 143 void crw_wait_for_channel_report(void)
 144 {
 145         crw_handle_channel_report();
 146         wait_event(crw_handler_wait_q, atomic_read(&crw_nr_req) == 0);
 147 }
 148 
 149 /*
 150  * Machine checks for the channel subsystem must be enabled
 151  * after the channel subsystem is initialized
 152  */
 153 static int __init crw_machine_check_init(void)
 154 {
 155         struct task_struct *task;
 156 
 157         task = kthread_run(crw_collect_info, NULL, "kmcheck");
 158         if (IS_ERR(task))
 159                 return PTR_ERR(task);
 160         ctl_set_bit(14, 28);    /* enable channel report MCH */
 161         return 0;
 162 }
 163 device_initcall(crw_machine_check_init);

/* [<][>][^][v][top][bottom][index][help] */