diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/crw.c | 29 |
1 files changed, 15 insertions, 14 deletions
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c index d157665d0e76..425f741a280c 100644 --- a/drivers/s390/cio/crw.c +++ b/drivers/s390/cio/crw.c | |||
@@ -8,15 +8,16 @@ | |||
8 | * Heiko Carstens <heiko.carstens@de.ibm.com>, | 8 | * Heiko Carstens <heiko.carstens@de.ibm.com>, |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/semaphore.h> | ||
12 | #include <linux/mutex.h> | 11 | #include <linux/mutex.h> |
13 | #include <linux/kthread.h> | 12 | #include <linux/kthread.h> |
14 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/wait.h> | ||
15 | #include <asm/crw.h> | 15 | #include <asm/crw.h> |
16 | 16 | ||
17 | static struct semaphore crw_semaphore; | ||
18 | static DEFINE_MUTEX(crw_handler_mutex); | 17 | static DEFINE_MUTEX(crw_handler_mutex); |
19 | static crw_handler_t crw_handlers[NR_RSCS]; | 18 | static crw_handler_t crw_handlers[NR_RSCS]; |
19 | static atomic_t crw_nr_req = ATOMIC_INIT(0); | ||
20 | static DECLARE_WAIT_QUEUE_HEAD(crw_handler_wait_q); | ||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * crw_register_handler() - register a channel report word handler | 23 | * crw_register_handler() - register a channel report word handler |
@@ -59,12 +60,14 @@ void crw_unregister_handler(int rsc) | |||
59 | static int crw_collect_info(void *unused) | 60 | static int crw_collect_info(void *unused) |
60 | { | 61 | { |
61 | struct crw crw[2]; | 62 | struct crw crw[2]; |
62 | int ccode; | 63 | int ccode, signal; |
63 | unsigned int chain; | 64 | unsigned int chain; |
64 | int ignore; | ||
65 | 65 | ||
66 | repeat: | 66 | repeat: |
67 | ignore = down_interruptible(&crw_semaphore); | 67 | signal = wait_event_interruptible(crw_handler_wait_q, |
68 | atomic_read(&crw_nr_req) > 0); | ||
69 | if (unlikely(signal)) | ||
70 | atomic_inc(&crw_nr_req); | ||
68 | chain = 0; | 71 | chain = 0; |
69 | while (1) { | 72 | while (1) { |
70 | crw_handler_t handler; | 73 | crw_handler_t handler; |
@@ -122,25 +125,23 @@ repeat: | |||
122 | /* chain is always 0 or 1 here. */ | 125 | /* chain is always 0 or 1 here. */ |
123 | chain = crw[chain].chn ? chain + 1 : 0; | 126 | chain = crw[chain].chn ? chain + 1 : 0; |
124 | } | 127 | } |
128 | if (atomic_dec_and_test(&crw_nr_req)) | ||
129 | wake_up(&crw_handler_wait_q); | ||
125 | goto repeat; | 130 | goto repeat; |
126 | return 0; | 131 | return 0; |
127 | } | 132 | } |
128 | 133 | ||
129 | void crw_handle_channel_report(void) | 134 | void crw_handle_channel_report(void) |
130 | { | 135 | { |
131 | up(&crw_semaphore); | 136 | atomic_inc(&crw_nr_req); |
137 | wake_up(&crw_handler_wait_q); | ||
132 | } | 138 | } |
133 | 139 | ||
134 | /* | 140 | void crw_wait_for_channel_report(void) |
135 | * Separate initcall needed for semaphore initialization since | ||
136 | * crw_handle_channel_report might be called before crw_machine_check_init. | ||
137 | */ | ||
138 | static int __init crw_init_semaphore(void) | ||
139 | { | 141 | { |
140 | init_MUTEX_LOCKED(&crw_semaphore); | 142 | crw_handle_channel_report(); |
141 | return 0; | 143 | wait_event(crw_handler_wait_q, atomic_read(&crw_nr_req) == 0); |
142 | } | 144 | } |
143 | pure_initcall(crw_init_semaphore); | ||
144 | 145 | ||
145 | /* | 146 | /* |
146 | * Machine checks for the channel subsystem must be enabled | 147 | * Machine checks for the channel subsystem must be enabled |