master
c 94 lines 3.16 KB
Raw
1 /*
2 * QEMU RISC-V Advanced Interrupt Architecture (AIA)
3 *
4 * Copyright (C) 2019 Western Digital Corporation or its affiliates.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "system/kvm.h"
11 #include "hw/intc/riscv_aplic.h"
12 #include "hw/intc/riscv_imsic.h"
13
14 #include "aia.h"
15
16 uint32_t imsic_num_bits(uint32_t count)
17 {
18 uint32_t ret = 0;
19
20 while (BIT(ret) < count) {
21 ret++;
22 }
23
24 return ret;
25 }
26
27 DeviceState *riscv_create_aia(bool msimode, int aia_guests,
28 uint32_t m_imsic_stride,
29 uint16_t num_sources,
30 const MemMapEntry *aplic_m,
31 const MemMapEntry *aplic_s,
32 const MemMapEntry *imsic_m,
33 const MemMapEntry *imsic_s,
34 int socket, int base_hartid, int hart_count,
35 uint32_t num_msis, uint32_t num_prio_bits)
36 {
37 int i;
38 hwaddr addr = 0;
39 uint32_t guest_bits;
40 DeviceState *aplic_s_dev = NULL;
41 DeviceState *aplic_m_dev = NULL;
42
43 /* The RISC-V Advanced Interrupt Architecture, Chapter 1.2. Limits */
44 g_assert(num_sources <= 1023);
45
46 if (msimode) {
47 if (!kvm_enabled()) {
48 /* Per-socket M-level IMSICs */
49 addr = imsic_m->base + socket * (1U << IMSIC_MMIO_GROUP_MIN_SHIFT);
50 for (i = 0; i < hart_count; i++) {
51 riscv_imsic_create(addr + i * m_imsic_stride,
52 base_hartid + i, true, 1,
53 num_msis);
54 }
55 }
56
57 /* Per-socket S-level IMSICs */
58 guest_bits = imsic_num_bits(aia_guests + 1);
59 addr = imsic_s->base + socket * (1U << IMSIC_MMIO_GROUP_MIN_SHIFT);
60 for (i = 0; i < hart_count; i++) {
61 riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits),
62 base_hartid + i, false, 1 + aia_guests,
63 num_msis);
64 }
65 }
66
67 if (!kvm_enabled()) {
68 /* Per-socket M-level APLIC */
69 aplic_m_dev = riscv_aplic_create(aplic_m->base +
70 socket * aplic_m->size,
71 aplic_m->size,
72 (msimode) ? 0 : base_hartid,
73 (msimode) ? 0 : hart_count,
74 num_sources,
75 num_prio_bits,
76 msimode, true, NULL);
77 }
78
79 /* Per-socket S-level APLIC */
80 aplic_s_dev = riscv_aplic_create(aplic_s->base +
81 socket * aplic_s->size,
82 aplic_s->size,
83 (msimode) ? 0 : base_hartid,
84 (msimode) ? 0 : hart_count,
85 num_sources,
86 num_prio_bits,
87 msimode, false, aplic_m_dev);
88
89 if (kvm_enabled() && msimode) {
90 riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s_dev), addr);
91 }
92
93 return kvm_enabled() ? aplic_s_dev : aplic_m_dev;
94 }