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