aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/irq_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/irq_user.c')
-rw-r--r--arch/um/kernel/irq_user.c204
1 files changed, 58 insertions, 146 deletions
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
index 0e32f5f4a887..483e79c5ab98 100644
--- a/arch/um/kernel/irq_user.c
+++ b/arch/um/kernel/irq_user.c
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
@@ -18,53 +18,25 @@
18#include "sigio.h" 18#include "sigio.h"
19#include "irq_user.h" 19#include "irq_user.h"
20#include "os.h" 20#include "os.h"
21#include "misc_constants.h"
21 22
22struct irq_fd { 23struct irq_fd *active_fds = NULL;
23 struct irq_fd *next;
24 void *id;
25 int fd;
26 int type;
27 int irq;
28 int pid;
29 int events;
30 int current_events;
31};
32
33static struct irq_fd *active_fds = NULL;
34static struct irq_fd **last_irq_ptr = &active_fds; 24static struct irq_fd **last_irq_ptr = &active_fds;
35 25
36static struct pollfd *pollfds = NULL;
37static int pollfds_num = 0;
38static int pollfds_size = 0;
39
40extern int io_count, intr_count;
41
42extern void free_irqs(void); 26extern void free_irqs(void);
43 27
44void sigio_handler(int sig, union uml_pt_regs *regs) 28void sigio_handler(int sig, union uml_pt_regs *regs)
45{ 29{
46 struct irq_fd *irq_fd; 30 struct irq_fd *irq_fd;
47 int i, n; 31 int n;
48 32
49 if(smp_sigio_handler()) return; 33 if(smp_sigio_handler()) return;
50 while(1){ 34 while(1){
51 n = poll(pollfds, pollfds_num, 0); 35 n = os_waiting_for_events(active_fds);
52 if(n < 0){ 36 if (n <= 0) {
53 if(errno == EINTR) continue; 37 if(n == -EINTR) continue;
54 printk("sigio_handler : poll returned %d, " 38 else break;
55 "errno = %d\n", n, errno); 39 }
56 break;
57 }
58 if(n == 0) break;
59
60 irq_fd = active_fds;
61 for(i = 0; i < pollfds_num; i++){
62 if(pollfds[i].revents != 0){
63 irq_fd->current_events = pollfds[i].revents;
64 pollfds[i].fd = -1;
65 }
66 irq_fd = irq_fd->next;
67 }
68 40
69 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ 41 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
70 if(irq_fd->current_events != 0){ 42 if(irq_fd->current_events != 0){
@@ -77,14 +49,9 @@ void sigio_handler(int sig, union uml_pt_regs *regs)
77 free_irqs(); 49 free_irqs();
78} 50}
79 51
80int activate_ipi(int fd, int pid)
81{
82 return(os_set_fd_async(fd, pid));
83}
84
85static void maybe_sigio_broken(int fd, int type) 52static void maybe_sigio_broken(int fd, int type)
86{ 53{
87 if(isatty(fd)){ 54 if(os_isatty(fd)){
88 if((type == IRQ_WRITE) && !pty_output_sigio){ 55 if((type == IRQ_WRITE) && !pty_output_sigio){
89 write_sigio_workaround(); 56 write_sigio_workaround();
90 add_sigio_fd(fd, 0); 57 add_sigio_fd(fd, 0);
@@ -96,12 +63,13 @@ static void maybe_sigio_broken(int fd, int type)
96 } 63 }
97} 64}
98 65
66
99int activate_fd(int irq, int fd, int type, void *dev_id) 67int activate_fd(int irq, int fd, int type, void *dev_id)
100{ 68{
101 struct pollfd *tmp_pfd; 69 struct pollfd *tmp_pfd;
102 struct irq_fd *new_fd, *irq_fd; 70 struct irq_fd *new_fd, *irq_fd;
103 unsigned long flags; 71 unsigned long flags;
104 int pid, events, err, n, size; 72 int pid, events, err, n;
105 73
106 pid = os_getpid(); 74 pid = os_getpid();
107 err = os_set_fd_async(fd, pid); 75 err = os_set_fd_async(fd, pid);
@@ -113,8 +81,8 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
113 if(new_fd == NULL) 81 if(new_fd == NULL)
114 goto out; 82 goto out;
115 83
116 if(type == IRQ_READ) events = POLLIN | POLLPRI; 84 if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI;
117 else events = POLLOUT; 85 else events = UM_POLLOUT;
118 *new_fd = ((struct irq_fd) { .next = NULL, 86 *new_fd = ((struct irq_fd) { .next = NULL,
119 .id = dev_id, 87 .id = dev_id,
120 .fd = fd, 88 .fd = fd,
@@ -125,12 +93,12 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
125 .current_events = 0 } ); 93 .current_events = 0 } );
126 94
127 /* Critical section - locked by a spinlock because this stuff can 95 /* Critical section - locked by a spinlock because this stuff can
128 * be changed from interrupt handlers. The stuff above is done 96 * be changed from interrupt handlers. The stuff above is done
129 * outside the lock because it allocates memory. 97 * outside the lock because it allocates memory.
130 */ 98 */
131 99
132 /* Actually, it only looks like it can be called from interrupt 100 /* Actually, it only looks like it can be called from interrupt
133 * context. The culprit is reactivate_fd, which calls 101 * context. The culprit is reactivate_fd, which calls
134 * maybe_sigio_broken, which calls write_sigio_workaround, 102 * maybe_sigio_broken, which calls write_sigio_workaround,
135 * which calls activate_fd. However, write_sigio_workaround should 103 * which calls activate_fd. However, write_sigio_workaround should
136 * only be called once, at boot time. That would make it clear that 104 * only be called once, at boot time. That would make it clear that
@@ -147,40 +115,42 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
147 } 115 }
148 } 116 }
149 117
150 n = pollfds_num; 118 /*-------------*/
151 if(n == pollfds_size){ 119 if(type == IRQ_WRITE)
152 while(1){ 120 fd = -1;
153 /* Here we have to drop the lock in order to call 121
154 * kmalloc, which might sleep. If something else 122 tmp_pfd = NULL;
155 * came in and changed the pollfds array, we free 123 n = 0;
156 * the buffer and try again. 124
157 */ 125 while(1){
158 irq_unlock(flags); 126 n = os_create_pollfd(fd, events, tmp_pfd, n);
159 size = (pollfds_num + 1) * sizeof(pollfds[0]); 127 if (n == 0)
160 tmp_pfd = um_kmalloc(size); 128 break;
161 flags = irq_lock(); 129
162 if(tmp_pfd == NULL) 130 /* n > 0
163 goto out_unlock; 131 * It means we couldn't put new pollfd to current pollfds
164 if(n == pollfds_size) 132 * and tmp_fds is NULL or too small for new pollfds array.
165 break; 133 * Needed size is equal to n as minimum.
134 *
135 * Here we have to drop the lock in order to call
136 * kmalloc, which might sleep.
137 * If something else came in and changed the pollfds array
138 * so we will not be able to put new pollfd struct to pollfds
139 * then we free the buffer tmp_fds and try again.
140 */
141 irq_unlock(flags);
142 if (tmp_pfd != NULL) {
166 kfree(tmp_pfd); 143 kfree(tmp_pfd);
144 tmp_pfd = NULL;
167 } 145 }
168 if(pollfds != NULL){
169 memcpy(tmp_pfd, pollfds,
170 sizeof(pollfds[0]) * pollfds_size);
171 kfree(pollfds);
172 }
173 pollfds = tmp_pfd;
174 pollfds_size++;
175 }
176 146
177 if(type == IRQ_WRITE) 147 tmp_pfd = um_kmalloc(n);
178 fd = -1; 148 if (tmp_pfd == NULL)
149 goto out_kfree;
179 150
180 pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, 151 flags = irq_lock();
181 .events = events, 152 }
182 .revents = 0 }); 153 /*-------------*/
183 pollfds_num++;
184 154
185 *last_irq_ptr = new_fd; 155 *last_irq_ptr = new_fd;
186 last_irq_ptr = &new_fd->next; 156 last_irq_ptr = &new_fd->next;
@@ -196,6 +166,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
196 166
197 out_unlock: 167 out_unlock:
198 irq_unlock(flags); 168 irq_unlock(flags);
169 out_kfree:
199 kfree(new_fd); 170 kfree(new_fd);
200 out: 171 out:
201 return(err); 172 return(err);
@@ -203,43 +174,10 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
203 174
204static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) 175static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
205{ 176{
206 struct irq_fd **prev;
207 unsigned long flags; 177 unsigned long flags;
208 int i = 0;
209 178
210 flags = irq_lock(); 179 flags = irq_lock();
211 prev = &active_fds; 180 os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
212 while(*prev != NULL){
213 if((*test)(*prev, arg)){
214 struct irq_fd *old_fd = *prev;
215 if((pollfds[i].fd != -1) &&
216 (pollfds[i].fd != (*prev)->fd)){
217 printk("free_irq_by_cb - mismatch between "
218 "active_fds and pollfds, fd %d vs %d\n",
219 (*prev)->fd, pollfds[i].fd);
220 goto out;
221 }
222
223 pollfds_num--;
224
225 /* This moves the *whole* array after pollfds[i] (though
226 * it doesn't spot as such)! */
227
228 memmove(&pollfds[i], &pollfds[i + 1],
229 (pollfds_num - i) * sizeof(pollfds[0]));
230
231 if(last_irq_ptr == &old_fd->next)
232 last_irq_ptr = prev;
233 *prev = (*prev)->next;
234 if(old_fd->type == IRQ_WRITE)
235 ignore_sigio_fd(old_fd->fd);
236 kfree(old_fd);
237 continue;
238 }
239 prev = &(*prev)->next;
240 i++;
241 }
242 out:
243 irq_unlock(flags); 181 irq_unlock(flags);
244} 182}
245 183
@@ -277,6 +215,7 @@ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
277{ 215{
278 struct irq_fd *irq; 216 struct irq_fd *irq;
279 int i = 0; 217 int i = 0;
218 int fdi;
280 219
281 for(irq=active_fds; irq != NULL; irq = irq->next){ 220 for(irq=active_fds; irq != NULL; irq = irq->next){
282 if((irq->fd == fd) && (irq->irq == irqnum)) break; 221 if((irq->fd == fd) && (irq->irq == irqnum)) break;
@@ -286,10 +225,11 @@ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
286 printk("find_irq_by_fd doesn't have descriptor %d\n", fd); 225 printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
287 goto out; 226 goto out;
288 } 227 }
289 if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){ 228 fdi = os_get_pollfd(i);
229 if((fdi != -1) && (fdi != fd)){
290 printk("find_irq_by_fd - mismatch between active_fds and " 230 printk("find_irq_by_fd - mismatch between active_fds and "
291 "pollfds, fd %d vs %d, need %d\n", irq->fd, 231 "pollfds, fd %d vs %d, need %d\n", irq->fd,
292 pollfds[i].fd, fd); 232 fdi, fd);
293 irq = NULL; 233 irq = NULL;
294 goto out; 234 goto out;
295 } 235 }
@@ -310,9 +250,7 @@ void reactivate_fd(int fd, int irqnum)
310 irq_unlock(flags); 250 irq_unlock(flags);
311 return; 251 return;
312 } 252 }
313 253 os_set_pollfd(i, irq->fd);
314 pollfds[i].fd = irq->fd;
315
316 irq_unlock(flags); 254 irq_unlock(flags);
317 255
318 /* This calls activate_fd, so it has to be outside the critical 256 /* This calls activate_fd, so it has to be outside the critical
@@ -331,7 +269,7 @@ void deactivate_fd(int fd, int irqnum)
331 irq = find_irq_by_fd(fd, irqnum, &i); 269 irq = find_irq_by_fd(fd, irqnum, &i);
332 if(irq == NULL) 270 if(irq == NULL)
333 goto out; 271 goto out;
334 pollfds[i].fd = -1; 272 os_set_pollfd(i, -1);
335 out: 273 out:
336 irq_unlock(flags); 274 irq_unlock(flags);
337} 275}
@@ -347,21 +285,11 @@ int deactivate_all_fds(void)
347 return(err); 285 return(err);
348 } 286 }
349 /* If there is a signal already queued, after unblocking ignore it */ 287 /* If there is a signal already queued, after unblocking ignore it */
350 set_handler(SIGIO, SIG_IGN, 0, -1); 288 os_set_ioignore();
351 289
352 return(0); 290 return(0);
353} 291}
354 292
355void forward_ipi(int fd, int pid)
356{
357 int err;
358
359 err = os_set_owner(fd, pid);
360 if(err < 0)
361 printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
362 "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
363}
364
365void forward_interrupts(int pid) 293void forward_interrupts(int pid)
366{ 294{
367 struct irq_fd *irq; 295 struct irq_fd *irq;
@@ -384,22 +312,6 @@ void forward_interrupts(int pid)
384 irq_unlock(flags); 312 irq_unlock(flags);
385} 313}
386 314
387void init_irq_signals(int on_sigstack)
388{
389 __sighandler_t h;
390 int flags;
391
392 flags = on_sigstack ? SA_ONSTACK : 0;
393 if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
394 else h = boot_timer_handler;
395
396 set_handler(SIGVTALRM, h, flags | SA_RESTART,
397 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
398 set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
399 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
400 signal(SIGWINCH, SIG_IGN);
401}
402
403/* 315/*
404 * Overrides for Emacs so that we follow Linus's tabbing style. 316 * Overrides for Emacs so that we follow Linus's tabbing style.
405 * Emacs will notice this stuff at the end of the file and automatically 317 * Emacs will notice this stuff at the end of the file and automatically