irq.c 9.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/* 
 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
 * Licensed under the GPL
 * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
 *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
 */

#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/smp.h"
#include "linux/kernel_stat.h"
#include "linux/interrupt.h"
#include "linux/random.h"
#include "linux/slab.h"
#include "linux/file.h"
#include "linux/proc_fs.h"
#include "linux/init.h"
#include "linux/seq_file.h"
#include "linux/profile.h"
#include "linux/hardirq.h"
#include "asm/irq.h"
#include "asm/hw_irq.h"
#include "asm/atomic.h"
#include "asm/signal.h"
#include "asm/system.h"
#include "asm/errno.h"
#include "asm/uaccess.h"
#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
#include "irq_kern.h"
J
Jeff Dike 已提交
32
#include "os.h"
33
#include "sigio.h"
34
#include "um_malloc.h"
35
#include "misc_constants.h"
L
Linus Torvalds 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

/*
 * Generic, controller-independent functions:
 */

int show_interrupts(struct seq_file *p, void *v)
{
	int i = *(loff_t *) v, j;
	struct irqaction * action;
	unsigned long flags;

	if (i == 0) {
		seq_printf(p, "           ");
		for_each_online_cpu(j)
			seq_printf(p, "CPU%d       ",j);
		seq_putc(p, '\n');
	}

	if (i < NR_IRQS) {
		spin_lock_irqsave(&irq_desc[i].lock, flags);
		action = irq_desc[i].action;
		if (!action) 
			goto skip;
		seq_printf(p, "%3d: ",i);
#ifndef CONFIG_SMP
		seq_printf(p, "%10u ", kstat_irqs(i));
#else
		for_each_online_cpu(j)
			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
66
		seq_printf(p, " %14s", irq_desc[i].chip->typename);
L
Linus Torvalds 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
		seq_printf(p, "  %s", action->name);

		for (action=action->next; action; action = action->next)
			seq_printf(p, ", %s", action->name);

		seq_putc(p, '\n');
skip:
		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
	} else if (i == NR_IRQS) {
		seq_putc(p, '\n');
	}

	return 0;
}

J
Jeff Dike 已提交
82
static struct irq_fd *active_fds = NULL;
83 84 85 86 87 88 89 90 91
static struct irq_fd **last_irq_ptr = &active_fds;

extern void free_irqs(void);

void sigio_handler(int sig, union uml_pt_regs *regs)
{
	struct irq_fd *irq_fd;
	int n;

92 93 94 95
	if (smp_sigio_handler())
		return;

	while (1) {
96 97 98 99 100 101
		n = os_waiting_for_events(active_fds);
		if (n <= 0) {
			if(n == -EINTR) continue;
			else break;
		}

102 103
		for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) {
			if (irq_fd->current_events != 0) {
104 105 106 107 108 109 110 111 112
				irq_fd->current_events = 0;
				do_IRQ(irq_fd->irq, regs);
			}
		}
	}

	free_irqs();
}

113 114
static DEFINE_SPINLOCK(irq_lock);

115 116 117 118 119 120 121 122 123
int activate_fd(int irq, int fd, int type, void *dev_id)
{
	struct pollfd *tmp_pfd;
	struct irq_fd *new_fd, *irq_fd;
	unsigned long flags;
	int pid, events, err, n;

	pid = os_getpid();
	err = os_set_fd_async(fd, pid);
124
	if (err < 0)
125 126 127
		goto out;

	err = -ENOMEM;
J
Jeff Dike 已提交
128
	new_fd = kmalloc(sizeof(struct irq_fd), GFP_KERNEL);
129
	if (new_fd == NULL)
130 131
		goto out;

132 133 134 135
	if (type == IRQ_READ)
		events = UM_POLLIN | UM_POLLPRI;
	else
		events = UM_POLLOUT;
136 137 138 139 140 141 142 143 144
	*new_fd = ((struct irq_fd) { .next  		= NULL,
				     .id 		= dev_id,
				     .fd 		= fd,
				     .type 		= type,
				     .irq 		= irq,
				     .pid  		= pid,
				     .events 		= events,
				     .current_events 	= 0 } );

145
	err = -EBUSY;
146
	spin_lock_irqsave(&irq_lock, flags);
147 148
	for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) {
		if ((irq_fd->fd == fd) && (irq_fd->type == type)) {
149 150 151 152 153 154 155
			printk("Registering fd %d twice\n", fd);
			printk("Irqs : %d, %d\n", irq_fd->irq, irq);
			printk("Ids : 0x%p, 0x%p\n", irq_fd->id, dev_id);
			goto out_unlock;
		}
	}

156
	if (type == IRQ_WRITE)
157 158 159 160 161
		fd = -1;

	tmp_pfd = NULL;
	n = 0;

162
	while (1) {
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
		n = os_create_pollfd(fd, events, tmp_pfd, n);
		if (n == 0)
			break;

		/* n > 0
		 * It means we couldn't put new pollfd to current pollfds
		 * and tmp_fds is NULL or too small for new pollfds array.
		 * Needed size is equal to n as minimum.
		 *
		 * Here we have to drop the lock in order to call
		 * kmalloc, which might sleep.
		 * If something else came in and changed the pollfds array
		 * so we will not be able to put new pollfd struct to pollfds
		 * then we free the buffer tmp_fds and try again.
		 */
178
		spin_unlock_irqrestore(&irq_lock, flags);
179
		kfree(tmp_pfd);
180

J
Jeff Dike 已提交
181
		tmp_pfd = kmalloc(n, GFP_KERNEL);
182 183 184
		if (tmp_pfd == NULL)
			goto out_kfree;

185
		spin_lock_irqsave(&irq_lock, flags);
186 187 188 189 190
	}

	*last_irq_ptr = new_fd;
	last_irq_ptr = &new_fd->next;

191
	spin_unlock_irqrestore(&irq_lock, flags);
192 193 194 195

	/* This calls activate_fd, so it has to be outside the critical
	 * section.
	 */
J
Jeff Dike 已提交
196
	maybe_sigio_broken(fd, (type == IRQ_READ));
197

J
Jeff Dike 已提交
198
	return 0;
199 200

 out_unlock:
201
	spin_unlock_irqrestore(&irq_lock, flags);
202 203 204
 out_kfree:
	kfree(new_fd);
 out:
J
Jeff Dike 已提交
205
	return err;
206 207 208 209 210 211
}

static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
{
	unsigned long flags;

212
	spin_lock_irqsave(&irq_lock, flags);
213
	os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
214
	spin_unlock_irqrestore(&irq_lock, flags);
215 216 217 218 219 220 221 222 223 224 225
}

struct irq_and_dev {
	int irq;
	void *dev;
};

static int same_irq_and_dev(struct irq_fd *irq, void *d)
{
	struct irq_and_dev *data = d;

226
	return ((irq->irq == data->irq) && (irq->id == data->dev));
227 228 229 230 231 232 233 234 235 236 237 238
}

void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
{
	struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
							  .dev  = dev });

	free_irq_by_cb(same_irq_and_dev, &data);
}

static int same_fd(struct irq_fd *irq, void *fd)
{
239
	return (irq->fd == *((int *)fd));
240 241 242 243 244 245 246 247 248 249 250 251 252
}

void free_irq_by_fd(int fd)
{
	free_irq_by_cb(same_fd, &fd);
}

static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
{
	struct irq_fd *irq;
	int i = 0;
	int fdi;

253 254 255
	for (irq = active_fds; irq != NULL; irq = irq->next) {
		if ((irq->fd == fd) && (irq->irq == irqnum))
			break;
256 257
		i++;
	}
258
	if (irq == NULL) {
259 260 261 262
		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
		goto out;
	}
	fdi = os_get_pollfd(i);
263
	if ((fdi != -1) && (fdi != fd)) {
264 265 266 267 268 269 270 271
		printk("find_irq_by_fd - mismatch between active_fds and "
		       "pollfds, fd %d vs %d, need %d\n", irq->fd,
		       fdi, fd);
		irq = NULL;
		goto out;
	}
	*index_out = i;
 out:
272
	return irq;
273 274 275 276 277 278 279 280
}

void reactivate_fd(int fd, int irqnum)
{
	struct irq_fd *irq;
	unsigned long flags;
	int i;

281
	spin_lock_irqsave(&irq_lock, flags);
282
	irq = find_irq_by_fd(fd, irqnum, &i);
283
	if (irq == NULL) {
284
		spin_unlock_irqrestore(&irq_lock, flags);
285 286 287
		return;
	}
	os_set_pollfd(i, irq->fd);
288
	spin_unlock_irqrestore(&irq_lock, flags);
289

J
Jeff Dike 已提交
290
	add_sigio_fd(fd);
291 292 293 294 295 296 297 298
}

void deactivate_fd(int fd, int irqnum)
{
	struct irq_fd *irq;
	unsigned long flags;
	int i;

299
	spin_lock_irqsave(&irq_lock, flags);
300
	irq = find_irq_by_fd(fd, irqnum, &i);
J
Jeff Dike 已提交
301 302 303 304 305
	if(irq == NULL){
		spin_unlock_irqrestore(&irq_lock, flags);
		return;
	}

306
	os_set_pollfd(i, -1);
307
	spin_unlock_irqrestore(&irq_lock, flags);
J
Jeff Dike 已提交
308 309

	ignore_sigio_fd(fd);
310 311 312 313 314 315 316
}

int deactivate_all_fds(void)
{
	struct irq_fd *irq;
	int err;

317
	for (irq = active_fds; irq != NULL; irq = irq->next) {
318
		err = os_clear_fd_async(irq->fd);
319 320
		if (err)
			return err;
321 322 323 324
	}
	/* If there is a signal already queued, after unblocking ignore it */
	os_set_ioignore();

325
	return 0;
326 327
}

328
#ifdef CONFIG_MODE_TT
329 330 331 332 333 334
void forward_interrupts(int pid)
{
	struct irq_fd *irq;
	unsigned long flags;
	int err;

335
	spin_lock_irqsave(&irq_lock, flags);
336
	for (irq = active_fds; irq != NULL; irq = irq->next) {
337
		err = os_set_owner(irq->fd, pid);
338
		if (err < 0) {
339 340 341 342 343 344 345 346 347
			/* XXX Just remove the irq rather than
			 * print out an infinite stream of these
			 */
			printk("Failed to forward %d to pid %d, err = %d\n",
			       irq->fd, pid, -err);
		}

		irq->pid = pid;
	}
348
	spin_unlock_irqrestore(&irq_lock, flags);
349
}
350
#endif
351

L
Linus Torvalds 已提交
352 353 354 355 356 357 358
/*
 * do_IRQ handles all normal device IRQ's (the special
 * SMP cross-CPU interrupts have their own specific
 * handlers).
 */
unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
{
A
Al Viro 已提交
359 360 361 362 363 364
	struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
	irq_enter();
	__do_IRQ(irq);
	irq_exit();
	set_irq_regs(old_regs);
	return 1;
L
Linus Torvalds 已提交
365 366 367
}

int um_request_irq(unsigned int irq, int fd, int type,
368
		   irq_handler_t handler,
L
Linus Torvalds 已提交
369 370 371 372 373 374
		   unsigned long irqflags, const char * devname,
		   void *dev_id)
{
	int err;

	err = request_irq(irq, handler, irqflags, devname, dev_id);
375 376
	if (err)
		return err;
L
Linus Torvalds 已提交
377

378
	if (fd != -1)
L
Linus Torvalds 已提交
379
		err = activate_fd(irq, fd, type, dev_id);
380
	return err;
L
Linus Torvalds 已提交
381 382 383 384
}
EXPORT_SYMBOL(um_request_irq);
EXPORT_SYMBOL(reactivate_fd);

385 386
/* hw_interrupt_type must define (startup || enable) &&
 * (shutdown || disable) && end */
L
Linus Torvalds 已提交
387 388 389 390
static void dummy(unsigned int irq)
{
}

391 392
/* This is used for everything else than the timer. */
static struct hw_interrupt_type normal_irq_type = {
L
Linus Torvalds 已提交
393
	.typename = "SIGIO",
394
	.release = free_irq_by_irq_and_dev,
L
Linus Torvalds 已提交
395 396 397 398 399 400 401 402
	.disable = dummy,
	.enable = dummy,
	.ack = dummy,
	.end = dummy
};

static struct hw_interrupt_type SIGVTALRM_irq_type = {
	.typename = "SIGVTALRM",
403
	.release = free_irq_by_irq_and_dev,
L
Linus Torvalds 已提交
404 405 406 407 408 409 410 411 412 413 414 415 416 417
	.shutdown = dummy, /* never called */
	.disable = dummy,
	.enable = dummy,
	.ack = dummy,
	.end = dummy
};

void __init init_IRQ(void)
{
	int i;

	irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
	irq_desc[TIMER_IRQ].action = NULL;
	irq_desc[TIMER_IRQ].depth = 1;
418
	irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type;
L
Linus Torvalds 已提交
419
	enable_irq(TIMER_IRQ);
420
	for (i = 1; i < NR_IRQS; i++) {
L
Linus Torvalds 已提交
421 422 423
		irq_desc[i].status = IRQ_DISABLED;
		irq_desc[i].action = NULL;
		irq_desc[i].depth = 1;
424
		irq_desc[i].chip = &normal_irq_type;
L
Linus Torvalds 已提交
425 426 427 428
		enable_irq(i);
	}
}

429
int init_aio_irq(int irq, char *name, irq_handler_t handler)
J
Jeff Dike 已提交
430 431 432 433
{
	int fds[2], err;

	err = os_pipe(fds, 1, 1);
434
	if (err) {
J
Jeff Dike 已提交
435 436 437 438 439
		printk("init_aio_irq - os_pipe failed, err = %d\n", -err);
		goto out;
	}

	err = um_request_irq(irq, fds[0], IRQ_READ, handler,
440
			     IRQF_DISABLED | IRQF_SAMPLE_RANDOM, name,
J
Jeff Dike 已提交
441
			     (void *) (long) fds[0]);
442
	if (err) {
J
Jeff Dike 已提交
443 444 445 446 447 448 449 450 451 452 453 454
		printk("init_aio_irq - : um_request_irq failed, err = %d\n",
		       err);
		goto out_close;
	}

	err = fds[1];
	goto out;

 out_close:
	os_close_file(fds[0]);
	os_close_file(fds[1]);
 out:
455
	return err;
J
Jeff Dike 已提交
456
}