mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-loongarch-20250928' of https://github.com/gaosong715/qemu into staging
pull-loongarch-20250928 v2: fix build win64 errors. # -----BEGIN PGP SIGNATURE----- # # iLMEAAEIAB0WIQTKRzxE1qCcGJoZP81FK5aFKyaCFgUCaNkDHQAKCRBFK5aFKyaC # Fn06A/0SQKLVcktq2lX+aRurdGw/LKt/1mtSFJes6s5VVCrNuFFzmkXzjs/m0CcX # scgDF67Z+PhJpLtNLRV8FiJ+z3bOH/j+yRHqj1xnvvITb+i5bUYbt+A81wrzX6Bi # J/Ayqu49oQj33hX3lqTcTBmwYDBc2v7nu0PfvFqOUi9bTvYgfA== # =C4NB # -----END PGP SIGNATURE----- # gpg: Signature made Sun 28 Sep 2025 02:42:53 AM PDT # gpg: using RSA key CA473C44D6A09C189A193FCD452B96852B268216 # gpg: Good signature from "Song Gao <gaosong@loongson.cn>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: CA47 3C44 D6A0 9C18 9A19 3FCD 452B 9685 2B26 8216 * tag 'pull-loongarch-20250928' of https://github.com/gaosong715/qemu: hw/loongarch: Implement DINTC plug/unplug interfaces target/loongarch:Implement csrrd CSR_MSGIR register target/loongarch: Add CSR_ESTAT.bit15 and CSR_ECFG.bit15 for msg interrupts. hw/loongarch: Implement dintc set irq hw/loongarch: Implement dintc realize and unrealize hw/loongarch: DINTC add a MemoryRegion target/loongarch: add msg interrupt CSR registers loongarch: add a direct interrupt controller device hw/loongarch: add misc register support dmsi hw/loongarch: add virt feature dmsi support target/loongarch: move some machine define to virt.h Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -109,3 +109,6 @@ config LOONGARCH_PCH_MSI
|
||||
|
||||
config LOONGARCH_EXTIOI
|
||||
bool
|
||||
|
||||
config LOONGARCH_DINTC
|
||||
bool
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QEMU LoongArch direct interrupt controller.
|
||||
*
|
||||
* Copyright (C) 2025 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/intc/loongarch_pch_msi.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "hw/intc/loongarch_dintc.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "target/loongarch/cpu.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "system/hw_accel.h"
|
||||
|
||||
/* msg addr field */
|
||||
FIELD(MSG_ADDR, IRQ_NUM, 4, 8)
|
||||
FIELD(MSG_ADDR, CPU_NUM, 12, 8)
|
||||
FIELD(MSG_ADDR, FIX, 28, 12)
|
||||
|
||||
static uint64_t loongarch_dintc_mem_read(void *opaque,
|
||||
hwaddr addr, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_set_vcpu_dintc_irq(CPUState *cs, run_on_cpu_data data)
|
||||
{
|
||||
int irq = data.host_int;
|
||||
CPULoongArchState *env;
|
||||
|
||||
env = &LOONGARCH_CPU(cs)->env;
|
||||
cpu_synchronize_state(cs);
|
||||
set_bit(irq, (unsigned long *)&env->CSR_MSGIS);
|
||||
}
|
||||
|
||||
static void loongarch_dintc_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
int irq_num, cpu_num = 0;
|
||||
LoongArchDINTCState *s = LOONGARCH_DINTC(opaque);
|
||||
uint64_t msg_addr = addr + VIRT_DINTC_BASE;
|
||||
CPUState *cs;
|
||||
|
||||
cpu_num = FIELD_EX64(msg_addr, MSG_ADDR, CPU_NUM);
|
||||
cs = cpu_by_arch_id(cpu_num);
|
||||
irq_num = FIELD_EX64(msg_addr, MSG_ADDR, IRQ_NUM);
|
||||
|
||||
async_run_on_cpu(cs, do_set_vcpu_dintc_irq,
|
||||
RUN_ON_CPU_HOST_INT(irq_num));
|
||||
qemu_set_irq(s->cpu[cpu_num].parent_irq, 1);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps loongarch_dintc_ops = {
|
||||
.read = loongarch_dintc_mem_read,
|
||||
.write = loongarch_dintc_mem_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void loongarch_dintc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongArchDINTCState *s = LOONGARCH_DINTC(dev);
|
||||
LoongArchDINTCClass *lac = LOONGARCH_DINTC_GET_CLASS(dev);
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
const CPUArchIdList *id_list;
|
||||
int i;
|
||||
|
||||
Error *local_err = NULL;
|
||||
lac->parent_realize(dev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(mc->possible_cpu_arch_ids);
|
||||
id_list = mc->possible_cpu_arch_ids(machine);
|
||||
s->num_cpu = id_list->len;
|
||||
s->cpu = g_new(DINTCCore, s->num_cpu);
|
||||
if (s->cpu == NULL) {
|
||||
error_setg(errp, "Memory allocation for DINTCCore fail");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
s->cpu[i].arch_id = id_list->cpus[i].arch_id;
|
||||
s->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
|
||||
qdev_init_gpio_out(dev, &s->cpu[i].parent_irq, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void loongarch_dintc_unrealize(DeviceState *dev)
|
||||
{
|
||||
LoongArchDINTCState *s = LOONGARCH_DINTC(dev);
|
||||
g_free(s->cpu);
|
||||
}
|
||||
|
||||
static void loongarch_dintc_init(Object *obj)
|
||||
{
|
||||
LoongArchDINTCState *s = LOONGARCH_DINTC(obj);
|
||||
SysBusDevice *shd = SYS_BUS_DEVICE(obj);
|
||||
memory_region_init_io(&s->dintc_mmio, OBJECT(s), &loongarch_dintc_ops,
|
||||
s, TYPE_LOONGARCH_DINTC, VIRT_DINTC_SIZE);
|
||||
sysbus_init_mmio(shd, &s->dintc_mmio);
|
||||
msi_nonbroken = true;
|
||||
return;
|
||||
}
|
||||
|
||||
static DINTCCore *loongarch_dintc_get_cpu(LoongArchDINTCState *s,
|
||||
DeviceState *dev)
|
||||
{
|
||||
CPUClass *k = CPU_GET_CLASS(dev);
|
||||
uint64_t arch_id = k->get_arch_id(CPU(dev));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
if (s->cpu[i].arch_id == arch_id) {
|
||||
return &s->cpu[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void loongarch_dintc_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongArchDINTCState *s = LOONGARCH_DINTC(hotplug_dev);
|
||||
Object *obj = OBJECT(dev);
|
||||
DINTCCore *core;
|
||||
int index;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
|
||||
warn_report("LoongArch DINTC: Invalid %s device type",
|
||||
object_get_typename(obj));
|
||||
return;
|
||||
}
|
||||
core = loongarch_dintc_get_cpu(s, dev);
|
||||
if (!core) {
|
||||
return;
|
||||
}
|
||||
|
||||
core->cpu = CPU(dev);
|
||||
index = core - s->cpu;
|
||||
|
||||
/* connect dintc msg irq to cpu irq */
|
||||
qdev_connect_gpio_out(DEVICE(s), index, qdev_get_gpio_in(dev, INT_DMSI));
|
||||
return;
|
||||
}
|
||||
|
||||
static void loongarch_dintc_cpu_unplug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongArchDINTCState *s = LOONGARCH_DINTC(hotplug_dev);
|
||||
Object *obj = OBJECT(dev);
|
||||
DINTCCore *core;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
|
||||
warn_report("LoongArch DINTC: Invalid %s device type",
|
||||
object_get_typename(obj));
|
||||
return;
|
||||
}
|
||||
|
||||
core = loongarch_dintc_get_cpu(s, dev);
|
||||
|
||||
if (!core) {
|
||||
return;
|
||||
}
|
||||
|
||||
core->cpu = NULL;
|
||||
}
|
||||
|
||||
static void loongarch_dintc_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
|
||||
LoongArchDINTCClass *lac = LOONGARCH_DINTC_CLASS(klass);
|
||||
|
||||
dc->unrealize = loongarch_dintc_unrealize;
|
||||
device_class_set_parent_realize(dc, loongarch_dintc_realize,
|
||||
&lac->parent_realize);
|
||||
hc->plug = loongarch_dintc_cpu_plug;
|
||||
hc->unplug = loongarch_dintc_cpu_unplug;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_dintc_info = {
|
||||
.name = TYPE_LOONGARCH_DINTC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LoongArchDINTCState),
|
||||
.instance_init = loongarch_dintc_init,
|
||||
.class_init = loongarch_dintc_class_init,
|
||||
.interfaces = (const InterfaceInfo[]) {
|
||||
{ TYPE_HOTPLUG_HANDLER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void loongarch_dintc_register_types(void)
|
||||
{
|
||||
type_register_static(&loongarch_dintc_info);
|
||||
}
|
||||
|
||||
type_init(loongarch_dintc_register_types)
|
||||
@@ -80,3 +80,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c', 'loongarch_extioi_common.c'))
|
||||
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_EXTIOI'],
|
||||
if_true: files('loongarch_extioi_kvm.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_DINTC', if_true: files('loongarch_dintc.c'))
|
||||
|
||||
@@ -15,6 +15,7 @@ config LOONGARCH_VIRT
|
||||
select LOONGARCH_PCH_PIC
|
||||
select LOONGARCH_PCH_MSI
|
||||
select LOONGARCH_EXTIOI
|
||||
select LOONGARCH_DINTC
|
||||
select LS7A_RTC
|
||||
select SMBIOS
|
||||
select ACPI_CPU_HOTPLUG
|
||||
|
||||
+109
-1
@@ -28,6 +28,7 @@
|
||||
#include "hw/intc/loongarch_extioi.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "hw/intc/loongarch_pch_msi.h"
|
||||
#include "hw/intc/loongarch_dintc.h"
|
||||
#include "hw/pci-host/ls7a.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
@@ -48,6 +49,30 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "kvm/kvm_loongarch.h"
|
||||
|
||||
static void virt_get_dmsi(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
|
||||
OnOffAuto dmsi = lvms->dmsi;
|
||||
|
||||
visit_type_OnOffAuto(v, name, &dmsi, errp);
|
||||
|
||||
}
|
||||
static void virt_set_dmsi(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
|
||||
|
||||
visit_type_OnOffAuto(v, name, &lvms->dmsi, errp);
|
||||
|
||||
if (lvms->dmsi == ON_OFF_AUTO_OFF) {
|
||||
lvms->misc_feature &= ~BIT(IOCSRF_DMSI);
|
||||
lvms->misc_status &= ~BIT_ULL(IOCSRM_DMSI_EN);
|
||||
} else if (lvms->dmsi == ON_OFF_AUTO_ON) {
|
||||
lvms->misc_feature = BIT(IOCSRF_DMSI);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
@@ -356,13 +381,17 @@ static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
|
||||
&error_abort);
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), DEVICE(cs),
|
||||
&error_abort);
|
||||
if (lvms->dintc) {
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->dintc), DEVICE(cs),
|
||||
&error_abort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
DeviceState *pch_pic, *pch_msi;
|
||||
DeviceState *ipi, *extioi;
|
||||
DeviceState *ipi, *extioi, *dintc;
|
||||
SysBusDevice *d;
|
||||
int i, start, num;
|
||||
|
||||
@@ -408,6 +437,33 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
||||
* +--------+ +---------+ +---------+
|
||||
* | UARTs | | Devices | | Devices |
|
||||
* +--------+ +---------+ +---------+
|
||||
*
|
||||
*
|
||||
* Advanced Extended IRQ model
|
||||
*
|
||||
* +-----+ +---------------------------------+ +-------+
|
||||
* | IPI | --> | CPUINTC | <-- | Timer |
|
||||
* +-----+ +---------------------------------+ +-------+
|
||||
* ^ ^ ^
|
||||
* | | |
|
||||
* +-------------+ +----------+ +---------+ +-------+
|
||||
* | EIOINTC | | DINTC | | LIOINTC | <-- | UARTs |
|
||||
* +-------------+ +----------+ +---------+ +-------+
|
||||
* ^ ^ ^
|
||||
* | | |
|
||||
* +---------+ +---------+ |
|
||||
* | PCH-PIC | | PCH-MSI | |
|
||||
* +---------+ +---------+ |
|
||||
* ^ ^ ^ |
|
||||
* | | | |
|
||||
* +---------+ +---------+ +---------+
|
||||
* | Devices | | PCH-LPC | | Devices |
|
||||
* +---------+ +---------+ +---------+
|
||||
* ^
|
||||
* |
|
||||
* +---------+
|
||||
* | Devices |
|
||||
* +---------+
|
||||
*/
|
||||
|
||||
/* Create IPI device */
|
||||
@@ -415,6 +471,14 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
||||
lvms->ipi = ipi;
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
|
||||
|
||||
/* Create DINTC device*/
|
||||
if (virt_has_dmsi(lvms)) {
|
||||
dintc = qdev_new(TYPE_LOONGARCH_DINTC);
|
||||
lvms->dintc = dintc;
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dintc), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dintc), 0, VIRT_DINTC_BASE);
|
||||
}
|
||||
|
||||
/* Create EXTIOI device */
|
||||
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
|
||||
lvms->extioi = extioi;
|
||||
@@ -540,6 +604,10 @@ static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
||||
if (virt_has_dmsi(lvms) && val & BIT_ULL(IOCSRM_DMSI_EN)) {
|
||||
lvms->misc_status |= BIT_ULL(IOCSRM_DMSI_EN);
|
||||
}
|
||||
|
||||
features = address_space_ldl(&lvms->as_iocsr,
|
||||
EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
|
||||
attrs, NULL);
|
||||
@@ -575,6 +643,9 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
|
||||
break;
|
||||
case FEATURE_REG:
|
||||
ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI);
|
||||
if (virt_has_dmsi(lvms)) {
|
||||
ret |= BIT(IOCSRF_DMSI);
|
||||
}
|
||||
if (kvm_enabled()) {
|
||||
ret |= BIT(IOCSRF_VM);
|
||||
}
|
||||
@@ -604,6 +675,10 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
|
||||
if (features & BIT(EXTIOI_ENABLE_INT_ENCODE)) {
|
||||
ret |= BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE);
|
||||
}
|
||||
if (virt_has_dmsi(lvms) &&
|
||||
(lvms->misc_status & BIT_ULL(IOCSRM_DMSI_EN))) {
|
||||
ret |= BIT_ULL(IOCSRM_DMSI_EN);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@@ -683,6 +758,25 @@ static void fw_cfg_add_memory(MachineState *ms)
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_check_dmsi(MachineState *machine)
|
||||
{
|
||||
LoongArchCPU *cpu;
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
|
||||
cpu = LOONGARCH_CPU(first_cpu);
|
||||
if (lvms->dmsi == ON_OFF_AUTO_AUTO) {
|
||||
if (cpu->msgint != ON_OFF_AUTO_OFF) {
|
||||
lvms->misc_feature = BIT(IOCSRF_DMSI);
|
||||
}
|
||||
}
|
||||
|
||||
if (lvms->dmsi == ON_OFF_AUTO_ON && cpu->msgint == ON_OFF_AUTO_OFF) {
|
||||
error_report("Fail to enable dmsi , cpu msgint is off "
|
||||
"pleass add cpu feature mesgint=on.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = machine->cpu_type;
|
||||
@@ -717,6 +811,7 @@ static void virt_init(MachineState *machine)
|
||||
}
|
||||
qdev_realize_and_unref(DEVICE(cpuobj), NULL, &error_fatal);
|
||||
}
|
||||
virt_check_dmsi(machine);
|
||||
fw_cfg_add_memory(machine);
|
||||
|
||||
/* Node0 memory */
|
||||
@@ -847,6 +942,8 @@ static void virt_initfn(Object *obj)
|
||||
if (tcg_enabled()) {
|
||||
lvms->veiointc = ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
lvms->dmsi = ON_OFF_AUTO_AUTO;
|
||||
lvms->acpi = ON_OFF_AUTO_AUTO;
|
||||
lvms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
|
||||
lvms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
|
||||
@@ -1010,6 +1107,9 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev,
|
||||
/* Notify ipi and extioi irqchip to remove interrupt routing to CPU */
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->ipi), dev, &error_abort);
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort);
|
||||
if (lvms->dintc) {
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->dintc), dev, &error_abort);
|
||||
}
|
||||
|
||||
/* Notify acpi ged CPU removed */
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &error_abort);
|
||||
@@ -1034,6 +1134,10 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort);
|
||||
}
|
||||
|
||||
if (lvms->dintc) {
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->dintc), dev, &error_abort);
|
||||
}
|
||||
|
||||
if (lvms->acpi_ged) {
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev,
|
||||
&error_abort);
|
||||
@@ -1241,6 +1345,10 @@ static void virt_class_init(ObjectClass *oc, const void *data)
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "v-eiointc",
|
||||
"Enable Virt Extend I/O Interrupt Controller.");
|
||||
object_class_property_add(oc, "dmsi", "OnOffAuto",
|
||||
virt_get_dmsi, virt_set_dmsi, NULL, NULL);
|
||||
object_class_property_set_description(oc, "dmsi",
|
||||
"Enable direct Message-interrupts Controller.");
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
|
||||
#ifdef CONFIG_TPM
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch direct interrupt controller definitions
|
||||
*
|
||||
* Copyright (C) 2025 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
|
||||
|
||||
#define NR_VECTORS 256
|
||||
|
||||
#define TYPE_LOONGARCH_DINTC "loongarch_dintc"
|
||||
OBJECT_DECLARE_TYPE(LoongArchDINTCState, LoongArchDINTCClass, LOONGARCH_DINTC)
|
||||
|
||||
typedef struct DINTCCore {
|
||||
CPUState *cpu;
|
||||
qemu_irq parent_irq;
|
||||
uint64_t arch_id;
|
||||
} DINTCCore;
|
||||
|
||||
struct LoongArchDINTCState {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion dintc_mmio;
|
||||
DINTCCore *cpu;
|
||||
uint32_t num_cpu;
|
||||
};
|
||||
|
||||
struct LoongArchDINTCClass {
|
||||
SysBusDeviceClass parent_class;
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
DeviceUnrealize parent_unrealize;
|
||||
};
|
||||
@@ -13,6 +13,27 @@
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/loongarch/boot.h"
|
||||
|
||||
#define IOCSRF_TEMP 0
|
||||
#define IOCSRF_NODECNT 1
|
||||
#define IOCSRF_MSI 2
|
||||
#define IOCSRF_EXTIOI 3
|
||||
#define IOCSRF_CSRIPI 4
|
||||
#define IOCSRF_FREQCSR 5
|
||||
#define IOCSRF_FREQSCALE 6
|
||||
#define IOCSRF_DVFSV1 7
|
||||
#define IOCSRF_GMOD 9
|
||||
#define IOCSRF_VM 11
|
||||
#define IOCSRF_DMSI 15
|
||||
|
||||
#define VERSION_REG 0x0
|
||||
#define FEATURE_REG 0x8
|
||||
#define VENDOR_REG 0x10
|
||||
#define CPUNAME_REG 0x20
|
||||
#define MISC_FUNC_REG 0x420
|
||||
#define IOCSRM_EXTIOI_EN 48
|
||||
#define IOCSRM_EXTIOI_INT_ENCODE 49
|
||||
#define IOCSRM_DMSI_EN 51
|
||||
|
||||
#define LOONGARCH_MAX_CPUS 256
|
||||
|
||||
#define VIRT_FWCFG_BASE 0x1e020000UL
|
||||
@@ -50,6 +71,7 @@ struct LoongArchVirtMachineState {
|
||||
Notifier powerdown_notifier;
|
||||
OnOffAuto acpi;
|
||||
OnOffAuto veiointc;
|
||||
OnOffAuto dmsi;
|
||||
char *oem_id;
|
||||
char *oem_table_id;
|
||||
DeviceState *acpi_ged;
|
||||
@@ -65,6 +87,9 @@ struct LoongArchVirtMachineState {
|
||||
DeviceState *extioi;
|
||||
struct memmap_entry *memmap_table;
|
||||
unsigned int memmap_entries;
|
||||
uint64_t misc_feature;
|
||||
uint64_t misc_status;
|
||||
DeviceState *dintc;
|
||||
};
|
||||
|
||||
#define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
||||
@@ -72,6 +97,15 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE)
|
||||
void virt_acpi_setup(LoongArchVirtMachineState *lvms);
|
||||
void virt_fdt_setup(LoongArchVirtMachineState *lvms);
|
||||
|
||||
static inline bool virt_has_dmsi(LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
if (!(lvms->misc_feature & BIT(IOCSRF_DMSI))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
if (lvms->veiointc == ON_OFF_AUTO_OFF) {
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#define VIRT_PCH_REG_BASE 0x10000000UL
|
||||
#define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
|
||||
#define VIRT_PCH_MSI_ADDR_LOW 0x2FF00000UL
|
||||
#define VIRT_DINTC_SIZE 0x100000UL
|
||||
#define VIRT_DINTC_BASE 0x2FE00000UL
|
||||
#define VIRT_PCH_REG_SIZE 0x400
|
||||
#define VIRT_PCH_MSI_SIZE 0x8
|
||||
|
||||
|
||||
@@ -34,11 +34,13 @@ FIELD(CSR_MISC, ALCL, 12, 4)
|
||||
FIELD(CSR_MISC, DWPL, 16, 3)
|
||||
|
||||
#define LOONGARCH_CSR_ECFG 0x4 /* Exception config */
|
||||
FIELD(CSR_ECFG, LIE, 0, 13)
|
||||
FIELD(CSR_ECFG, LIE, 0, 15) /* bit 15 is msg interrupt enabled */
|
||||
FIELD(CSR_ECFG, MSGINT, 14, 1)
|
||||
FIELD(CSR_ECFG, VS, 16, 3)
|
||||
|
||||
#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */
|
||||
FIELD(CSR_ESTAT, IS, 0, 13)
|
||||
FIELD(CSR_ESTAT, IS, 0, 15) /* bit 15 is msg interrupt enabled */
|
||||
FIELD(CSR_ESTAT, MSGINT, 14, 1)
|
||||
FIELD(CSR_ESTAT, ECODE, 16, 6)
|
||||
FIELD(CSR_ESTAT, ESUBCODE, 22, 9)
|
||||
|
||||
@@ -186,6 +188,9 @@ FIELD(CSR_MERRCTL, ISMERR, 0, 1)
|
||||
|
||||
#define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */
|
||||
|
||||
#define LOONGARCH_CSR_MSGIS(N) (0xa0 + N)
|
||||
#define LOONGARCH_CSR_MSGIR 0xa4
|
||||
|
||||
/* Direct map windows CSRs*/
|
||||
#define LOONGARCH_CSR_DMW(N) (0x180 + N)
|
||||
FIELD(CSR_DMW, PLV0, 0, 1)
|
||||
|
||||
@@ -495,6 +495,25 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp)
|
||||
cpu->env.cpucfg[2] = FIELD_DP32(val, CPUCFG2, LASX, value);
|
||||
}
|
||||
|
||||
static bool loongarch_get_msgint(Object *obj, Error **errp)
|
||||
{
|
||||
return LOONGARCH_CPU(obj)->msgint != ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
static void loongarch_set_msgint(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
|
||||
cpu->msgint = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/* kvm feature detection in function kvm_arch_init_vcpu */
|
||||
return;
|
||||
}
|
||||
|
||||
cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, value);
|
||||
}
|
||||
|
||||
static void loongarch_cpu_post_init(Object *obj)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
@@ -507,6 +526,8 @@ static void loongarch_cpu_post_init(Object *obj)
|
||||
loongarch_set_lsx);
|
||||
object_property_add_bool(obj, "lasx", loongarch_get_lasx,
|
||||
loongarch_set_lasx);
|
||||
object_property_add_bool(obj, "msgint", loongarch_get_msgint,
|
||||
loongarch_set_msgint);
|
||||
/* lbt is enabled only in kvm mode, not supported in tcg mode */
|
||||
if (kvm_enabled()) {
|
||||
kvm_loongarch_cpu_post_init(cpu);
|
||||
@@ -614,6 +635,7 @@ static void loongarch_la464_initfn(Object *obj)
|
||||
env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7);
|
||||
env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8);
|
||||
|
||||
cpu->msgint = ON_OFF_AUTO_OFF;
|
||||
loongarch_la464_init_csr(obj);
|
||||
loongarch_cpu_post_init(obj);
|
||||
}
|
||||
@@ -644,12 +666,19 @@ static void loongarch_la132_initfn(Object *obj)
|
||||
data = FIELD_DP32(data, CPUCFG1, HP, 1);
|
||||
data = FIELD_DP32(data, CPUCFG1, CRC, 1);
|
||||
env->cpucfg[1] = data;
|
||||
cpu->msgint = ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
static void loongarch_max_initfn(Object *obj)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
/* '-cpu max' for TCG: we use cpu la464. */
|
||||
loongarch_la464_initfn(obj);
|
||||
|
||||
if (tcg_enabled()) {
|
||||
cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, 1);
|
||||
cpu->msgint = ON_OFF_AUTO_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
|
||||
|
||||
+14
-22
@@ -21,27 +21,6 @@
|
||||
#include "cpu-csr.h"
|
||||
#include "cpu-qom.h"
|
||||
|
||||
#define IOCSRF_TEMP 0
|
||||
#define IOCSRF_NODECNT 1
|
||||
#define IOCSRF_MSI 2
|
||||
#define IOCSRF_EXTIOI 3
|
||||
#define IOCSRF_CSRIPI 4
|
||||
#define IOCSRF_FREQCSR 5
|
||||
#define IOCSRF_FREQSCALE 6
|
||||
#define IOCSRF_DVFSV1 7
|
||||
#define IOCSRF_GMOD 9
|
||||
#define IOCSRF_VM 11
|
||||
|
||||
#define VERSION_REG 0x0
|
||||
#define FEATURE_REG 0x8
|
||||
#define VENDOR_REG 0x10
|
||||
#define CPUNAME_REG 0x20
|
||||
#define MISC_FUNC_REG 0x420
|
||||
#define IOCSRM_EXTIOI_EN 48
|
||||
#define IOCSRM_EXTIOI_INT_ENCODE 49
|
||||
|
||||
#define IOCSR_MEM_SIZE 0x428
|
||||
|
||||
#define FCSR0_M1 0x1f /* FCSR1 mask, Enables */
|
||||
#define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */
|
||||
#define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */
|
||||
@@ -238,9 +217,10 @@ FIELD(CSR_CRMD, WE, 9, 1)
|
||||
extern const char * const regnames[32];
|
||||
extern const char * const fregnames[32];
|
||||
|
||||
#define N_IRQS 13
|
||||
#define N_IRQS 15
|
||||
#define IRQ_TIMER 11
|
||||
#define IRQ_IPI 12
|
||||
#define INT_DMSI 14
|
||||
|
||||
#define LOONGARCH_STLB 2048 /* 2048 STLB */
|
||||
#define LOONGARCH_MTLB 64 /* 64 MTLB */
|
||||
@@ -254,6 +234,13 @@ FIELD(TLB_MISC, ASID, 1, 10)
|
||||
FIELD(TLB_MISC, VPPN, 13, 35)
|
||||
FIELD(TLB_MISC, PS, 48, 6)
|
||||
|
||||
/*Msg interrupt registers */
|
||||
#define N_MSGIS 4
|
||||
FIELD(CSR_MSGIS, IS, 0, 63)
|
||||
FIELD(CSR_MSGIR, INTNUM, 0, 8)
|
||||
FIELD(CSR_MSGIR, ACTIVE, 31, 1)
|
||||
FIELD(CSR_MSGIE, PT, 0, 8)
|
||||
|
||||
#define LSX_LEN (128)
|
||||
#define LASX_LEN (256)
|
||||
|
||||
@@ -371,6 +358,10 @@ typedef struct CPUArchState {
|
||||
uint64_t CSR_DBG;
|
||||
uint64_t CSR_DERA;
|
||||
uint64_t CSR_DSAVE;
|
||||
/* Msg interrupt registers */
|
||||
uint64_t CSR_MSGIS[N_MSGIS];
|
||||
uint64_t CSR_MSGIR;
|
||||
uint64_t CSR_MSGIE;
|
||||
struct {
|
||||
uint64_t guest_addr;
|
||||
} stealtime;
|
||||
@@ -413,6 +404,7 @@ struct ArchCPU {
|
||||
OnOffAuto pmu;
|
||||
OnOffAuto lsx;
|
||||
OnOffAuto lasx;
|
||||
OnOffAuto msgint;
|
||||
OnOffAuto kvm_pv_ipi;
|
||||
OnOffAuto kvm_steal_time;
|
||||
int32_t socket_id; /* socket-id of this CPU */
|
||||
|
||||
@@ -97,6 +97,11 @@ static CSRInfo csr_info[] = {
|
||||
CSR_OFF(DBG),
|
||||
CSR_OFF(DERA),
|
||||
CSR_OFF(DSAVE),
|
||||
CSR_OFF_ARRAY(MSGIS, 0),
|
||||
CSR_OFF_ARRAY(MSGIS, 1),
|
||||
CSR_OFF_ARRAY(MSGIS, 2),
|
||||
CSR_OFF_ARRAY(MSGIS, 3),
|
||||
CSR_OFF(MSGIR),
|
||||
};
|
||||
|
||||
CSRInfo *get_csr(unsigned int csr_num)
|
||||
|
||||
@@ -45,6 +45,26 @@ static const VMStateDescription vmstate_fpu = {
|
||||
},
|
||||
};
|
||||
|
||||
static bool msgint_needed(void *opaque)
|
||||
{
|
||||
LoongArchCPU *cpu = opaque;
|
||||
|
||||
return FIELD_EX64(cpu->env.cpucfg[1], CPUCFG1, MSG_INT);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_msgint = {
|
||||
.name = "cpu/msgint",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = msgint_needed,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT64_ARRAY(env.CSR_MSGIS, LoongArchCPU, N_MSGIS),
|
||||
VMSTATE_UINT64(env.CSR_MSGIR, LoongArchCPU),
|
||||
VMSTATE_UINT64(env.CSR_MSGIE, LoongArchCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_lsxh_reg = {
|
||||
.name = "lsxh_reg",
|
||||
.version_id = 1,
|
||||
@@ -168,8 +188,8 @@ static const VMStateDescription vmstate_tlb = {
|
||||
/* LoongArch CPU state */
|
||||
const VMStateDescription vmstate_loongarch_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.version_id = 4,
|
||||
.minimum_version_id = 4,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
|
||||
VMSTATE_UINTTL(env.pc, LoongArchCPU),
|
||||
@@ -245,6 +265,7 @@ const VMStateDescription vmstate_loongarch_cpu = {
|
||||
&vmstate_tlb,
|
||||
#endif
|
||||
&vmstate_lbt,
|
||||
&vmstate_msgint,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,6 +73,27 @@ target_ulong helper_csrrd_tval(CPULoongArchState *env)
|
||||
return cpu_loongarch_get_constant_timer_ticks(cpu);
|
||||
}
|
||||
|
||||
target_ulong helper_csrrd_msgir(CPULoongArchState *env)
|
||||
{
|
||||
int irq, new;
|
||||
|
||||
irq = find_first_bit((unsigned long *)env->CSR_MSGIS, 256);
|
||||
if (irq < 256) {
|
||||
clear_bit(irq, (unsigned long *)env->CSR_MSGIS);
|
||||
new = find_first_bit((unsigned long *)env->CSR_MSGIS, 256);
|
||||
if (new < 256) {
|
||||
return irq;
|
||||
}
|
||||
|
||||
env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, MSGINT, 0);
|
||||
} else {
|
||||
/* bit 31 set 1 for no invalid irq */
|
||||
irq = BIT(31);
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
|
||||
{
|
||||
int64_t old_v = env->CSR_ESTAT;
|
||||
|
||||
@@ -100,6 +100,7 @@ DEF_HELPER_1(rdtime_d, i64, env)
|
||||
DEF_HELPER_1(csrrd_pgd, i64, env)
|
||||
DEF_HELPER_1(csrrd_cpuid, i64, env)
|
||||
DEF_HELPER_1(csrrd_tval, i64, env)
|
||||
DEF_HELPER_1(csrrd_msgir, i64, env)
|
||||
DEF_HELPER_2(csrwr_stlbps, i64, env, tl)
|
||||
DEF_HELPER_2(csrwr_estat, i64, env, tl)
|
||||
DEF_HELPER_2(csrwr_asid, i64, env, tl)
|
||||
|
||||
@@ -83,6 +83,7 @@ void loongarch_csr_translate_init(void)
|
||||
SET_CSR_FUNC(TCFG, NULL, gen_helper_csrwr_tcfg);
|
||||
SET_CSR_FUNC(TVAL, gen_helper_csrrd_tval, NULL);
|
||||
SET_CSR_FUNC(TICLR, NULL, gen_helper_csrwr_ticlr);
|
||||
SET_CSR_FUNC(MSGIR, gen_helper_csrrd_msgir, NULL);
|
||||
}
|
||||
#undef SET_CSR_FUNC
|
||||
|
||||
|
||||
Reference in New Issue
Block a user