aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/kernel/Makefile2
-rw-r--r--arch/um/kernel/irq.c294
-rw-r--r--arch/um/kernel/irq_user.c324
3 files changed, 295 insertions, 325 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 693018ba80f1..8458c30a6265 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -7,7 +7,7 @@ extra-y := vmlinux.lds
7clean-files := 7clean-files :=
8 8
9obj-y = config.o exec_kern.o exitcode.o \ 9obj-y = config.o exec_kern.o exitcode.o \
10 init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ 10 init_task.o irq.o ksyms.o mem.o physmem.o \
11 process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ 11 process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \
12 signal_kern.o smp.o syscall_kern.o sysrq.o \ 12 signal_kern.o smp.o syscall_kern.o sysrq.o \
13 time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o 13 time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index bbf94bf2921e..c39ea3abeda4 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -31,6 +31,8 @@
31#include "irq_user.h" 31#include "irq_user.h"
32#include "irq_kern.h" 32#include "irq_kern.h"
33#include "os.h" 33#include "os.h"
34#include "sigio.h"
35#include "misc_constants.h"
34 36
35/* 37/*
36 * Generic, controller-independent functions: 38 * Generic, controller-independent functions:
@@ -77,6 +79,298 @@ skip:
77 return 0; 79 return 0;
78} 80}
79 81
82struct irq_fd *active_fds = NULL;
83static struct irq_fd **last_irq_ptr = &active_fds;
84
85extern void free_irqs(void);
86
87void sigio_handler(int sig, union uml_pt_regs *regs)
88{
89 struct irq_fd *irq_fd;
90 int n;
91
92 if(smp_sigio_handler()) return;
93 while(1){
94 n = os_waiting_for_events(active_fds);
95 if (n <= 0) {
96 if(n == -EINTR) continue;
97 else break;
98 }
99
100 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
101 if(irq_fd->current_events != 0){
102 irq_fd->current_events = 0;
103 do_IRQ(irq_fd->irq, regs);
104 }
105 }
106 }
107
108 free_irqs();
109}
110
111static void maybe_sigio_broken(int fd, int type)
112{
113 if(os_isatty(fd)){
114 if((type == IRQ_WRITE) && !pty_output_sigio){
115 write_sigio_workaround();
116 add_sigio_fd(fd, 0);
117 }
118 else if((type == IRQ_READ) && !pty_close_sigio){
119 write_sigio_workaround();
120 add_sigio_fd(fd, 1);
121 }
122 }
123}
124
125
126int activate_fd(int irq, int fd, int type, void *dev_id)
127{
128 struct pollfd *tmp_pfd;
129 struct irq_fd *new_fd, *irq_fd;
130 unsigned long flags;
131 int pid, events, err, n;
132
133 pid = os_getpid();
134 err = os_set_fd_async(fd, pid);
135 if(err < 0)
136 goto out;
137
138 new_fd = um_kmalloc(sizeof(*new_fd));
139 err = -ENOMEM;
140 if(new_fd == NULL)
141 goto out;
142
143 if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI;
144 else events = UM_POLLOUT;
145 *new_fd = ((struct irq_fd) { .next = NULL,
146 .id = dev_id,
147 .fd = fd,
148 .type = type,
149 .irq = irq,
150 .pid = pid,
151 .events = events,
152 .current_events = 0 } );
153
154 /* Critical section - locked by a spinlock because this stuff can
155 * be changed from interrupt handlers. The stuff above is done
156 * outside the lock because it allocates memory.
157 */
158
159 /* Actually, it only looks like it can be called from interrupt
160 * context. The culprit is reactivate_fd, which calls
161 * maybe_sigio_broken, which calls write_sigio_workaround,
162 * which calls activate_fd. However, write_sigio_workaround should
163 * only be called once, at boot time. That would make it clear that
164 * this is called only from process context, and can be locked with
165 * a semaphore.
166 */
167 flags = irq_lock();
168 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
169 if((irq_fd->fd == fd) && (irq_fd->type == type)){
170 printk("Registering fd %d twice\n", fd);
171 printk("Irqs : %d, %d\n", irq_fd->irq, irq);
172 printk("Ids : 0x%p, 0x%p\n", irq_fd->id, dev_id);
173 goto out_unlock;
174 }
175 }
176
177 /*-------------*/
178 if(type == IRQ_WRITE)
179 fd = -1;
180
181 tmp_pfd = NULL;
182 n = 0;
183
184 while(1){
185 n = os_create_pollfd(fd, events, tmp_pfd, n);
186 if (n == 0)
187 break;
188
189 /* n > 0
190 * It means we couldn't put new pollfd to current pollfds
191 * and tmp_fds is NULL or too small for new pollfds array.
192 * Needed size is equal to n as minimum.
193 *
194 * Here we have to drop the lock in order to call
195 * kmalloc, which might sleep.
196 * If something else came in and changed the pollfds array
197 * so we will not be able to put new pollfd struct to pollfds
198 * then we free the buffer tmp_fds and try again.
199 */
200 irq_unlock(flags);
201 if (tmp_pfd != NULL) {
202 kfree(tmp_pfd);
203 tmp_pfd = NULL;
204 }
205
206 tmp_pfd = um_kmalloc(n);
207 if (tmp_pfd == NULL)
208 goto out_kfree;
209
210 flags = irq_lock();
211 }
212 /*-------------*/
213
214 *last_irq_ptr = new_fd;
215 last_irq_ptr = &new_fd->next;
216
217 irq_unlock(flags);
218
219 /* This calls activate_fd, so it has to be outside the critical
220 * section.
221 */
222 maybe_sigio_broken(fd, type);
223
224 return(0);
225
226 out_unlock:
227 irq_unlock(flags);
228 out_kfree:
229 kfree(new_fd);
230 out:
231 return(err);
232}
233
234static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
235{
236 unsigned long flags;
237
238 flags = irq_lock();
239 os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
240 irq_unlock(flags);
241}
242
243struct irq_and_dev {
244 int irq;
245 void *dev;
246};
247
248static int same_irq_and_dev(struct irq_fd *irq, void *d)
249{
250 struct irq_and_dev *data = d;
251
252 return((irq->irq == data->irq) && (irq->id == data->dev));
253}
254
255void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
256{
257 struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq,
258 .dev = dev });
259
260 free_irq_by_cb(same_irq_and_dev, &data);
261}
262
263static int same_fd(struct irq_fd *irq, void *fd)
264{
265 return(irq->fd == *((int *) fd));
266}
267
268void free_irq_by_fd(int fd)
269{
270 free_irq_by_cb(same_fd, &fd);
271}
272
273static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
274{
275 struct irq_fd *irq;
276 int i = 0;
277 int fdi;
278
279 for(irq=active_fds; irq != NULL; irq = irq->next){
280 if((irq->fd == fd) && (irq->irq == irqnum)) break;
281 i++;
282 }
283 if(irq == NULL){
284 printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
285 goto out;
286 }
287 fdi = os_get_pollfd(i);
288 if((fdi != -1) && (fdi != fd)){
289 printk("find_irq_by_fd - mismatch between active_fds and "
290 "pollfds, fd %d vs %d, need %d\n", irq->fd,
291 fdi, fd);
292 irq = NULL;
293 goto out;
294 }
295 *index_out = i;
296 out:
297 return(irq);
298}
299
300void reactivate_fd(int fd, int irqnum)
301{
302 struct irq_fd *irq;
303 unsigned long flags;
304 int i;
305
306 flags = irq_lock();
307 irq = find_irq_by_fd(fd, irqnum, &i);
308 if(irq == NULL){
309 irq_unlock(flags);
310 return;
311 }
312 os_set_pollfd(i, irq->fd);
313 irq_unlock(flags);
314
315 /* This calls activate_fd, so it has to be outside the critical
316 * section.
317 */
318 maybe_sigio_broken(fd, irq->type);
319}
320
321void deactivate_fd(int fd, int irqnum)
322{
323 struct irq_fd *irq;
324 unsigned long flags;
325 int i;
326
327 flags = irq_lock();
328 irq = find_irq_by_fd(fd, irqnum, &i);
329 if(irq == NULL)
330 goto out;
331 os_set_pollfd(i, -1);
332 out:
333 irq_unlock(flags);
334}
335
336int deactivate_all_fds(void)
337{
338 struct irq_fd *irq;
339 int err;
340
341 for(irq=active_fds;irq != NULL;irq = irq->next){
342 err = os_clear_fd_async(irq->fd);
343 if(err)
344 return(err);
345 }
346 /* If there is a signal already queued, after unblocking ignore it */
347 os_set_ioignore();
348
349 return(0);
350}
351
352void forward_interrupts(int pid)
353{
354 struct irq_fd *irq;
355 unsigned long flags;
356 int err;
357
358 flags = irq_lock();
359 for(irq=active_fds;irq != NULL;irq = irq->next){
360 err = os_set_owner(irq->fd, pid);
361 if(err < 0){
362 /* XXX Just remove the irq rather than
363 * print out an infinite stream of these
364 */
365 printk("Failed to forward %d to pid %d, err = %d\n",
366 irq->fd, pid, -err);
367 }
368
369 irq->pid = pid;
370 }
371 irq_unlock(flags);
372}
373
80/* 374/*
81 * do_IRQ handles all normal device IRQ's (the special 375 * do_IRQ handles all normal device IRQ's (the special
82 * SMP cross-CPU interrupts have their own specific 376 * SMP cross-CPU interrupts have their own specific
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
deleted file mode 100644
index 483e79c5ab98..000000000000
--- a/arch/um/kernel/irq_user.c
+++ /dev/null
@@ -1,324 +0,0 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <unistd.h>
8#include <errno.h>
9#include <signal.h>
10#include <string.h>
11#include <sys/poll.h>
12#include <sys/types.h>
13#include <sys/time.h>
14#include "user_util.h"
15#include "kern_util.h"
16#include "user.h"
17#include "process.h"
18#include "sigio.h"
19#include "irq_user.h"
20#include "os.h"
21#include "misc_constants.h"
22
23struct irq_fd *active_fds = NULL;
24static struct irq_fd **last_irq_ptr = &active_fds;
25
26extern void free_irqs(void);
27
28void sigio_handler(int sig, union uml_pt_regs *regs)
29{
30 struct irq_fd *irq_fd;
31 int n;
32
33 if(smp_sigio_handler()) return;
34 while(1){
35 n = os_waiting_for_events(active_fds);
36 if (n <= 0) {
37 if(n == -EINTR) continue;
38 else break;
39 }
40
41 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
42 if(irq_fd->current_events != 0){
43 irq_fd->current_events = 0;
44 do_IRQ(irq_fd->irq, regs);
45 }
46 }
47 }
48
49 free_irqs();
50}
51
52static void maybe_sigio_broken(int fd, int type)
53{
54 if(os_isatty(fd)){
55 if((type == IRQ_WRITE) && !pty_output_sigio){
56 write_sigio_workaround();
57 add_sigio_fd(fd, 0);
58 }
59 else if((type == IRQ_READ) && !pty_close_sigio){
60 write_sigio_workaround();
61 add_sigio_fd(fd, 1);
62 }
63 }
64}
65
66
67int activate_fd(int irq, int fd, int type, void *dev_id)
68{
69 struct pollfd *tmp_pfd;
70 struct irq_fd *new_fd, *irq_fd;
71 unsigned long flags;
72 int pid, events, err, n;
73
74 pid = os_getpid();
75 err = os_set_fd_async(fd, pid);
76 if(err < 0)
77 goto out;
78
79 new_fd = um_kmalloc(sizeof(*new_fd));
80 err = -ENOMEM;
81 if(new_fd == NULL)
82 goto out;
83
84 if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI;
85 else events = UM_POLLOUT;
86 *new_fd = ((struct irq_fd) { .next = NULL,
87 .id = dev_id,
88 .fd = fd,
89 .type = type,
90 .irq = irq,
91 .pid = pid,
92 .events = events,
93 .current_events = 0 } );
94
95 /* Critical section - locked by a spinlock because this stuff can
96 * be changed from interrupt handlers. The stuff above is done
97 * outside the lock because it allocates memory.
98 */
99
100 /* Actually, it only looks like it can be called from interrupt
101 * context. The culprit is reactivate_fd, which calls
102 * maybe_sigio_broken, which calls write_sigio_workaround,
103 * which calls activate_fd. However, write_sigio_workaround should
104 * only be called once, at boot time. That would make it clear that
105 * this is called only from process context, and can be locked with
106 * a semaphore.
107 */
108 flags = irq_lock();
109 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
110 if((irq_fd->fd == fd) && (irq_fd->type == type)){
111 printk("Registering fd %d twice\n", fd);
112 printk("Irqs : %d, %d\n", irq_fd->irq, irq);
113 printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
114 goto out_unlock;
115 }
116 }
117
118 /*-------------*/
119 if(type == IRQ_WRITE)
120 fd = -1;
121
122 tmp_pfd = NULL;
123 n = 0;
124
125 while(1){
126 n = os_create_pollfd(fd, events, tmp_pfd, n);
127 if (n == 0)
128 break;
129
130 /* n > 0
131 * It means we couldn't put new pollfd to current pollfds
132 * and tmp_fds is NULL or too small for new pollfds array.
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) {
143 kfree(tmp_pfd);
144 tmp_pfd = NULL;
145 }
146
147 tmp_pfd = um_kmalloc(n);
148 if (tmp_pfd == NULL)
149 goto out_kfree;
150
151 flags = irq_lock();
152 }
153 /*-------------*/
154
155 *last_irq_ptr = new_fd;
156 last_irq_ptr = &new_fd->next;
157
158 irq_unlock(flags);
159
160 /* This calls activate_fd, so it has to be outside the critical
161 * section.
162 */
163 maybe_sigio_broken(fd, type);
164
165 return(0);
166
167 out_unlock:
168 irq_unlock(flags);
169 out_kfree:
170 kfree(new_fd);
171 out:
172 return(err);
173}
174
175static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
176{
177 unsigned long flags;
178
179 flags = irq_lock();
180 os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
181 irq_unlock(flags);
182}
183
184struct irq_and_dev {
185 int irq;
186 void *dev;
187};
188
189static int same_irq_and_dev(struct irq_fd *irq, void *d)
190{
191 struct irq_and_dev *data = d;
192
193 return((irq->irq == data->irq) && (irq->id == data->dev));
194}
195
196void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
197{
198 struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq,
199 .dev = dev });
200
201 free_irq_by_cb(same_irq_and_dev, &data);
202}
203
204static int same_fd(struct irq_fd *irq, void *fd)
205{
206 return(irq->fd == *((int *) fd));
207}
208
209void free_irq_by_fd(int fd)
210{
211 free_irq_by_cb(same_fd, &fd);
212}
213
214static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
215{
216 struct irq_fd *irq;
217 int i = 0;
218 int fdi;
219
220 for(irq=active_fds; irq != NULL; irq = irq->next){
221 if((irq->fd == fd) && (irq->irq == irqnum)) break;
222 i++;
223 }
224 if(irq == NULL){
225 printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
226 goto out;
227 }
228 fdi = os_get_pollfd(i);
229 if((fdi != -1) && (fdi != fd)){
230 printk("find_irq_by_fd - mismatch between active_fds and "
231 "pollfds, fd %d vs %d, need %d\n", irq->fd,
232 fdi, fd);
233 irq = NULL;
234 goto out;
235 }
236 *index_out = i;
237 out:
238 return(irq);
239}
240
241void reactivate_fd(int fd, int irqnum)
242{
243 struct irq_fd *irq;
244 unsigned long flags;
245 int i;
246
247 flags = irq_lock();
248 irq = find_irq_by_fd(fd, irqnum, &i);
249 if(irq == NULL){
250 irq_unlock(flags);
251 return;
252 }
253 os_set_pollfd(i, irq->fd);
254 irq_unlock(flags);
255
256 /* This calls activate_fd, so it has to be outside the critical
257 * section.
258 */
259 maybe_sigio_broken(fd, irq->type);
260}
261
262void deactivate_fd(int fd, int irqnum)
263{
264 struct irq_fd *irq;
265 unsigned long flags;
266 int i;
267
268 flags = irq_lock();
269 irq = find_irq_by_fd(fd, irqnum, &i);
270 if(irq == NULL)
271 goto out;
272 os_set_pollfd(i, -1);
273 out:
274 irq_unlock(flags);
275}
276
277int deactivate_all_fds(void)
278{
279 struct irq_fd *irq;
280 int err;
281
282 for(irq=active_fds;irq != NULL;irq = irq->next){
283 err = os_clear_fd_async(irq->fd);
284 if(err)
285 return(err);
286 }
287 /* If there is a signal already queued, after unblocking ignore it */
288 os_set_ioignore();
289
290 return(0);
291}
292
293void forward_interrupts(int pid)
294{
295 struct irq_fd *irq;
296 unsigned long flags;
297 int err;
298
299 flags = irq_lock();
300 for(irq=active_fds;irq != NULL;irq = irq->next){
301 err = os_set_owner(irq->fd, pid);
302 if(err < 0){
303 /* XXX Just remove the irq rather than
304 * print out an infinite stream of these
305 */
306 printk("Failed to forward %d to pid %d, err = %d\n",
307 irq->fd, pid, -err);
308 }
309
310 irq->pid = pid;
311 }
312 irq_unlock(flags);
313}
314
315/*
316 * Overrides for Emacs so that we follow Linus's tabbing style.
317 * Emacs will notice this stuff at the end of the file and automatically
318 * adjust the settings for this buffer only. This must remain at the end
319 * of the file.
320 * ---------------------------------------------------------------------------
321 * Local variables:
322 * c-file-style: "linux"
323 * End:
324 */