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