]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - kernel/irq/irqdomain.c
irq_domain: Remove irq_domain_add_simple()
[mirror_ubuntu-artful-kernel.git] / kernel / irq / irqdomain.c
CommitLineData
cc79ca69
GL
1#include <linux/debugfs.h>
2#include <linux/hardirq.h>
3#include <linux/interrupt.h>
08a543ad 4#include <linux/irq.h>
cc79ca69 5#include <linux/irqdesc.h>
08a543ad
GL
6#include <linux/irqdomain.h>
7#include <linux/module.h>
8#include <linux/mutex.h>
9#include <linux/of.h>
7e713301 10#include <linux/of_address.h>
cc79ca69 11#include <linux/seq_file.h>
7e713301 12#include <linux/slab.h>
cc79ca69
GL
13#include <linux/smp.h>
14#include <linux/fs.h>
08a543ad 15
1bc04f2c
GL
16#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs.
17 * ie. legacy 8259, gets irqs 1..15 */
a8db8cf0
GL
18#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
19#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
20#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
21
08a543ad
GL
22static LIST_HEAD(irq_domain_list);
23static DEFINE_MUTEX(irq_domain_mutex);
24
cc79ca69
GL
25static DEFINE_MUTEX(revmap_trees_mutex);
26static unsigned int irq_virq_count = NR_IRQS;
68700650 27static struct irq_domain *irq_default_domain;
cc79ca69 28
68700650 29static int default_irq_domain_match(struct irq_domain *d, struct device_node *np)
cc79ca69 30{
68700650 31 return d->of_node != NULL && d->of_node == np;
cc79ca69
GL
32}
33
34/**
a8db8cf0 35 * irq_domain_alloc() - Allocate a new irq_domain data structure
cc79ca69
GL
36 * @of_node: optional device-tree node of the interrupt controller
37 * @revmap_type: type of reverse mapping to use
68700650 38 * @ops: map/unmap domain callbacks
a8db8cf0 39 * @host_data: Controller private data pointer
cc79ca69 40 *
a8db8cf0
GL
41 * Allocates and initialize and irq_domain structure. Caller is expected to
42 * register allocated irq_domain with irq_domain_register(). Returns pointer
43 * to IRQ domain, or NULL on failure.
cc79ca69 44 */
a8db8cf0
GL
45static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
46 unsigned int revmap_type,
47 struct irq_domain_ops *ops,
48 void *host_data)
cc79ca69 49{
a8db8cf0 50 struct irq_domain *domain;
cc79ca69 51
a8db8cf0
GL
52 domain = kzalloc(sizeof(*domain), GFP_KERNEL);
53 if (WARN_ON(!domain))
cc79ca69
GL
54 return NULL;
55
56 /* Fill structure */
68700650 57 domain->revmap_type = revmap_type;
68700650 58 domain->ops = ops;
a8db8cf0 59 domain->host_data = host_data;
68700650 60 domain->of_node = of_node_get(of_node);
cc79ca69 61
68700650
GL
62 if (domain->ops->match == NULL)
63 domain->ops->match = default_irq_domain_match;
cc79ca69 64
a8db8cf0
GL
65 return domain;
66}
67
68static void irq_domain_add(struct irq_domain *domain)
69{
70 mutex_lock(&irq_domain_mutex);
71 list_add(&domain->link, &irq_domain_list);
72 mutex_unlock(&irq_domain_mutex);
73 pr_debug("irq: Allocated domain of type %d @0x%p\n",
74 domain->revmap_type, domain);
75}
76
1bc04f2c
GL
77static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
78 irq_hw_number_t hwirq)
79{
80 irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq;
81 int size = domain->revmap_data.legacy.size;
82
83 if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size))
84 return 0;
85 return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq;
86}
87
a8db8cf0
GL
88/**
89 * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
90 * @of_node: pointer to interrupt controller's device tree node.
1bc04f2c
GL
91 * @size: total number of irqs in legacy mapping
92 * @first_irq: first number of irq block assigned to the domain
93 * @first_hwirq: first hwirq number to use for the translation. Should normally
94 * be '0', but a positive integer can be used if the effective
95 * hwirqs numbering does not begin at zero.
a8db8cf0
GL
96 * @ops: map/unmap domain callbacks
97 * @host_data: Controller private data pointer
98 *
99 * Note: the map() callback will be called before this function returns
100 * for all legacy interrupts except 0 (which is always the invalid irq for
101 * a legacy controller).
102 */
103struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
1bc04f2c
GL
104 unsigned int size,
105 unsigned int first_irq,
106 irq_hw_number_t first_hwirq,
a8db8cf0
GL
107 struct irq_domain_ops *ops,
108 void *host_data)
109{
1bc04f2c 110 struct irq_domain *domain;
a8db8cf0
GL
111 unsigned int i;
112
113 domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data);
114 if (!domain)
115 return NULL;
116
1bc04f2c
GL
117 domain->revmap_data.legacy.first_irq = first_irq;
118 domain->revmap_data.legacy.first_hwirq = first_hwirq;
119 domain->revmap_data.legacy.size = size;
120
cc79ca69 121 mutex_lock(&irq_domain_mutex);
1bc04f2c
GL
122 /* Verify that all the irqs are available */
123 for (i = 0; i < size; i++) {
124 int irq = first_irq + i;
125 struct irq_data *irq_data = irq_get_irq_data(irq);
126
127 if (WARN_ON(!irq_data || irq_data->domain)) {
a8db8cf0
GL
128 mutex_unlock(&irq_domain_mutex);
129 of_node_put(domain->of_node);
130 kfree(domain);
131 return NULL;
cc79ca69
GL
132 }
133 }
cc79ca69 134
1bc04f2c
GL
135 /* Claim all of the irqs before registering a legacy domain */
136 for (i = 0; i < size; i++) {
137 struct irq_data *irq_data = irq_get_irq_data(first_irq + i);
138 irq_data->hwirq = first_hwirq + i;
a8db8cf0 139 irq_data->domain = domain;
1bc04f2c
GL
140 }
141 mutex_unlock(&irq_domain_mutex);
142
143 for (i = 0; i < size; i++) {
144 int irq = first_irq + i;
145 int hwirq = first_hwirq + i;
146
147 /* IRQ0 gets ignored */
148 if (!irq)
149 continue;
a8db8cf0
GL
150
151 /* Legacy flags are left to default at this point,
152 * one can then use irq_create_mapping() to
153 * explicitly change them
154 */
1bc04f2c 155 ops->map(domain, irq, hwirq);
a8db8cf0
GL
156
157 /* Clear norequest flags */
1bc04f2c 158 irq_clear_status_flags(irq, IRQ_NOREQUEST);
cc79ca69 159 }
1bc04f2c
GL
160
161 irq_domain_add(domain);
a8db8cf0
GL
162 return domain;
163}
164
165/**
166 * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
167 * @of_node: pointer to interrupt controller's device tree node.
168 * @ops: map/unmap domain callbacks
169 * @host_data: Controller private data pointer
170 */
171struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
172 unsigned int size,
173 struct irq_domain_ops *ops,
174 void *host_data)
175{
176 struct irq_domain *domain;
177 unsigned int *revmap;
cc79ca69 178
a8db8cf0
GL
179 revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL);
180 if (WARN_ON(!revmap))
181 return NULL;
cc79ca69 182
a8db8cf0
GL
183 domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data);
184 if (!domain) {
185 kfree(revmap);
186 return NULL;
187 }
188 domain->revmap_data.linear.size = size;
189 domain->revmap_data.linear.revmap = revmap;
190 irq_domain_add(domain);
191 return domain;
192}
193
194struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
195 struct irq_domain_ops *ops,
196 void *host_data)
197{
198 struct irq_domain *domain = irq_domain_alloc(of_node,
199 IRQ_DOMAIN_MAP_NOMAP, ops, host_data);
200 if (domain)
201 irq_domain_add(domain);
202 return domain;
203}
204
205/**
206 * irq_domain_add_tree()
207 * @of_node: pointer to interrupt controller's device tree node.
208 * @ops: map/unmap domain callbacks
209 *
210 * Note: The radix tree will be allocated later during boot automatically
211 * (the reverse mapping will use the slow path until that happens).
212 */
213struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
214 struct irq_domain_ops *ops,
215 void *host_data)
216{
217 struct irq_domain *domain = irq_domain_alloc(of_node,
218 IRQ_DOMAIN_MAP_TREE, ops, host_data);
219 if (domain) {
220 INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
221 irq_domain_add(domain);
222 }
68700650 223 return domain;
cc79ca69
GL
224}
225
226/**
227 * irq_find_host() - Locates a domain for a given device node
228 * @node: device-tree node of the interrupt controller
229 */
230struct irq_domain *irq_find_host(struct device_node *node)
231{
232 struct irq_domain *h, *found = NULL;
233
234 /* We might want to match the legacy controller last since
235 * it might potentially be set to match all interrupts in
236 * the absence of a device node. This isn't a problem so far
237 * yet though...
238 */
239 mutex_lock(&irq_domain_mutex);
240 list_for_each_entry(h, &irq_domain_list, link)
241 if (h->ops->match(h, node)) {
242 found = h;
243 break;
244 }
245 mutex_unlock(&irq_domain_mutex);
246 return found;
247}
248EXPORT_SYMBOL_GPL(irq_find_host);
249
250/**
251 * irq_set_default_host() - Set a "default" irq domain
68700650 252 * @domain: default domain pointer
cc79ca69
GL
253 *
254 * For convenience, it's possible to set a "default" domain that will be used
255 * whenever NULL is passed to irq_create_mapping(). It makes life easier for
256 * platforms that want to manipulate a few hard coded interrupt numbers that
257 * aren't properly represented in the device-tree.
258 */
68700650 259void irq_set_default_host(struct irq_domain *domain)
cc79ca69 260{
68700650 261 pr_debug("irq: Default domain set to @0x%p\n", domain);
cc79ca69 262
68700650 263 irq_default_domain = domain;
cc79ca69
GL
264}
265
266/**
267 * irq_set_virq_count() - Set the maximum number of linux irqs
268 * @count: number of linux irqs, capped with NR_IRQS
269 *
270 * This is mainly for use by platforms like iSeries who want to program
271 * the virtual irq number in the controller to avoid the reverse mapping
272 */
273void irq_set_virq_count(unsigned int count)
274{
275 pr_debug("irq: Trying to set virq count to %d\n", count);
276
277 BUG_ON(count < NUM_ISA_INTERRUPTS);
278 if (count < NR_IRQS)
279 irq_virq_count = count;
280}
281
68700650 282static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
cc79ca69
GL
283 irq_hw_number_t hwirq)
284{
285 struct irq_data *irq_data = irq_get_irq_data(virq);
286
287 irq_data->hwirq = hwirq;
68700650
GL
288 irq_data->domain = domain;
289 if (domain->ops->map(domain, virq, hwirq)) {
cc79ca69
GL
290 pr_debug("irq: -> mapping failed, freeing\n");
291 irq_data->domain = NULL;
292 irq_data->hwirq = 0;
293 return -1;
294 }
295
296 irq_clear_status_flags(virq, IRQ_NOREQUEST);
297
298 return 0;
299}
300
301/**
302 * irq_create_direct_mapping() - Allocate an irq for direct mapping
68700650 303 * @domain: domain to allocate the irq for or NULL for default domain
cc79ca69
GL
304 *
305 * This routine is used for irq controllers which can choose the hardware
306 * interrupt numbers they generate. In such a case it's simplest to use
307 * the linux irq as the hardware interrupt number.
308 */
68700650 309unsigned int irq_create_direct_mapping(struct irq_domain *domain)
cc79ca69
GL
310{
311 unsigned int virq;
312
68700650
GL
313 if (domain == NULL)
314 domain = irq_default_domain;
cc79ca69 315
68700650
GL
316 BUG_ON(domain == NULL);
317 WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP);
cc79ca69
GL
318
319 virq = irq_alloc_desc_from(1, 0);
03848373 320 if (!virq) {
cc79ca69 321 pr_debug("irq: create_direct virq allocation failed\n");
03848373 322 return 0;
cc79ca69
GL
323 }
324 if (virq >= irq_virq_count) {
325 pr_err("ERROR: no free irqs available below %i maximum\n",
326 irq_virq_count);
327 irq_free_desc(virq);
328 return 0;
329 }
330
331 pr_debug("irq: create_direct obtained virq %d\n", virq);
332
68700650 333 if (irq_setup_virq(domain, virq, virq)) {
cc79ca69 334 irq_free_desc(virq);
03848373 335 return 0;
cc79ca69
GL
336 }
337
338 return virq;
339}
340
341/**
342 * irq_create_mapping() - Map a hardware interrupt into linux irq space
68700650
GL
343 * @domain: domain owning this hardware interrupt or NULL for default domain
344 * @hwirq: hardware irq number in that domain space
cc79ca69
GL
345 *
346 * Only one mapping per hardware interrupt is permitted. Returns a linux
347 * irq number.
348 * If the sense/trigger is to be specified, set_irq_type() should be called
349 * on the number returned from that call.
350 */
68700650 351unsigned int irq_create_mapping(struct irq_domain *domain,
cc79ca69
GL
352 irq_hw_number_t hwirq)
353{
354 unsigned int virq, hint;
355
68700650 356 pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
cc79ca69 357
68700650
GL
358 /* Look for default domain if nececssary */
359 if (domain == NULL)
360 domain = irq_default_domain;
361 if (domain == NULL) {
cc79ca69 362 printk(KERN_WARNING "irq_create_mapping called for"
68700650 363 " NULL domain, hwirq=%lx\n", hwirq);
cc79ca69 364 WARN_ON(1);
03848373 365 return 0;
cc79ca69 366 }
68700650 367 pr_debug("irq: -> using domain @%p\n", domain);
cc79ca69
GL
368
369 /* Check if mapping already exists */
68700650 370 virq = irq_find_mapping(domain, hwirq);
03848373 371 if (virq) {
cc79ca69
GL
372 pr_debug("irq: -> existing mapping on virq %d\n", virq);
373 return virq;
374 }
375
376 /* Get a virtual interrupt number */
1bc04f2c
GL
377 if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
378 return irq_domain_legacy_revmap(domain, hwirq);
379
380 /* Allocate a virtual interrupt number */
381 hint = hwirq % irq_virq_count;
382 if (hint == 0)
383 hint++;
384 virq = irq_alloc_desc_from(hint, 0);
385 if (!virq)
386 virq = irq_alloc_desc_from(1, 0);
387 if (!virq) {
388 pr_debug("irq: -> virq allocation failed\n");
389 return 0;
cc79ca69
GL
390 }
391
68700650
GL
392 if (irq_setup_virq(domain, virq, hwirq)) {
393 if (domain->revmap_type != IRQ_DOMAIN_MAP_LEGACY)
cc79ca69 394 irq_free_desc(virq);
03848373 395 return 0;
cc79ca69
GL
396 }
397
68700650
GL
398 pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n",
399 hwirq, domain->of_node ? domain->of_node->full_name : "null", virq);
cc79ca69
GL
400
401 return virq;
402}
403EXPORT_SYMBOL_GPL(irq_create_mapping);
404
405unsigned int irq_create_of_mapping(struct device_node *controller,
406 const u32 *intspec, unsigned int intsize)
407{
68700650 408 struct irq_domain *domain;
cc79ca69
GL
409 irq_hw_number_t hwirq;
410 unsigned int type = IRQ_TYPE_NONE;
411 unsigned int virq;
412
68700650
GL
413 domain = controller ? irq_find_host(controller) : irq_default_domain;
414 if (!domain) {
415 printk(KERN_WARNING "irq: no irq domain found for %s !\n",
cc79ca69 416 controller->full_name);
03848373 417 return 0;
cc79ca69
GL
418 }
419
68700650
GL
420 /* If domain has no translation, then we assume interrupt line */
421 if (domain->ops->xlate == NULL)
cc79ca69
GL
422 hwirq = intspec[0];
423 else {
68700650 424 if (domain->ops->xlate(domain, controller, intspec, intsize,
cc79ca69 425 &hwirq, &type))
03848373 426 return 0;
cc79ca69
GL
427 }
428
429 /* Create mapping */
68700650 430 virq = irq_create_mapping(domain, hwirq);
03848373 431 if (!virq)
cc79ca69
GL
432 return virq;
433
434 /* Set type if specified and different than the current one */
435 if (type != IRQ_TYPE_NONE &&
436 type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
437 irq_set_irq_type(virq, type);
438 return virq;
439}
440EXPORT_SYMBOL_GPL(irq_create_of_mapping);
441
442/**
443 * irq_dispose_mapping() - Unmap an interrupt
444 * @virq: linux irq number of the interrupt to unmap
445 */
446void irq_dispose_mapping(unsigned int virq)
447{
448 struct irq_data *irq_data = irq_get_irq_data(virq);
68700650 449 struct irq_domain *domain;
cc79ca69
GL
450 irq_hw_number_t hwirq;
451
03848373 452 if (!virq || !irq_data)
cc79ca69
GL
453 return;
454
68700650
GL
455 domain = irq_data->domain;
456 if (WARN_ON(domain == NULL))
cc79ca69
GL
457 return;
458
459 /* Never unmap legacy interrupts */
68700650 460 if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
cc79ca69
GL
461 return;
462
463 irq_set_status_flags(virq, IRQ_NOREQUEST);
464
465 /* remove chip and handler */
466 irq_set_chip_and_handler(virq, NULL, NULL);
467
468 /* Make sure it's completed */
469 synchronize_irq(virq);
470
471 /* Tell the PIC about it */
68700650
GL
472 if (domain->ops->unmap)
473 domain->ops->unmap(domain, virq);
cc79ca69
GL
474 smp_mb();
475
476 /* Clear reverse map */
477 hwirq = irq_data->hwirq;
68700650 478 switch(domain->revmap_type) {
cc79ca69 479 case IRQ_DOMAIN_MAP_LINEAR:
68700650
GL
480 if (hwirq < domain->revmap_data.linear.size)
481 domain->revmap_data.linear.revmap[hwirq] = 0;
cc79ca69
GL
482 break;
483 case IRQ_DOMAIN_MAP_TREE:
484 mutex_lock(&revmap_trees_mutex);
68700650 485 radix_tree_delete(&domain->revmap_data.tree, hwirq);
cc79ca69
GL
486 mutex_unlock(&revmap_trees_mutex);
487 break;
488 }
489
cc79ca69
GL
490 irq_free_desc(virq);
491}
492EXPORT_SYMBOL_GPL(irq_dispose_mapping);
493
494/**
495 * irq_find_mapping() - Find a linux irq from an hw irq number.
68700650
GL
496 * @domain: domain owning this hardware interrupt
497 * @hwirq: hardware irq number in that domain space
cc79ca69
GL
498 *
499 * This is a slow path, for use by generic code. It's expected that an
500 * irq controller implementation directly calls the appropriate low level
501 * mapping function.
502 */
68700650 503unsigned int irq_find_mapping(struct irq_domain *domain,
cc79ca69
GL
504 irq_hw_number_t hwirq)
505{
506 unsigned int i;
507 unsigned int hint = hwirq % irq_virq_count;
508
68700650
GL
509 /* Look for default domain if nececssary */
510 if (domain == NULL)
511 domain = irq_default_domain;
512 if (domain == NULL)
03848373 513 return 0;
cc79ca69
GL
514
515 /* legacy -> bail early */
68700650 516 if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
1bc04f2c 517 return irq_domain_legacy_revmap(domain, hwirq);
cc79ca69
GL
518
519 /* Slow path does a linear search of the map */
520 if (hint == 0)
521 hint = 1;
522 i = hint;
523 do {
524 struct irq_data *data = irq_get_irq_data(i);
68700650 525 if (data && (data->domain == domain) && (data->hwirq == hwirq))
cc79ca69
GL
526 return i;
527 i++;
528 if (i >= irq_virq_count)
529 i = 1;
530 } while(i != hint);
03848373 531 return 0;
cc79ca69
GL
532}
533EXPORT_SYMBOL_GPL(irq_find_mapping);
534
535/**
536 * irq_radix_revmap_lookup() - Find a linux irq from a hw irq number.
68700650
GL
537 * @domain: domain owning this hardware interrupt
538 * @hwirq: hardware irq number in that domain space
cc79ca69
GL
539 *
540 * This is a fast path, for use by irq controller code that uses radix tree
541 * revmaps
542 */
68700650 543unsigned int irq_radix_revmap_lookup(struct irq_domain *domain,
cc79ca69
GL
544 irq_hw_number_t hwirq)
545{
546 struct irq_data *irq_data;
547
68700650
GL
548 if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_TREE))
549 return irq_find_mapping(domain, hwirq);
cc79ca69
GL
550
551 /*
552 * Freeing an irq can delete nodes along the path to
553 * do the lookup via call_rcu.
554 */
555 rcu_read_lock();
68700650 556 irq_data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
cc79ca69
GL
557 rcu_read_unlock();
558
559 /*
560 * If found in radix tree, then fine.
561 * Else fallback to linear lookup - this should not happen in practice
562 * as it means that we failed to insert the node in the radix tree.
563 */
68700650 564 return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq);
cc79ca69
GL
565}
566
567/**
568 * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping.
68700650 569 * @domain: domain owning this hardware interrupt
cc79ca69 570 * @virq: linux irq number
68700650 571 * @hwirq: hardware irq number in that domain space
cc79ca69
GL
572 *
573 * This is for use by irq controllers that use a radix tree reverse
574 * mapping for fast lookup.
575 */
68700650 576void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq,
cc79ca69
GL
577 irq_hw_number_t hwirq)
578{
579 struct irq_data *irq_data = irq_get_irq_data(virq);
580
68700650 581 if (WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_TREE))
cc79ca69
GL
582 return;
583
03848373 584 if (virq) {
cc79ca69 585 mutex_lock(&revmap_trees_mutex);
68700650 586 radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data);
cc79ca69
GL
587 mutex_unlock(&revmap_trees_mutex);
588 }
589}
590
591/**
592 * irq_linear_revmap() - Find a linux irq from a hw irq number.
68700650
GL
593 * @domain: domain owning this hardware interrupt
594 * @hwirq: hardware irq number in that domain space
cc79ca69
GL
595 *
596 * This is a fast path, for use by irq controller code that uses linear
597 * revmaps. It does fallback to the slow path if the revmap doesn't exist
598 * yet and will create the revmap entry with appropriate locking
599 */
68700650 600unsigned int irq_linear_revmap(struct irq_domain *domain,
cc79ca69
GL
601 irq_hw_number_t hwirq)
602{
603 unsigned int *revmap;
604
68700650
GL
605 if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR))
606 return irq_find_mapping(domain, hwirq);
cc79ca69
GL
607
608 /* Check revmap bounds */
68700650
GL
609 if (unlikely(hwirq >= domain->revmap_data.linear.size))
610 return irq_find_mapping(domain, hwirq);
cc79ca69
GL
611
612 /* Check if revmap was allocated */
68700650 613 revmap = domain->revmap_data.linear.revmap;
cc79ca69 614 if (unlikely(revmap == NULL))
68700650 615 return irq_find_mapping(domain, hwirq);
cc79ca69
GL
616
617 /* Fill up revmap with slow path if no mapping found */
03848373 618 if (unlikely(!revmap[hwirq]))
68700650 619 revmap[hwirq] = irq_find_mapping(domain, hwirq);
cc79ca69
GL
620
621 return revmap[hwirq];
622}
623
624#ifdef CONFIG_VIRQ_DEBUG
625static int virq_debug_show(struct seq_file *m, void *private)
626{
627 unsigned long flags;
628 struct irq_desc *desc;
629 const char *p;
630 static const char none[] = "none";
631 void *data;
632 int i;
633
634 seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
68700650 635 "chip name", "chip data", "domain name");
cc79ca69
GL
636
637 for (i = 1; i < nr_irqs; i++) {
638 desc = irq_to_desc(i);
639 if (!desc)
640 continue;
641
642 raw_spin_lock_irqsave(&desc->lock, flags);
643
644 if (desc->action && desc->action->handler) {
645 struct irq_chip *chip;
646
647 seq_printf(m, "%5d ", i);
648 seq_printf(m, "0x%05lx ", desc->irq_data.hwirq);
649
650 chip = irq_desc_get_chip(desc);
651 if (chip && chip->name)
652 p = chip->name;
653 else
654 p = none;
655 seq_printf(m, "%-15s ", p);
656
657 data = irq_desc_get_chip_data(desc);
658 seq_printf(m, "0x%16p ", data);
659
660 if (desc->irq_data.domain->of_node)
661 p = desc->irq_data.domain->of_node->full_name;
662 else
663 p = none;
664 seq_printf(m, "%s\n", p);
665 }
666
667 raw_spin_unlock_irqrestore(&desc->lock, flags);
668 }
669
670 return 0;
671}
672
673static int virq_debug_open(struct inode *inode, struct file *file)
674{
675 return single_open(file, virq_debug_show, inode->i_private);
676}
677
678static const struct file_operations virq_debug_fops = {
679 .open = virq_debug_open,
680 .read = seq_read,
681 .llseek = seq_lseek,
682 .release = single_release,
683};
684
685static int __init irq_debugfs_init(void)
686{
687 if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
688 NULL, &virq_debug_fops) == NULL)
689 return -ENOMEM;
690
691 return 0;
692}
693__initcall(irq_debugfs_init);
694#endif /* CONFIG_VIRQ_DEBUG */
695
75294957
GL
696int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
697 irq_hw_number_t hwirq)
08a543ad 698{
75294957 699 return 0;
08a543ad 700}
7e713301 701
7bb69bad 702int irq_domain_simple_xlate(struct irq_domain *d,
7e713301
GL
703 struct device_node *controller,
704 const u32 *intspec, unsigned int intsize,
705 unsigned long *out_hwirq, unsigned int *out_type)
706{
707 if (d->of_node != controller)
708 return -EINVAL;
709 if (intsize < 1)
710 return -EINVAL;
7e713301
GL
711 *out_hwirq = intspec[0];
712 *out_type = IRQ_TYPE_NONE;
713 if (intsize > 1)
714 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
715 return 0;
716}
717
75294957
GL
718struct irq_domain_ops irq_domain_simple_ops = {
719 .map = irq_domain_simple_map,
720 .xlate = irq_domain_simple_xlate,
721};
722EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
723
724#ifdef CONFIG_OF_IRQ
7e713301
GL
725void irq_domain_generate_simple(const struct of_device_id *match,
726 u64 phys_base, unsigned int irq_start)
727{
728 struct device_node *node;
e1964c50 729 pr_debug("looking for phys_base=%llx, irq_start=%i\n",
7e713301
GL
730 (unsigned long long) phys_base, (int) irq_start);
731 node = of_find_matching_node_by_address(NULL, match, phys_base);
732 if (node)
6b783f7c
GL
733 irq_domain_add_legacy(node, 32, irq_start, 0,
734 &irq_domain_simple_ops, NULL);
7e713301
GL
735}
736EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
75294957 737#endif