aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/irq.h27
-rw-r--r--arch/powerpc/kernel/irq.c240
2 files changed, 69 insertions, 198 deletions
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index cb06b39f8e61..abdd7ef28cbf 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -191,33 +191,6 @@ extern unsigned int irq_linear_revmap(struct irq_domain *host,
191 irq_hw_number_t hwirq); 191 irq_hw_number_t hwirq);
192 192
193 193
194
195/**
196 * irq_alloc_virt - Allocate virtual irq numbers
197 * @host: host owning these new virtual irqs
198 * @count: number of consecutive numbers to allocate
199 * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
200 *
201 * This is a low level function that is used internally by irq_create_mapping()
202 * and that can be used by some irq controllers implementations for things
203 * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
204 */
205extern unsigned int irq_alloc_virt(struct irq_domain *host,
206 unsigned int count,
207 unsigned int hint);
208
209/**
210 * irq_free_virt - Free virtual irq numbers
211 * @virq: virtual irq number of the first interrupt to free
212 * @count: number of interrupts to free
213 *
214 * This function is the opposite of irq_alloc_virt. It will not clear reverse
215 * maps, this should be done previously by unmap'ing the interrupt. In fact,
216 * all interrupts covered by the range being freed should have been unmapped
217 * prior to calling this.
218 */
219extern void irq_free_virt(unsigned int virq, unsigned int count);
220
221/** 194/**
222 * irq_early_init - Init irq remapping subsystem 195 * irq_early_init - Init irq remapping subsystem
223 */ 196 */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 7305f2f65534..03c95f03d792 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -491,38 +491,29 @@ void do_softirq(void)
491 * IRQ controller and virtual interrupts 491 * IRQ controller and virtual interrupts
492 */ 492 */
493 493
494/* The main irq map itself is an array of NR_IRQ entries containing the
495 * associate host and irq number. An entry with a host of NULL is free.
496 * An entry can be allocated if it's free, the allocator always then sets
497 * hwirq first to the host's invalid irq number and then fills ops.
498 */
499struct irq_map_entry {
500 irq_hw_number_t hwirq;
501 struct irq_domain *host;
502};
503
504static LIST_HEAD(irq_domain_list); 494static LIST_HEAD(irq_domain_list);
505static DEFINE_RAW_SPINLOCK(irq_big_lock); 495static DEFINE_MUTEX(irq_domain_mutex);
506static DEFINE_MUTEX(revmap_trees_mutex); 496static DEFINE_MUTEX(revmap_trees_mutex);
507static struct irq_map_entry irq_map[NR_IRQS];
508static unsigned int irq_virq_count = NR_IRQS; 497static unsigned int irq_virq_count = NR_IRQS;
509static struct irq_domain *irq_default_host; 498static struct irq_domain *irq_default_host;
510 499
511irq_hw_number_t irqd_to_hwirq(struct irq_data *d) 500irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
512{ 501{
513 return irq_map[d->irq].hwirq; 502 return d->hwirq;
514} 503}
515EXPORT_SYMBOL_GPL(irqd_to_hwirq); 504EXPORT_SYMBOL_GPL(irqd_to_hwirq);
516 505
517irq_hw_number_t virq_to_hw(unsigned int virq) 506irq_hw_number_t virq_to_hw(unsigned int virq)
518{ 507{
519 return irq_map[virq].hwirq; 508 struct irq_data *irq_data = irq_get_irq_data(virq);
509 return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;
520} 510}
521EXPORT_SYMBOL_GPL(virq_to_hw); 511EXPORT_SYMBOL_GPL(virq_to_hw);
522 512
523bool virq_is_host(unsigned int virq, struct irq_domain *host) 513bool virq_is_host(unsigned int virq, struct irq_domain *host)
524{ 514{
525 return irq_map[virq].host == host; 515 struct irq_data *irq_data = irq_get_irq_data(virq);
516 return irq_data ? irq_data->domain == host : false;
526} 517}
527EXPORT_SYMBOL_GPL(virq_is_host); 518EXPORT_SYMBOL_GPL(virq_is_host);
528 519
@@ -537,11 +528,10 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node,
537 struct irq_domain_ops *ops, 528 struct irq_domain_ops *ops,
538 irq_hw_number_t inval_irq) 529 irq_hw_number_t inval_irq)
539{ 530{
540 struct irq_domain *host; 531 struct irq_domain *host, *h;
541 unsigned int size = sizeof(struct irq_domain); 532 unsigned int size = sizeof(struct irq_domain);
542 unsigned int i; 533 unsigned int i;
543 unsigned int *rmap; 534 unsigned int *rmap;
544 unsigned long flags;
545 535
546 /* Allocate structure and revmap table if using linear mapping */ 536 /* Allocate structure and revmap table if using linear mapping */
547 if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) 537 if (revmap_type == IRQ_DOMAIN_MAP_LINEAR)
@@ -559,23 +549,20 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node,
559 if (host->ops->match == NULL) 549 if (host->ops->match == NULL)
560 host->ops->match = default_irq_host_match; 550 host->ops->match = default_irq_host_match;
561 551
562 raw_spin_lock_irqsave(&irq_big_lock, flags); 552 mutex_lock(&irq_domain_mutex);
563 553 /* Make sure only one legacy controller can be created */
564 /* If it's a legacy controller, check for duplicates and
565 * mark it as allocated (we use irq 0 host pointer for that
566 */
567 if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { 554 if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) {
568 if (irq_map[0].host != NULL) { 555 list_for_each_entry(h, &irq_domain_list, link) {
569 raw_spin_unlock_irqrestore(&irq_big_lock, flags); 556 if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) {
570 of_node_put(host->of_node); 557 mutex_unlock(&irq_domain_mutex);
571 kfree(host); 558 of_node_put(host->of_node);
572 return NULL; 559 kfree(host);
560 return NULL;
561 }
573 } 562 }
574 irq_map[0].host = host;
575 } 563 }
576
577 list_add(&host->link, &irq_domain_list); 564 list_add(&host->link, &irq_domain_list);
578 raw_spin_unlock_irqrestore(&irq_big_lock, flags); 565 mutex_unlock(&irq_domain_mutex);
579 566
580 /* Additional setups per revmap type */ 567 /* Additional setups per revmap type */
581 switch(revmap_type) { 568 switch(revmap_type) {
@@ -584,10 +571,9 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node,
584 host->inval_irq = 0; 571 host->inval_irq = 0;
585 /* setup us as the host for all legacy interrupts */ 572 /* setup us as the host for all legacy interrupts */
586 for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { 573 for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
587 irq_map[i].hwirq = i; 574 struct irq_data *irq_data = irq_get_irq_data(i);
588 smp_wmb(); 575 irq_data->hwirq = i;
589 irq_map[i].host = host; 576 irq_data->domain = host;
590 smp_wmb();
591 577
592 /* Legacy flags are left to default at this point, 578 /* Legacy flags are left to default at this point,
593 * one can then use irq_create_mapping() to 579 * one can then use irq_create_mapping() to
@@ -604,7 +590,6 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node,
604 for (i = 0; i < revmap_arg; i++) 590 for (i = 0; i < revmap_arg; i++)
605 rmap[i] = NO_IRQ; 591 rmap[i] = NO_IRQ;
606 host->revmap_data.linear.size = revmap_arg; 592 host->revmap_data.linear.size = revmap_arg;
607 smp_wmb();
608 host->revmap_data.linear.revmap = rmap; 593 host->revmap_data.linear.revmap = rmap;
609 break; 594 break;
610 case IRQ_DOMAIN_MAP_TREE: 595 case IRQ_DOMAIN_MAP_TREE:
@@ -622,20 +607,19 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node,
622struct irq_domain *irq_find_host(struct device_node *node) 607struct irq_domain *irq_find_host(struct device_node *node)
623{ 608{
624 struct irq_domain *h, *found = NULL; 609 struct irq_domain *h, *found = NULL;
625 unsigned long flags;
626 610
627 /* We might want to match the legacy controller last since 611 /* We might want to match the legacy controller last since
628 * it might potentially be set to match all interrupts in 612 * it might potentially be set to match all interrupts in
629 * the absence of a device node. This isn't a problem so far 613 * the absence of a device node. This isn't a problem so far
630 * yet though... 614 * yet though...
631 */ 615 */
632 raw_spin_lock_irqsave(&irq_big_lock, flags); 616 mutex_lock(&irq_domain_mutex);
633 list_for_each_entry(h, &irq_domain_list, link) 617 list_for_each_entry(h, &irq_domain_list, link)
634 if (h->ops->match(h, node)) { 618