17
17
#include <linux/module.h>
18
18
#include <linux/of.h>
19
19
#include <linux/smp.h>
20
+ #include <linux/soc/andes/irq.h>
20
21
21
22
static struct irq_domain * intc_domain ;
23
+ static unsigned int riscv_intc_nr_irqs __ro_after_init = BITS_PER_LONG ;
24
+ static unsigned int riscv_intc_custom_base __ro_after_init = BITS_PER_LONG ;
25
+ static unsigned int riscv_intc_custom_nr_irqs __ro_after_init ;
22
26
23
27
static asmlinkage void riscv_intc_irq (struct pt_regs * regs )
24
28
{
25
29
unsigned long cause = regs -> cause & ~CAUSE_IRQ_FLAG ;
26
30
27
- if (unlikely (cause >= BITS_PER_LONG ))
28
- panic ("unexpected interrupt cause" );
29
-
30
- generic_handle_domain_irq (intc_domain , cause );
31
+ if (generic_handle_domain_irq (intc_domain , cause ))
32
+ pr_warn_ratelimited ("Failed to handle interrupt (cause: %ld)\n" , cause );
31
33
}
32
34
33
35
/*
@@ -47,6 +49,31 @@ static void riscv_intc_irq_unmask(struct irq_data *d)
47
49
csr_set (CSR_IE , BIT (d -> hwirq ));
48
50
}
49
51
52
+ static void andes_intc_irq_mask (struct irq_data * d )
53
+ {
54
+ /*
55
+ * Andes specific S-mode local interrupt causes (hwirq)
56
+ * are defined as (256 + n) and controlled by n-th bit
57
+ * of SLIE.
58
+ */
59
+ unsigned int mask = BIT (d -> hwirq % BITS_PER_LONG );
60
+
61
+ if (d -> hwirq < ANDES_SLI_CAUSE_BASE )
62
+ csr_clear (CSR_IE , mask );
63
+ else
64
+ csr_clear (ANDES_CSR_SLIE , mask );
65
+ }
66
+
67
+ static void andes_intc_irq_unmask (struct irq_data * d )
68
+ {
69
+ unsigned int mask = BIT (d -> hwirq % BITS_PER_LONG );
70
+
71
+ if (d -> hwirq < ANDES_SLI_CAUSE_BASE )
72
+ csr_set (CSR_IE , mask );
73
+ else
74
+ csr_set (ANDES_CSR_SLIE , mask );
75
+ }
76
+
50
77
static void riscv_intc_irq_eoi (struct irq_data * d )
51
78
{
52
79
/*
@@ -70,12 +97,21 @@ static struct irq_chip riscv_intc_chip = {
70
97
.irq_eoi = riscv_intc_irq_eoi ,
71
98
};
72
99
100
+ static struct irq_chip andes_intc_chip = {
101
+ .name = "RISC-V INTC" ,
102
+ .irq_mask = andes_intc_irq_mask ,
103
+ .irq_unmask = andes_intc_irq_unmask ,
104
+ .irq_eoi = riscv_intc_irq_eoi ,
105
+ };
106
+
73
107
static int riscv_intc_domain_map (struct irq_domain * d , unsigned int irq ,
74
108
irq_hw_number_t hwirq )
75
109
{
110
+ struct irq_chip * chip = d -> host_data ;
111
+
76
112
irq_set_percpu_devid (irq );
77
- irq_domain_set_info (d , irq , hwirq , & riscv_intc_chip , d -> host_data ,
78
- handle_percpu_devid_irq , NULL , NULL );
113
+ irq_domain_set_info (d , irq , hwirq , chip , NULL , handle_percpu_devid_irq ,
114
+ NULL , NULL );
79
115
80
116
return 0 ;
81
117
}
@@ -93,6 +129,14 @@ static int riscv_intc_domain_alloc(struct irq_domain *domain,
93
129
if (ret )
94
130
return ret ;
95
131
132
+ /*
133
+ * Only allow hwirq for which we have corresponding standard or
134
+ * custom interrupt enable register.
135
+ */
136
+ if ((hwirq >= riscv_intc_nr_irqs && hwirq < riscv_intc_custom_base ) ||
137
+ (hwirq >= riscv_intc_custom_base + riscv_intc_custom_nr_irqs ))
138
+ return - EINVAL ;
139
+
96
140
for (i = 0 ; i < nr_irqs ; i ++ ) {
97
141
ret = riscv_intc_domain_map (domain , virq + i , hwirq + i );
98
142
if (ret )
@@ -113,12 +157,12 @@ static struct fwnode_handle *riscv_intc_hwnode(void)
113
157
return intc_domain -> fwnode ;
114
158
}
115
159
116
- static int __init riscv_intc_init_common (struct fwnode_handle * fn )
160
+ static int __init riscv_intc_init_common (struct fwnode_handle * fn ,
161
+ struct irq_chip * chip )
117
162
{
118
163
int rc ;
119
164
120
- intc_domain = irq_domain_create_linear (fn , BITS_PER_LONG ,
121
- & riscv_intc_domain_ops , NULL );
165
+ intc_domain = irq_domain_create_tree (fn , & riscv_intc_domain_ops , chip );
122
166
if (!intc_domain ) {
123
167
pr_err ("unable to add IRQ domain\n" );
124
168
return - ENXIO ;
@@ -132,16 +176,21 @@ static int __init riscv_intc_init_common(struct fwnode_handle *fn)
132
176
133
177
riscv_set_intc_hwnode_fn (riscv_intc_hwnode );
134
178
135
- pr_info ("%d local interrupts mapped\n" , BITS_PER_LONG );
179
+ pr_info ("%d local interrupts mapped\n" , riscv_intc_nr_irqs );
180
+ if (riscv_intc_custom_nr_irqs ) {
181
+ pr_info ("%d custom local interrupts mapped\n" ,
182
+ riscv_intc_custom_nr_irqs );
183
+ }
136
184
137
185
return 0 ;
138
186
}
139
187
140
188
static int __init riscv_intc_init (struct device_node * node ,
141
189
struct device_node * parent )
142
190
{
143
- int rc ;
191
+ struct irq_chip * chip = & riscv_intc_chip ;
144
192
unsigned long hartid ;
193
+ int rc ;
145
194
146
195
rc = riscv_of_parent_hartid (node , & hartid );
147
196
if (rc < 0 ) {
@@ -166,10 +215,17 @@ static int __init riscv_intc_init(struct device_node *node,
166
215
return 0 ;
167
216
}
168
217
169
- return riscv_intc_init_common (of_node_to_fwnode (node ));
218
+ if (of_device_is_compatible (node , "andestech,cpu-intc" )) {
219
+ riscv_intc_custom_base = ANDES_SLI_CAUSE_BASE ;
220
+ riscv_intc_custom_nr_irqs = ANDES_RV_IRQ_LAST ;
221
+ chip = & andes_intc_chip ;
222
+ }
223
+
224
+ return riscv_intc_init_common (of_node_to_fwnode (node ), chip );
170
225
}
171
226
172
227
IRQCHIP_DECLARE (riscv , "riscv,cpu-intc" , riscv_intc_init );
228
+ IRQCHIP_DECLARE (andes , "andestech,cpu-intc" , riscv_intc_init );
173
229
174
230
#ifdef CONFIG_ACPI
175
231
@@ -196,7 +252,7 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
196
252
return - ENOMEM ;
197
253
}
198
254
199
- return riscv_intc_init_common (fn );
255
+ return riscv_intc_init_common (fn , & riscv_intc_chip );
200
256
}
201
257
202
258
IRQCHIP_ACPI_DECLARE (riscv_intc , ACPI_MADT_TYPE_RINTC , NULL ,
0 commit comments