irq.c 29.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 *  Derived from arch/i386/kernel/irq.c
 *    Copyright (C) 1992 Linus Torvalds
 *  Adapted from arch/i386 by Gary Thomas
 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
S
Stephen Rothwell 已提交
6 7
 *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
 *    Copyright (C) 1996-2001 Cort Dougan
L
Linus Torvalds 已提交
8 9
 *  Adapted for Power Macintosh by Paul Mackerras
 *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
S
Stephen Rothwell 已提交
10
 *
L
Linus Torvalds 已提交
11 12 13 14 15 16 17 18 19 20
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 * This file contains the code used by various IRQ handling routines:
 * asking for different IRQ's should be done through these routines
 * instead of just grabbing them. Thus setups with different IRQ numbers
 * shouldn't result in any weird surprises, and installing new handlers
 * should be easier.
S
Stephen Rothwell 已提交
21 22 23 24 25 26 27 28
 *
 * The MPC8xx has an interrupt mask in the SIU.  If a bit is set, the
 * interrupt is _enabled_.  As expected, IRQ0 is bit 0 in the 32-bit
 * mask register (of which only 16 are defined), hence the weird shifting
 * and complement of the cached_irq_mask.  I want to be able to stuff
 * this right into the SIU SMASK register.
 * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx
 * to reduce code space and undefined function references.
L
Linus Torvalds 已提交
29 30
 */

31 32
#undef DEBUG

33
#include <linux/export.h>
L
Linus Torvalds 已提交
34 35 36 37
#include <linux/threads.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
S
Stephen Rothwell 已提交
38
#include <linux/ptrace.h>
L
Linus Torvalds 已提交
39 40 41 42 43 44 45
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/irq.h>
S
Stephen Rothwell 已提交
46 47
#include <linux/seq_file.h>
#include <linux/cpumask.h>
L
Linus Torvalds 已提交
48 49
#include <linux/profile.h>
#include <linux/bitops.h>
50 51 52 53
#include <linux/list.h>
#include <linux/radix-tree.h>
#include <linux/mutex.h>
#include <linux/bootmem.h>
J
Jake Moilanen 已提交
54
#include <linux/pci.h>
55
#include <linux/debugfs.h>
56 57
#include <linux/of.h>
#include <linux/of_irq.h>
L
Linus Torvalds 已提交
58 59 60 61 62 63 64 65 66 67

#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/cache.h>
#include <asm/prom.h>
#include <asm/ptrace.h>
#include <asm/machdep.h>
68
#include <asm/udbg.h>
69
#include <asm/smp.h>
70

71
#ifdef CONFIG_PPC64
L
Linus Torvalds 已提交
72
#include <asm/paca.h>
73
#include <asm/firmware.h>
74
#include <asm/lv1call.h>
S
Stephen Rothwell 已提交
75
#endif
76 77
#define CREATE_TRACE_POINTS
#include <asm/trace.h>
L
Linus Torvalds 已提交
78

79 80 81
DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
EXPORT_PER_CPU_SYMBOL(irq_stat);

82
int __irq_offset_value;
S
Stephen Rothwell 已提交
83 84

#ifdef CONFIG_PPC32
85 86
EXPORT_SYMBOL(__irq_offset_value);
atomic_t ppc_n_lost_interrupts;
S
Stephen Rothwell 已提交
87 88 89 90 91

#ifdef CONFIG_TAU_INT
extern int tau_initialized;
extern int tau_interrupts(int);
#endif
92
#endif /* CONFIG_PPC32 */
S
Stephen Rothwell 已提交
93 94

#ifdef CONFIG_PPC64
95

L
Linus Torvalds 已提交
96
int distribute_irqs = 1;
97

98
static inline notrace unsigned long get_irq_happened(void)
99
{
100
	unsigned long happened;
101 102

	__asm__ __volatile__("lbz %0,%1(13)"
103
	: "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened)));
104

105
	return happened;
106 107
}

S
Steven Rostedt 已提交
108
static inline notrace void set_soft_enabled(unsigned long enable)
109 110 111 112 113
{
	__asm__ __volatile__("stb %0,%1(13)"
	: : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
}

114
static inline notrace int decrementer_check_overflow(void)
115
{
116 117 118
 	u64 now = get_tb_or_rtc();
 	u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
 
119 120
	if (now >= *next_tb)
		set_dec(1);
121
	return now >= *next_tb;
122 123
}

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/* This is called whenever we are re-enabling interrupts
 * and returns either 0 (nothing to do) or 500/900 if there's
 * either an EE or a DEC to generate.
 *
 * This is called in two contexts: From arch_local_irq_restore()
 * before soft-enabling interrupts, and from the exception exit
 * path when returning from an interrupt from a soft-disabled to
 * a soft enabled context. In both case we have interrupts hard
 * disabled.
 *
 * We take care of only clearing the bits we handled in the
 * PACA irq_happened field since we can only re-emit one at a
 * time and we don't want to "lose" one.
 */
notrace unsigned int __check_irq_replay(void)
139
{
140
	/*
141 142 143
	 * We use local_paca rather than get_paca() to avoid all
	 * the debug_smp_processor_id() business in this low level
	 * function
144
	 */
145
	unsigned char happened = local_paca->irq_happened;
146

147 148 149 150 151 152 153 154 155 156
	/* Clear bit 0 which we wouldn't clear otherwise */
	local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;

	/*
	 * Force the delivery of pending soft-disabled interrupts on PS3.
	 * Any HV call will have this side effect.
	 */
	if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
		u64 tmp, tmp2;
		lv1_get_version_info(&tmp, &tmp2);
157 158
	}

159
	/*
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	 * We may have missed a decrementer interrupt. We check the
	 * decrementer itself rather than the paca irq_happened field
	 * in case we also had a rollover while hard disabled
	 */
	local_paca->irq_happened &= ~PACA_IRQ_DEC;
	if (decrementer_check_overflow())
		return 0x900;

	/* Finally check if an external interrupt happened */
	local_paca->irq_happened &= ~PACA_IRQ_EE;
	if (happened & PACA_IRQ_EE)
		return 0x500;

#ifdef CONFIG_PPC_BOOK3E
	/* Finally check if an EPR external interrupt happened
	 * this bit is typically set if we need to handle another
	 * "edge" interrupt from within the MPIC "EPR" handler
	 */
	local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE;
	if (happened & PACA_IRQ_EE_EDGE)
		return 0x500;

	local_paca->irq_happened &= ~PACA_IRQ_DBELL;
	if (happened & PACA_IRQ_DBELL)
		return 0x280;
#endif /* CONFIG_PPC_BOOK3E */

	/* There should be nothing left ! */
	BUG_ON(local_paca->irq_happened != 0);

	return 0;
}

notrace void arch_local_irq_restore(unsigned long en)
{
	unsigned char irq_happened;
	unsigned int replay;

	/* Write the new soft-enabled value */
	set_soft_enabled(en);
	if (!en)
		return;
	/*
	 * From this point onward, we can take interrupts, preempt,
	 * etc... unless we got hard-disabled. We check if an event
	 * happened. If none happened, we know we can just return.
	 *
	 * We may have preempted before the check below, in which case
	 * we are checking the "new" CPU instead of the old one. This
	 * is only a problem if an event happened on the "old" CPU.
	 *
	 * External interrupt events on non-iseries will have caused
	 * interrupts to be hard-disabled, so there is no problem, we
	 * cannot have preempted.
214
	 */
215 216
	irq_happened = get_irq_happened();
	if (!irq_happened)
217
		return;
218 219

	/*
220 221 222 223 224 225 226 227 228
	 * We need to hard disable to get a trusted value from
	 * __check_irq_replay(). We also need to soft-disable
	 * again to avoid warnings in there due to the use of
	 * per-cpu variables.
	 *
	 * We know that if the value in irq_happened is exactly 0x01
	 * then we are already hard disabled (there are other less
	 * common cases that we'll ignore for now), so we skip the
	 * (expensive) mtmsrd.
229
	 */
230 231 232
	if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
		__hard_irq_disable();
	set_soft_enabled(0);
233

234
	/*
235 236 237
	 * Check if anything needs to be re-emitted. We haven't
	 * soft-enabled yet to avoid warnings in decrementer_check_overflow
	 * accessing per-cpu variables
238
	 */
239 240 241 242
	replay = __check_irq_replay();

	/* We can soft-enable now */
	set_soft_enabled(1);
243 244

	/*
245 246
	 * And replay if we have to. This will return with interrupts
	 * hard-enabled.
247
	 */
248 249 250
	if (replay) {
		__replay_interrupt(replay);
		return;
251 252
	}

253
	/* Finally, let's ensure we are hard enabled */
254
	__hard_irq_enable();
255
}
D
David Howells 已提交
256
EXPORT_SYMBOL(arch_local_irq_restore);
257 258 259 260 261 262 263 264 265 266 267 268 269

/*
 * This is specifically called by assembly code to re-enable interrupts
 * if they are currently disabled. This is typically called before
 * schedule() or do_signal() when returning to userspace. We do it
 * in C to avoid the burden of dealing with lockdep etc...
 */
void restore_interrupts(void)
{
	if (irqs_disabled())
		local_irq_enable();
}

S
Stephen Rothwell 已提交
270
#endif /* CONFIG_PPC64 */
L
Linus Torvalds 已提交
271

272
int arch_show_interrupts(struct seq_file *p, int prec)
273 274 275 276 277 278 279 280 281 282 283 284
{
	int j;

#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
	if (tau_initialized) {
		seq_printf(p, "%*s: ", prec, "TAU");
		for_each_online_cpu(j)
			seq_printf(p, "%10u ", tau_interrupts(j));
		seq_puts(p, "  PowerPC             Thermal Assist (cpu temp)\n");
	}
#endif /* CONFIG_PPC32 && CONFIG_TAU_INT */

285 286 287 288 289
	seq_printf(p, "%*s: ", prec, "LOC");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs);
        seq_printf(p, "  Local timer interrupts\n");

290 291 292 293 294
	seq_printf(p, "%*s: ", prec, "SPU");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs);
	seq_printf(p, "  Spurious interrupts\n");

295 296 297 298 299 300 301 302 303 304
	seq_printf(p, "%*s: ", prec, "CNT");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs);
	seq_printf(p, "  Performance monitoring interrupts\n");

	seq_printf(p, "%*s: ", prec, "MCE");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", per_cpu(irq_stat, j).mce_exceptions);
	seq_printf(p, "  Machine check exceptions\n");

305 306 307
	return 0;
}

308 309 310 311 312 313 314 315 316
/*
 * /proc/stat helpers
 */
u64 arch_irq_stat_cpu(unsigned int cpu)
{
	u64 sum = per_cpu(irq_stat, cpu).timer_irqs;

	sum += per_cpu(irq_stat, cpu).pmu_irqs;
	sum += per_cpu(irq_stat, cpu).mce_exceptions;
317
	sum += per_cpu(irq_stat, cpu).spurious_irqs;
318 319 320 321

	return sum;
}

L
Linus Torvalds 已提交
322
#ifdef CONFIG_HOTPLUG_CPU
323
void migrate_irqs(void)
L
Linus Torvalds 已提交
324
{
M
Michael Ellerman 已提交
325
	struct irq_desc *desc;
L
Linus Torvalds 已提交
326 327
	unsigned int irq;
	static int warned;
328
	cpumask_var_t mask;
329
	const struct cpumask *map = cpu_online_mask;
L
Linus Torvalds 已提交
330

331
	alloc_cpumask_var(&mask, GFP_KERNEL);
L
Linus Torvalds 已提交
332

333
	for_each_irq(irq) {
334
		struct irq_data *data;
335 336
		struct irq_chip *chip;

M
Michael Ellerman 已提交
337
		desc = irq_to_desc(irq);
338 339 340
		if (!desc)
			continue;

341 342
		data = irq_desc_get_irq_data(desc);
		if (irqd_is_per_cpu(data))
L
Linus Torvalds 已提交
343 344
			continue;

345
		chip = irq_data_get_irq_chip(data);
346

347
		cpumask_and(mask, data->affinity, map);
348
		if (cpumask_any(mask) >= nr_cpu_ids) {
L
Linus Torvalds 已提交
349
			printk("Breaking affinity for irq %i\n", irq);
350
			cpumask_copy(mask, map);
L
Linus Torvalds 已提交
351
		}
352
		if (chip->irq_set_affinity)
353
			chip->irq_set_affinity(data, mask, true);
M
Michael Ellerman 已提交
354
		else if (desc->action && !(warned++))
L
Linus Torvalds 已提交
355 356 357
			printk("Cannot set affinity for irq %i\n", irq);
	}

358 359
	free_cpumask_var(mask);

L
Linus Torvalds 已提交
360 361 362 363 364 365
	local_irq_enable();
	mdelay(1);
	local_irq_disable();
}
#endif

366 367 368 369 370 371
static inline void handle_one_irq(unsigned int irq)
{
	struct thread_info *curtp, *irqtp;
	unsigned long saved_sp_limit;
	struct irq_desc *desc;

372 373 374 375
	desc = irq_to_desc(irq);
	if (!desc)
		return;

376 377 378 379 380 381
	/* Switch to the irq stack to handle this */
	curtp = current_thread_info();
	irqtp = hardirq_ctx[smp_processor_id()];

	if (curtp == irqtp) {
		/* We're already on the irq stack, just handle it */
382
		desc->handle_irq(irq, desc);
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
		return;
	}

	saved_sp_limit = current->thread.ksp_limit;

	irqtp->task = curtp->task;
	irqtp->flags = 0;

	/* Copy the softirq bits in preempt_count so that the
	 * softirq checks work in the hardirq context. */
	irqtp->preempt_count = (irqtp->preempt_count & ~SOFTIRQ_MASK) |
			       (curtp->preempt_count & SOFTIRQ_MASK);

	current->thread.ksp_limit = (unsigned long)irqtp +
		_ALIGN_UP(sizeof(struct thread_info), 16);

399
	call_handle_irq(irq, desc, irqtp, desc->handle_irq);
400 401 402 403 404 405 406 407 408 409
	current->thread.ksp_limit = saved_sp_limit;
	irqtp->task = NULL;

	/* Set any flag that may have been set on the
	 * alternate stack
	 */
	if (irqtp->flags)
		set_bits(irqtp->flags, &curtp->flags);
}

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
static inline void check_stack_overflow(void)
{
#ifdef CONFIG_DEBUG_STACKOVERFLOW
	long sp;

	sp = __get_SP() & (THREAD_SIZE-1);

	/* check for stack overflow: is there less than 2KB free? */
	if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
		printk("do_IRQ: stack overflow: %ld\n",
			sp - sizeof(struct thread_info));
		dump_stack();
	}
#endif
}

L
Linus Torvalds 已提交
426 427
void do_IRQ(struct pt_regs *regs)
{
428
	struct pt_regs *old_regs = set_irq_regs(regs);
429
	unsigned int irq;
L
Linus Torvalds 已提交
430

431 432
	trace_irq_entry(regs);

433
	irq_enter();
L
Linus Torvalds 已提交
434

435
	check_stack_overflow();
L
Linus Torvalds 已提交
436

437 438 439 440 441
	/*
	 * Query the platform PIC for the interrupt & ack it.
	 *
	 * This will typically lower the interrupt line to the CPU
	 */
O
Olaf Hering 已提交
442
	irq = ppc_md.get_irq();
L
Linus Torvalds 已提交
443

444 445 446 447
	/* We can hard enable interrupts now */
	may_hard_irq_enable();

	/* And finally process it */
448 449 450
	if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
		handle_one_irq(irq);
	else if (irq != NO_IRQ_IGNORE)
451
		__get_cpu_var(irq_stat).spurious_irqs++;
452

453
	irq_exit();
454
	set_irq_regs(old_regs);
S
Stephen Rothwell 已提交
455

456
	trace_irq_exit(regs);
457
}
L
Linus Torvalds 已提交
458 459 460

void __init init_IRQ(void)
{
461 462
	if (ppc_md.init_IRQ)
		ppc_md.init_IRQ();
463 464 465

	exc_lvl_ctx_init();

L
Linus Torvalds 已提交
466 467 468
	irq_ctx_init();
}

469 470 471 472 473 474 475 476
#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
struct thread_info   *critirq_ctx[NR_CPUS] __read_mostly;
struct thread_info    *dbgirq_ctx[NR_CPUS] __read_mostly;
struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly;

void exc_lvl_ctx_init(void)
{
	struct thread_info *tp;
477
	int i, cpu_nr;
478 479

	for_each_possible_cpu(i) {
480 481 482 483 484 485 486 487
#ifdef CONFIG_PPC64
		cpu_nr = i;
#else
		cpu_nr = get_hard_smp_processor_id(i);
#endif
		memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE);
		tp = critirq_ctx[cpu_nr];
		tp->cpu = cpu_nr;
488 489 490
		tp->preempt_count = 0;

#ifdef CONFIG_BOOKE
491 492 493
		memset((void *)dbgirq_ctx[cpu_nr], 0, THREAD_SIZE);
		tp = dbgirq_ctx[cpu_nr];
		tp->cpu = cpu_nr;
494 495
		tp->preempt_count = 0;

496 497 498
		memset((void *)mcheckirq_ctx[cpu_nr], 0, THREAD_SIZE);
		tp = mcheckirq_ctx[cpu_nr];
		tp->cpu = cpu_nr;
499 500 501 502 503
		tp->preempt_count = HARDIRQ_OFFSET;
#endif
	}
}
#endif
L
Linus Torvalds 已提交
504

505 506
struct thread_info *softirq_ctx[NR_CPUS] __read_mostly;
struct thread_info *hardirq_ctx[NR_CPUS] __read_mostly;
L
Linus Torvalds 已提交
507 508 509 510 511 512

void irq_ctx_init(void)
{
	struct thread_info *tp;
	int i;

513
	for_each_possible_cpu(i) {
L
Linus Torvalds 已提交
514 515 516
		memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
		tp = softirq_ctx[i];
		tp->cpu = i;
517
		tp->preempt_count = 0;
L
Linus Torvalds 已提交
518 519 520 521 522 523 524 525

		memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
		tp = hardirq_ctx[i];
		tp->cpu = i;
		tp->preempt_count = HARDIRQ_OFFSET;
	}
}

526 527 528
static inline void do_softirq_onstack(void)
{
	struct thread_info *curtp, *irqtp;
529
	unsigned long saved_sp_limit = current->thread.ksp_limit;
530 531 532 533

	curtp = current_thread_info();
	irqtp = softirq_ctx[smp_processor_id()];
	irqtp->task = curtp->task;
534
	irqtp->flags = 0;
535 536
	current->thread.ksp_limit = (unsigned long)irqtp +
				    _ALIGN_UP(sizeof(struct thread_info), 16);
537
	call_do_softirq(irqtp);
538
	current->thread.ksp_limit = saved_sp_limit;
539
	irqtp->task = NULL;
540 541 542 543 544 545

	/* Set any flag that may have been set on the
	 * alternate stack
	 */
	if (irqtp->flags)
		set_bits(irqtp->flags, &curtp->flags);
546
}
L
Linus Torvalds 已提交
547 548 549 550 551 552 553 554 555 556

void do_softirq(void)
{
	unsigned long flags;

	if (in_interrupt())
		return;

	local_irq_save(flags);

557
	if (local_softirq_pending())
558
		do_softirq_onstack();
L
Linus Torvalds 已提交
559 560 561 562 563 564

	local_irq_restore(flags);
}


/*
565
 * IRQ controller and virtual interrupts
L
Linus Torvalds 已提交
566 567
 */

568 569 570 571 572 573 574 575 576 577
/* The main irq map itself is an array of NR_IRQ entries containing the
 * associate host and irq number. An entry with a host of NULL is free.
 * An entry can be allocated if it's free, the allocator always then sets
 * hwirq first to the host's invalid irq number and then fills ops.
 */
struct irq_map_entry {
	irq_hw_number_t	hwirq;
	struct irq_host	*host;
};

578
static LIST_HEAD(irq_hosts);
579
static DEFINE_RAW_SPINLOCK(irq_big_lock);
580
static DEFINE_MUTEX(revmap_trees_mutex);
581
static struct irq_map_entry irq_map[NR_IRQS];
582 583
static unsigned int irq_virq_count = NR_IRQS;
static struct irq_host *irq_default_host;
L
Linus Torvalds 已提交
584

585 586 587 588 589 590
irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
{
	return irq_map[d->irq].hwirq;
}
EXPORT_SYMBOL_GPL(irqd_to_hwirq);

591 592 593 594 595 596
irq_hw_number_t virq_to_hw(unsigned int virq)
{
	return irq_map[virq].hwirq;
}
EXPORT_SYMBOL_GPL(virq_to_hw);

597 598 599 600 601 602
bool virq_is_host(unsigned int virq, struct irq_host *host)
{
	return irq_map[virq].host == host;
}
EXPORT_SYMBOL_GPL(virq_is_host);

603 604 605 606 607
static int default_irq_host_match(struct irq_host *h, struct device_node *np)
{
	return h->of_node != NULL && h->of_node == np;
}

608
struct irq_host *irq_alloc_host(struct device_node *of_node,
609 610 611 612
				unsigned int revmap_type,
				unsigned int revmap_arg,
				struct irq_host_ops *ops,
				irq_hw_number_t inval_irq)
L
Linus Torvalds 已提交
613
{
614 615 616 617 618 619 620 621 622
	struct irq_host *host;
	unsigned int size = sizeof(struct irq_host);
	unsigned int i;
	unsigned int *rmap;
	unsigned long flags;

	/* Allocate structure and revmap table if using linear mapping */
	if (revmap_type == IRQ_HOST_MAP_LINEAR)
		size += revmap_arg * sizeof(unsigned int);
623
	host = kzalloc(size, GFP_KERNEL);
624 625
	if (host == NULL)
		return NULL;
626

627 628 629 630
	/* Fill structure */
	host->revmap_type = revmap_type;
	host->inval_irq = inval_irq;
	host->ops = ops;
631
	host->of_node = of_node_get(of_node);
632

633 634
	if (host->ops->match == NULL)
		host->ops->match = default_irq_host_match;
635

636
	raw_spin_lock_irqsave(&irq_big_lock, flags);
637 638 639 640 641 642

	/* If it's a legacy controller, check for duplicates and
	 * mark it as allocated (we use irq 0 host pointer for that
	 */
	if (revmap_type == IRQ_HOST_MAP_LEGACY) {
		if (irq_map[0].host != NULL) {
643
			raw_spin_unlock_irqrestore(&irq_big_lock, flags);
644 645
			of_node_put(host->of_node);
			kfree(host);
646 647 648 649 650 651
			return NULL;
		}
		irq_map[0].host = host;
	}

	list_add(&host->link, &irq_hosts);
652
	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
653 654 655 656 657 658 659 660

	/* Additional setups per revmap type */
	switch(revmap_type) {
	case IRQ_HOST_MAP_LEGACY:
		/* 0 is always the invalid number for legacy */
		host->inval_irq = 0;
		/* setup us as the host for all legacy interrupts */
		for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
661
			irq_map[i].hwirq = i;
662 663 664 665 666 667
			smp_wmb();
			irq_map[i].host = host;
			smp_wmb();

			/* Legacy flags are left to default at this point,
			 * one can then use irq_create_mapping() to
J
Jean Delvare 已提交
668
			 * explicitly change them
669
			 */
670
			ops->map(host, i, i);
671 672 673

			/* Clear norequest flags */
			irq_clear_status_flags(i, IRQ_NOREQUEST);
674 675 676 677 678
		}
		break;
	case IRQ_HOST_MAP_LINEAR:
		rmap = (unsigned int *)(host + 1);
		for (i = 0; i < revmap_arg; i++)
679
			rmap[i] = NO_IRQ;
680 681 682 683
		host->revmap_data.linear.size = revmap_arg;
		smp_wmb();
		host->revmap_data.linear.revmap = rmap;
		break;
684 685 686
	case IRQ_HOST_MAP_TREE:
		INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
		break;
687 688 689 690 691 692 693
	default:
		break;
	}

	pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);

	return host;
L
Linus Torvalds 已提交
694 695
}

696
struct irq_host *irq_find_host(struct device_node *node)
L
Linus Torvalds 已提交
697
{
698 699 700 701 702 703 704 705
	struct irq_host *h, *found = NULL;
	unsigned long flags;

	/* We might want to match the legacy controller last since
	 * it might potentially be set to match all interrupts in
	 * the absence of a device node. This isn't a problem so far
	 * yet though...
	 */
706
	raw_spin_lock_irqsave(&irq_big_lock, flags);
707
	list_for_each_entry(h, &irq_hosts, link)
708
		if (h->ops->match(h, node)) {
709 710 711
			found = h;
			break;
		}
712
	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
713 714 715 716 717 718 719
	return found;
}
EXPORT_SYMBOL_GPL(irq_find_host);

void irq_set_default_host(struct irq_host *host)
{
	pr_debug("irq: Default host set to @0x%p\n", host);
L
Linus Torvalds 已提交
720

721 722
	irq_default_host = host;
}
L
Linus Torvalds 已提交
723

724 725 726
void irq_set_virq_count(unsigned int count)
{
	pr_debug("irq: Trying to set virq count to %d\n", count);
727

728 729 730 731 732
	BUG_ON(count < NUM_ISA_INTERRUPTS);
	if (count < NR_IRQS)
		irq_virq_count = count;
}

733 734 735
static int irq_setup_virq(struct irq_host *host, unsigned int virq,
			    irq_hw_number_t hwirq)
{
T
Thomas Gleixner 已提交
736
	int res;
737

T
Thomas Gleixner 已提交
738 739
	res = irq_alloc_desc_at(virq, 0);
	if (res != virq) {
740 741 742 743
		pr_debug("irq: -> allocating desc failed\n");
		goto error;
	}

744 745 746 747 748 749 750
	/* map it */
	smp_wmb();
	irq_map[virq].hwirq = hwirq;
	smp_mb();

	if (host->ops->map(host, virq, hwirq)) {
		pr_debug("irq: -> mapping failed, freeing\n");
T
Thomas Gleixner 已提交
751
		goto errdesc;
752 753
	}

754 755
	irq_clear_status_flags(virq, IRQ_NOREQUEST);

756
	return 0;
757

T
Thomas Gleixner 已提交
758 759
errdesc:
	irq_free_descs(virq, 1);
760 761 762
error:
	irq_free_virt(virq, 1);
	return -1;
763
}
764

765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
unsigned int irq_create_direct_mapping(struct irq_host *host)
{
	unsigned int virq;

	if (host == NULL)
		host = irq_default_host;

	BUG_ON(host == NULL);
	WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);

	virq = irq_alloc_virt(host, 1, 0);
	if (virq == NO_IRQ) {
		pr_debug("irq: create_direct virq allocation failed\n");
		return NO_IRQ;
	}

	pr_debug("irq: create_direct obtained virq %d\n", virq);

	if (irq_setup_virq(host, virq, virq))
		return NO_IRQ;

	return virq;
}

789
unsigned int irq_create_mapping(struct irq_host *host,
790
				irq_hw_number_t hwirq)
791 792 793
{
	unsigned int virq, hint;

794
	pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
795 796 797 798 799 800 801 802 803

	/* Look for default host if nececssary */
	if (host == NULL)
		host = irq_default_host;
	if (host == NULL) {
		printk(KERN_WARNING "irq_create_mapping called for"
		       " NULL host, hwirq=%lx\n", hwirq);
		WARN_ON(1);
		return NO_IRQ;
L
Linus Torvalds 已提交
804
	}
805
	pr_debug("irq: -> using host @%p\n", host);
L
Linus Torvalds 已提交
806

807
	/* Check if mapping already exists */
808
	virq = irq_find_mapping(host, hwirq);
809
	if (virq != NO_IRQ) {
810 811
		pr_debug("irq: -> existing mapping on virq %d\n", virq);
		return virq;
L
Linus Torvalds 已提交
812 813
	}

814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
	/* Get a virtual interrupt number */
	if (host->revmap_type == IRQ_HOST_MAP_LEGACY) {
		/* Handle legacy */
		virq = (unsigned int)hwirq;
		if (virq == 0 || virq >= NUM_ISA_INTERRUPTS)
			return NO_IRQ;
		return virq;
	} else {
		/* Allocate a virtual interrupt number */
		hint = hwirq % irq_virq_count;
		virq = irq_alloc_virt(host, 1, hint);
		if (virq == NO_IRQ) {
			pr_debug("irq: -> virq allocation failed\n");
			return NO_IRQ;
		}
	}

831
	if (irq_setup_virq(host, virq, hwirq))
832
		return NO_IRQ;
833

834
	pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
835 836
		hwirq, host->of_node ? host->of_node->full_name : "null", virq);

L
Linus Torvalds 已提交
837
	return virq;
838 839 840
}
EXPORT_SYMBOL_GPL(irq_create_mapping);

841
unsigned int irq_create_of_mapping(struct device_node *controller,
842
				   const u32 *intspec, unsigned int intsize)
843 844 845
{
	struct irq_host *host;
	irq_hw_number_t hwirq;
846 847
	unsigned int type = IRQ_TYPE_NONE;
	unsigned int virq;
L
Linus Torvalds 已提交
848

849 850 851 852
	if (controller == NULL)
		host = irq_default_host;
	else
		host = irq_find_host(controller);
853 854 855
	if (host == NULL) {
		printk(KERN_WARNING "irq: no irq host found for %s !\n",
		       controller->full_name);
856
		return NO_IRQ;
857
	}
858 859 860 861 862 863

	/* If host has no translation, then we assume interrupt line */
	if (host->ops->xlate == NULL)
		hwirq = intspec[0];
	else {
		if (host->ops->xlate(host, controller, intspec, intsize,
864
				     &hwirq, &type))
865
			return NO_IRQ;
L
Linus Torvalds 已提交
866
	}
867

868 869 870 871 872 873 874
	/* Create mapping */
	virq = irq_create_mapping(host, hwirq);
	if (virq == NO_IRQ)
		return virq;

	/* Set type if specified and different than the current one */
	if (type != IRQ_TYPE_NONE &&
875
	    type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
876
		irq_set_irq_type(virq, type);
877
	return virq;
L
Linus Torvalds 已提交
878
}
879
EXPORT_SYMBOL_GPL(irq_create_of_mapping);
L
Linus Torvalds 已提交
880

881 882
void irq_dispose_mapping(unsigned int virq)
{
883
	struct irq_host *host;
884
	irq_hw_number_t hwirq;
L
Linus Torvalds 已提交
885

886 887 888 889
	if (virq == NO_IRQ)
		return;

	host = irq_map[virq].host;
890
	if (WARN_ON(host == NULL))
891
		return;
L
Linus Torvalds 已提交
892

893 894 895
	/* Never unmap legacy interrupts */
	if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
		return;
L
Linus Torvalds 已提交
896

897 898
	irq_set_status_flags(virq, IRQ_NOREQUEST);

899
	/* remove chip and handler */
900
	irq_set_chip_and_handler(virq, NULL, NULL);
901 902 903 904 905 906 907 908 909 910 911 912 913 914

	/* Make sure it's completed */
	synchronize_irq(virq);

	/* Tell the PIC about it */
	if (host->ops->unmap)
		host->ops->unmap(host, virq);
	smp_mb();

	/* Clear reverse map */
	hwirq = irq_map[virq].hwirq;
	switch(host->revmap_type) {
	case IRQ_HOST_MAP_LINEAR:
		if (hwirq < host->revmap_data.linear.size)
915
			host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
916 917
		break;
	case IRQ_HOST_MAP_TREE:
918
		mutex_lock(&revmap_trees_mutex);
919
		radix_tree_delete(&host->revmap_data.tree, hwirq);
920
		mutex_unlock(&revmap_trees_mutex);
921 922
		break;
	}
L
Linus Torvalds 已提交
923

924 925 926
	/* Destroy map */
	smp_mb();
	irq_map[virq].hwirq = host->inval_irq;
L
Linus Torvalds 已提交
927

T
Thomas Gleixner 已提交
928
	irq_free_descs(virq, 1);
929 930
	/* Free it */
	irq_free_virt(virq, 1);
L
Linus Torvalds 已提交
931
}
932
EXPORT_SYMBOL_GPL(irq_dispose_mapping);
L
Linus Torvalds 已提交
933

934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
unsigned int irq_find_mapping(struct irq_host *host,
			      irq_hw_number_t hwirq)
{
	unsigned int i;
	unsigned int hint = hwirq % irq_virq_count;

	/* Look for default host if nececssary */
	if (host == NULL)
		host = irq_default_host;
	if (host == NULL)
		return NO_IRQ;

	/* legacy -> bail early */
	if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
		return hwirq;

	/* Slow path does a linear search of the map */
	if (hint < NUM_ISA_INTERRUPTS)
		hint = NUM_ISA_INTERRUPTS;
	i = hint;
	do  {
		if (irq_map[i].host == host &&
		    irq_map[i].hwirq == hwirq)
			return i;
		i++;
		if (i >= irq_virq_count)
			i = NUM_ISA_INTERRUPTS;
	} while(i != hint);
	return NO_IRQ;
}
EXPORT_SYMBOL_GPL(irq_find_mapping);
L
Linus Torvalds 已提交
965

966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
#ifdef CONFIG_SMP
int irq_choose_cpu(const struct cpumask *mask)
{
	int cpuid;

	if (cpumask_equal(mask, cpu_all_mask)) {
		static int irq_rover;
		static DEFINE_RAW_SPINLOCK(irq_rover_lock);
		unsigned long flags;

		/* Round-robin distribution... */
do_round_robin:
		raw_spin_lock_irqsave(&irq_rover_lock, flags);

		irq_rover = cpumask_next(irq_rover, cpu_online_mask);
		if (irq_rover >= nr_cpu_ids)
			irq_rover = cpumask_first(cpu_online_mask);

		cpuid = irq_rover;

		raw_spin_unlock_irqrestore(&irq_rover_lock, flags);
	} else {
		cpuid = cpumask_first_and(mask, cpu_online_mask);
		if (cpuid >= nr_cpu_ids)
			goto do_round_robin;
	}

	return get_hard_smp_processor_id(cpuid);
}
#else
int irq_choose_cpu(const struct cpumask *mask)
{
	return hard_smp_processor_id();
}
#endif
1001

1002 1003
unsigned int irq_radix_revmap_lookup(struct irq_host *host,
				     irq_hw_number_t hwirq)
L
Linus Torvalds 已提交
1004
{
1005 1006
	struct irq_map_entry *ptr;
	unsigned int virq;
L
Linus Torvalds 已提交
1007

1008 1009
	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
		return irq_find_mapping(host, hwirq);
L
Linus Torvalds 已提交
1010

1011
	/*
1012 1013 1014
	 * The ptr returned references the static global irq_map.
	 * but freeing an irq can delete nodes along the path to
	 * do the lookup via call_rcu.
1015
	 */
1016
	rcu_read_lock();
1017
	ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
1018
	rcu_read_unlock();
1019

1020 1021 1022 1023 1024 1025
	/*
	 * If found in radix tree, then fine.
	 * Else fallback to linear lookup - this should not happen in practice
	 * as it means that we failed to insert the node in the radix tree.
	 */
	if (ptr)
1026
		virq = ptr - irq_map;
1027 1028 1029 1030 1031 1032 1033 1034 1035
	else
		virq = irq_find_mapping(host, hwirq);

	return virq;
}

void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
			     irq_hw_number_t hwirq)
{
1036 1037
	if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
		return;
1038

1039
	if (virq != NO_IRQ) {
1040
		mutex_lock(&revmap_trees_mutex);
1041 1042
		radix_tree_insert(&host->revmap_data.tree, hwirq,
				  &irq_map[virq]);
1043
		mutex_unlock(&revmap_trees_mutex);
1044
	}
L
Linus Torvalds 已提交
1045 1046
}

1047 1048
unsigned int irq_linear_revmap(struct irq_host *host,
			       irq_hw_number_t hwirq)
1049
{
1050
	unsigned int *revmap;
1051

1052 1053
	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
		return irq_find_mapping(host, hwirq);
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068

	/* Check revmap bounds */
	if (unlikely(hwirq >= host->revmap_data.linear.size))
		return irq_find_mapping(host, hwirq);

	/* Check if revmap was allocated */
	revmap = host->revmap_data.linear.revmap;
	if (unlikely(revmap == NULL))
		return irq_find_mapping(host, hwirq);

	/* Fill up revmap with slow path if no mapping found */
	if (unlikely(revmap[hwirq] == NO_IRQ))
		revmap[hwirq] = irq_find_mapping(host, hwirq);

	return revmap[hwirq];
1069 1070
}

1071 1072 1073 1074 1075 1076
unsigned int irq_alloc_virt(struct irq_host *host,
			    unsigned int count,
			    unsigned int hint)
{
	unsigned long flags;
	unsigned int i, j, found = NO_IRQ;
1077

1078 1079 1080
	if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
		return NO_IRQ;

1081
	raw_spin_lock_irqsave(&irq_big_lock, flags);
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092

	/* Use hint for 1 interrupt if any */
	if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
	    hint < irq_virq_count && irq_map[hint].host == NULL) {
		found = hint;
		goto hint_found;
	}

	/* Look for count consecutive numbers in the allocatable
	 * (non-legacy) space
	 */
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
	for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
		if (irq_map[i].host != NULL)
			j = 0;
		else
			j++;

		if (j == count) {
			found = i - count + 1;
			break;
		}
1103 1104
	}
	if (found == NO_IRQ) {
1105
		raw_spin_unlock_irqrestore(&irq_big_lock, flags);
1106 1107 1108 1109 1110 1111 1112 1113
		return NO_IRQ;
	}
 hint_found:
	for (i = found; i < (found + count); i++) {
		irq_map[i].hwirq = host->inval_irq;
		smp_wmb();
		irq_map[i].host = host;
	}
1114
	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
1115 1116 1117 1118
	return found;
}

void irq_free_virt(unsigned int virq, unsigned int count)
L
Linus Torvalds 已提交
1119 1120
{
	unsigned long flags;
1121
	unsigned int i;
L
Linus Torvalds 已提交
1122

1123 1124
	WARN_ON (virq < NUM_ISA_INTERRUPTS);
	WARN_ON (count == 0 || (virq + count) > irq_virq_count);
L
Linus Torvalds 已提交
1125

1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
	if (virq < NUM_ISA_INTERRUPTS) {
		if (virq + count < NUM_ISA_INTERRUPTS)
			return;
		count  =- NUM_ISA_INTERRUPTS - virq;
		virq = NUM_ISA_INTERRUPTS;
	}

	if (count > irq_virq_count || virq > irq_virq_count - count) {
		if (virq > irq_virq_count)
			return;
		count = irq_virq_count - virq;
	}

1139
	raw_spin_lock_irqsave(&irq_big_lock, flags);
1140 1141
	for (i = virq; i < (virq + count); i++) {
		struct irq_host *host;
L
Linus Torvalds 已提交
1142

1143 1144 1145 1146 1147
		host = irq_map[i].host;
		irq_map[i].hwirq = host->inval_irq;
		smp_wmb();
		irq_map[i].host = NULL;
	}
1148
	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
L
Linus Torvalds 已提交
1149
}
1150

1151
int arch_early_irq_init(void)
1152
{
1153
	return 0;
1154 1155
}

1156 1157 1158 1159
#ifdef CONFIG_VIRQ_DEBUG
static int virq_debug_show(struct seq_file *m, void *private)
{
	unsigned long flags;
1160
	struct irq_desc *desc;
1161
	const char *p;
1162
	static const char none[] = "none";
1163
	void *data;
1164 1165
	int i;

1166 1167
	seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq",
		      "chip name", "chip data", "host name");
1168

1169
	for (i = 1; i < nr_irqs; i++) {
M
Michael Ellerman 已提交
1170
		desc = irq_to_desc(i);
1171 1172 1173
		if (!desc)
			continue;

1174
		raw_spin_lock_irqsave(&desc->lock, flags);
1175 1176

		if (desc->action && desc->action->handler) {
1177 1178
			struct irq_chip *chip;

1179
			seq_printf(m, "%5d  ", i);
1180
			seq_printf(m, "0x%05lx  ", irq_map[i].hwirq);
1181

1182
			chip = irq_desc_get_chip(desc);
1183 1184
			if (chip && chip->name)
				p = chip->name;
1185 1186 1187 1188
			else
				p = none;
			seq_printf(m, "%-15s  ", p);

1189 1190 1191
			data = irq_desc_get_chip_data(desc);
			seq_printf(m, "0x%16p  ", data);

1192 1193 1194 1195 1196 1197 1198
			if (irq_map[i].host && irq_map[i].host->of_node)
				p = irq_map[i].host->of_node->full_name;
			else
				p = none;
			seq_printf(m, "%s\n", p);
		}

1199
		raw_spin_unlock_irqrestore(&desc->lock, flags);
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
	}

	return 0;
}

static int virq_debug_open(struct inode *inode, struct file *file)
{
	return single_open(file, virq_debug_show, inode->i_private);
}

static const struct file_operations virq_debug_fops = {
	.open = virq_debug_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};

static int __init irq_debugfs_init(void)
{
	if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
1220
				 NULL, &virq_debug_fops) == NULL)
1221 1222 1223 1224 1225 1226 1227
		return -ENOMEM;

	return 0;
}
__initcall(irq_debugfs_init);
#endif /* CONFIG_VIRQ_DEBUG */

1228
#ifdef CONFIG_PPC64
L
Linus Torvalds 已提交
1229 1230 1231 1232 1233 1234 1235
static int __init setup_noirqdistrib(char *str)
{
	distribute_irqs = 0;
	return 1;
}

__setup("noirqdistrib", setup_noirqdistrib);
S
Stephen Rothwell 已提交
1236
#endif /* CONFIG_PPC64 */