diff options
| -rw-r--r-- | include/linux/irqdomain.h | 4 | ||||
| -rw-r--r-- | kernel/irq/irqdomain.c | 61 |
2 files changed, 62 insertions, 3 deletions
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index c65740d76e66..a796dbf80b67 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h | |||
| @@ -141,10 +141,12 @@ static inline struct irq_domain *irq_domain_add_legacy_isa( | |||
| 141 | return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, | 141 | return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, |
| 142 | host_data); | 142 | host_data); |
| 143 | } | 143 | } |
| 144 | |||
| 145 | extern void irq_domain_remove(struct irq_domain *host); | ||
| 146 | |||
| 144 | extern struct irq_domain *irq_find_host(struct device_node *node); | 147 | extern struct irq_domain *irq_find_host(struct device_node *node); |
| 145 | extern void irq_set_default_host(struct irq_domain *host); | 148 | extern void irq_set_default_host(struct irq_domain *host); |
| 146 | 149 | ||
| 147 | |||
| 148 | extern unsigned int irq_create_mapping(struct irq_domain *host, | 150 | extern unsigned int irq_create_mapping(struct irq_domain *host, |
| 149 | irq_hw_number_t hwirq); | 151 | irq_hw_number_t hwirq); |
| 150 | extern void irq_dispose_mapping(unsigned int virq); | 152 | extern void irq_dispose_mapping(unsigned int virq); |
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 0e0ba5f840b2..9cae0b2f509f 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
| @@ -56,6 +56,12 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node, | |||
| 56 | return domain; | 56 | return domain; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static void irq_domain_free(struct irq_domain *domain) | ||
| 60 | { | ||
| 61 | of_node_put(domain->of_node); | ||
| 62 | kfree(domain); | ||
| 63 | } | ||
| 64 | |||
| 59 | static void irq_domain_add(struct irq_domain *domain) | 65 | static void irq_domain_add(struct irq_domain *domain) |
| 60 | { | 66 | { |
| 61 | mutex_lock(&irq_domain_mutex); | 67 | mutex_lock(&irq_domain_mutex); |
| @@ -65,6 +71,58 @@ static void irq_domain_add(struct irq_domain *domain) | |||
| 65 | domain->revmap_type, domain); | 71 | domain->revmap_type, domain); |
| 66 | } | 72 | } |
| 67 | 73 | ||
| 74 | /** | ||
| 75 | * irq_domain_remove() - Remove an irq domain. | ||
| 76 | * @domain: domain to remove | ||
| 77 | * | ||
| 78 | * This routine is used to remove an irq domain. The caller must ensure | ||
| 79 | * that all mappings within the domain have been disposed of prior to | ||
| 80 | * use, depending on the revmap type. | ||
| 81 | */ | ||
| 82 | void irq_domain_remove(struct irq_domain *domain) | ||
| 83 | { | ||
| 84 | mutex_lock(&irq_domain_mutex); | ||
| 85 | |||
| 86 | switch (domain->revmap_type) { | ||
| 87 | case IRQ_DOMAIN_MAP_LEGACY: | ||
| 88 | /* | ||
| 89 | * Legacy domains don't manage their own irq_desc | ||
| 90 | * allocations, we expect the caller to handle irq_desc | ||
| 91 | * freeing on their own. | ||
| 92 | */ | ||
| 93 | break; | ||
| 94 | case IRQ_DOMAIN_MAP_TREE: | ||
| 95 | /* | ||
| 96 | * radix_tree_delete() takes care of destroying the root | ||
| 97 | * node when all entries are removed. Shout if there are | ||
| 98 | * any mappings left. | ||
| 99 | */ | ||
| 100 | WARN_ON(domain->revmap_data.tree.height); | ||
| 101 | break; | ||
| 102 | case IRQ_DOMAIN_MAP_LINEAR: | ||
| 103 | kfree(domain->revmap_data.linear.revmap); | ||
| 104 | domain->revmap_data.linear.size = 0; | ||
| 105 | break; | ||
| 106 | case IRQ_DOMAIN_MAP_NOMAP: | ||
| 107 | break; | ||
| 108 | } | ||
| 109 | |||
| 110 | list_del(&domain->link); | ||
| 111 | |||
| 112 | /* | ||
| 113 | * If the going away domain is the default one, reset it. | ||
| 114 | */ | ||
| 115 | if (unlikely(irq_default_domain == domain)) | ||
| 116 | irq_set_default_host(NULL); | ||
| 117 | |||
| 118 | mutex_unlock(&irq_domain_mutex); | ||
| 119 | |||
| 120 | pr_debug("irq: Removed domain of type %d @0x%p\n", | ||
| 121 | domain->revmap_type, domain); | ||
| 122 | |||
| 123 | irq_domain_free(domain); | ||
| 124 | } | ||
| 125 | |||
| 68 | static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, | 126 | static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, |
| 69 | irq_hw_number_t hwirq) | 127 | irq_hw_number_t hwirq) |
| 70 | { | 128 | { |
| @@ -117,8 +175,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, | |||
| 117 | 175 | ||
| 118 | if (WARN_ON(!irq_data || irq_data->domain)) { | 176 | if (WARN_ON(!irq_data || irq_data->domain)) { |
| 119 | mutex_unlock(&irq_domain_mutex); | 177 | mutex_unlock(&irq_domain_mutex); |
| 120 | of_node_put(domain->of_node); | 178 | irq_domain_free(domain); |
| 121 | kfree(domain); | ||
| 122 | return NULL; | 179 | return NULL; |
| 123 | } | 180 | } |
| 124 | } | 181 | } |
