aboutsummaryrefslogtreecommitdiff
path: root/hw/loongarch/virt.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/loongarch/virt.c')
-rw-r--r--hw/loongarch/virt.c110
1 files changed, 109 insertions, 1 deletions
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index bd5cff1..c176042 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -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