2 * RISC-V IMSIC (Incoming Message Signaled Interrupt Controller)
4 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
22 #include "qemu/module.h"
23 #include "qemu/error-report.h"
24 #include "qemu/bswap.h"
25 #include "exec/address-spaces.h"
26 #include "hw/sysbus.h"
27 #include "hw/pci/msi.h"
28 #include "hw/boards.h"
29 #include "hw/qdev-properties.h"
30 #include "hw/intc/riscv_imsic.h"
32 #include "target/riscv/cpu.h"
33 #include "target/riscv/cpu_bits.h"
34 #include "sysemu/sysemu.h"
35 #include "migration/vmstate.h"
37 #define IMSIC_MMIO_PAGE_LE 0x00
38 #define IMSIC_MMIO_PAGE_BE 0x04
40 #define IMSIC_MIN_ID ((IMSIC_EIPx_BITS * 2) - 1)
41 #define IMSIC_MAX_ID (IMSIC_TOPEI_IID_MASK)
43 #define IMSIC_EISTATE_PENDING (1U << 0)
44 #define IMSIC_EISTATE_ENABLED (1U << 1)
45 #define IMSIC_EISTATE_ENPEND (IMSIC_EISTATE_ENABLED | \
46 IMSIC_EISTATE_PENDING)
48 static uint32_t riscv_imsic_topei(RISCVIMSICState
*imsic
, uint32_t page
)
50 uint32_t i
, max_irq
, base
;
52 base
= page
* imsic
->num_irqs
;
53 max_irq
= (imsic
->eithreshold
[page
] &&
54 (imsic
->eithreshold
[page
] <= imsic
->num_irqs
)) ?
55 imsic
->eithreshold
[page
] : imsic
->num_irqs
;
56 for (i
= 1; i
< max_irq
; i
++) {
57 if ((imsic
->eistate
[base
+ i
] & IMSIC_EISTATE_ENPEND
) ==
58 IMSIC_EISTATE_ENPEND
) {
59 return (i
<< IMSIC_TOPEI_IID_SHIFT
) | i
;
66 static void riscv_imsic_update(RISCVIMSICState
*imsic
, uint32_t page
)
68 if (imsic
->eidelivery
[page
] && riscv_imsic_topei(imsic
, page
)) {
69 qemu_irq_raise(imsic
->external_irqs
[page
]);
71 qemu_irq_lower(imsic
->external_irqs
[page
]);
75 static int riscv_imsic_eidelivery_rmw(RISCVIMSICState
*imsic
, uint32_t page
,
80 target_ulong old_val
= imsic
->eidelivery
[page
];
87 imsic
->eidelivery
[page
] = (old_val
& ~wr_mask
) | (new_val
& wr_mask
);
89 riscv_imsic_update(imsic
, page
);
93 static int riscv_imsic_eithreshold_rmw(RISCVIMSICState
*imsic
, uint32_t page
,
98 target_ulong old_val
= imsic
->eithreshold
[page
];
104 wr_mask
&= IMSIC_MAX_ID
;
105 imsic
->eithreshold
[page
] = (old_val
& ~wr_mask
) | (new_val
& wr_mask
);
107 riscv_imsic_update(imsic
, page
);
111 static int riscv_imsic_topei_rmw(RISCVIMSICState
*imsic
, uint32_t page
,
112 target_ulong
*val
, target_ulong new_val
,
113 target_ulong wr_mask
)
115 uint32_t base
, topei
= riscv_imsic_topei(imsic
, page
);
117 /* Read pending and enabled interrupt with highest priority */
122 /* Writes ignore value and clear top pending interrupt */
123 if (topei
&& wr_mask
) {
124 topei
>>= IMSIC_TOPEI_IID_SHIFT
;
125 base
= page
* imsic
->num_irqs
;
127 imsic
->eistate
[base
+ topei
] &= ~IMSIC_EISTATE_PENDING
;
130 riscv_imsic_update(imsic
, page
);
136 static int riscv_imsic_eix_rmw(RISCVIMSICState
*imsic
,
137 uint32_t xlen
, uint32_t page
,
138 uint32_t num
, bool pend
, target_ulong
*val
,
139 target_ulong new_val
, target_ulong wr_mask
)
143 uint32_t state
= (pend
) ? IMSIC_EISTATE_PENDING
: IMSIC_EISTATE_ENABLED
;
151 if (num
>= (imsic
->num_irqs
/ xlen
)) {
155 base
= (page
* imsic
->num_irqs
) + (num
* xlen
);
159 for (i
= 0; i
< xlen
; i
++) {
160 mask
= (target_ulong
)1 << i
;
161 *val
|= (imsic
->eistate
[base
+ i
] & state
) ? mask
: 0;
165 for (i
= 0; i
< xlen
; i
++) {
166 /* Bit0 of eip0 and eie0 are read-only zero */
171 mask
= (target_ulong
)1 << i
;
172 if (wr_mask
& mask
) {
173 if (new_val
& mask
) {
174 imsic
->eistate
[base
+ i
] |= state
;
176 imsic
->eistate
[base
+ i
] &= ~state
;
181 riscv_imsic_update(imsic
, page
);
185 static int riscv_imsic_rmw(void *arg
, target_ulong reg
, target_ulong
*val
,
186 target_ulong new_val
, target_ulong wr_mask
)
188 RISCVIMSICState
*imsic
= arg
;
189 uint32_t isel
, priv
, virt
, vgein
, xlen
, page
;
191 priv
= AIA_IREG_PRIV(reg
);
192 virt
= AIA_IREG_VIRT(reg
);
193 isel
= AIA_IREG_ISEL(reg
);
194 vgein
= AIA_IREG_VGEIN(reg
);
195 xlen
= AIA_IREG_XLEN(reg
);
198 if (priv
== PRV_M
&& !virt
) {
206 if (vgein
&& vgein
< imsic
->num_pages
) {
220 case ISELECT_IMSIC_EIDELIVERY
:
221 return riscv_imsic_eidelivery_rmw(imsic
, page
, val
,
223 case ISELECT_IMSIC_EITHRESHOLD
:
224 return riscv_imsic_eithreshold_rmw(imsic
, page
, val
,
226 case ISELECT_IMSIC_TOPEI
:
227 return riscv_imsic_topei_rmw(imsic
, page
, val
, new_val
, wr_mask
);
228 case ISELECT_IMSIC_EIP0
... ISELECT_IMSIC_EIP63
:
229 return riscv_imsic_eix_rmw(imsic
, xlen
, page
,
230 isel
- ISELECT_IMSIC_EIP0
,
231 true, val
, new_val
, wr_mask
);
232 case ISELECT_IMSIC_EIE0
... ISELECT_IMSIC_EIE63
:
233 return riscv_imsic_eix_rmw(imsic
, xlen
, page
,
234 isel
- ISELECT_IMSIC_EIE0
,
235 false, val
, new_val
, wr_mask
);
241 qemu_log_mask(LOG_GUEST_ERROR
,
242 "%s: Invalid register priv=%d virt=%d isel=%d vgein=%d\n",
243 __func__
, priv
, virt
, isel
, vgein
);
247 static uint64_t riscv_imsic_read(void *opaque
, hwaddr addr
, unsigned size
)
249 RISCVIMSICState
*imsic
= opaque
;
251 /* Reads must be 4 byte words */
252 if ((addr
& 0x3) != 0) {
256 /* Reads cannot be out of range */
257 if (addr
> IMSIC_MMIO_SIZE(imsic
->num_pages
)) {
264 qemu_log_mask(LOG_GUEST_ERROR
,
265 "%s: Invalid register read 0x%" HWADDR_PRIx
"\n",
270 static void riscv_imsic_write(void *opaque
, hwaddr addr
, uint64_t value
,
273 RISCVIMSICState
*imsic
= opaque
;
276 /* Writes must be 4 byte words */
277 if ((addr
& 0x3) != 0) {
281 /* Writes cannot be out of range */
282 if (addr
> IMSIC_MMIO_SIZE(imsic
->num_pages
)) {
286 /* Writes only supported for MSI little-endian registers */
287 page
= addr
>> IMSIC_MMIO_PAGE_SHIFT
;
288 if ((addr
& (IMSIC_MMIO_PAGE_SZ
- 1)) == IMSIC_MMIO_PAGE_LE
) {
289 if (value
&& (value
< imsic
->num_irqs
)) {
290 imsic
->eistate
[(page
* imsic
->num_irqs
) + value
] |=
291 IMSIC_EISTATE_PENDING
;
295 /* Update CPU external interrupt status */
296 riscv_imsic_update(imsic
, page
);
301 qemu_log_mask(LOG_GUEST_ERROR
,
302 "%s: Invalid register write 0x%" HWADDR_PRIx
"\n",
306 static const MemoryRegionOps riscv_imsic_ops
= {
307 .read
= riscv_imsic_read
,
308 .write
= riscv_imsic_write
,
309 .endianness
= DEVICE_LITTLE_ENDIAN
,
311 .min_access_size
= 4,
316 static void riscv_imsic_realize(DeviceState
*dev
, Error
**errp
)
318 RISCVIMSICState
*imsic
= RISCV_IMSIC(dev
);
319 RISCVCPU
*rcpu
= RISCV_CPU(qemu_get_cpu(imsic
->hartid
));
320 CPUState
*cpu
= qemu_get_cpu(imsic
->hartid
);
321 CPURISCVState
*env
= cpu
? cpu
->env_ptr
: NULL
;
323 imsic
->num_eistate
= imsic
->num_pages
* imsic
->num_irqs
;
324 imsic
->eidelivery
= g_new0(uint32_t, imsic
->num_pages
);
325 imsic
->eithreshold
= g_new0(uint32_t, imsic
->num_pages
);
326 imsic
->eistate
= g_new0(uint32_t, imsic
->num_eistate
);
328 memory_region_init_io(&imsic
->mmio
, OBJECT(dev
), &riscv_imsic_ops
,
329 imsic
, TYPE_RISCV_IMSIC
,
330 IMSIC_MMIO_SIZE(imsic
->num_pages
));
331 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &imsic
->mmio
);
333 /* Claim the CPU interrupt to be triggered by this IMSIC */
334 if (riscv_cpu_claim_interrupts(rcpu
,
335 (imsic
->mmode
) ? MIP_MEIP
: MIP_SEIP
) < 0) {
336 error_setg(errp
, "%s already claimed",
337 (imsic
->mmode
) ? "MEIP" : "SEIP");
341 /* Create output IRQ lines */
342 imsic
->external_irqs
= g_malloc(sizeof(qemu_irq
) * imsic
->num_pages
);
343 qdev_init_gpio_out(dev
, imsic
->external_irqs
, imsic
->num_pages
);
345 /* Force select AIA feature and setup CSR read-modify-write callback */
348 rcpu
->cfg
.ext_ssaia
= true;
349 riscv_cpu_set_geilen(env
, imsic
->num_pages
- 1);
351 rcpu
->cfg
.ext_smaia
= true;
353 riscv_cpu_set_aia_ireg_rmw_fn(env
, (imsic
->mmode
) ? PRV_M
: PRV_S
,
354 riscv_imsic_rmw
, imsic
);
357 msi_nonbroken
= true;
360 static Property riscv_imsic_properties
[] = {
361 DEFINE_PROP_BOOL("mmode", RISCVIMSICState
, mmode
, 0),
362 DEFINE_PROP_UINT32("hartid", RISCVIMSICState
, hartid
, 0),
363 DEFINE_PROP_UINT32("num-pages", RISCVIMSICState
, num_pages
, 0),
364 DEFINE_PROP_UINT32("num-irqs", RISCVIMSICState
, num_irqs
, 0),
365 DEFINE_PROP_END_OF_LIST(),
368 static const VMStateDescription vmstate_riscv_imsic
= {
369 .name
= "riscv_imsic",
371 .minimum_version_id
= 1,
372 .fields
= (VMStateField
[]) {
373 VMSTATE_VARRAY_UINT32(eidelivery
, RISCVIMSICState
,
375 vmstate_info_uint32
, uint32_t),
376 VMSTATE_VARRAY_UINT32(eithreshold
, RISCVIMSICState
,
378 vmstate_info_uint32
, uint32_t),
379 VMSTATE_VARRAY_UINT32(eistate
, RISCVIMSICState
,
381 vmstate_info_uint32
, uint32_t),
382 VMSTATE_END_OF_LIST()
386 static void riscv_imsic_class_init(ObjectClass
*klass
, void *data
)
388 DeviceClass
*dc
= DEVICE_CLASS(klass
);
390 device_class_set_props(dc
, riscv_imsic_properties
);
391 dc
->realize
= riscv_imsic_realize
;
392 dc
->vmsd
= &vmstate_riscv_imsic
;
395 static const TypeInfo riscv_imsic_info
= {
396 .name
= TYPE_RISCV_IMSIC
,
397 .parent
= TYPE_SYS_BUS_DEVICE
,
398 .instance_size
= sizeof(RISCVIMSICState
),
399 .class_init
= riscv_imsic_class_init
,
402 static void riscv_imsic_register_types(void)
404 type_register_static(&riscv_imsic_info
);
407 type_init(riscv_imsic_register_types
)
410 * Create IMSIC device.
412 DeviceState
*riscv_imsic_create(hwaddr addr
, uint32_t hartid
, bool mmode
,
413 uint32_t num_pages
, uint32_t num_ids
)
415 DeviceState
*dev
= qdev_new(TYPE_RISCV_IMSIC
);
416 CPUState
*cpu
= qemu_get_cpu(hartid
);
419 assert(!(addr
& (IMSIC_MMIO_PAGE_SZ
- 1)));
421 assert(num_pages
== 1);
423 assert(num_pages
>= 1 && num_pages
<= (IRQ_LOCAL_GUEST_MAX
+ 1));
425 assert(IMSIC_MIN_ID
<= num_ids
);
426 assert(num_ids
<= IMSIC_MAX_ID
);
427 assert((num_ids
& IMSIC_MIN_ID
) == IMSIC_MIN_ID
);
429 qdev_prop_set_bit(dev
, "mmode", mmode
);
430 qdev_prop_set_uint32(dev
, "hartid", hartid
);
431 qdev_prop_set_uint32(dev
, "num-pages", num_pages
);
432 qdev_prop_set_uint32(dev
, "num-irqs", num_ids
+ 1);
434 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev
), &error_fatal
);
435 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 0, addr
);
437 for (i
= 0; i
< num_pages
; i
++) {
439 qdev_connect_gpio_out_named(dev
, NULL
, i
,
440 qdev_get_gpio_in(DEVICE(cpu
),
441 (mmode
) ? IRQ_M_EXT
: IRQ_S_EXT
));
443 qdev_connect_gpio_out_named(dev
, NULL
, i
,
444 qdev_get_gpio_in(DEVICE(cpu
),
445 IRQ_LOCAL_MAX
+ i
- 1));