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
  17#include <asm/lowcore.h>
  18#include <asm/s390_ext.h>
  19#include <asm/irq_regs.h>
  20#include <asm/irq.h>
  21
  22/*
  23 * ext_int_hash[index] is the start of the list for all external interrupts
  24 * that hash to this index. With the current set of external interrupts 
  25 * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
  26 * iucv and 0x2603 pfault) this is always the first element. 
  27 */
  28ext_int_info_t *ext_int_hash[256] = { NULL, };
  29
  30static inline int ext_hash(__u16 code)
  31{
  32        return (code + (code >> 9)) & 0xff;
  33}
  34
  35int register_external_interrupt(__u16 code, ext_int_handler_t handler)
  36{
  37        ext_int_info_t *p;
  38        int index;
  39
  40        p = kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
  41        if (p == NULL)
  42                return -ENOMEM;
  43        p->code = code;
  44        p->handler = handler;
  45        index = ext_hash(code);
  46        p->next = ext_int_hash[index];
  47        ext_int_hash[index] = p;
  48        return 0;
  49}
  50
  51int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
  52                                      ext_int_info_t *p)
  53{
  54        int index;
  55
  56        if (p == NULL)
  57                return -EINVAL;
  58        p->code = code;
  59        p->handler = handler;
  60        index = ext_hash(code);
  61        p->next = ext_int_hash[index];
  62        ext_int_hash[index] = p;
  63        return 0;
  64}
  65
  66int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
  67{
  68        ext_int_info_t *p, *q;
  69        int index;
  70
  71        index = ext_hash(code);
  72        q = NULL;
  73        p = ext_int_hash[index];
  74        while (p != NULL) {
  75                if (p->code == code && p->handler == handler)
  76                        break;
  77                q = p;
  78                p = p->next;
  79        }
  80        if (p == NULL)
  81                return -ENOENT;
  82        if (q != NULL)
  83                q->next = p->next;
  84        else
  85                ext_int_hash[index] = p->next;
  86        kfree(p);
  87        return 0;
  88}
  89
  90int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
  91                                        ext_int_info_t *p)
  92{
  93        ext_int_info_t *q;
  94        int index;
  95
  96        if (p == NULL || p->code != code || p->handler != handler)
  97                return -EINVAL;
  98        index = ext_hash(code);
  99        q = ext_int_hash[index];
 100        if (p != q) {
 101                while (q != NULL) {
 102                        if (q->next == p)
 103                                break;
 104                        q = q->next;
 105                }
 106                if (q == NULL)
 107                        return -ENOENT;
 108                q->next = p->next;
 109        } else
 110                ext_int_hash[index] = p->next;
 111        return 0;
 112}
 113
 114void do_extint(struct pt_regs *regs, unsigned short code)
 115{
 116        ext_int_info_t *p;
 117        int index;
 118        struct pt_regs *old_regs;
 119
 120        old_regs = set_irq_regs(regs);
 121        irq_enter();
 122        asm volatile ("mc 0,0");
 123        if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
 124                /**
 125                 * Make sure that the i/o interrupt did not "overtake"
 126                 * the last HZ timer interrupt.
 127                 */
 128                account_ticks(S390_lowcore.int_clock);
 129        kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
 130        index = ext_hash(code);
 131        for (p = ext_int_hash[index]; p; p = p->next) {
 132                if (likely(p->code == code))
 133                        p->handler(code);
 134        }
 135        irq_exit();
 136        set_irq_regs(old_regs);
 137}
 138
 139EXPORT_SYMBOL(register_external_interrupt);
 140EXPORT_SYMBOL(unregister_external_interrupt);
 141