Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux

Pull irqdomain refactoring from Grant Likely:
"This is the long awaited simplification of irqdomain. It gets rid of
the different types of irq domains and instead both linear and tree
mappings can be supported in a single domain. Doing this removes a
lot of special case code and makes irq domains simpler to understand
overall"

* tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux:
irq: fix checkpatch error
irqdomain: Include hwirq number in /proc/interrupts
irqdomain: make irq_linear_revmap() a fast path again
irqdomain: remove irq_domain_generate_simple()
irqdomain: Refactor irq_domain_associate_many()
irqdomain: Beef up debugfs output
irqdomain: Clean up aftermath of irq_domain refactoring
irqdomain: Eliminate revmap type
irqdomain: merge linear and tree reverse mappings.
irqdomain: Add a name field
irqdomain: Replace LEGACY mapping with LINEAR
irqdomain: Relax failure path on setting up mappings

+269 -478
+1 -1
arch/powerpc/platforms/cell/beat_interrupt.c
··· 239 239 ppc_md.get_irq = beatic_get_irq; 240 240 241 241 /* Allocate an irq host */ 242 - beatic_host = irq_domain_add_nomap(NULL, 0, &beatic_pic_host_ops, NULL); 242 + beatic_host = irq_domain_add_nomap(NULL, ~0, &beatic_pic_host_ops, NULL); 243 243 BUG_ON(beatic_host == NULL); 244 244 irq_set_default_host(beatic_host); 245 245 }
+1 -1
arch/powerpc/platforms/powermac/smp.c
··· 192 192 { 193 193 int rc = -ENOMEM; 194 194 195 - psurge_host = irq_domain_add_nomap(NULL, 0, &psurge_host_ops, NULL); 195 + psurge_host = irq_domain_add_nomap(NULL, ~0, &psurge_host_ops, NULL); 196 196 197 197 if (psurge_host) 198 198 psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
+1 -3
arch/x86/kernel/devicetree.c
··· 364 364 * and assigned so we can keep the 1:1 mapping which the ioapic 365 365 * is having. 366 366 */ 367 - ret = irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY); 368 - if (ret) 369 - pr_err("Error mapping legacy IRQs: %d\n", ret); 367 + irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY); 370 368 371 369 if (num > NR_IRQS_LEGACY) { 372 370 ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY,
+76 -68
include/linux/irqdomain.h
··· 73 73 /** 74 74 * struct irq_domain - Hardware interrupt number translation object 75 75 * @link: Element in global irq_domain list. 76 - * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This 77 - * will be one of the IRQ_DOMAIN_MAP_* values. 78 - * @revmap_data: Revmap method specific data. 76 + * @name: Name of interrupt domain 79 77 * @ops: pointer to irq_domain methods 80 78 * @host_data: private data pointer for use by owner. Not touched by irq_domain 81 79 * core code. 82 - * @irq_base: Start of irq_desc range assigned to the irq_domain. The creator 83 - * of the irq_domain is responsible for allocating the array of 84 - * irq_desc structures. 85 - * @nr_irq: Number of irqs managed by the irq domain 86 - * @hwirq_base: Starting number for hwirqs managed by the irq domain 87 - * @of_node: (optional) Pointer to device tree nodes associated with the 88 - * irq_domain. Used when decoding device tree interrupt specifiers. 80 + * 81 + * Optional elements 82 + * @of_node: Pointer to device tree nodes associated with the irq_domain. Used 83 + * when decoding device tree interrupt specifiers. 84 + * @gc: Pointer to a list of generic chips. There is a helper function for 85 + * setting up one or more generic chips for interrupt controllers 86 + * drivers using the generic chip library which uses this pointer. 87 + * 88 + * Revmap data, used internally by irq_domain 89 + * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that 90 + * support direct mapping 91 + * @revmap_size: Size of the linear map table @linear_revmap[] 92 + * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map 93 + * @linear_revmap: Linear table of hwirq->virq reverse mappings 89 94 */ 90 95 struct irq_domain { 91 96 struct list_head link; 92 - 93 - /* type of reverse mapping_technique */ 94 - unsigned int revmap_type; 95 - union { 96 - struct { 97 - unsigned int size; 98 - unsigned int first_irq; 99 - irq_hw_number_t first_hwirq; 100 - } legacy; 101 - struct { 102 - unsigned int size; 103 - unsigned int *revmap; 104 - } linear; 105 - struct { 106 - unsigned int max_irq; 107 - } nomap; 108 - struct radix_tree_root tree; 109 - } revmap_data; 97 + const char *name; 110 98 const struct irq_domain_ops *ops; 111 99 void *host_data; 112 - irq_hw_number_t inval_irq; 113 100 114 - /* Optional device node pointer */ 101 + /* Optional data */ 115 102 struct device_node *of_node; 116 - /* Optional pointer to generic interrupt chips */ 117 103 struct irq_domain_chip_generic *gc; 104 + 105 + /* reverse map data. The linear map gets appended to the irq_domain */ 106 + irq_hw_number_t hwirq_max; 107 + unsigned int revmap_direct_max_irq; 108 + unsigned int revmap_size; 109 + struct radix_tree_root revmap_tree; 110 + unsigned int linear_revmap[]; 118 111 }; 119 112 120 - #define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs. 121 - * ie. legacy 8259, gets irqs 1..15 */ 122 - #define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */ 123 - #define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */ 124 - #define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */ 125 - 126 113 #ifdef CONFIG_IRQ_DOMAIN 114 + struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, 115 + irq_hw_number_t hwirq_max, int direct_max, 116 + const struct irq_domain_ops *ops, 117 + void *host_data); 127 118 struct irq_domain *irq_domain_add_simple(struct device_node *of_node, 128 119 unsigned int size, 129 120 unsigned int first_irq, ··· 126 135 irq_hw_number_t first_hwirq, 127 136 const struct irq_domain_ops *ops, 128 137 void *host_data); 129 - struct irq_domain *irq_domain_add_linear(struct device_node *of_node, 130 - unsigned int size, 131 - const struct irq_domain_ops *ops, 132 - void *host_data); 133 - struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, 134 - unsigned int max_irq, 135 - const struct irq_domain_ops *ops, 136 - void *host_data); 137 - struct irq_domain *irq_domain_add_tree(struct device_node *of_node, 138 - const struct irq_domain_ops *ops, 139 - void *host_data); 140 - 141 138 extern struct irq_domain *irq_find_host(struct device_node *node); 142 139 extern void irq_set_default_host(struct irq_domain *host); 143 140 141 + /** 142 + * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain. 143 + * @of_node: pointer to interrupt controller's device tree node. 144 + * @size: Number of interrupts in the domain. 145 + * @ops: map/unmap domain callbacks 146 + * @host_data: Controller private data pointer 147 + */ 148 + static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node, 149 + unsigned int size, 150 + const struct irq_domain_ops *ops, 151 + void *host_data) 152 + { 153 + return __irq_domain_add(of_node, size, size, 0, ops, host_data); 154 + } 155 + static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, 156 + unsigned int max_irq, 157 + const struct irq_domain_ops *ops, 158 + void *host_data) 159 + { 160 + return __irq_domain_add(of_node, 0, max_irq, max_irq, ops, host_data); 161 + } 144 162 static inline struct irq_domain *irq_domain_add_legacy_isa( 145 163 struct device_node *of_node, 146 164 const struct irq_domain_ops *ops, ··· 158 158 return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, 159 159 host_data); 160 160 } 161 + static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node, 162 + const struct irq_domain_ops *ops, 163 + void *host_data) 164 + { 165 + return __irq_domain_add(of_node, 0, ~0, 0, ops, host_data); 166 + } 161 167 162 168 extern void irq_domain_remove(struct irq_domain *host); 163 169 164 - extern int irq_domain_associate_many(struct irq_domain *domain, 165 - unsigned int irq_base, 166 - irq_hw_number_t hwirq_base, int count); 167 - static inline int irq_domain_associate(struct irq_domain *domain, unsigned int irq, 168 - irq_hw_number_t hwirq) 169 - { 170 - return irq_domain_associate_many(domain, irq, hwirq, 1); 171 - } 170 + extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq, 171 + irq_hw_number_t hwirq); 172 + extern void irq_domain_associate_many(struct irq_domain *domain, 173 + unsigned int irq_base, 174 + irq_hw_number_t hwirq_base, int count); 172 175 173 176 extern unsigned int irq_create_mapping(struct irq_domain *host, 174 177 irq_hw_number_t hwirq); 175 178 extern void irq_dispose_mapping(unsigned int virq); 179 + 180 + /** 181 + * irq_linear_revmap() - Find a linux irq from a hw irq number. 182 + * @domain: domain owning this hardware interrupt 183 + * @hwirq: hardware irq number in that domain space 184 + * 185 + * This is a fast path alternative to irq_find_mapping() that can be 186 + * called directly by irq controller code to save a handful of 187 + * instructions. It is always safe to call, but won't find irqs mapped 188 + * using the radix tree. 189 + */ 190 + static inline unsigned int irq_linear_revmap(struct irq_domain *domain, 191 + irq_hw_number_t hwirq) 192 + { 193 + return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0; 194 + } 176 195 extern unsigned int irq_find_mapping(struct irq_domain *host, 177 196 irq_hw_number_t hwirq); 178 197 extern unsigned int irq_create_direct_mapping(struct irq_domain *host); ··· 205 186 return irq_create_strict_mappings(host, hwirq, hwirq, 1); 206 187 } 207 188 208 - extern unsigned int irq_linear_revmap(struct irq_domain *host, 209 - irq_hw_number_t hwirq); 210 - 211 189 extern const struct irq_domain_ops irq_domain_simple_ops; 212 190 213 191 /* stock xlate functions */ ··· 217 201 int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, 218 202 const u32 *intspec, unsigned int intsize, 219 203 irq_hw_number_t *out_hwirq, unsigned int *out_type); 220 - 221 - #if defined(CONFIG_OF_IRQ) 222 - extern void irq_domain_generate_simple(const struct of_device_id *match, 223 - u64 phys_base, unsigned int irq_start); 224 - #else /* CONFIG_OF_IRQ */ 225 - static inline void irq_domain_generate_simple(const struct of_device_id *match, 226 - u64 phys_base, unsigned int irq_start) { } 227 - #endif /* !CONFIG_OF_IRQ */ 228 204 229 205 #else /* CONFIG_IRQ_DOMAIN */ 230 206 static inline void irq_dispose_mapping(unsigned int virq) { }
+2 -4
kernel/irq/generic-chip.c
··· 275 275 if (d->gc) 276 276 return -EBUSY; 277 277 278 - if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR) 279 - return -EINVAL; 280 - 281 - numchips = d->revmap_data.linear.size / irqs_per_chip; 278 + numchips = d->revmap_size / irqs_per_chip; 282 279 if (!numchips) 283 280 return -EINVAL; 284 281 ··· 307 310 /* Calc pointer to the next generic chip */ 308 311 tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); 309 312 } 313 + d->name = name; 310 314 return 0; 311 315 } 312 316 EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips);
+186 -401
kernel/irq/irqdomain.c
··· 23 23 static struct irq_domain *irq_default_domain; 24 24 25 25 /** 26 - * irq_domain_alloc() - Allocate a new irq_domain data structure 26 + * __irq_domain_add() - Allocate a new irq_domain data structure 27 27 * @of_node: optional device-tree node of the interrupt controller 28 - * @revmap_type: type of reverse mapping to use 28 + * @size: Size of linear map; 0 for radix mapping only 29 + * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no 30 + * direct mapping 29 31 * @ops: map/unmap domain callbacks 30 32 * @host_data: Controller private data pointer 31 33 * ··· 35 33 * register allocated irq_domain with irq_domain_register(). Returns pointer 36 34 * to IRQ domain, or NULL on failure. 37 35 */ 38 - static struct irq_domain *irq_domain_alloc(struct device_node *of_node, 39 - unsigned int revmap_type, 40 - const struct irq_domain_ops *ops, 41 - void *host_data) 36 + struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, 37 + irq_hw_number_t hwirq_max, int direct_max, 38 + const struct irq_domain_ops *ops, 39 + void *host_data) 42 40 { 43 41 struct irq_domain *domain; 44 42 45 - domain = kzalloc_node(sizeof(*domain), GFP_KERNEL, 46 - of_node_to_nid(of_node)); 43 + domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size), 44 + GFP_KERNEL, of_node_to_nid(of_node)); 47 45 if (WARN_ON(!domain)) 48 46 return NULL; 49 47 50 48 /* Fill structure */ 51 - domain->revmap_type = revmap_type; 49 + INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL); 52 50 domain->ops = ops; 53 51 domain->host_data = host_data; 54 52 domain->of_node = of_node_get(of_node); 53 + domain->hwirq_max = hwirq_max; 54 + domain->revmap_size = size; 55 + domain->revmap_direct_max_irq = direct_max; 55 56 56 - return domain; 57 - } 58 - 59 - static void irq_domain_free(struct irq_domain *domain) 60 - { 61 - of_node_put(domain->of_node); 62 - kfree(domain); 63 - } 64 - 65 - static void irq_domain_add(struct irq_domain *domain) 66 - { 67 57 mutex_lock(&irq_domain_mutex); 68 58 list_add(&domain->link, &irq_domain_list); 69 59 mutex_unlock(&irq_domain_mutex); 70 - pr_debug("Allocated domain of type %d @0x%p\n", 71 - domain->revmap_type, domain); 60 + 61 + pr_debug("Added domain %s\n", domain->name); 62 + return domain; 72 63 } 64 + EXPORT_SYMBOL_GPL(__irq_domain_add); 73 65 74 66 /** 75 67 * irq_domain_remove() - Remove an irq domain. ··· 77 81 { 78 82 mutex_lock(&irq_domain_mutex); 79 83 80 - switch (domain->revmap_type) { 81 - case IRQ_DOMAIN_MAP_LEGACY: 82 - /* 83 - * Legacy domains don't manage their own irq_desc 84 - * allocations, we expect the caller to handle irq_desc 85 - * freeing on their own. 86 - */ 87 - break; 88 - case IRQ_DOMAIN_MAP_TREE: 89 - /* 90 - * radix_tree_delete() takes care of destroying the root 91 - * node when all entries are removed. Shout if there are 92 - * any mappings left. 93 - */ 94 - WARN_ON(domain->revmap_data.tree.height); 95 - break; 96 - case IRQ_DOMAIN_MAP_LINEAR: 97 - kfree(domain->revmap_data.linear.revmap); 98 - domain->revmap_data.linear.size = 0; 99 - break; 100 - case IRQ_DOMAIN_MAP_NOMAP: 101 - break; 102 - } 84 + /* 85 + * radix_tree_delete() takes care of destroying the root 86 + * node when all entries are removed. Shout if there are 87 + * any mappings left. 88 + */ 89 + WARN_ON(domain->revmap_tree.height); 103 90 104 91 list_del(&domain->link); 105 92 ··· 94 115 95 116 mutex_unlock(&irq_domain_mutex); 96 117 97 - pr_debug("Removed domain of type %d @0x%p\n", 98 - domain->revmap_type, domain); 118 + pr_debug("Removed domain %s\n", domain->name); 99 119 100 - irq_domain_free(domain); 120 + of_node_put(domain->of_node); 121 + kfree(domain); 101 122 } 102 123 EXPORT_SYMBOL_GPL(irq_domain_remove); 103 124 104 - static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, 105 - irq_hw_number_t hwirq) 106 - { 107 - irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq; 108 - int size = domain->revmap_data.legacy.size; 109 - 110 - if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size)) 111 - return 0; 112 - return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq; 113 - } 114 - 115 125 /** 116 - * irq_domain_add_simple() - Allocate and register a simple irq_domain. 126 + * irq_domain_add_simple() - Register an irq_domain and optionally map a range of irqs 117 127 * @of_node: pointer to interrupt controller's device tree node. 118 128 * @size: total number of irqs in mapping 119 129 * @first_irq: first number of irq block assigned to the domain, 120 - * pass zero to assign irqs on-the-fly. This will result in a 121 - * linear IRQ domain so it is important to use irq_create_mapping() 122 - * for each used IRQ, especially when SPARSE_IRQ is enabled. 130 + * pass zero to assign irqs on-the-fly. If first_irq is non-zero, then 131 + * pre-map all of the irqs in the domain to virqs starting at first_irq. 123 132 * @ops: map/unmap domain callbacks 124 133 * @host_data: Controller private data pointer 125 134 * 126 - * Allocates a legacy irq_domain if irq_base is positive or a linear 127 - * domain otherwise. For the legacy domain, IRQ descriptors will also 128 - * be allocated. 135 + * Allocates an irq_domain, and optionally if first_irq is positive then also 136 + * allocate irq_descs and map all of the hwirqs to virqs starting at first_irq. 129 137 * 130 138 * This is intended to implement the expected behaviour for most 131 - * interrupt controllers which is that a linear mapping should 132 - * normally be used unless the system requires a legacy mapping in 133 - * order to support supplying interrupt numbers during non-DT 134 - * registration of devices. 139 + * interrupt controllers. If device tree is used, then first_irq will be 0 and 140 + * irqs get mapped dynamically on the fly. However, if the controller requires 141 + * static virq assignments (non-DT boot) then it will set that up correctly. 135 142 */ 136 143 struct irq_domain *irq_domain_add_simple(struct device_node *of_node, 137 144 unsigned int size, ··· 125 160 const struct irq_domain_ops *ops, 126 161 void *host_data) 127 162 { 128 - if (first_irq > 0) { 129 - int irq_base; 163 + struct irq_domain *domain; 130 164 165 + domain = __irq_domain_add(of_node, size, size, 0, ops, host_data); 166 + if (!domain) 167 + return NULL; 168 + 169 + if (first_irq > 0) { 131 170 if (IS_ENABLED(CONFIG_SPARSE_IRQ)) { 132 - /* 133 - * Set the descriptor allocator to search for a 134 - * 1-to-1 mapping, such as irq_alloc_desc_at(). 135 - * Use of_node_to_nid() which is defined to 136 - * numa_node_id() on platforms that have no custom 137 - * implementation. 138 - */ 139 - irq_base = irq_alloc_descs(first_irq, first_irq, size, 140 - of_node_to_nid(of_node)); 141 - if (irq_base < 0) { 171 + /* attempt to allocated irq_descs */ 172 + int rc = irq_alloc_descs(first_irq, first_irq, size, 173 + of_node_to_nid(of_node)); 174 + if (rc < 0) 142 175 pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", 143 176 first_irq); 144 - irq_base = first_irq; 145 - } 146 - } else 147 - irq_base = first_irq; 148 - 149 - return irq_domain_add_legacy(of_node, size, irq_base, 0, 150 - ops, host_data); 177 + } 178 + irq_domain_associate_many(domain, first_irq, 0, size); 151 179 } 152 180 153 - /* A linear domain is the default */ 154 - return irq_domain_add_linear(of_node, size, ops, host_data); 181 + return domain; 155 182 } 156 183 EXPORT_SYMBOL_GPL(irq_domain_add_simple); 157 184 ··· 170 213 void *host_data) 171 214 { 172 215 struct irq_domain *domain; 173 - unsigned int i; 174 216 175 - domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data); 217 + domain = __irq_domain_add(of_node, first_hwirq + size, 218 + first_hwirq + size, 0, ops, host_data); 176 219 if (!domain) 177 220 return NULL; 178 221 179 - domain->revmap_data.legacy.first_irq = first_irq; 180 - domain->revmap_data.legacy.first_hwirq = first_hwirq; 181 - domain->revmap_data.legacy.size = size; 222 + irq_domain_associate_many(domain, first_irq, first_hwirq, size); 182 223 183 - mutex_lock(&irq_domain_mutex); 184 - /* Verify that all the irqs are available */ 185 - for (i = 0; i < size; i++) { 186 - int irq = first_irq + i; 187 - struct irq_data *irq_data = irq_get_irq_data(irq); 188 - 189 - if (WARN_ON(!irq_data || irq_data->domain)) { 190 - mutex_unlock(&irq_domain_mutex); 191 - irq_domain_free(domain); 192 - return NULL; 193 - } 194 - } 195 - 196 - /* Claim all of the irqs before registering a legacy domain */ 197 - for (i = 0; i < size; i++) { 198 - struct irq_data *irq_data = irq_get_irq_data(first_irq + i); 199 - irq_data->hwirq = first_hwirq + i; 200 - irq_data->domain = domain; 201 - } 202 - mutex_unlock(&irq_domain_mutex); 203 - 204 - for (i = 0; i < size; i++) { 205 - int irq = first_irq + i; 206 - int hwirq = first_hwirq + i; 207 - 208 - /* IRQ0 gets ignored */ 209 - if (!irq) 210 - continue; 211 - 212 - /* Legacy flags are left to default at this point, 213 - * one can then use irq_create_mapping() to 214 - * explicitly change them 215 - */ 216 - if (ops->map) 217 - ops->map(domain, irq, hwirq); 218 - 219 - /* Clear norequest flags */ 220 - irq_clear_status_flags(irq, IRQ_NOREQUEST); 221 - } 222 - 223 - irq_domain_add(domain); 224 224 return domain; 225 225 } 226 226 EXPORT_SYMBOL_GPL(irq_domain_add_legacy); 227 - 228 - /** 229 - * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain. 230 - * @of_node: pointer to interrupt controller's device tree node. 231 - * @size: Number of interrupts in the domain. 232 - * @ops: map/unmap domain callbacks 233 - * @host_data: Controller private data pointer 234 - */ 235 - struct irq_domain *irq_domain_add_linear(struct device_node *of_node, 236 - unsigned int size, 237 - const struct irq_domain_ops *ops, 238 - void *host_data) 239 - { 240 - struct irq_domain *domain; 241 - unsigned int *revmap; 242 - 243 - revmap = kzalloc_node(sizeof(*revmap) * size, GFP_KERNEL, 244 - of_node_to_nid(of_node)); 245 - if (WARN_ON(!revmap)) 246 - return NULL; 247 - 248 - domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data); 249 - if (!domain) { 250 - kfree(revmap); 251 - return NULL; 252 - } 253 - domain->revmap_data.linear.size = size; 254 - domain->revmap_data.linear.revmap = revmap; 255 - irq_domain_add(domain); 256 - return domain; 257 - } 258 - EXPORT_SYMBOL_GPL(irq_domain_add_linear); 259 - 260 - struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, 261 - unsigned int max_irq, 262 - const struct irq_domain_ops *ops, 263 - void *host_data) 264 - { 265 - struct irq_domain *domain = irq_domain_alloc(of_node, 266 - IRQ_DOMAIN_MAP_NOMAP, ops, host_data); 267 - if (domain) { 268 - domain->revmap_data.nomap.max_irq = max_irq ? max_irq : ~0; 269 - irq_domain_add(domain); 270 - } 271 - return domain; 272 - } 273 - EXPORT_SYMBOL_GPL(irq_domain_add_nomap); 274 - 275 - /** 276 - * irq_domain_add_tree() 277 - * @of_node: pointer to interrupt controller's device tree node. 278 - * @ops: map/unmap domain callbacks 279 - * 280 - * Note: The radix tree will be allocated later during boot automatically 281 - * (the reverse mapping will use the slow path until that happens). 282 - */ 283 - struct irq_domain *irq_domain_add_tree(struct device_node *of_node, 284 - const struct irq_domain_ops *ops, 285 - void *host_data) 286 - { 287 - struct irq_domain *domain = irq_domain_alloc(of_node, 288 - IRQ_DOMAIN_MAP_TREE, ops, host_data); 289 - if (domain) { 290 - INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL); 291 - irq_domain_add(domain); 292 - } 293 - return domain; 294 - } 295 - EXPORT_SYMBOL_GPL(irq_domain_add_tree); 296 227 297 228 /** 298 229 * irq_find_host() - Locates a domain for a given device node ··· 230 385 } 231 386 EXPORT_SYMBOL_GPL(irq_set_default_host); 232 387 233 - static void irq_domain_disassociate_many(struct irq_domain *domain, 234 - unsigned int irq_base, int count) 388 + static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq) 235 389 { 236 - /* 237 - * disassociate in reverse order; 238 - * not strictly necessary, but nice for unwinding 239 - */ 240 - while (count--) { 241 - int irq = irq_base + count; 242 - struct irq_data *irq_data = irq_get_irq_data(irq); 243 - irq_hw_number_t hwirq; 390 + struct irq_data *irq_data = irq_get_irq_data(irq); 391 + irq_hw_number_t hwirq; 244 392 245 - if (WARN_ON(!irq_data || irq_data->domain != domain)) 246 - continue; 393 + if (WARN(!irq_data || irq_data->domain != domain, 394 + "virq%i doesn't exist; cannot disassociate\n", irq)) 395 + return; 247 396 248 - hwirq = irq_data->hwirq; 249 - irq_set_status_flags(irq, IRQ_NOREQUEST); 397 + hwirq = irq_data->hwirq; 398 + irq_set_status_flags(irq, IRQ_NOREQUEST); 250 399 251 - /* remove chip and handler */ 252 - irq_set_chip_and_handler(irq, NULL, NULL); 400 + /* remove chip and handler */ 401 + irq_set_chip_and_handler(irq, NULL, NULL); 253 402 254 - /* Make sure it's completed */ 255 - synchronize_irq(irq); 403 + /* Make sure it's completed */ 404 + synchronize_irq(irq); 256 405 257 - /* Tell the PIC about it */ 258 - if (domain->ops->unmap) 259 - domain->ops->unmap(domain, irq); 260 - smp_mb(); 406 + /* Tell the PIC about it */ 407 + if (domain->ops->unmap) 408 + domain->ops->unmap(domain, irq); 409 + smp_mb(); 261 410 262 - irq_data->domain = NULL; 263 - irq_data->hwirq = 0; 411 + irq_data->domain = NULL; 412 + irq_data->hwirq = 0; 264 413 265 - /* Clear reverse map */ 266 - switch(domain->revmap_type) { 267 - case IRQ_DOMAIN_MAP_LINEAR: 268 - if (hwirq < domain->revmap_data.linear.size) 269 - domain->revmap_data.linear.revmap[hwirq] = 0; 270 - break; 271 - case IRQ_DOMAIN_MAP_TREE: 272 - mutex_lock(&revmap_trees_mutex); 273 - radix_tree_delete(&domain->revmap_data.tree, hwirq); 274 - mutex_unlock(&revmap_trees_mutex); 275 - break; 276 - } 414 + /* Clear reverse map for this hwirq */ 415 + if (hwirq < domain->revmap_size) { 416 + domain->linear_revmap[hwirq] = 0; 417 + } else { 418 + mutex_lock(&revmap_trees_mutex); 419 + radix_tree_delete(&domain->revmap_tree, hwirq); 420 + mutex_unlock(&revmap_trees_mutex); 277 421 } 278 422 } 279 423 280 - int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, 281 - irq_hw_number_t hwirq_base, int count) 424 + int irq_domain_associate(struct irq_domain *domain, unsigned int virq, 425 + irq_hw_number_t hwirq) 282 426 { 283 - unsigned int virq = irq_base; 284 - irq_hw_number_t hwirq = hwirq_base; 285 - int i, ret; 427 + struct irq_data *irq_data = irq_get_irq_data(virq); 428 + int ret; 429 + 430 + if (WARN(hwirq >= domain->hwirq_max, 431 + "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name)) 432 + return -EINVAL; 433 + if (WARN(!irq_data, "error: virq%i is not allocated", virq)) 434 + return -EINVAL; 435 + if (WARN(irq_data->domain, "error: virq%i is already associated", virq)) 436 + return -EINVAL; 437 + 438 + mutex_lock(&irq_domain_mutex); 439 + irq_data->hwirq = hwirq; 440 + irq_data->domain = domain; 441 + if (domain->ops->map) { 442 + ret = domain->ops->map(domain, virq, hwirq); 443 + if (ret != 0) { 444 + /* 445 + * If map() returns -EPERM, this interrupt is protected 446 + * by the firmware or some other service and shall not 447 + * be mapped. Don't bother telling the user about it. 448 + */ 449 + if (ret != -EPERM) { 450 + pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n", 451 + domain->name, hwirq, virq, ret); 452 + } 453 + irq_data->domain = NULL; 454 + irq_data->hwirq = 0; 455 + mutex_unlock(&irq_domain_mutex); 456 + return ret; 457 + } 458 + 459 + /* If not already assigned, give the domain the chip's name */ 460 + if (!domain->name && irq_data->chip) 461 + domain->name = irq_data->chip->name; 462 + } 463 + 464 + if (hwirq < domain->revmap_size) { 465 + domain->linear_revmap[hwirq] = virq; 466 + } else { 467 + mutex_lock(&revmap_trees_mutex); 468 + radix_tree_insert(&domain->revmap_tree, hwirq, irq_data); 469 + mutex_unlock(&revmap_trees_mutex); 470 + } 471 + mutex_unlock(&irq_domain_mutex); 472 + 473 + irq_clear_status_flags(virq, IRQ_NOREQUEST); 474 + 475 + return 0; 476 + } 477 + EXPORT_SYMBOL_GPL(irq_domain_associate); 478 + 479 + void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, 480 + irq_hw_number_t hwirq_base, int count) 481 + { 482 + int i; 286 483 287 484 pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__, 288 485 of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count); 289 486 290 487 for (i = 0; i < count; i++) { 291 - struct irq_data *irq_data = irq_get_irq_data(virq + i); 292 - 293 - if (WARN(!irq_data, "error: irq_desc not allocated; " 294 - "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i)) 295 - return -EINVAL; 296 - if (WARN(irq_data->domain, "error: irq_desc already associated; " 297 - "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i)) 298 - return -EINVAL; 299 - }; 300 - 301 - for (i = 0; i < count; i++, virq++, hwirq++) { 302 - struct irq_data *irq_data = irq_get_irq_data(virq); 303 - 304 - irq_data->hwirq = hwirq; 305 - irq_data->domain = domain; 306 - if (domain->ops->map) { 307 - ret = domain->ops->map(domain, virq, hwirq); 308 - if (ret != 0) { 309 - /* 310 - * If map() returns -EPERM, this interrupt is protected 311 - * by the firmware or some other service and shall not 312 - * be mapped. 313 - * 314 - * Since on some platforms we blindly try to map everything 315 - * we end up with a log full of backtraces. 316 - * 317 - * So instead, we silently fail on -EPERM, it is the 318 - * responsibility of the PIC driver to display a relevant 319 - * message if needed. 320 - */ 321 - if (ret != -EPERM) { 322 - pr_err("irq-%i==>hwirq-0x%lx mapping failed: %d\n", 323 - virq, hwirq, ret); 324 - WARN_ON(1); 325 - } 326 - irq_data->domain = NULL; 327 - irq_data->hwirq = 0; 328 - goto err_unmap; 329 - } 330 - } 331 - 332 - switch (domain->revmap_type) { 333 - case IRQ_DOMAIN_MAP_LINEAR: 334 - if (hwirq < domain->revmap_data.linear.size) 335 - domain->revmap_data.linear.revmap[hwirq] = virq; 336 - break; 337 - case IRQ_DOMAIN_MAP_TREE: 338 - mutex_lock(&revmap_trees_mutex); 339 - radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data); 340 - mutex_unlock(&revmap_trees_mutex); 341 - break; 342 - } 343 - 344 - irq_clear_status_flags(virq, IRQ_NOREQUEST); 488 + irq_domain_associate(domain, irq_base + i, hwirq_base + i); 345 489 } 346 - 347 - return 0; 348 - 349 - err_unmap: 350 - irq_domain_disassociate_many(domain, irq_base, i); 351 - return -EINVAL; 352 490 } 353 491 EXPORT_SYMBOL_GPL(irq_domain_associate_many); 354 492 ··· 341 513 * 342 514 * This routine is used for irq controllers which can choose the hardware 343 515 * interrupt numbers they generate. In such a case it's simplest to use 344 - * the linux irq as the hardware interrupt number. 516 + * the linux irq as the hardware interrupt number. It still uses the linear 517 + * or radix tree to store the mapping, but the irq controller can optimize 518 + * the revmap path by using the hwirq directly. 345 519 */ 346 520 unsigned int irq_create_direct_mapping(struct irq_domain *domain) 347 521 { ··· 352 522 if (domain == NULL) 353 523 domain = irq_default_domain; 354 524 355 - if (WARN_ON(!domain || domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP)) 356 - return 0; 357 - 358 525 virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node)); 359 526 if (!virq) { 360 527 pr_debug("create_direct virq allocation failed\n"); 361 528 return 0; 362 529 } 363 - if (virq >= domain->revmap_data.nomap.max_irq) { 530 + if (virq >= domain->revmap_direct_max_irq) { 364 531 pr_err("ERROR: no free irqs available below %i maximum\n", 365 - domain->revmap_data.nomap.max_irq); 532 + domain->revmap_direct_max_irq); 366 533 irq_free_desc(virq); 367 534 return 0; 368 535 } ··· 396 569 if (domain == NULL) 397 570 domain = irq_default_domain; 398 571 if (domain == NULL) { 399 - pr_warning("irq_create_mapping called for" 400 - " NULL domain, hwirq=%lx\n", hwirq); 401 - WARN_ON(1); 572 + WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq); 402 573 return 0; 403 574 } 404 575 pr_debug("-> using domain @%p\n", domain); ··· 407 582 pr_debug("-> existing mapping on virq %d\n", virq); 408 583 return virq; 409 584 } 410 - 411 - /* Get a virtual interrupt number */ 412 - if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) 413 - return irq_domain_legacy_revmap(domain, hwirq); 414 585 415 586 /* Allocate a virtual interrupt number */ 416 587 hint = hwirq % nr_irqs; ··· 460 639 if (unlikely(ret < 0)) 461 640 return ret; 462 641 463 - ret = irq_domain_associate_many(domain, irq_base, hwirq_base, count); 464 - if (unlikely(ret < 0)) { 465 - irq_free_descs(irq_base, count); 466 - return ret; 467 - } 468 - 642 + irq_domain_associate_many(domain, irq_base, hwirq_base, count); 469 643 return 0; 470 644 } 471 645 EXPORT_SYMBOL_GPL(irq_create_strict_mappings); ··· 487 671 if (intsize > 0) 488 672 return intspec[0]; 489 673 #endif 490 - pr_warning("no irq domain found for %s !\n", 491 - of_node_full_name(controller)); 674 + pr_warn("no irq domain found for %s !\n", 675 + of_node_full_name(controller)); 492 676 return 0; 493 677 } 494 678 ··· 530 714 if (WARN_ON(domain == NULL)) 531 715 return; 532 716 533 - /* Never unmap legacy interrupts */ 534 - if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) 535 - return; 536 - 537 - irq_domain_disassociate_many(domain, virq, 1); 717 + irq_domain_disassociate(domain, virq); 538 718 irq_free_desc(virq); 539 719 } 540 720 EXPORT_SYMBOL_GPL(irq_dispose_mapping); ··· 551 739 if (domain == NULL) 552 740 return 0; 553 741 554 - switch (domain->revmap_type) { 555 - case IRQ_DOMAIN_MAP_LEGACY: 556 - return irq_domain_legacy_revmap(domain, hwirq); 557 - case IRQ_DOMAIN_MAP_LINEAR: 558 - return irq_linear_revmap(domain, hwirq); 559 - case IRQ_DOMAIN_MAP_TREE: 560 - rcu_read_lock(); 561 - data = radix_tree_lookup(&domain->revmap_data.tree, hwirq); 562 - rcu_read_unlock(); 563 - if (data) 564 - return data->irq; 565 - break; 566 - case IRQ_DOMAIN_MAP_NOMAP: 742 + if (hwirq < domain->revmap_direct_max_irq) { 567 743 data = irq_get_irq_data(hwirq); 568 744 if (data && (data->domain == domain) && (data->hwirq == hwirq)) 569 745 return hwirq; 570 - break; 571 746 } 572 747 573 - return 0; 748 + /* Check if the hwirq is in the linear revmap. */ 749 + if (hwirq < domain->revmap_size) 750 + return domain->linear_revmap[hwirq]; 751 + 752 + rcu_read_lock(); 753 + data = radix_tree_lookup(&domain->revmap_tree, hwirq); 754 + rcu_read_unlock(); 755 + return data ? data->irq : 0; 574 756 } 575 757 EXPORT_SYMBOL_GPL(irq_find_mapping); 576 - 577 - /** 578 - * irq_linear_revmap() - Find a linux irq from a hw irq number. 579 - * @domain: domain owning this hardware interrupt 580 - * @hwirq: hardware irq number in that domain space 581 - * 582 - * This is a fast path that can be called directly by irq controller code to 583 - * save a handful of instructions. 584 - */ 585 - unsigned int irq_linear_revmap(struct irq_domain *domain, 586 - irq_hw_number_t hwirq) 587 - { 588 - BUG_ON(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR); 589 - 590 - /* Check revmap bounds; complain if exceeded */ 591 - if (WARN_ON(hwirq >= domain->revmap_data.linear.size)) 592 - return 0; 593 - 594 - return domain->revmap_data.linear.revmap[hwirq]; 595 - } 596 - EXPORT_SYMBOL_GPL(irq_linear_revmap); 597 758 598 759 #ifdef CONFIG_IRQ_DOMAIN_DEBUG 599 760 static int virq_debug_show(struct seq_file *m, void *private) 600 761 { 601 762 unsigned long flags; 602 763 struct irq_desc *desc; 603 - const char *p; 604 - static const char none[] = "none"; 605 - void *data; 764 + struct irq_domain *domain; 765 + struct radix_tree_iter iter; 766 + void *data, **slot; 606 767 int i; 607 768 608 - seq_printf(m, "%-5s %-7s %-15s %-*s %s\n", "irq", "hwirq", 769 + seq_printf(m, " %-16s %-6s %-10s %-10s %s\n", 770 + "name", "mapped", "linear-max", "direct-max", "devtree-node"); 771 + mutex_lock(&irq_domain_mutex); 772 + list_for_each_entry(domain, &irq_domain_list, link) { 773 + int count = 0; 774 + radix_tree_for_each_slot(slot, &domain->revmap_tree, &iter, 0) 775 + count++; 776 + seq_printf(m, "%c%-16s %6u %10u %10u %s\n", 777 + domain == irq_default_domain ? '*' : ' ', domain->name, 778 + domain->revmap_size + count, domain->revmap_size, 779 + domain->revmap_direct_max_irq, 780 + domain->of_node ? of_node_full_name(domain->of_node) : ""); 781 + } 782 + mutex_unlock(&irq_domain_mutex); 783 + 784 + seq_printf(m, "%-5s %-7s %-15s %-*s %6s %-14s %s\n", "irq", "hwirq", 609 785 "chip name", (int)(2 * sizeof(void *) + 2), "chip data", 610 - "domain name"); 786 + "active", "type", "domain"); 611 787 612 788 for (i = 1; i < nr_irqs; i++) { 613 789 desc = irq_to_desc(i); ··· 603 803 continue; 604 804 605 805 raw_spin_lock_irqsave(&desc->lock, flags); 806 + domain = desc->irq_data.domain; 606 807 607 - if (desc->action && desc->action->handler) { 808 + if (domain) { 608 809 struct irq_chip *chip; 810 + int hwirq = desc->irq_data.hwirq; 811 + bool direct; 609 812 610 813 seq_printf(m, "%5d ", i); 611 - seq_printf(m, "0x%05lx ", desc->irq_data.hwirq); 814 + seq_printf(m, "0x%05x ", hwirq); 612 815 613 816 chip = irq_desc_get_chip(desc); 614 - if (chip && chip->name) 615 - p = chip->name; 616 - else 617 - p = none; 618 - seq_printf(m, "%-15s ", p); 817 + seq_printf(m, "%-15s ", (chip && chip->name) ? chip->name : "none"); 619 818 620 819 data = irq_desc_get_chip_data(desc); 621 820 seq_printf(m, data ? "0x%p " : " %p ", data); 622 821 623 - if (desc->irq_data.domain) 624 - p = of_node_full_name(desc->irq_data.domain->of_node); 625 - else 626 - p = none; 627 - seq_printf(m, "%s\n", p); 822 + seq_printf(m, " %c ", (desc->action && desc->action->handler) ? '*' : ' '); 823 + direct = (i == hwirq) && (i < domain->revmap_direct_max_irq); 824 + seq_printf(m, "%6s%-8s ", 825 + (hwirq < domain->revmap_size) ? "LINEAR" : "RADIX", 826 + direct ? "(DIRECT)" : ""); 827 + seq_printf(m, "%s\n", desc->irq_data.domain->name); 628 828 } 629 829 630 830 raw_spin_unlock_irqrestore(&desc->lock, flags); ··· 721 921 .xlate = irq_domain_xlate_onetwocell, 722 922 }; 723 923 EXPORT_SYMBOL_GPL(irq_domain_simple_ops); 724 - 725 - #ifdef CONFIG_OF_IRQ 726 - void irq_domain_generate_simple(const struct of_device_id *match, 727 - u64 phys_base, unsigned int irq_start) 728 - { 729 - struct device_node *node; 730 - pr_debug("looking for phys_base=%llx, irq_start=%i\n", 731 - (unsigned long long) phys_base, (int) irq_start); 732 - node = of_find_matching_node_by_address(NULL, match, phys_base); 733 - if (node) 734 - irq_domain_add_legacy(node, 32, irq_start, 0, 735 - &irq_domain_simple_ops, NULL); 736 - } 737 - EXPORT_SYMBOL_GPL(irq_domain_generate_simple); 738 - #endif
+2
kernel/irq/proc.c
··· 462 462 } else { 463 463 seq_printf(p, " %8s", "None"); 464 464 } 465 + if (desc->irq_data.domain) 466 + seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq); 465 467 #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL 466 468 seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); 467 469 #endif