linux/arch/s390/kernel/s390_ext.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/kernel/s390_ext.c
   3 *
   4 *  S390 version
   5 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
   6 *    Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
   7 *               Martin Schwidefsky (schwidefsky@de.ibm.com)
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/kernel.h>
  12#include <linux/slab.h>
  13#include <linux/errno.h>
  14#include <linux/kernel_stat.h>
  15#include <linux/interrupt.h>
  16#include <asm/cpu.h>
  17#include <asm/lowcore.h>
  18#include <asm/s390_ext.h>
  19#include <asm/irq_regs.h>
  20#include <asm/irq.h>
  21#include "entry.h"
  22
  23/*
  24 * ext_int_hash[index] is the start of the list for all external interrupts
  25 * that hash to this index. With the current set of external interrupts 
  26 * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
  27 * iucv and 0x2603 pfault) this is always the first element. 
  28 */
  29ext_int_info_t *ext_int_hash[256] = { NULL, };
  30
  31static inline int ext_hash(__u16 code)
  32{
  33        return (code + (code >> 9)) & 0xff;
  34}
  35
  36int register_external_interrupt(__u16 code, ext_int_handler_t handler)
  37{
  38        ext_int_info_t *p;
  39        int index;
  40
  41        p = kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
  42        if (p == NULL)
  43                return -ENOMEM;
  44        p->code = code;
  45        p->handler = handler;
  46        index = ext_hash(code);
  47        p->next = ext_int_hash[index];
  48        ext_int_hash[index] = p;
  49        return 0;
  50}
  51
  52int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
  53                                      ext_int_info_t *p)
  54{
  55        int index;
  56
  57        if (p == NULL)
  58                return -EINVAL;
  59        p->code = code;
  60        p->handler = handler;
  61        index = ext_hash(code);
  62        p->next = ext_int_hash[index];
  63        ext_int_hash[index] = p;
  64        return 0;
  65}
  66
  67int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
  68{
  69        ext_int_info_t *p, *q;
  70        int index;
  71
  72        index = ext_hash(code);
  73        q = NULL;
  74        p = ext_int_hash[index];
  75        while (p != NULL) {
  76                if (p->code == code && p->handler == handler)
  77                        break;
  78                q = p;
  79                p = p->next;
  80        }
  81        if (p == NULL)
  82                return -ENOENT;
  83        if (q != NULL)
  84                q->next = p->next;
  85        else
  86                ext_int_hash[index] = p->next;
  87        kfree(p);
  88        return 0;
  89}
  90
  91int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
  92                                        ext_int_info_t *p)
  93{
  94        ext_int_info_t *q;
  95        int index;
  96
  97        if (p == NULL || p->code != code || p->handler != handler)
  98                return -EINVAL;
  99        index = ext_hash(code);
 100        q = ext_int_hash[index];
 101        if (p != q) {
 102                while (q != NULL) {
 103                        if (q->next == p)
 104                                break;
 105                        q = q->next;
 106                }
 107                if (q == NULL)
 108                        return -ENOENT;
 109                q->next = p->next;
 110        } else
 111                ext_int_hash[index] = p->next;
 112        return 0;
 113}
 114
 115void do_extint(struct pt_regs *regs, unsigned short code)
 116{
 117        ext_int_info_t *p;
 118        int index;
 119        struct pt_regs *old_regs;
 120
 121        old_regs = set_irq_regs(regs);
 122        irq_enter();
 123        s390_idle_check();
 124        if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
 125                /* Serve timer interrupts first. */
 126                clock_comparator_work();
 127        kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
 128        index = ext_hash(code);
 129        for (p = ext_int_hash[index]; p; p = p->next) {
 130                if (likely(p->code == code))
 131                        p->handler(code);
 132        }
 133        irq_exit();
 134        set_irq_regs(old_regs);
 135}
 136
 137EXPORT_SYMBOL(register_external_interrupt);
 138EXPORT_SYMBOL(unregister_external_interrupt);
 139