irqdomain.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include <linux/irq.h>
  2. #include <linux/irqdomain.h>
  3. #include <linux/module.h>
  4. #include <linux/mutex.h>
  5. #include <linux/of.h>
  6. #include <linux/of_address.h>
  7. #include <linux/slab.h>
  8. static LIST_HEAD(irq_domain_list);
  9. static DEFINE_MUTEX(irq_domain_mutex);
  10. /**
  11. * irq_domain_add() - Register an irq_domain
  12. * @domain: ptr to initialized irq_domain structure
  13. *
  14. * Registers an irq_domain structure. The irq_domain must at a minimum be
  15. * initialized with an ops structure pointer, and either a ->to_irq hook or
  16. * a valid irq_base value. Everything else is optional.
  17. */
  18. void irq_domain_add(struct irq_domain *domain)
  19. {
  20. struct irq_data *d;
  21. int hwirq, irq;
  22. /*
  23. * This assumes that the irq_domain owner has already allocated
  24. * the irq_descs. This block will be removed when support for dynamic
  25. * allocation of irq_descs is added to irq_domain.
  26. */
  27. irq_domain_for_each_irq(domain, hwirq, irq) {
  28. d = irq_get_irq_data(irq);
  29. if (!d) {
  30. WARN(1, "error: assigning domain to non existant irq_desc");
  31. return;
  32. }
  33. if (d->domain) {
  34. /* things are broken; just report, don't clean up */
  35. WARN(1, "error: irq_desc already assigned to a domain");
  36. return;
  37. }
  38. d->domain = domain;
  39. d->hwirq = hwirq;
  40. }
  41. mutex_lock(&irq_domain_mutex);
  42. list_add(&domain->list, &irq_domain_list);
  43. mutex_unlock(&irq_domain_mutex);
  44. }
  45. /**
  46. * irq_domain_del() - Unregister an irq_domain
  47. * @domain: ptr to registered irq_domain.
  48. */
  49. void irq_domain_del(struct irq_domain *domain)
  50. {
  51. struct irq_data *d;
  52. int hwirq, irq;
  53. mutex_lock(&irq_domain_mutex);
  54. list_del(&domain->list);
  55. mutex_unlock(&irq_domain_mutex);
  56. /* Clear the irq_domain assignments */
  57. irq_domain_for_each_irq(domain, hwirq, irq) {
  58. d = irq_get_irq_data(irq);
  59. d->domain = NULL;
  60. }
  61. }
  62. #if defined(CONFIG_OF_IRQ)
  63. /**
  64. * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
  65. *
  66. * Used by the device tree interrupt mapping code to translate a device tree
  67. * interrupt specifier to a valid linux irq number. Returns either a valid
  68. * linux IRQ number or 0.
  69. *
  70. * When the caller no longer need the irq number returned by this function it
  71. * should arrange to call irq_dispose_mapping().
  72. */
  73. unsigned int irq_create_of_mapping(struct device_node *controller,
  74. const u32 *intspec, unsigned int intsize)
  75. {
  76. struct irq_domain *domain;
  77. unsigned long hwirq;
  78. unsigned int irq, type;
  79. int rc = -EINVAL;
  80. /* Find a domain which can translate the irq spec */
  81. mutex_lock(&irq_domain_mutex);
  82. list_for_each_entry(domain, &irq_domain_list, list) {
  83. if (!domain->ops->dt_translate)
  84. continue;
  85. rc = domain->ops->dt_translate(domain, controller,
  86. intspec, intsize, &hwirq, &type);
  87. if (rc == 0)
  88. break;
  89. }
  90. mutex_unlock(&irq_domain_mutex);
  91. if (rc != 0)
  92. return 0;
  93. irq = irq_domain_to_irq(domain, hwirq);
  94. if (type != IRQ_TYPE_NONE)
  95. irq_set_irq_type(irq, type);
  96. pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
  97. controller->full_name, (int)hwirq, irq, type);
  98. return irq;
  99. }
  100. EXPORT_SYMBOL_GPL(irq_create_of_mapping);
  101. /**
  102. * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
  103. * @irq: linux irq number to be discarded
  104. *
  105. * Calling this function indicates the caller no longer needs a reference to
  106. * the linux irq number returned by a prior call to irq_create_of_mapping().
  107. */
  108. void irq_dispose_mapping(unsigned int irq)
  109. {
  110. /*
  111. * nothing yet; will be filled when support for dynamic allocation of
  112. * irq_descs is added to irq_domain
  113. */
  114. }
  115. EXPORT_SYMBOL_GPL(irq_dispose_mapping);
  116. int irq_domain_simple_dt_translate(struct irq_domain *d,
  117. struct device_node *controller,
  118. const u32 *intspec, unsigned int intsize,
  119. unsigned long *out_hwirq, unsigned int *out_type)
  120. {
  121. if (d->of_node != controller)
  122. return -EINVAL;
  123. if (intsize < 1)
  124. return -EINVAL;
  125. if (d->nr_irq && ((intspec[0] < d->hwirq_base) ||
  126. (intspec[0] >= d->hwirq_base + d->nr_irq)))
  127. return -EINVAL;
  128. *out_hwirq = intspec[0];
  129. *out_type = IRQ_TYPE_NONE;
  130. if (intsize > 1)
  131. *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
  132. return 0;
  133. }
  134. /**
  135. * irq_domain_create_simple() - Set up a 'simple' translation range
  136. */
  137. void irq_domain_add_simple(struct device_node *controller, int irq_base)
  138. {
  139. struct irq_domain *domain;
  140. domain = kzalloc(sizeof(*domain), GFP_KERNEL);
  141. if (!domain) {
  142. WARN_ON(1);
  143. return;
  144. }
  145. domain->irq_base = irq_base;
  146. domain->of_node = of_node_get(controller);
  147. domain->ops = &irq_domain_simple_ops;
  148. irq_domain_add(domain);
  149. }
  150. EXPORT_SYMBOL_GPL(irq_domain_add_simple);
  151. void irq_domain_generate_simple(const struct of_device_id *match,
  152. u64 phys_base, unsigned int irq_start)
  153. {
  154. struct device_node *node;
  155. pr_info("looking for phys_base=%llx, irq_start=%i\n",
  156. (unsigned long long) phys_base, (int) irq_start);
  157. node = of_find_matching_node_by_address(NULL, match, phys_base);
  158. if (node)
  159. irq_domain_add_simple(node, irq_start);
  160. else
  161. pr_info("no node found\n");
  162. }
  163. EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
  164. #endif /* CONFIG_OF_IRQ */
  165. struct irq_domain_ops irq_domain_simple_ops = {
  166. #ifdef CONFIG_OF_IRQ
  167. .dt_translate = irq_domain_simple_dt_translate,
  168. #endif /* CONFIG_OF_IRQ */
  169. };
  170. EXPORT_SYMBOL_GPL(irq_domain_simple_ops);