aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/irqdomain.c113
1 files changed, 88 insertions, 25 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 091732c9dbdc..a07d92446b66 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -410,36 +410,61 @@ static void irq_domain_disassociate_many(struct irq_domain *domain,
410 } 410 }
411} 411}
412 412
413static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, 413int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
414 irq_hw_number_t hwirq) 414 irq_hw_number_t hwirq_base, int count)
415{ 415{
416 struct irq_data *irq_data = irq_get_irq_data(virq); 416 unsigned int virq = irq_base;
417 irq_hw_number_t hwirq = hwirq_base;
418 int i;
417 419
418 irq_data->hwirq = hwirq; 420 pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
419 irq_data->domain = domain; 421 of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
420 if (domain->ops->map && domain->ops->map(domain, virq, hwirq)) {
421 pr_err("irq-%i==>hwirq-0x%lx mapping failed\n", virq, hwirq);
422 irq_data->domain = NULL;
423 irq_data->hwirq = 0;
424 return -1;
425 }
426 422
427 switch (domain->revmap_type) { 423 for (i = 0; i < count; i++) {
428 case IRQ_DOMAIN_MAP_LINEAR: 424 struct irq_data *irq_data = irq_get_irq_data(virq + i);
429 if (hwirq < domain->revmap_data.linear.size) 425
430 domain->revmap_data.linear.revmap[hwirq] = virq; 426 if (WARN(!irq_data, "error: irq_desc not allocated; "
431 break; 427 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
432 case IRQ_DOMAIN_MAP_TREE: 428 return -EINVAL;
433 mutex_lock(&revmap_trees_mutex); 429 if (WARN(irq_data->domain, "error: irq_desc already associated; "
434 irq_radix_revmap_insert(domain, virq, hwirq); 430 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
435 mutex_unlock(&revmap_trees_mutex); 431 return -EINVAL;
436 break; 432 };
437 } 433
434 for (i = 0; i < count; i++, virq++, hwirq++) {
435 struct irq_data *irq_data = irq_get_irq_data(virq);
436
437 irq_data->hwirq = hwirq;
438 irq_data->domain = domain;
439 if (domain->ops->map && domain->ops->map(domain, virq, hwirq)) {
440 pr_err("irq-%i==>hwirq-0x%lx mapping failed\n", virq, hwirq);
441 irq_data->domain = NULL;
442 irq_data->hwirq = 0;
443 goto err_unmap;
444 }
445
446 switch (domain->revmap_type) {
447 case IRQ_DOMAIN_MAP_LINEAR:
448 if (hwirq < domain->revmap_data.linear.size)
449 domain->revmap_data.linear.revmap[hwirq] = virq;
450 break;
451 case IRQ_DOMAIN_MAP_TREE:
452 mutex_lock(&revmap_trees_mutex);
453 irq_radix_revmap_insert(domain, virq, hwirq);
454 mutex_unlock(&revmap_trees_mutex);
455 break;
456 }
438 457
439 irq_clear_status_flags(virq, IRQ_NOREQUEST); 458 irq_clear_status_flags(virq, IRQ_NOREQUEST);
459 }
440 460
441 return 0; 461 return 0;
462
463 err_unmap:
464 irq_domain_disassociate_many(domain, irq_base, i);
465 return -EINVAL;
442} 466}
467EXPORT_SYMBOL_GPL(irq_domain_associate_many);
443 468
444/** 469/**
445 * irq_create_direct_mapping() - Allocate an irq for direct mapping 470 * irq_create_direct_mapping() - Allocate an irq for direct mapping
@@ -472,7 +497,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
472 } 497 }
473 pr_debug("create_direct obtained virq %d\n", virq); 498 pr_debug("create_direct obtained virq %d\n", virq);
474 499
475 if (irq_setup_virq(domain, virq, virq)) { 500 if (irq_domain_associate(domain, virq, virq)) {
476 irq_free_desc(virq); 501 irq_free_desc(virq);
477 return 0; 502 return 0;
478 } 503 }
@@ -533,7 +558,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
533 return 0; 558 return 0;
534 } 559 }
535 560
536 if (irq_setup_virq(domain, virq, hwirq)) { 561 if (irq_domain_associate(domain, virq, hwirq)) {
537 irq_free_desc(virq); 562 irq_free_desc(virq);
538 return 0; 563 return 0;
539 } 564 }
@@ -545,6 +570,44 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
545} 570}
546EXPORT_SYMBOL_GPL(irq_create_mapping); 571EXPORT_SYMBOL_GPL(irq_create_mapping);
547 572
573/**
574 * irq_create_strict_mappings() - Map a range of hw irqs to fixed linux irqs
575 * @domain: domain owning the interrupt range
576 * @irq_base: beginning of linux IRQ range
577 * @hwirq_base: beginning of hardware IRQ range
578 * @count: Number of interrupts to map
579 *
580 * This routine is used for allocating and mapping a range of hardware
581 * irqs to linux irqs where the linux irq numbers are at pre-defined
582 * locations. For use by controllers that already have static mappings
583 * to insert in to the domain.
584 *
585 * Non-linear users can use irq_create_identity_mapping() for IRQ-at-a-time
586 * domain insertion.
587 *
588 * 0 is returned upon success, while any failure to establish a static
589 * mapping is treated as an error.
590 */
591int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
592 irq_hw_number_t hwirq_base, int count)
593{
594 int ret;
595
596 ret = irq_alloc_descs(irq_base, irq_base, count,
597 of_node_to_nid(domain->of_node));
598 if (unlikely(ret < 0))
599 return ret;
600
601 ret = irq_domain_associate_many(domain, irq_base, hwirq_base, count);
602 if (unlikely(ret < 0)) {
603 irq_free_descs(irq_base, count);
604 return ret;
605 }
606
607 return 0;
608}
609EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
610
548unsigned int irq_create_of_mapping(struct device_node *controller, 611unsigned int irq_create_of_mapping(struct device_node *controller,
549 const u32 *intspec, unsigned int intsize) 612 const u32 *intspec, unsigned int intsize)
550{ 613{