2 * Copyright (C) 2011 Texas Instruments Incorporated
4 * This borrows heavily from powerpc version, which is:
6 * Derived from arch/i386/kernel/irq.c
7 * Copyright (C) 1992 Linus Torvalds
8 * Adapted from arch/i386 by Gary Thomas
9 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
10 * Updated and modified by Cort Dougan <cort@fsmlabs.com>
11 * Copyright (C) 1996-2001 Cort Dougan
12 * Adapted for Power Macintosh by Paul Mackerras
13 * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
20 #include <linux/slab.h>
21 #include <linux/seq_file.h>
22 #include <linux/radix-tree.h>
23 #include <linux/module.h>
25 #include <linux/of_irq.h>
26 #include <linux/interrupt.h>
27 #include <linux/kernel_stat.h>
29 #include <asm/megamod-pic.h>
31 unsigned long irq_err_count
;
33 static DEFINE_RAW_SPINLOCK(core_irq_lock
);
35 static void mask_core_irq(struct irq_data
*data
)
37 unsigned int prio
= data
->irq
;
39 BUG_ON(prio
< 4 || prio
>= NR_PRIORITY_IRQS
);
41 raw_spin_lock(&core_irq_lock
);
42 and_creg(IER
, ~(1 << prio
));
43 raw_spin_unlock(&core_irq_lock
);
46 static void unmask_core_irq(struct irq_data
*data
)
48 unsigned int prio
= data
->irq
;
50 raw_spin_lock(&core_irq_lock
);
51 or_creg(IER
, 1 << prio
);
52 raw_spin_unlock(&core_irq_lock
);
55 static struct irq_chip core_chip
= {
57 .irq_mask
= mask_core_irq
,
58 .irq_unmask
= unmask_core_irq
,
61 asmlinkage
void c6x_do_IRQ(unsigned int prio
, struct pt_regs
*regs
)
63 struct pt_regs
*old_regs
= set_irq_regs(regs
);
67 BUG_ON(prio
< 4 || prio
>= NR_PRIORITY_IRQS
);
69 generic_handle_irq(prio
);
73 set_irq_regs(old_regs
);
76 static struct irq_host
*core_host
;
78 static int core_host_map(struct irq_host
*h
, unsigned int virq
,
81 if (hw
< 4 || hw
>= NR_PRIORITY_IRQS
)
84 irq_set_status_flags(virq
, IRQ_LEVEL
);
85 irq_set_chip_and_handler(virq
, &core_chip
, handle_level_irq
);
89 static struct irq_host_ops core_host_ops
= {
93 void __init
init_IRQ(void)
95 struct device_node
*np
;
97 /* Mask all priority IRQs */
98 and_creg(IER
, ~0xfff0);
100 np
= of_find_compatible_node(NULL
, NULL
, "ti,c64x+core-pic");
102 /* create the core host */
103 core_host
= irq_alloc_host(np
, IRQ_HOST_MAP_PRIORITY
, 0,
106 irq_set_default_host(core_host
);
110 printk(KERN_INFO
"Core interrupt controller initialized\n");
112 /* now we're ready for other SoC controllers */
115 /* Clear all general IRQ flags */
116 set_creg(ICR
, 0xfff0);
119 void ack_bad_irq(int irq
)
121 printk(KERN_ERR
"IRQ: spurious interrupt %d\n", irq
);
125 int arch_show_interrupts(struct seq_file
*p
, int prec
)
127 seq_printf(p
, "%*s: %10lu\n", prec
, "Err", irq_err_count
);
132 * IRQ controller and virtual interrupts
135 /* The main irq map itself is an array of NR_IRQ entries containing the
136 * associate host and irq number. An entry with a host of NULL is free.
137 * An entry can be allocated if it's free, the allocator always then sets
138 * hwirq first to the host's invalid irq number and then fills ops.
140 struct irq_map_entry
{
141 irq_hw_number_t hwirq
;
142 struct irq_host
*host
;
145 static LIST_HEAD(irq_hosts
);
146 static DEFINE_RAW_SPINLOCK(irq_big_lock
);
147 static DEFINE_MUTEX(revmap_trees_mutex
);
148 static struct irq_map_entry irq_map
[NR_IRQS
];
149 static unsigned int irq_virq_count
= NR_IRQS
;
150 static struct irq_host
*irq_default_host
;
152 irq_hw_number_t
irqd_to_hwirq(struct irq_data
*d
)
154 return irq_map
[d
->irq
].hwirq
;
156 EXPORT_SYMBOL_GPL(irqd_to_hwirq
);
158 irq_hw_number_t
virq_to_hw(unsigned int virq
)
160 return irq_map
[virq
].hwirq
;
162 EXPORT_SYMBOL_GPL(virq_to_hw
);
164 bool virq_is_host(unsigned int virq
, struct irq_host
*host
)
166 return irq_map
[virq
].host
== host
;
168 EXPORT_SYMBOL_GPL(virq_is_host
);
170 static int default_irq_host_match(struct irq_host
*h
, struct device_node
*np
)
172 return h
->of_node
!= NULL
&& h
->of_node
== np
;
175 struct irq_host
*irq_alloc_host(struct device_node
*of_node
,
176 unsigned int revmap_type
,
177 unsigned int revmap_arg
,
178 struct irq_host_ops
*ops
,
179 irq_hw_number_t inval_irq
)
181 struct irq_host
*host
;
182 unsigned int size
= sizeof(struct irq_host
);
187 /* Allocate structure and revmap table if using linear mapping */
188 if (revmap_type
== IRQ_HOST_MAP_LINEAR
)
189 size
+= revmap_arg
* sizeof(unsigned int);
190 host
= kzalloc(size
, GFP_KERNEL
);
195 host
->revmap_type
= revmap_type
;
196 host
->inval_irq
= inval_irq
;
198 host
->of_node
= of_node_get(of_node
);
200 if (host
->ops
->match
== NULL
)
201 host
->ops
->match
= default_irq_host_match
;
203 raw_spin_lock_irqsave(&irq_big_lock
, flags
);
205 /* Check for the priority controller. */
206 if (revmap_type
== IRQ_HOST_MAP_PRIORITY
) {
207 if (irq_map
[0].host
!= NULL
) {
208 raw_spin_unlock_irqrestore(&irq_big_lock
, flags
);
209 of_node_put(host
->of_node
);
213 irq_map
[0].host
= host
;
216 list_add(&host
->link
, &irq_hosts
);
217 raw_spin_unlock_irqrestore(&irq_big_lock
, flags
);
219 /* Additional setups per revmap type */
220 switch (revmap_type
) {
221 case IRQ_HOST_MAP_PRIORITY
:
222 /* 0 is always the invalid number for priority */
224 /* setup us as the host for all priority interrupts */
225 for (i
= 1; i
< NR_PRIORITY_IRQS
; i
++) {
226 irq_map
[i
].hwirq
= i
;
228 irq_map
[i
].host
= host
;
231 ops
->map(host
, i
, i
);
234 case IRQ_HOST_MAP_LINEAR
:
235 rmap
= (unsigned int *)(host
+ 1);
236 for (i
= 0; i
< revmap_arg
; i
++)
238 host
->revmap_data
.linear
.size
= revmap_arg
;
240 host
->revmap_data
.linear
.revmap
= rmap
;
242 case IRQ_HOST_MAP_TREE
:
243 INIT_RADIX_TREE(&host
->revmap_data
.tree
, GFP_KERNEL
);
249 pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type
, host
);
254 struct irq_host
*irq_find_host(struct device_node
*node
)
256 struct irq_host
*h
, *found
= NULL
;
259 /* We might want to match the legacy controller last since
260 * it might potentially be set to match all interrupts in
261 * the absence of a device node. This isn't a problem so far
264 raw_spin_lock_irqsave(&irq_big_lock
, flags
);
265 list_for_each_entry(h
, &irq_hosts
, link
)
266 if (h
->ops
->match(h
, node
)) {
270 raw_spin_unlock_irqrestore(&irq_big_lock
, flags
);
273 EXPORT_SYMBOL_GPL(irq_find_host
);
275 void irq_set_default_host(struct irq_host
*host
)
277 pr_debug("irq: Default host set to @0x%p\n", host
);
279 irq_default_host
= host
;
282 void irq_set_virq_count(unsigned int count
)
284 pr_debug("irq: Trying to set virq count to %d\n", count
);
286 BUG_ON(count
< NR_PRIORITY_IRQS
);
288 irq_virq_count
= count
;
291 static int irq_setup_virq(struct irq_host
*host
, unsigned int virq
,
292 irq_hw_number_t hwirq
)
296 res
= irq_alloc_desc_at(virq
, 0);
298 pr_debug("irq: -> allocating desc failed\n");
304 irq_map
[virq
].hwirq
= hwirq
;
307 if (host
->ops
->map(host
, virq
, hwirq
)) {
308 pr_debug("irq: -> mapping failed, freeing\n");
312 irq_clear_status_flags(virq
, IRQ_NOREQUEST
);
317 irq_free_descs(virq
, 1);
319 irq_free_virt(virq
, 1);
323 unsigned int irq_create_direct_mapping(struct irq_host
*host
)
328 host
= irq_default_host
;
330 BUG_ON(host
== NULL
);
331 WARN_ON(host
->revmap_type
!= IRQ_HOST_MAP_NOMAP
);
333 virq
= irq_alloc_virt(host
, 1, 0);
334 if (virq
== NO_IRQ
) {
335 pr_debug("irq: create_direct virq allocation failed\n");
339 pr_debug("irq: create_direct obtained virq %d\n", virq
);
341 if (irq_setup_virq(host
, virq
, virq
))
347 unsigned int irq_create_mapping(struct irq_host
*host
,
348 irq_hw_number_t hwirq
)
350 unsigned int virq
, hint
;
352 pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host
, hwirq
);
354 /* Look for default host if nececssary */
356 host
= irq_default_host
;
358 printk(KERN_WARNING
"irq_create_mapping called for"
359 " NULL host, hwirq=%lx\n", hwirq
);
363 pr_debug("irq: -> using host @%p\n", host
);
365 /* Check if mapping already exists */
366 virq
= irq_find_mapping(host
, hwirq
);
367 if (virq
!= NO_IRQ
) {
368 pr_debug("irq: -> existing mapping on virq %d\n", virq
);
372 /* Allocate a virtual interrupt number */
373 hint
= hwirq
% irq_virq_count
;
374 virq
= irq_alloc_virt(host
, 1, hint
);
375 if (virq
== NO_IRQ
) {
376 pr_debug("irq: -> virq allocation failed\n");
380 if (irq_setup_virq(host
, virq
, hwirq
))
383 pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
384 hwirq
, host
->of_node
? host
->of_node
->full_name
: "null", virq
);
388 EXPORT_SYMBOL_GPL(irq_create_mapping
);
390 unsigned int irq_create_of_mapping(struct device_node
*controller
,
391 const u32
*intspec
, unsigned int intsize
)
393 struct irq_host
*host
;
394 irq_hw_number_t hwirq
;
395 unsigned int type
= IRQ_TYPE_NONE
;
398 if (controller
== NULL
)
399 host
= irq_default_host
;
401 host
= irq_find_host(controller
);
403 printk(KERN_WARNING
"irq: no irq host found for %s !\n",
404 controller
->full_name
);
408 /* If host has no translation, then we assume interrupt line */
409 if (host
->ops
->xlate
== NULL
)
412 if (host
->ops
->xlate(host
, controller
, intspec
, intsize
,
418 virq
= irq_create_mapping(host
, hwirq
);
422 /* Set type if specified and different than the current one */
423 if (type
!= IRQ_TYPE_NONE
&&
424 type
!= (irqd_get_trigger_type(irq_get_irq_data(virq
))))
425 irq_set_irq_type(virq
, type
);
428 EXPORT_SYMBOL_GPL(irq_create_of_mapping
);
430 void irq_dispose_mapping(unsigned int virq
)
432 struct irq_host
*host
;
433 irq_hw_number_t hwirq
;
438 /* Never unmap priority interrupts */
439 if (virq
< NR_PRIORITY_IRQS
)
442 host
= irq_map
[virq
].host
;
443 if (WARN_ON(host
== NULL
))
446 irq_set_status_flags(virq
, IRQ_NOREQUEST
);
448 /* remove chip and handler */
449 irq_set_chip_and_handler(virq
, NULL
, NULL
);
451 /* Make sure it's completed */
452 synchronize_irq(virq
);
454 /* Tell the PIC about it */
455 if (host
->ops
->unmap
)
456 host
->ops
->unmap(host
, virq
);
459 /* Clear reverse map */
460 hwirq
= irq_map
[virq
].hwirq
;
461 switch (host
->revmap_type
) {
462 case IRQ_HOST_MAP_LINEAR
:
463 if (hwirq
< host
->revmap_data
.linear
.size
)
464 host
->revmap_data
.linear
.revmap
[hwirq
] = NO_IRQ
;
466 case IRQ_HOST_MAP_TREE
:
467 mutex_lock(&revmap_trees_mutex
);
468 radix_tree_delete(&host
->revmap_data
.tree
, hwirq
);
469 mutex_unlock(&revmap_trees_mutex
);
475 irq_map
[virq
].hwirq
= host
->inval_irq
;
477 irq_free_descs(virq
, 1);
479 irq_free_virt(virq
, 1);
481 EXPORT_SYMBOL_GPL(irq_dispose_mapping
);
483 unsigned int irq_find_mapping(struct irq_host
*host
,
484 irq_hw_number_t hwirq
)
487 unsigned int hint
= hwirq
% irq_virq_count
;
489 /* Look for default host if nececssary */
491 host
= irq_default_host
;
495 /* Slow path does a linear search of the map */
498 if (irq_map
[i
].host
== host
&&
499 irq_map
[i
].hwirq
== hwirq
)
502 if (i
>= irq_virq_count
)
507 EXPORT_SYMBOL_GPL(irq_find_mapping
);
509 unsigned int irq_radix_revmap_lookup(struct irq_host
*host
,
510 irq_hw_number_t hwirq
)
512 struct irq_map_entry
*ptr
;
515 if (WARN_ON_ONCE(host
->revmap_type
!= IRQ_HOST_MAP_TREE
))
516 return irq_find_mapping(host
, hwirq
);
519 * The ptr returned references the static global irq_map.
520 * but freeing an irq can delete nodes along the path to
521 * do the lookup via call_rcu.
524 ptr
= radix_tree_lookup(&host
->revmap_data
.tree
, hwirq
);
528 * If found in radix tree, then fine.
529 * Else fallback to linear lookup - this should not happen in practice
530 * as it means that we failed to insert the node in the radix tree.
533 virq
= ptr
- irq_map
;
535 virq
= irq_find_mapping(host
, hwirq
);
540 void irq_radix_revmap_insert(struct irq_host
*host
, unsigned int virq
,
541 irq_hw_number_t hwirq
)
543 if (WARN_ON(host
->revmap_type
!= IRQ_HOST_MAP_TREE
))
546 if (virq
!= NO_IRQ
) {
547 mutex_lock(&revmap_trees_mutex
);
548 radix_tree_insert(&host
->revmap_data
.tree
, hwirq
,
550 mutex_unlock(&revmap_trees_mutex
);
554 unsigned int irq_linear_revmap(struct irq_host
*host
,
555 irq_hw_number_t hwirq
)
557 unsigned int *revmap
;
559 if (WARN_ON_ONCE(host
->revmap_type
!= IRQ_HOST_MAP_LINEAR
))
560 return irq_find_mapping(host
, hwirq
);
562 /* Check revmap bounds */
563 if (unlikely(hwirq
>= host
->revmap_data
.linear
.size
))
564 return irq_find_mapping(host
, hwirq
);
566 /* Check if revmap was allocated */
567 revmap
= host
->revmap_data
.linear
.revmap
;
568 if (unlikely(revmap
== NULL
))
569 return irq_find_mapping(host
, hwirq
);
571 /* Fill up revmap with slow path if no mapping found */
572 if (unlikely(revmap
[hwirq
] == NO_IRQ
))
573 revmap
[hwirq
] = irq_find_mapping(host
, hwirq
);
575 return revmap
[hwirq
];
578 unsigned int irq_alloc_virt(struct irq_host
*host
,
583 unsigned int i
, j
, found
= NO_IRQ
;
585 if (count
== 0 || count
> (irq_virq_count
- NR_PRIORITY_IRQS
))
588 raw_spin_lock_irqsave(&irq_big_lock
, flags
);
590 /* Use hint for 1 interrupt if any */
591 if (count
== 1 && hint
>= NR_PRIORITY_IRQS
&&
592 hint
< irq_virq_count
&& irq_map
[hint
].host
== NULL
) {
597 /* Look for count consecutive numbers in the allocatable
600 for (i
= NR_PRIORITY_IRQS
, j
= 0; i
< irq_virq_count
; i
++) {
601 if (irq_map
[i
].host
!= NULL
)
607 found
= i
- count
+ 1;
611 if (found
== NO_IRQ
) {
612 raw_spin_unlock_irqrestore(&irq_big_lock
, flags
);
616 for (i
= found
; i
< (found
+ count
); i
++) {
617 irq_map
[i
].hwirq
= host
->inval_irq
;
619 irq_map
[i
].host
= host
;
621 raw_spin_unlock_irqrestore(&irq_big_lock
, flags
);
625 void irq_free_virt(unsigned int virq
, unsigned int count
)
630 WARN_ON(virq
< NR_PRIORITY_IRQS
);
631 WARN_ON(count
== 0 || (virq
+ count
) > irq_virq_count
);
633 if (virq
< NR_PRIORITY_IRQS
) {
634 if (virq
+ count
< NR_PRIORITY_IRQS
)
636 count
-= NR_PRIORITY_IRQS
- virq
;
637 virq
= NR_PRIORITY_IRQS
;
640 if (count
> irq_virq_count
|| virq
> irq_virq_count
- count
) {
641 if (virq
> irq_virq_count
)
643 count
= irq_virq_count
- virq
;
646 raw_spin_lock_irqsave(&irq_big_lock
, flags
);
647 for (i
= virq
; i
< (virq
+ count
); i
++) {
648 struct irq_host
*host
;
650 host
= irq_map
[i
].host
;
651 irq_map
[i
].hwirq
= host
->inval_irq
;
653 irq_map
[i
].host
= NULL
;
655 raw_spin_unlock_irqrestore(&irq_big_lock
, flags
);
658 #ifdef CONFIG_VIRQ_DEBUG
659 static int virq_debug_show(struct seq_file
*m
, void *private)
662 struct irq_desc
*desc
;
664 static const char none
[] = "none";
668 seq_printf(m
, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
669 "chip name", "chip data", "host name");
671 for (i
= 1; i
< nr_irqs
; i
++) {
672 desc
= irq_to_desc(i
);
676 raw_spin_lock_irqsave(&desc
->lock
, flags
);
678 if (desc
->action
&& desc
->action
->handler
) {
679 struct irq_chip
*chip
;
681 seq_printf(m
, "%5d ", i
);
682 seq_printf(m
, "0x%05lx ", irq_map
[i
].hwirq
);
684 chip
= irq_desc_get_chip(desc
);
685 if (chip
&& chip
->name
)
689 seq_printf(m
, "%-15s ", p
);
691 data
= irq_desc_get_chip_data(desc
);
692 seq_printf(m
, "0x%16p ", data
);
694 if (irq_map
[i
].host
&& irq_map
[i
].host
->of_node
)
695 p
= irq_map
[i
].host
->of_node
->full_name
;
698 seq_printf(m
, "%s\n", p
);
701 raw_spin_unlock_irqrestore(&desc
->lock
, flags
);
707 static int virq_debug_open(struct inode
*inode
, struct file
*file
)
709 return single_open(file
, virq_debug_show
, inode
->i_private
);
712 static const struct file_operations virq_debug_fops
= {
713 .open
= virq_debug_open
,
716 .release
= single_release
,
719 static int __init
irq_debugfs_init(void)
721 if (debugfs_create_file("virq_mapping", S_IRUGO
, powerpc_debugfs_root
,
722 NULL
, &virq_debug_fops
) == NULL
)
727 device_initcall(irq_debugfs_init
);
728 #endif /* CONFIG_VIRQ_DEBUG */