irq.c 13.6 KB
Newer Older
J
Jeff Dike 已提交
1
/*
L
Linus Torvalds 已提交
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
 * 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 "kern_util.h"
#include "irq_user.h"
#include "irq_kern.h"
J
Jeff Dike 已提交
31
#include "os.h"
32
#include "sigio.h"
33
#include "um_malloc.h"
34
#include "misc_constants.h"
J
Jeff Dike 已提交
35
#include "as-layout.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

/*
 * 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;
J
Jeff Dike 已提交
57
		if (!action)
L
Linus Torvalds 已提交
58 59 60 61 62 63 64 65
			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 83 84 85 86 87 88 89
/*
 * This list is accessed under irq_lock, except in sigio_handler,
 * where it is safe from being modified.  IRQ handlers won't change it -
 * if an IRQ source has vanished, it will be freed by free_irqs just
 * before returning from sigio_handler.  That will process a separate
 * list of irqs to free, with its own locking, coming back here to
 * remove list elements, taking the irq_lock to do so.
 */
J
Jeff Dike 已提交
90
static struct irq_fd *active_fds = NULL;
91 92 93 94 95 96 97 98 99
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;

100 101 102 103
	if (smp_sigio_handler())
		return;

	while (1) {
104 105 106 107 108 109
		n = os_waiting_for_events(active_fds);
		if (n <= 0) {
			if(n == -EINTR) continue;
			else break;
		}

110 111
		for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) {
			if (irq_fd->current_events != 0) {
112 113 114 115 116 117 118 119 120
				irq_fd->current_events = 0;
				do_IRQ(irq_fd->irq, regs);
			}
		}
	}

	free_irqs();
}

121 122
static DEFINE_SPINLOCK(irq_lock);

123 124 125 126 127 128 129 130 131
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);
132
	if (err < 0)
133 134 135
		goto out;

	err = -ENOMEM;
J
Jeff Dike 已提交
136
	new_fd = kmalloc(sizeof(struct irq_fd), GFP_KERNEL);
137
	if (new_fd == NULL)
138 139
		goto out;

140 141 142 143
	if (type == IRQ_READ)
		events = UM_POLLIN | UM_POLLPRI;
	else
		events = UM_POLLOUT;
144 145 146 147 148 149 150 151 152
	*new_fd = ((struct irq_fd) { .next  		= NULL,
				     .id 		= dev_id,
				     .fd 		= fd,
				     .type 		= type,
				     .irq 		= irq,
				     .pid  		= pid,
				     .events 		= events,
				     .current_events 	= 0 } );

153
	err = -EBUSY;
154
	spin_lock_irqsave(&irq_lock, flags);
155 156
	for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) {
		if ((irq_fd->fd == fd) && (irq_fd->type == type)) {
157 158 159 160 161 162 163
			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;
		}
	}

164
	if (type == IRQ_WRITE)
165 166 167 168 169
		fd = -1;

	tmp_pfd = NULL;
	n = 0;

170
	while (1) {
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
		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.
		 */
186
		spin_unlock_irqrestore(&irq_lock, flags);
187
		kfree(tmp_pfd);
188

J
Jeff Dike 已提交
189
		tmp_pfd = kmalloc(n, GFP_KERNEL);
190 191 192
		if (tmp_pfd == NULL)
			goto out_kfree;

193
		spin_lock_irqsave(&irq_lock, flags);
194 195 196 197 198
	}

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

199
	spin_unlock_irqrestore(&irq_lock, flags);
200 201 202 203

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

J
Jeff Dike 已提交
206
	return 0;
207 208

 out_unlock:
209
	spin_unlock_irqrestore(&irq_lock, flags);
210 211 212
 out_kfree:
	kfree(new_fd);
 out:
J
Jeff Dike 已提交
213
	return err;
214 215 216 217 218 219
}

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

220
	spin_lock_irqsave(&irq_lock, flags);
221
	os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
222
	spin_unlock_irqrestore(&irq_lock, flags);
223 224 225 226 227 228 229 230 231 232 233
}

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;

234
	return ((irq->irq == data->irq) && (irq->id == data->dev));
235 236 237 238 239 240 241 242 243 244 245 246
}

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)
{
247
	return (irq->fd == *((int *)fd));
248 249 250 251 252 253 254
}

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

J
Jeff Dike 已提交
255
/* Must be called with irq_lock held */
256 257 258 259 260 261
static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
{
	struct irq_fd *irq;
	int i = 0;
	int fdi;

262 263 264
	for (irq = active_fds; irq != NULL; irq = irq->next) {
		if ((irq->fd == fd) && (irq->irq == irqnum))
			break;
265 266
		i++;
	}
267
	if (irq == NULL) {
268 269 270 271
		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
		goto out;
	}
	fdi = os_get_pollfd(i);
272
	if ((fdi != -1) && (fdi != fd)) {
273 274 275 276 277 278 279 280
		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:
281
	return irq;
282 283 284 285 286 287 288 289
}

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

290
	spin_lock_irqsave(&irq_lock, flags);
291
	irq = find_irq_by_fd(fd, irqnum, &i);
292
	if (irq == NULL) {
293
		spin_unlock_irqrestore(&irq_lock, flags);
294 295 296
		return;
	}
	os_set_pollfd(i, irq->fd);
297
	spin_unlock_irqrestore(&irq_lock, flags);
298

J
Jeff Dike 已提交
299
	add_sigio_fd(fd);
300 301 302 303 304 305 306 307
}

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

308
	spin_lock_irqsave(&irq_lock, flags);
309
	irq = find_irq_by_fd(fd, irqnum, &i);
J
Jeff Dike 已提交
310 311 312 313 314
	if(irq == NULL){
		spin_unlock_irqrestore(&irq_lock, flags);
		return;
	}

315
	os_set_pollfd(i, -1);
316
	spin_unlock_irqrestore(&irq_lock, flags);
J
Jeff Dike 已提交
317 318

	ignore_sigio_fd(fd);
319 320
}

J
Jeff Dike 已提交
321 322 323 324 325 326
/*
 * Called just before shutdown in order to provide a clean exec
 * environment in case the system is rebooting.  No locking because
 * that would cause a pointless shutdown hang if something hadn't
 * released the lock.
 */
327 328 329 330 331
int deactivate_all_fds(void)
{
	struct irq_fd *irq;
	int err;

332
	for (irq = active_fds; irq != NULL; irq = irq->next) {
333
		err = os_clear_fd_async(irq->fd);
334 335
		if (err)
			return err;
336 337 338 339
	}
	/* If there is a signal already queued, after unblocking ignore it */
	os_set_ioignore();

340
	return 0;
341 342
}

343
#ifdef CONFIG_MODE_TT
344 345 346 347 348 349
void forward_interrupts(int pid)
{
	struct irq_fd *irq;
	unsigned long flags;
	int err;

350
	spin_lock_irqsave(&irq_lock, flags);
351
	for (irq = active_fds; irq != NULL; irq = irq->next) {
352
		err = os_set_owner(irq->fd, pid);
353
		if (err < 0) {
354 355 356 357 358 359 360 361 362
			/* 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;
	}
363
	spin_unlock_irqrestore(&irq_lock, flags);
364
}
365
#endif
366

L
Linus Torvalds 已提交
367 368 369 370 371 372 373
/*
 * 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 已提交
374 375 376 377 378 379
	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 已提交
380 381 382
}

int um_request_irq(unsigned int irq, int fd, int type,
383
		   irq_handler_t handler,
L
Linus Torvalds 已提交
384 385 386 387 388 389
		   unsigned long irqflags, const char * devname,
		   void *dev_id)
{
	int err;

	err = request_irq(irq, handler, irqflags, devname, dev_id);
390 391
	if (err)
		return err;
L
Linus Torvalds 已提交
392

393
	if (fd != -1)
L
Linus Torvalds 已提交
394
		err = activate_fd(irq, fd, type, dev_id);
395
	return err;
L
Linus Torvalds 已提交
396 397 398 399
}
EXPORT_SYMBOL(um_request_irq);
EXPORT_SYMBOL(reactivate_fd);

400 401
/* hw_interrupt_type must define (startup || enable) &&
 * (shutdown || disable) && end */
L
Linus Torvalds 已提交
402 403 404 405
static void dummy(unsigned int irq)
{
}

406 407
/* This is used for everything else than the timer. */
static struct hw_interrupt_type normal_irq_type = {
L
Linus Torvalds 已提交
408
	.typename = "SIGIO",
409
	.release = free_irq_by_irq_and_dev,
L
Linus Torvalds 已提交
410 411 412 413 414 415 416 417
	.disable = dummy,
	.enable = dummy,
	.ack = dummy,
	.end = dummy
};

static struct hw_interrupt_type SIGVTALRM_irq_type = {
	.typename = "SIGVTALRM",
418
	.release = free_irq_by_irq_and_dev,
L
Linus Torvalds 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432
	.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;
433
	irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type;
L
Linus Torvalds 已提交
434
	enable_irq(TIMER_IRQ);
435
	for (i = 1; i < NR_IRQS; i++) {
L
Linus Torvalds 已提交
436 437 438
		irq_desc[i].status = IRQ_DISABLED;
		irq_desc[i].action = NULL;
		irq_desc[i].depth = 1;
439
		irq_desc[i].chip = &normal_irq_type;
L
Linus Torvalds 已提交
440 441 442 443
		enable_irq(i);
	}
}

444
int init_aio_irq(int irq, char *name, irq_handler_t handler)
J
Jeff Dike 已提交
445 446 447 448
{
	int fds[2], err;

	err = os_pipe(fds, 1, 1);
449
	if (err) {
J
Jeff Dike 已提交
450 451 452 453 454
		printk("init_aio_irq - os_pipe failed, err = %d\n", -err);
		goto out;
	}

	err = um_request_irq(irq, fds[0], IRQ_READ, handler,
455
			     IRQF_DISABLED | IRQF_SAMPLE_RANDOM, name,
J
Jeff Dike 已提交
456
			     (void *) (long) fds[0]);
457
	if (err) {
J
Jeff Dike 已提交
458 459 460 461 462 463 464 465 466 467 468 469
		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:
470
	return err;
J
Jeff Dike 已提交
471
}
J
Jeff Dike 已提交
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581

/*
 * IRQ stack entry and exit:
 *
 * Unlike i386, UML doesn't receive IRQs on the normal kernel stack
 * and switch over to the IRQ stack after some preparation.  We use
 * sigaltstack to receive signals on a separate stack from the start.
 * These two functions make sure the rest of the kernel won't be too
 * upset by being on a different stack.  The IRQ stack has a
 * thread_info structure at the bottom so that current et al continue
 * to work.
 *
 * to_irq_stack copies the current task's thread_info to the IRQ stack
 * thread_info and sets the tasks's stack to point to the IRQ stack.
 *
 * from_irq_stack copies the thread_info struct back (flags may have
 * been modified) and resets the task's stack pointer.
 *
 * Tricky bits -
 *
 * What happens when two signals race each other?  UML doesn't block
 * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal
 * could arrive while a previous one is still setting up the
 * thread_info.
 *
 * There are three cases -
 *     The first interrupt on the stack - sets up the thread_info and
 * handles the interrupt
 *     A nested interrupt interrupting the copying of the thread_info -
 * can't handle the interrupt, as the stack is in an unknown state
 *     A nested interrupt not interrupting the copying of the
 * thread_info - doesn't do any setup, just handles the interrupt
 *
 * The first job is to figure out whether we interrupted stack setup.
 * This is done by xchging the signal mask with thread_info->pending.
 * If the value that comes back is zero, then there is no setup in
 * progress, and the interrupt can be handled.  If the value is
 * non-zero, then there is stack setup in progress.  In order to have
 * the interrupt handled, we leave our signal in the mask, and it will
 * be handled by the upper handler after it has set up the stack.
 *
 * Next is to figure out whether we are the outer handler or a nested
 * one.  As part of setting up the stack, thread_info->real_thread is
 * set to non-NULL (and is reset to NULL on exit).  This is the
 * nesting indicator.  If it is non-NULL, then the stack is already
 * set up and the handler can run.
 */

static unsigned long pending_mask;

unsigned long to_irq_stack(int sig, unsigned long *mask_out)
{
	struct thread_info *ti;
	unsigned long mask, old;
	int nested;

	mask = xchg(&pending_mask, 1 << sig);
	if(mask != 0){
		/* If any interrupts come in at this point, we want to
		 * make sure that their bits aren't lost by our
		 * putting our bit in.  So, this loop accumulates bits
		 * until xchg returns the same value that we put in.
		 * When that happens, there were no new interrupts,
		 * and pending_mask contains a bit for each interrupt
		 * that came in.
		 */
		old = 1 << sig;
		do {
			old |= mask;
			mask = xchg(&pending_mask, old);
		} while(mask != old);
		return 1;
	}

	ti = current_thread_info();
	nested = (ti->real_thread != NULL);
	if(!nested){
		struct task_struct *task;
		struct thread_info *tti;

		task = cpu_tasks[ti->cpu].task;
		tti = task_thread_info(task);
		*ti = *tti;
		ti->real_thread = tti;
		task->stack = ti;
	}

	mask = xchg(&pending_mask, 0);
	*mask_out |= mask | nested;
	return 0;
}

unsigned long from_irq_stack(int nested)
{
	struct thread_info *ti, *to;
	unsigned long mask;

	ti = current_thread_info();

	pending_mask = 1;

	to = ti->real_thread;
	current->stack = to;
	ti->real_thread = NULL;
	*to = *ti;

	mask = xchg(&pending_mask, 0);
	return mask & ~1;
}