diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/crw.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c index 508f88f6420c..d157665d0e76 100644 --- a/drivers/s390/cio/crw.c +++ b/drivers/s390/cio/crw.c | |||
@@ -9,11 +9,13 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/semaphore.h> | 11 | #include <linux/semaphore.h> |
12 | #include <linux/mutex.h> | ||
12 | #include <linux/kthread.h> | 13 | #include <linux/kthread.h> |
13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
14 | #include <asm/crw.h> | 15 | #include <asm/crw.h> |
15 | 16 | ||
16 | static struct semaphore crw_semaphore; | 17 | static struct semaphore crw_semaphore; |
18 | static DEFINE_MUTEX(crw_handler_mutex); | ||
17 | static crw_handler_t crw_handlers[NR_RSCS]; | 19 | static crw_handler_t crw_handlers[NR_RSCS]; |
18 | 20 | ||
19 | /** | 21 | /** |
@@ -25,11 +27,17 @@ static crw_handler_t crw_handlers[NR_RSCS]; | |||
25 | */ | 27 | */ |
26 | int crw_register_handler(int rsc, crw_handler_t handler) | 28 | int crw_register_handler(int rsc, crw_handler_t handler) |
27 | { | 29 | { |
30 | int rc = 0; | ||
31 | |||
28 | if ((rsc < 0) || (rsc >= NR_RSCS)) | 32 | if ((rsc < 0) || (rsc >= NR_RSCS)) |
29 | return -EINVAL; | 33 | return -EINVAL; |
30 | if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) | 34 | mutex_lock(&crw_handler_mutex); |
31 | return 0; | 35 | if (crw_handlers[rsc]) |
32 | return -EBUSY; | 36 | rc = -EBUSY; |
37 | else | ||
38 | crw_handlers[rsc] = handler; | ||
39 | mutex_unlock(&crw_handler_mutex); | ||
40 | return rc; | ||
33 | } | 41 | } |
34 | 42 | ||
35 | /** | 43 | /** |
@@ -40,8 +48,9 @@ void crw_unregister_handler(int rsc) | |||
40 | { | 48 | { |
41 | if ((rsc < 0) || (rsc >= NR_RSCS)) | 49 | if ((rsc < 0) || (rsc >= NR_RSCS)) |
42 | return; | 50 | return; |
43 | xchg(&crw_handlers[rsc], NULL); | 51 | mutex_lock(&crw_handler_mutex); |
44 | synchronize_sched(); | 52 | crw_handlers[rsc] = NULL; |
53 | mutex_unlock(&crw_handler_mutex); | ||
45 | } | 54 | } |
46 | 55 | ||
47 | /* | 56 | /* |
@@ -58,6 +67,8 @@ repeat: | |||
58 | ignore = down_interruptible(&crw_semaphore); | 67 | ignore = down_interruptible(&crw_semaphore); |
59 | chain = 0; | 68 | chain = 0; |
60 | while (1) { | 69 | while (1) { |
70 | crw_handler_t handler; | ||
71 | |||
61 | if (unlikely(chain > 1)) { | 72 | if (unlikely(chain > 1)) { |
62 | struct crw tmp_crw; | 73 | struct crw tmp_crw; |
63 | 74 | ||
@@ -90,10 +101,12 @@ repeat: | |||
90 | int i; | 101 | int i; |
91 | 102 | ||
92 | pr_debug("%s: crw overflow detected!\n", __func__); | 103 | pr_debug("%s: crw overflow detected!\n", __func__); |
104 | mutex_lock(&crw_handler_mutex); | ||
93 | for (i = 0; i < NR_RSCS; i++) { | 105 | for (i = 0; i < NR_RSCS; i++) { |
94 | if (crw_handlers[i]) | 106 | if (crw_handlers[i]) |
95 | crw_handlers[i](NULL, NULL, 1); | 107 | crw_handlers[i](NULL, NULL, 1); |
96 | } | 108 | } |
109 | mutex_unlock(&crw_handler_mutex); | ||
97 | chain = 0; | 110 | chain = 0; |
98 | continue; | 111 | continue; |
99 | } | 112 | } |
@@ -101,10 +114,11 @@ repeat: | |||
101 | chain++; | 114 | chain++; |
102 | continue; | 115 | continue; |
103 | } | 116 | } |
104 | if (crw_handlers[crw[chain].rsc]) | 117 | mutex_lock(&crw_handler_mutex); |
105 | crw_handlers[crw[chain].rsc](&crw[0], | 118 | handler = crw_handlers[crw[chain].rsc]; |
106 | chain ? &crw[1] : NULL, | 119 | if (handler) |
107 | 0); | 120 | handler(&crw[0], chain ? &crw[1] : NULL, 0); |
121 | mutex_unlock(&crw_handler_mutex); | ||
108 | /* chain is always 0 or 1 here. */ | 122 | /* chain is always 0 or 1 here. */ |
109 | chain = crw[chain].chn ? chain + 1 : 0; | 123 | chain = crw[chain].chn ? chain + 1 : 0; |
110 | } | 124 | } |