18
18
#include <linux/interrupt.h>
19
19
#include <linux/irq.h>
20
20
#include <linux/kernel_stat.h>
21
+ #include <linux/irqdomain.h>
21
22
22
23
#include <asm/uaccess.h>
23
24
#include <asm/platform.h>
@@ -26,19 +27,22 @@ static unsigned int cached_irq_mask;
26
27
27
28
atomic_t irq_err_count ;
28
29
30
+ static struct irq_domain * root_domain ;
31
+
29
32
/*
30
33
* do_IRQ handles all normal device IRQ's (the special
31
34
* SMP cross-CPU interrupts have their own specific
32
35
* handlers).
33
36
*/
34
37
35
- asmlinkage void do_IRQ (int irq , struct pt_regs * regs )
38
+ asmlinkage void do_IRQ (int hwirq , struct pt_regs * regs )
36
39
{
37
40
struct pt_regs * old_regs = set_irq_regs (regs );
41
+ int irq = irq_find_mapping (root_domain , hwirq );
38
42
39
- if (irq >= NR_IRQS ) {
43
+ if (hwirq >= NR_IRQS ) {
40
44
printk (KERN_EMERG "%s: cannot handle IRQ %d\n" ,
41
- __func__ , irq );
45
+ __func__ , hwirq );
42
46
}
43
47
44
48
irq_enter ();
@@ -71,40 +75,39 @@ int arch_show_interrupts(struct seq_file *p, int prec)
71
75
72
76
static void xtensa_irq_mask (struct irq_data * d )
73
77
{
74
- cached_irq_mask &= ~(1 << d -> irq );
78
+ cached_irq_mask &= ~(1 << d -> hwirq );
75
79
set_sr (cached_irq_mask , intenable );
76
80
}
77
81
78
82
static void xtensa_irq_unmask (struct irq_data * d )
79
83
{
80
- cached_irq_mask |= 1 << d -> irq ;
84
+ cached_irq_mask |= 1 << d -> hwirq ;
81
85
set_sr (cached_irq_mask , intenable );
82
86
}
83
87
84
88
static void xtensa_irq_enable (struct irq_data * d )
85
89
{
86
- variant_irq_enable (d -> irq );
90
+ variant_irq_enable (d -> hwirq );
87
91
xtensa_irq_unmask (d );
88
92
}
89
93
90
94
static void xtensa_irq_disable (struct irq_data * d )
91
95
{
92
96
xtensa_irq_mask (d );
93
- variant_irq_disable (d -> irq );
97
+ variant_irq_disable (d -> hwirq );
94
98
}
95
99
96
100
static void xtensa_irq_ack (struct irq_data * d )
97
101
{
98
- set_sr (1 << d -> irq , intclear );
102
+ set_sr (1 << d -> hwirq , intclear );
99
103
}
100
104
101
105
static int xtensa_irq_retrigger (struct irq_data * d )
102
106
{
103
- set_sr (1 << d -> irq , INTSET );
107
+ set_sr (1 << d -> hwirq , intset );
104
108
return 1 ;
105
109
}
106
110
107
-
108
111
static struct irq_chip xtensa_irq_chip = {
109
112
.name = "xtensa" ,
110
113
.irq_enable = xtensa_irq_enable ,
@@ -115,37 +118,90 @@ static struct irq_chip xtensa_irq_chip = {
115
118
.irq_retrigger = xtensa_irq_retrigger ,
116
119
};
117
120
118
- void __init init_IRQ (void )
121
+ static int xtensa_irq_map (struct irq_domain * d , unsigned int irq ,
122
+ irq_hw_number_t hw )
119
123
{
120
- int index ;
121
-
122
- for (index = 0 ; index < XTENSA_NR_IRQS ; index ++ ) {
123
- int mask = 1 << index ;
124
-
125
- if (mask & XCHAL_INTTYPE_MASK_SOFTWARE )
126
- irq_set_chip_and_handler (index , & xtensa_irq_chip ,
127
- handle_simple_irq );
124
+ u32 mask = 1 << hw ;
125
+
126
+ if (mask & XCHAL_INTTYPE_MASK_SOFTWARE ) {
127
+ irq_set_chip_and_handler_name (irq , & xtensa_irq_chip ,
128
+ handle_simple_irq , "level" );
129
+ irq_set_status_flags (irq , IRQ_LEVEL );
130
+ } else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE ) {
131
+ irq_set_chip_and_handler_name (irq , & xtensa_irq_chip ,
132
+ handle_edge_irq , "edge" );
133
+ irq_clear_status_flags (irq , IRQ_LEVEL );
134
+ } else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL ) {
135
+ irq_set_chip_and_handler_name (irq , & xtensa_irq_chip ,
136
+ handle_level_irq , "level" );
137
+ irq_set_status_flags (irq , IRQ_LEVEL );
138
+ } else if (mask & XCHAL_INTTYPE_MASK_TIMER ) {
139
+ irq_set_chip_and_handler_name (irq , & xtensa_irq_chip ,
140
+ handle_edge_irq , "edge" );
141
+ irq_clear_status_flags (irq , IRQ_LEVEL );
142
+ } else {/* XCHAL_INTTYPE_MASK_WRITE_ERROR */
143
+ /* XCHAL_INTTYPE_MASK_NMI */
144
+
145
+ irq_set_chip_and_handler_name (irq , & xtensa_irq_chip ,
146
+ handle_level_irq , "level" );
147
+ irq_set_status_flags (irq , IRQ_LEVEL );
148
+ }
149
+ return 0 ;
150
+ }
128
151
129
- else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE )
130
- irq_set_chip_and_handler (index , & xtensa_irq_chip ,
131
- handle_edge_irq );
152
+ static unsigned map_ext_irq (unsigned ext_irq )
153
+ {
154
+ unsigned mask = XCHAL_INTTYPE_MASK_EXTERN_EDGE |
155
+ XCHAL_INTTYPE_MASK_EXTERN_LEVEL ;
156
+ unsigned i ;
132
157
133
- else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL )
134
- irq_set_chip_and_handler (index , & xtensa_irq_chip ,
135
- handle_level_irq );
158
+ for (i = 0 ; mask ; ++ i , mask >>= 1 ) {
159
+ if ((mask & 1 ) && ext_irq -- == 0 )
160
+ return i ;
161
+ }
162
+ return XCHAL_NUM_INTERRUPTS ;
163
+ }
136
164
137
- else if (mask & XCHAL_INTTYPE_MASK_TIMER )
138
- irq_set_chip_and_handler (index , & xtensa_irq_chip ,
139
- handle_edge_irq );
165
+ /*
166
+ * Device Tree IRQ specifier translation function which works with one or
167
+ * two cell bindings. First cell value maps directly to the hwirq number.
168
+ * Second cell if present specifies whether hwirq number is external (1) or
169
+ * internal (0).
170
+ */
171
+ int xtensa_irq_domain_xlate (struct irq_domain * d , struct device_node * ctrlr ,
172
+ const u32 * intspec , unsigned int intsize ,
173
+ unsigned long * out_hwirq , unsigned int * out_type )
174
+ {
175
+ if (WARN_ON (intsize < 1 || intsize > 2 ))
176
+ return - EINVAL ;
177
+ if (intsize == 2 && intspec [1 ] == 1 ) {
178
+ unsigned int_irq = map_ext_irq (intspec [0 ]);
179
+ if (int_irq < XCHAL_NUM_INTERRUPTS )
180
+ * out_hwirq = int_irq ;
181
+ else
182
+ return - EINVAL ;
183
+ } else {
184
+ * out_hwirq = intspec [0 ];
185
+ }
186
+ * out_type = IRQ_TYPE_NONE ;
187
+ return 0 ;
188
+ }
140
189
141
- else /* XCHAL_INTTYPE_MASK_WRITE_ERROR */
142
- /* XCHAL_INTTYPE_MASK_NMI */
190
+ static const struct irq_domain_ops xtensa_irq_domain_ops = {
191
+ .xlate = xtensa_irq_domain_xlate ,
192
+ .map = xtensa_irq_map ,
193
+ };
143
194
144
- irq_set_chip_and_handler ( index , & xtensa_irq_chip ,
145
- handle_level_irq );
146
- }
195
+ void __init init_IRQ ( void )
196
+ {
197
+ struct device_node * intc = NULL ;
147
198
148
199
cached_irq_mask = 0 ;
200
+ set_sr (~0 , intclear );
201
+
202
+ root_domain = irq_domain_add_legacy (intc , NR_IRQS , 0 , 0 ,
203
+ & xtensa_irq_domain_ops , NULL );
204
+ irq_set_default_host (root_domain );
149
205
150
206
variant_init_irq ();
151
207
}
0 commit comments