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 <asm/lowcore.h>
14 #include <asm/s390_ext.h>
15 
16 /*
17  * Simple hash strategy: index = code & 0xff;
18  * ext_int_hash[index] is the start of the list for all external interrupts
19  * that hash to this index. With the current set of external interrupts
20  * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
21  * iucv and 0x2603 pfault) this is always the first element.
22  */
23 ext_int_info_t *ext_int_hash[256] = { 0, };
24 
register_external_interrupt(__u16 code,ext_int_handler_t handler)25 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
26         ext_int_info_t *p;
27         int index;
28 
29 	p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
30         if (p == NULL)
31                 return -ENOMEM;
32         p->code = code;
33         p->handler = handler;
34         index = code & 0xff;
35         p->next = ext_int_hash[index];
36         ext_int_hash[index] = p;
37         return 0;
38 }
39 
register_early_external_interrupt(__u16 code,ext_int_handler_t handler,ext_int_info_t * p)40 int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
41 				      ext_int_info_t *p) {
42         int index;
43 
44         if (p == NULL)
45                 return -EINVAL;
46         p->code = code;
47         p->handler = handler;
48         index = code & 0xff;
49         p->next = ext_int_hash[index];
50         ext_int_hash[index] = p;
51         return 0;
52 }
53 
unregister_external_interrupt(__u16 code,ext_int_handler_t handler)54 int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
55         ext_int_info_t *p, *q;
56         int index;
57 
58         index = code & 0xff;
59         q = NULL;
60         p = ext_int_hash[index];
61         while (p != NULL) {
62                 if (p->code == code && p->handler == handler)
63                         break;
64                 q = p;
65                 p = p->next;
66         }
67         if (p == NULL)
68                 return -ENOENT;
69         if (q != NULL)
70                 q->next = p->next;
71         else
72                 ext_int_hash[index] = p->next;
73 	kfree(p);
74         return 0;
75 }
76 
unregister_early_external_interrupt(__u16 code,ext_int_handler_t handler,ext_int_info_t * p)77 int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
78 					ext_int_info_t *p) {
79 	ext_int_info_t *q;
80 	int index;
81 
82 	if (p == NULL || p->code != code || p->handler != handler)
83 		return -EINVAL;
84 	index = code & 0xff;
85 	q = ext_int_hash[index];
86 	if (p != q) {
87 		while (q != NULL) {
88 			if (q->next == p)
89 				break;
90 			q = q->next;
91 		}
92 		if (q == NULL)
93 			return -ENOENT;
94 		q->next = p->next;
95 	} else
96 		ext_int_hash[index] = p->next;
97 	return 0;
98 }
99 
100 EXPORT_SYMBOL(register_external_interrupt);
101 EXPORT_SYMBOL(unregister_external_interrupt);
102 
103