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:
Richard Henderson
2025-09-28 09:00:36 -07:00
16 changed files with 499 additions and 27 deletions
+3
View File
@@ -109,3 +109,6 @@ config LOONGARCH_PCH_MSI
config LOONGARCH_EXTIOI
bool
config LOONGARCH_DINTC
bool
+212
View File
@@ -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)
+1
View File
@@ -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'))
+1
View File
@@ -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
View File
@@ -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
+36
View File
@@ -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;
};
+34
View File
@@ -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) {
+2
View File
@@ -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
+7 -2
View File
@@ -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)
+29
View File
@@ -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
View File
@@ -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 */
+5
View File
@@ -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)
+23 -2
View File
@@ -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
}
};
+21
View File
@@ -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;
+1
View File
@@ -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