aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/irq.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-03 07:36:01 -0400
committerPaul Mackerras <paulus@samba.org>2006-07-03 07:36:01 -0400
commit0ebfff1491ef85d41ddf9c633834838be144f69f (patch)
tree5b469a6d61a9fcfbf94e7b6d411e544dbdec8dec /arch/powerpc/kernel/irq.c
parentf63e115fb50db39706b955b81e3375ef6bab2268 (diff)
[POWERPC] Add new interrupt mapping core and change platforms to use it
This adds the new irq remapper core and removes the old one. Because there are some fundamental conflicts with the old code, like the value of NO_IRQ which I'm now setting to 0 (as per discussions with Linus), etc..., this commit also changes the relevant platform and driver code over to use the new remapper (so as not to cause difficulties later in bisecting). This patch removes the old pre-parsing of the open firmware interrupt tree along with all the bogus assumptions it made to try to renumber interrupts according to the platform. This is all to be handled by the new code now. For the pSeries XICS interrupt controller, a single remapper host is created for the whole machine regardless of how many interrupt presentation and source controllers are found, and it's set to match any device node that isn't a 8259. That works fine on pSeries and avoids having to deal with some of the complexities of split source controllers vs. presentation controllers in the pSeries device trees. The powerpc i8259 PIC driver now always requests the legacy interrupt range. It also has the feature of being able to match any device node (including NULL) if passed no device node as an input. That will help porting over platforms with broken device-trees like Pegasos who don't have a proper interrupt tree. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r--arch/powerpc/kernel/irq.c629
1 files changed, 507 insertions, 122 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 91248559099a..05a700940f67 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -29,6 +29,8 @@
29 * to reduce code space and undefined function references. 29 * to reduce code space and undefined function references.
30 */ 30 */
31 31
32#undef DEBUG
33
32#include <linux/module.h> 34#include <linux/module.h>
33#include <linux/threads.h> 35#include <linux/threads.h>
34#include <linux/kernel_stat.h> 36#include <linux/kernel_stat.h>
@@ -46,7 +48,10 @@
46#include <linux/cpumask.h> 48#include <linux/cpumask.h>
47#include <linux/profile.h> 49#include <linux/profile.h>
48#include <linux/bitops.h> 50#include <linux/bitops.h>
49#include <linux/pci.h> 51#include <linux/list.h>
52#include <linux/radix-tree.h>
53#include <linux/mutex.h>
54#include <linux/bootmem.h>
50 55
51#include <asm/uaccess.h> 56#include <asm/uaccess.h>
52#include <asm/system.h> 57#include <asm/system.h>
@@ -57,6 +62,7 @@
57#include <asm/prom.h> 62#include <asm/prom.h>
58#include <asm/ptrace.h> 63#include <asm/ptrace.h>
59#include <asm/machdep.h> 64#include <asm/machdep.h>
65#include <asm/udbg.h>
60#ifdef CONFIG_PPC_ISERIES 66#ifdef CONFIG_PPC_ISERIES
61#include <asm/paca.h> 67#include <asm/paca.h>
62#endif 68#endif
@@ -88,7 +94,6 @@ extern atomic_t ipi_sent;
88EXPORT_SYMBOL(irq_desc); 94EXPORT_SYMBOL(irq_desc);
89 95
90int distribute_irqs = 1; 96int distribute_irqs = 1;
91u64 ppc64_interrupt_controller;
92#endif /* CONFIG_PPC64 */ 97#endif /* CONFIG_PPC64 */
93 98
94int show_interrupts(struct seq_file *p, void *v) 99int show_interrupts(struct seq_file *p, void *v)
@@ -181,7 +186,7 @@ void fixup_irqs(cpumask_t map)
181 186
182void do_IRQ(struct pt_regs *regs) 187void do_IRQ(struct pt_regs *regs)
183{ 188{
184 int irq; 189 unsigned int irq;
185#ifdef CONFIG_IRQSTACKS 190#ifdef CONFIG_IRQSTACKS
186 struct thread_info *curtp, *irqtp; 191 struct thread_info *curtp, *irqtp;
187#endif 192#endif
@@ -212,7 +217,7 @@ void do_IRQ(struct pt_regs *regs)
212 */ 217 */
213 irq = ppc_md.get_irq(regs); 218 irq = ppc_md.get_irq(regs);
214 219
215 if (irq >= 0) { 220 if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
216#ifdef CONFIG_IRQSTACKS 221#ifdef CONFIG_IRQSTACKS
217 /* Switch to the irq stack to handle this */ 222 /* Switch to the irq stack to handle this */
218 curtp = current_thread_info(); 223 curtp = current_thread_info();
@@ -231,7 +236,7 @@ void do_IRQ(struct pt_regs *regs)
231 } else 236 } else
232#endif 237#endif
233 generic_handle_irq(irq, regs); 238 generic_handle_irq(irq, regs);
234 } else if (irq != -2) 239 } else if (irq != NO_IRQ_IGNORE)
235 /* That's not SMP safe ... but who cares ? */ 240 /* That's not SMP safe ... but who cares ? */
236 ppc_spurious_interrupts++; 241 ppc_spurious_interrupts++;
237 242
@@ -254,123 +259,6 @@ void __init init_IRQ(void)
254#endif 259#endif
255} 260}
256 261
257#ifdef CONFIG_PPC64
258/*
259 * Virtual IRQ mapping code, used on systems with XICS interrupt controllers.
260 */
261
262#define UNDEFINED_IRQ 0xffffffff
263unsigned int virt_irq_to_real_map[NR_IRQS];
264
265/*
266 * Don't use virtual irqs 0, 1, 2 for devices.
267 * The pcnet32 driver considers interrupt numbers < 2 to be invalid,
268 * and 2 is the XICS IPI interrupt.
269 * We limit virtual irqs to __irq_offet_value less than virt_irq_max so
270 * that when we offset them we don't end up with an interrupt
271 * number >= virt_irq_max.
272 */
273#define MIN_VIRT_IRQ 3
274
275unsigned int virt_irq_max;
276static unsigned int max_virt_irq;
277static unsigned int nr_virt_irqs;
278
279void
280virt_irq_init(void)
281{
282 int i;
283
284 if ((virt_irq_max == 0) || (virt_irq_max > (NR_IRQS - 1)))
285 virt_irq_max = NR_IRQS - 1;
286 max_virt_irq = virt_irq_max - __irq_offset_value;
287 nr_virt_irqs = max_virt_irq - MIN_VIRT_IRQ + 1;
288
289 for (i = 0; i < NR_IRQS; i++)
290 virt_irq_to_real_map[i] = UNDEFINED_IRQ;
291}
292
293/* Create a mapping for a real_irq if it doesn't already exist.
294 * Return the virtual irq as a convenience.
295 */
296int virt_irq_create_mapping(unsigned int real_irq)
297{
298 unsigned int virq, first_virq;
299 static int warned;
300
301 if (ppc64_interrupt_controller == IC_OPEN_PIC)
302 return real_irq; /* no mapping for openpic (for now) */
303
304 if (ppc64_interrupt_controller == IC_CELL_PIC)
305 return real_irq; /* no mapping for iic either */
306
307 /* don't map interrupts < MIN_VIRT_IRQ */
308 if (real_irq < MIN_VIRT_IRQ) {
309 virt_irq_to_real_map[real_irq] = real_irq;
310 return real_irq;
311 }
312
313 /* map to a number between MIN_VIRT_IRQ and max_virt_irq */
314 virq = real_irq;
315 if (virq > max_virt_irq)
316 virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
317
318 /* search for this number or a free slot */
319 first_virq = virq;
320 while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) {
321 if (virt_irq_to_real_map[virq] == real_irq)
322 return virq;
323 if (++virq > max_virt_irq)
324 virq = MIN_VIRT_IRQ;
325 if (virq == first_virq)
326 goto nospace; /* oops, no free slots */
327 }
328
329 virt_irq_to_real_map[virq] = real_irq;
330 return virq;
331
332 nospace:
333 if (!warned) {
334 printk(KERN_CRIT "Interrupt table is full\n");
335 printk(KERN_CRIT "Increase virt_irq_max (currently %d) "
336 "in your kernel sources and rebuild.\n", virt_irq_max);
337 warned = 1;
338 }
339 return NO_IRQ;
340}
341
342/*
343 * In most cases will get a hit on the very first slot checked in the
344 * virt_irq_to_real_map. Only when there are a large number of
345 * IRQs will this be expensive.
346 */
347unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
348{
349 unsigned int virq;
350 unsigned int first_virq;
351
352 virq = real_irq;
353
354 if (virq > max_virt_irq)
355 virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
356
357 first_virq = virq;
358
359 do {
360 if (virt_irq_to_real_map[virq] == real_irq)
361 return virq;
362
363 virq++;
364
365 if (virq >= max_virt_irq)
366 virq = 0;
367
368 } while (first_virq != virq);
369
370 return NO_IRQ;
371
372}
373#endif /* CONFIG_PPC64 */
374 262
375#ifdef CONFIG_IRQSTACKS 263#ifdef CONFIG_IRQSTACKS
376struct thread_info *softirq_ctx[NR_CPUS] __read_mostly; 264struct thread_info *softirq_ctx[NR_CPUS] __read_mostly;
@@ -430,6 +318,503 @@ void do_softirq(void)
430} 318}
431EXPORT_SYMBOL(do_softirq); 319EXPORT_SYMBOL(do_softirq);
432 320
321
322/*
323 * IRQ controller and virtual interrupts
324 */
325
326#ifdef CONFIG_PPC_MERGE
327
328static LIST_HEAD(irq_hosts);
329static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED;
330
331struct irq_map_entry irq_map[NR_IRQS];
332static unsigned int irq_virq_count = NR_IRQS;
333static struct irq_host *irq_default_host;
334
335struct irq_host *irq_alloc_host(unsigned int revmap_type,
336 unsigned int revmap_arg,
337 struct irq_host_ops *ops,
338 irq_hw_number_t inval_irq)
339{
340 struct irq_host *host;
341 unsigned int size = sizeof(struct irq_host);
342 unsigned int i;
343 unsigned int *rmap;
344 unsigned long flags;
345
346 /* Allocate structure and revmap table if using linear mapping */
347 if (revmap_type == IRQ_HOST_MAP_LINEAR)
348 size += revmap_arg * sizeof(unsigned int);
349 if (mem_init_done)
350 host = kzalloc(size, GFP_KERNEL);
351 else {
352 host = alloc_bootmem(size);
353 if (host)
354 memset(host, 0, size);
355 }
356 if (host == NULL)
357 return NULL;
358
359 /* Fill structure */
360 host->revmap_type = revmap_type;
361 host->inval_irq = inval_irq;
362 host->ops = ops;
363
364 spin_lock_irqsave(&irq_big_lock, flags);
365
366 /* If it's a legacy controller, check for duplicates and
367 * mark it as allocated (we use irq 0 host pointer for that
368 */
369 if (revmap_type == IRQ_HOST_MAP_LEGACY) {
370 if (irq_map[0].host != NULL) {
371 spin_unlock_irqrestore(&irq_big_lock, flags);
372 /* If we are early boot, we can't free the structure,
373 * too bad...
374 * this will be fixed once slab is made available early
375 * instead of the current cruft
376 */
377 if (mem_init_done)
378 kfree(host);
379 return NULL;
380 }
381 irq_map[0].host = host;
382 }
383
384 list_add(&host->link, &irq_hosts);
385 spin_unlock_irqrestore(&irq_big_lock, flags);
386
387 /* Additional setups per revmap type */
388 switch(revmap_type) {
389 case IRQ_HOST_MAP_LEGACY:
390 /* 0 is always the invalid number for legacy */
391 host->inval_irq = 0;
392 /* setup us as the host for all legacy interrupts */
393 for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
394 irq_map[i].hwirq = 0;
395 smp_wmb();
396 irq_map[i].host = host;
397 smp_wmb();
398
399 /* Clear some flags */
400 get_irq_desc(i)->status
401 &= ~(IRQ_NOREQUEST | IRQ_LEVEL);
402
403 /* Legacy flags are left to default at this point,
404 * one can then use irq_create_mapping() to
405 * explicitely change them
406 */
407 ops->map(host, i, i, 0);
408 }
409 break;
410 case IRQ_HOST_MAP_LINEAR:
411 rmap = (unsigned int *)(host + 1);
412 for (i = 0; i < revmap_arg; i++)
413 rmap[i] = IRQ_NONE;
414 host->revmap_data.linear.size = revmap_arg;
415 smp_wmb();
416 host->revmap_data.linear.revmap = rmap;
417 break;
418 default:
419 break;
420 }
421
422 pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
423
424 return host;
425}
426
427struct irq_host *irq_find_host(struct device_node *node)
428{
429 struct irq_host *h, *found = NULL;
430 unsigned long flags;
431
432 /* We might want to match the legacy controller last since
433 * it might potentially be set to match all interrupts in
434 * the absence of a device node. This isn't a problem so far
435 * yet though...
436 */
437 spin_lock_irqsave(&irq_big_lock, flags);
438 list_for_each_entry(h, &irq_hosts, link)
439 if (h->ops->match == NULL || h->ops->match(h, node)) {
440 found = h;
441 break;
442 }
443 spin_unlock_irqrestore(&irq_big_lock, flags);
444 return found;
445}
446EXPORT_SYMBOL_GPL(irq_find_host);
447
448void irq_set_default_host(struct irq_host *host)
449{
450 pr_debug("irq: Default host set to @0x%p\n", host);
451
452 irq_default_host = host;
453}
454
455void irq_set_virq_count(unsigned int count)
456{
457 pr_debug("irq: Trying to set virq count to %d\n", count);
458
459 BUG_ON(count < NUM_ISA_INTERRUPTS);
460 if (count < NR_IRQS)
461 irq_virq_count = count;
462}
463
464unsigned int irq_create_mapping(struct irq_host *host,
465 irq_hw_number_t hwirq,
466 unsigned int flags)
467{
468 unsigned int virq, hint;
469
470 pr_debug("irq: irq_create_mapping(0x%p, 0x%lx, 0x%x)\n",
471 host, hwirq, flags);
472
473 /* Look for default host if nececssary */
474 if (host == NULL)
475 host = irq_default_host;
476 if (host == NULL) {
477 printk(KERN_WARNING "irq_create_mapping called for"
478 " NULL host, hwirq=%lx\n", hwirq);
479 WARN_ON(1);
480 return NO_IRQ;
481 }
482 pr_debug("irq: -> using host @%p\n", host);
483
484 /* Check if mapping already exist, if it does, call
485 * host->ops->map() to update the flags
486 */
487 virq = irq_find_mapping(host, hwirq);
488 if (virq != IRQ_NONE) {
489 pr_debug("irq: -> existing mapping on virq %d\n", virq);
490 host->ops->map(host, virq, hwirq, flags);
491 return virq;
492 }
493
494 /* Get a virtual interrupt number */
495 if (host->revmap_type == IRQ_HOST_MAP_LEGACY) {
496 /* Handle legacy */
497 virq = (unsigned int)hwirq;
498 if (virq == 0 || virq >= NUM_ISA_INTERRUPTS)
499 return NO_IRQ;
500 return virq;
501 } else {
502 /* Allocate a virtual interrupt number */
503 hint = hwirq % irq_virq_count;
504 virq = irq_alloc_virt(host, 1, hint);
505 if (virq == NO_IRQ) {
506 pr_debug("irq: -> virq allocation failed\n");
507 return NO_IRQ;
508 }
509 }
510 pr_debug("irq: -> obtained virq %d\n", virq);
511
512 /* Clear some flags */
513 get_irq_desc(virq)->status &= ~(IRQ_NOREQUEST | IRQ_LEVEL);
514
515 /* map it */
516 if (host->ops->map(host, virq, hwirq, flags)) {
517 pr_debug("irq: -> mapping failed, freeing\n");
518 irq_free_virt(virq, 1);
519 return NO_IRQ;
520 }
521 smp_wmb();
522 irq_map[virq].hwirq = hwirq;
523 smp_mb();
524 return virq;
525}
526EXPORT_SYMBOL_GPL(irq_create_mapping);
527
528extern unsigned int irq_create_of_mapping(struct device_node *controller,
529 u32 *intspec, unsigned int intsize)
530{
531 struct irq_host *host;
532 irq_hw_number_t hwirq;
533 unsigned int flags = IRQ_TYPE_NONE;
534
535 if (controller == NULL)
536 host = irq_default_host;
537 else
538 host = irq_find_host(controller);
539 if (host == NULL)
540 return NO_IRQ;
541
542 /* If host has no translation, then we assume interrupt line */
543 if (host->ops->xlate == NULL)
544 hwirq = intspec[0];
545 else {
546 if (host->ops->xlate(host, controller, intspec, intsize,
547 &hwirq, &flags))
548 return NO_IRQ;
549 }
550
551 return irq_create_mapping(host, hwirq, flags);
552}
553EXPORT_SYMBOL_GPL(irq_create_of_mapping);
554
555unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
556{
557 struct of_irq oirq;
558
559 if (of_irq_map_one(dev, index, &oirq))
560 return NO_IRQ;
561
562 return irq_create_of_mapping(oirq.controller, oirq.specifier,
563 oirq.size);
564}
565EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
566
567void irq_dispose_mapping(unsigned int virq)
568{
569 struct irq_host *host = irq_map[virq].host;
570 irq_hw_number_t hwirq;
571 unsigned long flags;
572
573 WARN_ON (host == NULL);
574 if (host == NULL)
575 return;
576
577 /* Never unmap legacy interrupts */
578 if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
579 return;
580
581 /* remove chip and handler */
582 set_irq_chip_and_handler(virq, NULL, NULL);
583
584 /* Make sure it's completed */
585 synchronize_irq(virq);
586
587 /* Tell the PIC about it */
588 if (host->ops->unmap)
589 host->ops->unmap(host, virq);
590 smp_mb();
591
592 /* Clear reverse map */
593 hwirq = irq_map[virq].hwirq;
594 switch(host->revmap_type) {
595 case IRQ_HOST_MAP_LINEAR:
596 if (hwirq < host->revmap_data.linear.size)
597 host->revmap_data.linear.revmap[hwirq] = IRQ_NONE;
598 break;
599 case IRQ_HOST_MAP_TREE:
600 /* Check if radix tree allocated yet */
601 if (host->revmap_data.tree.gfp_mask == 0)
602 break;
603 /* XXX radix tree not safe ! remove lock whem it becomes safe
604 * and use some RCU sync to make sure everything is ok before we
605 * can re-use that map entry
606 */
607 spin_lock_irqsave(&irq_big_lock, flags);
608 radix_tree_delete(&host->revmap_data.tree, hwirq);
609 spin_unlock_irqrestore(&irq_big_lock, flags);
610 break;
611 }
612
613 /* Destroy map */
614 smp_mb();
615 irq_map[virq].hwirq = host->inval_irq;
616
617 /* Set some flags */
618 get_irq_desc(virq)->status |= IRQ_NOREQUEST;
619
620 /* Free it */
621 irq_free_virt(virq, 1);
622}
623EXPORT_SYMBOL_GPL(irq_dispose_mapping);
624
625unsigned int irq_find_mapping(struct irq_host *host,
626 irq_hw_number_t hwirq)
627{
628 unsigned int i;
629 unsigned int hint = hwirq % irq_virq_count;
630
631 /* Look for default host if nececssary */
632 if (host == NULL)
633 host = irq_default_host;
634 if (host == NULL)
635 return NO_IRQ;
636
637 /* legacy -> bail early */
638 if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
639 return hwirq;
640
641 /* Slow path does a linear search of the map */
642 if (hint < NUM_ISA_INTERRUPTS)
643 hint = NUM_ISA_INTERRUPTS;
644 i = hint;
645 do {
646 if (irq_map[i].host == host &&
647 irq_map[i].hwirq == hwirq)
648 return i;
649 i++;
650 if (i >= irq_virq_count)
651 i = NUM_ISA_INTERRUPTS;
652 } while(i != hint);
653 return NO_IRQ;
654}
655EXPORT_SYMBOL_GPL(irq_find_mapping);
656
657
658unsigned int irq_radix_revmap(struct irq_host *host,
659 irq_hw_number_t hwirq)
660{
661 struct radix_tree_root *tree;
662 struct irq_map_entry *ptr;
663 unsigned int virq;
664 unsigned long flags;
665
666 WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
667
668 /* Check if the radix tree exist yet. We test the value of
669 * the gfp_mask for that. Sneaky but saves another int in the
670 * structure. If not, we fallback to slow mode
671 */
672 tree = &host->revmap_data.tree;
673 if (tree->gfp_mask == 0)
674 return irq_find_mapping(host, hwirq);
675
676 /* XXX Current radix trees are NOT SMP safe !!! Remove that lock
677 * when that is fixed (when Nick's patch gets in
678 */
679 spin_lock_irqsave(&irq_big_lock, flags);
680
681 /* Now try to resolve */
682 ptr = radix_tree_lookup(tree, hwirq);
683 /* Found it, return */
684 if (ptr) {
685 virq = ptr - irq_map;
686 goto bail;
687 }
688
689 /* If not there, try to insert it */
690 virq = irq_find_mapping(host, hwirq);
691 if (virq != NO_IRQ)
692 radix_tree_insert(tree, virq, &irq_map[virq]);
693 bail:
694 spin_unlock_irqrestore(&irq_big_lock, flags);
695 return virq;
696}
697
698unsigned int irq_linear_revmap(struct irq_host *host,
699 irq_hw_number_t hwirq)
700{
701 unsigned int *revmap;
702
703 WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR);
704
705 /* Check revmap bounds */
706 if (unlikely(hwirq >= host->revmap_data.linear.size))
707 return irq_find_mapping(host, hwirq);
708
709 /* Check if revmap was allocated */
710 revmap = host->revmap_data.linear.revmap;
711 if (unlikely(revmap == NULL))
712 return irq_find_mapping(host, hwirq);
713
714 /* Fill up revmap with slow path if no mapping found */
715 if (unlikely(revmap[hwirq] == NO_IRQ))
716 revmap[hwirq] = irq_find_mapping(host, hwirq);
717
718 return revmap[hwirq];
719}
720
721unsigned int irq_alloc_virt(struct irq_host *host,
722 unsigned int count,
723 unsigned int hint)
724{
725 unsigned long flags;
726 unsigned int i, j, found = NO_IRQ;
727 unsigned int limit = irq_virq_count - count;
728
729 if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
730 return NO_IRQ;
731
732 spin_lock_irqsave(&irq_big_lock, flags);
733
734 /* Use hint for 1 interrupt if any */
735 if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
736 hint < irq_virq_count && irq_map[hint].host == NULL) {
737 found = hint;
738 goto hint_found;
739 }
740
741 /* Look for count consecutive numbers in the allocatable
742 * (non-legacy) space
743 */
744 for (i = NUM_ISA_INTERRUPTS; i <= limit; ) {
745 for (j = i; j < (i + count); j++)
746 if (irq_map[j].host != NULL) {
747 i = j + 1;
748 continue;
749 }
750 found = i;
751 break;
752 }
753 if (found == NO_IRQ) {
754 spin_unlock_irqrestore(&irq_big_lock, flags);
755 return NO_IRQ;
756 }
757 hint_found:
758 for (i = found; i < (found + count); i++) {
759 irq_map[i].hwirq = host->inval_irq;
760 smp_wmb();
761 irq_map[i].host = host;
762 }
763 spin_unlock_irqrestore(&irq_big_lock, flags);
764 return found;
765}
766
767void irq_free_virt(unsigned int virq, unsigned int count)
768{
769 unsigned long flags;
770 unsigned int i;
771
772 WARN_ON (virq < NUM_ISA_INTERRUPTS);
773 WARN_ON (count == 0 || (virq + count) > irq_virq_count);
774
775 spin_lock_irqsave(&irq_big_lock, flags);
776 for (i = virq; i < (virq + count); i++) {
777 struct irq_host *host;
778
779 if (i < NUM_ISA_INTERRUPTS ||
780 (virq + count) > irq_virq_count)
781 continue;
782
783 host = irq_map[i].host;
784 irq_map[i].hwirq = host->inval_irq;
785 smp_wmb();
786 irq_map[i].host = NULL;
787 }
788 spin_unlock_irqrestore(&irq_big_lock, flags);
789}
790
791void irq_early_init(void)
792{
793 unsigned int i;
794
795 for (i = 0; i < NR_IRQS; i++)
796 get_irq_desc(i)->status |= IRQ_NOREQUEST;
797}
798
799/* We need to create the radix trees late */
800static int irq_late_init(void)
801{
802 struct irq_host *h;
803 unsigned long flags;
804
805 spin_lock_irqsave(&irq_big_lock, flags);
806 list_for_each_entry(h, &irq_hosts, link) {
807 if (h->revmap_type == IRQ_HOST_MAP_TREE)
808 INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC);
809 }
810 spin_unlock_irqrestore(&irq_big_lock, flags);
811
812 return 0;
813}
814arch_initcall(irq_late_init);
815
816#endif /* CONFIG_PPC_MERGE */
817
433#ifdef CONFIG_PCI_MSI 818#ifdef CONFIG_PCI_MSI
434int pci_enable_msi(struct pci_dev * pdev) 819int pci_enable_msi(struct pci_dev * pdev)
435{ 820{