1 /* SPDX-License-Identifier: MIT */
2
3 /*
4 * xen/arch/riscv/imsic.c
5 *
6 * RISC-V Incoming MSI Controller support
7 *
8 * (c) Microchip Technology Inc.
9 * (c) Vates
10 */
11
12 #include <xen/bitops.h>
13 #include <xen/const.h>
14 #include <xen/cpumask.h>
15 #include <xen/device_tree.h>
16 #include <xen/errno.h>
17 #include <xen/init.h>
18 #include <xen/macros.h>
19 #include <xen/smp.h>
20 #include <xen/spinlock.h>
21 #include <xen/xvmalloc.h>
22
23 #include <asm/imsic.h>
24
25 #define IMSIC_HART_SIZE(guest_bits) (BIT(guest_bits, U) * IMSIC_MMIO_PAGE_SZ)
26
27 struct imsic_mmios {
28 paddr_t base_addr;
29 unsigned long size;
30 };
31
32 static struct imsic_config imsic_cfg = {
33 .lock = SPIN_LOCK_UNLOCKED,
34 };
35
36 #define IMSIC_DISABLE_EIDELIVERY 0
37 #define IMSIC_ENABLE_EIDELIVERY 1
38 #define IMSIC_DISABLE_EITHRESHOLD 1
39 #define IMSIC_ENABLE_EITHRESHOLD 0
40
41 #define imsic_csr_write(c, v) \
42 do { \
43 csr_write(CSR_SISELECT, c); \
44 csr_write(CSR_SIREG, v); \
45 } while (0)
46
47 #define imsic_csr_set(c, v) \
48 do { \
49 csr_write(CSR_SISELECT, c); \
50 csr_set(CSR_SIREG, v); \
51 } while (0)
52
53 #define imsic_csr_clear(c, v) \
54 do { \
55 csr_write(CSR_SISELECT, c); \
56 csr_clear(CSR_SIREG, v); \
57 } while (0)
58
imsic_ids_local_delivery(bool enable)59 void __init imsic_ids_local_delivery(bool enable)
60 {
61 if ( enable )
62 {
63 imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_ENABLE_EITHRESHOLD);
64 imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_ENABLE_EIDELIVERY);
65 }
66 else
67 {
68 imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_DISABLE_EITHRESHOLD);
69 imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_DISABLE_EIDELIVERY);
70 }
71 }
72
imsic_local_eix_update(unsigned long base_id,unsigned long num_id,bool pend,bool val)73 static void imsic_local_eix_update(unsigned long base_id, unsigned long num_id,
74 bool pend, bool val)
75 {
76 unsigned long id = base_id, last_id = base_id + num_id;
77
78 while ( id < last_id )
79 {
80 unsigned long isel, ireg;
81 unsigned long start_id = id & (__riscv_xlen - 1);
82 unsigned long chunk = __riscv_xlen - start_id;
83 unsigned long count = min(last_id - id, chunk);
84
85 isel = id / __riscv_xlen;
86 isel *= __riscv_xlen / IMSIC_EIPx_BITS;
87 isel += pend ? IMSIC_EIP0 : IMSIC_EIE0;
88
89 ireg = GENMASK(start_id + count - 1, start_id);
90
91 id += count;
92
93 if ( val )
94 imsic_csr_set(isel, ireg);
95 else
96 imsic_csr_clear(isel, ireg);
97 }
98 }
99
imsic_irq_enable(unsigned int irq)100 void imsic_irq_enable(unsigned int irq)
101 {
102 /*
103 * The only caller of imsic_irq_enable() is aplic_irq_enable(), which
104 * already runs with IRQs disabled. Therefore, there's no need to use
105 * spin_lock_irqsave() in this function.
106 *
107 * This ASSERT is added as a safeguard: if imsic_irq_enable() is ever
108 * called from a context where IRQs are not disabled,
109 * spin_lock_irqsave() should be used instead of spin_lock().
110 */
111 ASSERT(!local_irq_is_enabled());
112
113 spin_lock(&imsic_cfg.lock);
114 /*
115 * There is no irq - 1 here (look at aplic_set_irq_type()) because:
116 * From the spec:
117 * When an interrupt file supports distinct interrupt identities,
118 * valid identity numbers are between 1 and inclusive. The identity
119 * numbers within this range are said to be implemented by the interrupt
120 * file; numbers outside this range are not implemented. The number zero
121 * is never a valid interrupt identity.
122 * ...
123 * Bit positions in a valid eiek register that don’t correspond to a
124 * supported interrupt identity (such as bit 0 of eie0) are read-only zeros.
125 *
126 * So in EIx registers interrupt i corresponds to bit i in comparison wiht
127 * APLIC's sourcecfg which starts from 0.
128 */
129 imsic_local_eix_update(irq, 1, false, true);
130 spin_unlock(&imsic_cfg.lock);
131 }
132
imsic_irq_disable(unsigned int irq)133 void imsic_irq_disable(unsigned int irq)
134 {
135 /*
136 * The only caller of imsic_irq_disable() is aplic_irq_disable(), which
137 * already runs with IRQs disabled. Therefore, there's no need to use
138 * spin_lock_irqsave() in this function.
139 *
140 * This ASSERT is added as a safeguard: if imsic_irq_disable() is ever
141 * called from a context where IRQs are not disabled,
142 * spin_lock_irqsave() should be used instead of spin_lock().
143 */
144 ASSERT(!local_irq_is_enabled());
145
146 spin_lock(&imsic_cfg.lock);
147 imsic_local_eix_update(irq, 1, false, false);
148 spin_unlock(&imsic_cfg.lock);
149 }
150
151 /* Callers aren't intended to changed imsic_cfg so return const. */
imsic_get_config(void)152 const struct imsic_config *imsic_get_config(void)
153 {
154 return &imsic_cfg;
155 }
156
imsic_get_parent_hartid(const struct dt_device_node * node,unsigned int index,unsigned long * hartid)157 static int __init imsic_get_parent_hartid(const struct dt_device_node *node,
158 unsigned int index,
159 unsigned long *hartid)
160 {
161 int res;
162 struct dt_phandle_args args;
163
164 res = dt_parse_phandle_with_args(node, "interrupts-extended",
165 "#interrupt-cells", index, &args);
166 if ( !res )
167 res = dt_processor_hartid(args.np->parent, hartid);
168
169 return res;
170 }
171
172 /*
173 * Parses IMSIC DT node.
174 *
175 * Returns 0 if initialization is successful, a negative value on failure,
176 * or IRQ_M_EXT if the IMSIC node corresponds to a machine-mode IMSIC,
177 * which should be ignored by the hypervisor.
178 */
imsic_parse_node(const struct dt_device_node * node,unsigned int * nr_parent_irqs,unsigned int * nr_mmios)179 static int imsic_parse_node(const struct dt_device_node *node,
180 unsigned int *nr_parent_irqs,
181 unsigned int *nr_mmios)
182 {
183 int rc;
184 unsigned int tmp;
185 paddr_t base_addr;
186 uint32_t *irq_range;
187
188 *nr_parent_irqs = dt_number_of_irq(node);
189 if ( !*nr_parent_irqs )
190 panic("%s: irq_num can't be 0. Check %s node\n", __func__,
191 dt_node_full_name(node));
192
193 irq_range = xvzalloc_array(uint32_t, *nr_parent_irqs * 2);
194 if ( !irq_range )
195 panic("%s: irq_range[] allocation failed\n", __func__);
196
197 if ( (rc = dt_property_read_u32_array(node, "interrupts-extended",
198 irq_range, *nr_parent_irqs * 2)) )
199 panic("%s: unable to find interrupt-extended in %s node: %d\n",
200 __func__, dt_node_full_name(node), rc);
201
202 /* Check that interrupts-extended property is well-formed. */
203 for ( unsigned int i = 2; i < (*nr_parent_irqs * 2); i += 2 )
204 {
205 if ( irq_range[i + 1] != irq_range[1] )
206 panic("%s: mode[%u] != %u\n", __func__, i + 1, irq_range[1]);
207 }
208
209 if ( irq_range[1] == IRQ_M_EXT )
210 {
211 /* Machine mode imsic node, ignore it. */
212 xvfree(irq_range);
213
214 return IRQ_M_EXT;
215 }
216
217 xvfree(irq_range);
218
219 if ( !dt_property_read_u32(node, "riscv,guest-index-bits",
220 &imsic_cfg.guest_index_bits) )
221 imsic_cfg.guest_index_bits = 0;
222 tmp = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT;
223 if ( tmp < imsic_cfg.guest_index_bits )
224 {
225 printk(XENLOG_ERR "%s: guest index bits too big\n",
226 dt_node_name(node));
227 return -ENOENT;
228 }
229
230 /* Find number of HART index bits */
231 if ( !dt_property_read_u32(node, "riscv,hart-index-bits",
232 &imsic_cfg.hart_index_bits) )
233 /* Assume default value */
234 imsic_cfg.hart_index_bits = fls(*nr_parent_irqs - 1);
235 tmp -= imsic_cfg.guest_index_bits;
236 if ( tmp < imsic_cfg.hart_index_bits )
237 {
238 printk(XENLOG_ERR "%s: HART index bits too big\n",
239 dt_node_name(node));
240 return -ENOENT;
241 }
242
243 /* Find number of group index bits */
244 if ( !dt_property_read_u32(node, "riscv,group-index-bits",
245 &imsic_cfg.group_index_bits) )
246 imsic_cfg.group_index_bits = 0;
247 tmp -= imsic_cfg.hart_index_bits;
248 if ( tmp < imsic_cfg.group_index_bits )
249 {
250 printk(XENLOG_ERR "%s: group index bits too big\n",
251 dt_node_name(node));
252 return -ENOENT;
253 }
254
255 /* Find first bit position of group index */
256 tmp = IMSIC_MMIO_PAGE_SHIFT * 2;
257 if ( !dt_property_read_u32(node, "riscv,group-index-shift",
258 &imsic_cfg.group_index_shift) )
259 imsic_cfg.group_index_shift = tmp;
260 if ( imsic_cfg.group_index_shift < tmp )
261 {
262 printk(XENLOG_ERR "%s: group index shift too small\n",
263 dt_node_name(node));
264 return -ENOENT;
265 }
266 tmp = imsic_cfg.group_index_bits + imsic_cfg.group_index_shift - 1;
267 if ( tmp >= BITS_PER_LONG )
268 {
269 printk(XENLOG_ERR "%s: group index shift too big\n",
270 dt_node_name(node));
271 return -ENOENT;
272 }
273
274 /* Find number of interrupt identities */
275 if ( !dt_property_read_u32(node, "riscv,num-ids", &imsic_cfg.nr_ids) )
276 {
277 printk(XENLOG_ERR "%s: number of interrupt identities not found\n",
278 node->name);
279 return -ENOENT;
280 }
281
282 if ( (imsic_cfg.nr_ids < IMSIC_MIN_ID) ||
283 (imsic_cfg.nr_ids > IMSIC_MAX_ID) )
284 {
285 printk(XENLOG_ERR "%s: invalid number of interrupt identities\n",
286 node->name);
287 return -ENOENT;
288 }
289
290 /* Compute base address */
291 *nr_mmios = 0;
292 rc = dt_device_get_address(node, *nr_mmios, &base_addr, NULL);
293 if ( rc )
294 {
295 printk(XENLOG_ERR "%s: first MMIO resource not found: %d\n",
296 dt_node_name(node), rc);
297 return rc;
298 }
299
300 imsic_cfg.base_addr = base_addr;
301 imsic_cfg.base_addr &= ~(BIT(imsic_cfg.guest_index_bits +
302 imsic_cfg.hart_index_bits +
303 IMSIC_MMIO_PAGE_SHIFT, UL) - 1);
304 imsic_cfg.base_addr &= ~((BIT(imsic_cfg.group_index_bits, UL) - 1) <<
305 imsic_cfg.group_index_shift);
306
307 /* Find number of MMIO register sets */
308 do {
309 ++*nr_mmios;
310 } while ( !dt_device_get_address(node, *nr_mmios, &base_addr, NULL) );
311
312 return 0;
313 }
314
315 /*
316 * Initialize the imsic_cfg structure based on the IMSIC DT node.
317 *
318 * Returns 0 if initialization is successful, a negative value on failure,
319 * or IRQ_M_EXT if the IMSIC node corresponds to a machine-mode IMSIC,
320 * which should be ignored by the hypervisor.
321 */
imsic_init(const struct dt_device_node * node)322 int __init imsic_init(const struct dt_device_node *node)
323 {
324 int rc;
325 unsigned long reloff, hartid;
326 unsigned int nr_parent_irqs, index, nr_handlers = 0;
327 paddr_t base_addr;
328 unsigned int nr_mmios;
329 struct imsic_mmios *mmios;
330 struct imsic_msi *msi = NULL;
331
332 /* Parse IMSIC node */
333 rc = imsic_parse_node(node, &nr_parent_irqs, &nr_mmios);
334 /*
335 * If machine mode imsic node => ignore it.
336 * If rc < 0 => parsing of IMSIC DT node failed.
337 */
338 if ( (rc == IRQ_M_EXT) || (rc < 0) )
339 return rc;
340
341 /* Allocate MMIO resource array */
342 mmios = xvzalloc_array(struct imsic_mmios, nr_mmios);
343 if ( !mmios )
344 {
345 rc = -ENOMEM;
346 goto imsic_init_err;
347 }
348
349 msi = xvzalloc_array(struct imsic_msi, nr_parent_irqs);
350 if ( !msi )
351 {
352 rc = -ENOMEM;
353 goto imsic_init_err;
354 }
355
356 /* Check MMIO register sets */
357 for ( unsigned int i = 0; i < nr_mmios; i++ )
358 {
359 unsigned int guest_bits = imsic_cfg.guest_index_bits;
360 unsigned long expected_mmio_size =
361 IMSIC_HART_SIZE(guest_bits) * nr_parent_irqs;
362
363 rc = dt_device_get_address(node, i, &mmios[i].base_addr,
364 &mmios[i].size);
365 if ( rc )
366 {
367 printk(XENLOG_ERR "%s: unable to parse MMIO regset %u\n",
368 node->name, i);
369 goto imsic_init_err;
370 }
371
372 base_addr = mmios[i].base_addr;
373 base_addr &= ~(BIT(guest_bits +
374 imsic_cfg.hart_index_bits +
375 IMSIC_MMIO_PAGE_SHIFT, UL) - 1);
376 base_addr &= ~((BIT(imsic_cfg.group_index_bits, UL) - 1) <<
377 imsic_cfg.group_index_shift);
378 if ( base_addr != imsic_cfg.base_addr )
379 {
380 rc = -EINVAL;
381 printk(XENLOG_ERR "%s: address mismatch for regset %u\n",
382 node->name, i);
383 goto imsic_init_err;
384 }
385
386 if ( mmios[i].size != expected_mmio_size )
387 {
388 rc = -EINVAL;
389 printk(XENLOG_ERR "%s: IMSIC MMIO size is incorrect %ld, expected MMIO size: %ld\n",
390 node->name, mmios[i].size, expected_mmio_size);
391 goto imsic_init_err;
392 }
393 }
394
395 /* Configure handlers for target CPUs */
396 for ( unsigned int i = 0; i < nr_parent_irqs; i++ )
397 {
398 unsigned int cpu;
399
400 rc = imsic_get_parent_hartid(node, i, &hartid);
401 if ( rc )
402 {
403 printk(XENLOG_WARNING "%s: cpu ID for parent irq%u not found\n",
404 node->name, i);
405 continue;
406 }
407
408 cpu = hartid_to_cpuid(hartid);
409
410 /*
411 * If .base_addr is not 0, it indicates that the CPU has already been
412 * found.
413 * In this case, skip re-initialization to avoid duplicate setup.
414 * Also, print a warning message to signal that the DTS should be
415 * reviewed for possible duplication.
416 */
417 if ( msi[cpu].base_addr )
418 {
419 printk("%s: cpu%u is found twice in interrupts-extended prop\n",
420 node->name, cpu);
421 continue;
422 }
423
424 if ( cpu >= num_possible_cpus() )
425 {
426 printk(XENLOG_WARNING "%s: unsupported hart ID=%#lx for parent irq%u\n",
427 node->name, hartid, i);
428 continue;
429 }
430
431 /* Find MMIO location of MSI page */
432 reloff = i * IMSIC_HART_SIZE(imsic_cfg.guest_index_bits);
433 for ( index = 0; index < nr_mmios; index++ )
434 {
435 if ( reloff < mmios[index].size )
436 break;
437
438 /*
439 * MMIO region size may not be aligned to
440 * IMSIC_HART_SIZE(guest_index_bits) if
441 * holes are present.
442 */
443 reloff -= ROUNDUP(mmios[index].size,
444 IMSIC_HART_SIZE(imsic_cfg.guest_index_bits));
445 }
446
447 if ( index == nr_mmios )
448 {
449 printk(XENLOG_WARNING "%s: MMIO not found for parent irq%u\n",
450 node->name, i);
451 continue;
452 }
453
454 if ( !IS_ALIGNED(mmios[cpu].base_addr + reloff,
455 IMSIC_MMIO_PAGE_SZ) )
456 {
457 printk(XENLOG_WARNING "%s: MMIO address %#lx is not aligned on a page\n",
458 node->name, msi[cpu].base_addr + reloff);
459 continue;
460 }
461
462 msi[cpu].base_addr = mmios[index].base_addr;
463 msi[cpu].offset = reloff;
464
465 nr_handlers++;
466 }
467
468 if ( !nr_handlers )
469 {
470 printk(XENLOG_ERR "%s: No CPU handlers found\n", node->name);
471 rc = -ENODEV;
472 goto imsic_init_err;
473 }
474
475 /* Enable local interrupt delivery */
476 imsic_ids_local_delivery(true);
477
478 imsic_cfg.msi = msi;
479
480 xvfree(mmios);
481
482 return 0;
483
484 imsic_init_err:
485 xvfree(mmios);
486 xvfree(msi);
487
488 return rc;
489 }
490