Upstream: https://gitlab.com/qemu-project/qemu.git Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
95 lines
3.2 KiB
C
95 lines
3.2 KiB
C
/*
|
|
* QEMU RISC-V Advanced Interrupt Architecture (AIA)
|
|
*
|
|
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "system/kvm.h"
|
|
#include "hw/intc/riscv_aplic.h"
|
|
#include "hw/intc/riscv_imsic.h"
|
|
|
|
#include "aia.h"
|
|
|
|
uint32_t imsic_num_bits(uint32_t count)
|
|
{
|
|
uint32_t ret = 0;
|
|
|
|
while (BIT(ret) < count) {
|
|
ret++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
DeviceState *riscv_create_aia(bool msimode, int aia_guests,
|
|
uint32_t m_imsic_stride,
|
|
uint16_t num_sources,
|
|
const MemMapEntry *aplic_m,
|
|
const MemMapEntry *aplic_s,
|
|
const MemMapEntry *imsic_m,
|
|
const MemMapEntry *imsic_s,
|
|
int socket, int base_hartid, int hart_count,
|
|
uint32_t num_msis, uint32_t num_prio_bits)
|
|
{
|
|
int i;
|
|
hwaddr addr = 0;
|
|
uint32_t guest_bits;
|
|
DeviceState *aplic_s_dev = NULL;
|
|
DeviceState *aplic_m_dev = NULL;
|
|
|
|
/* The RISC-V Advanced Interrupt Architecture, Chapter 1.2. Limits */
|
|
g_assert(num_sources <= 1023);
|
|
|
|
if (msimode) {
|
|
if (!kvm_enabled()) {
|
|
/* Per-socket M-level IMSICs */
|
|
addr = imsic_m->base + socket * (1U << IMSIC_MMIO_GROUP_MIN_SHIFT);
|
|
for (i = 0; i < hart_count; i++) {
|
|
riscv_imsic_create(addr + i * m_imsic_stride,
|
|
base_hartid + i, true, 1,
|
|
num_msis);
|
|
}
|
|
}
|
|
|
|
/* Per-socket S-level IMSICs */
|
|
guest_bits = imsic_num_bits(aia_guests + 1);
|
|
addr = imsic_s->base + socket * (1U << IMSIC_MMIO_GROUP_MIN_SHIFT);
|
|
for (i = 0; i < hart_count; i++) {
|
|
riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits),
|
|
base_hartid + i, false, 1 + aia_guests,
|
|
num_msis);
|
|
}
|
|
}
|
|
|
|
if (!kvm_enabled()) {
|
|
/* Per-socket M-level APLIC */
|
|
aplic_m_dev = riscv_aplic_create(aplic_m->base +
|
|
socket * aplic_m->size,
|
|
aplic_m->size,
|
|
(msimode) ? 0 : base_hartid,
|
|
(msimode) ? 0 : hart_count,
|
|
num_sources,
|
|
num_prio_bits,
|
|
msimode, true, NULL);
|
|
}
|
|
|
|
/* Per-socket S-level APLIC */
|
|
aplic_s_dev = riscv_aplic_create(aplic_s->base +
|
|
socket * aplic_s->size,
|
|
aplic_s->size,
|
|
(msimode) ? 0 : base_hartid,
|
|
(msimode) ? 0 : hart_count,
|
|
num_sources,
|
|
num_prio_bits,
|
|
msimode, false, aplic_m_dev);
|
|
|
|
if (kvm_enabled() && msimode) {
|
|
riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s_dev), addr);
|
|
}
|
|
|
|
return kvm_enabled() ? aplic_s_dev : aplic_m_dev;
|
|
}
|