pull-loongarch-20250619

-----BEGIN PGP SIGNATURE-----
 
 iLMEAAEIAB0WIQTKRzxE1qCcGJoZP81FK5aFKyaCFgUCaFPPIgAKCRBFK5aFKyaC
 Fq67BACc5EYLK/T0Q2DxDmI84ZmK83GBAsQoB/81CLCDwA4ihotLAjqTB1liKFvY
 oFexqza3GBxpiyyw+zAUyrx1X/arnSrCAlgPOF2SIZgj1WnHm/jZb+8mdpgFGZc5
 6TkB4Dr5rmSa8OJLYIiC7gKYu9K3zEO/Dprgx9nj3D4tb8xRDQ==
 =601X
 -----END PGP SIGNATURE-----

Merge tag 'pull-loongarch-20250619' of https://github.com/gaosong715/qemu into staging

pull-loongarch-20250619

# -----BEGIN PGP SIGNATURE-----
#
# iLMEAAEIAB0WIQTKRzxE1qCcGJoZP81FK5aFKyaCFgUCaFPPIgAKCRBFK5aFKyaC
# Fq67BACc5EYLK/T0Q2DxDmI84ZmK83GBAsQoB/81CLCDwA4ihotLAjqTB1liKFvY
# oFexqza3GBxpiyyw+zAUyrx1X/arnSrCAlgPOF2SIZgj1WnHm/jZb+8mdpgFGZc5
# 6TkB4Dr5rmSa8OJLYIiC7gKYu9K3zEO/Dprgx9nj3D4tb8xRDQ==
# =601X
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 19 Jun 2025 04:49:38 EDT
# 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-20250619' of https://github.com/gaosong715/qemu:
  target/loongarch: fix vldi/xvldi raise wrong error
  hw/loongarch/virt: Add kernel irqchip support
  hw/loongarch/virt: Disable emulation with IOCSR misc register
  target/loongarch: Report error with split kernel_irqchip option
  hw/loongarch/virt: Add reset support for kernel irqchip
  hw/intc/loongarch_pch: Inject irq line interrupt to kernel
  hw/intc/loongarch_pch: Add kernel irqchip save and restore function
  hw/intc/loongarch_pch: Add kernel irqchip realize function
  hw/intc/loongarch_pch_msi: Inject MSI interrupt to kernel
  hw/intc/loongarch_ipi: Add kernel irqchip save and restore function
  hw/intc/loongson_ipi: Add load and save interface with ipi_common class
  hw/intc/loongarch_ipi: Add kernel irqchip realize function
  hw/intc/loongarch_extioi: Add kernel irqchip save and restore function
  hw/intc/loongarch_extioi: Add kernel irqchip realize function

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-06-23 15:14:56 -04:00
commit d01d42ccc9
18 changed files with 563 additions and 43 deletions

View file

@ -12,6 +12,7 @@
#include "hw/irq.h"
#include "hw/loongarch/virt.h"
#include "system/address-spaces.h"
#include "system/kvm.h"
#include "hw/intc/loongarch_extioi.h"
#include "trace.h"
@ -351,23 +352,29 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
return;
}
for (i = 0; i < EXTIOI_IRQS; i++) {
sysbus_init_irq(sbd, &s->irq[i]);
}
qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
s, "extioi_system_mem", 0x900);
sysbus_init_mmio(sbd, &s->extioi_system_mem);
if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
s, "extioi_virt", EXTIOI_VIRT_SIZE);
sysbus_init_mmio(sbd, &s->virt_extend);
s->features |= EXTIOI_VIRT_HAS_FEATURES;
} else {
s->status |= BIT(EXTIOI_ENABLE);
}
if (kvm_irqchip_in_kernel()) {
kvm_extioi_realize(dev, errp);
} else {
for (i = 0; i < EXTIOI_IRQS; i++) {
sysbus_init_irq(sbd, &s->irq[i]);
}
qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
s, "extioi_system_mem", 0x900);
sysbus_init_mmio(sbd, &s->extioi_system_mem);
if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
s, "extioi_virt", EXTIOI_VIRT_SIZE);
sysbus_init_mmio(sbd, &s->virt_extend);
}
}
}
static void loongarch_extioi_unrealize(DeviceState *dev)
@ -384,6 +391,19 @@ static void loongarch_extioi_reset_hold(Object *obj, ResetType type)
if (lec->parent_phases.hold) {
lec->parent_phases.hold(obj, type);
}
if (kvm_irqchip_in_kernel()) {
kvm_extioi_put(obj, 0);
}
}
static int vmstate_extioi_pre_save(void *opaque)
{
if (kvm_irqchip_in_kernel()) {
return kvm_extioi_get(opaque);
}
return 0;
}
static int vmstate_extioi_post_load(void *opaque, int version_id)
@ -391,6 +411,10 @@ static int vmstate_extioi_post_load(void *opaque, int version_id)
LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
int i, start_irq;
if (kvm_irqchip_in_kernel()) {
return kvm_extioi_put(opaque, version_id);
}
for (i = 0; i < (EXTIOI_IRQS / 4); i++) {
start_irq = i * 4;
extioi_update_sw_coremap(s, start_irq, s->coremap[i], false);
@ -416,6 +440,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, const void *data)
&lec->parent_unrealize);
resettable_class_set_parent_phases(rc, NULL, loongarch_extioi_reset_hold,
NULL, &lec->parent_phases);
lecc->pre_save = vmstate_extioi_pre_save;
lecc->post_load = vmstate_extioi_post_load;
}

View file

@ -0,0 +1,140 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* LoongArch EXTIOI interrupt kvm support
*
* Copyright (C) 2025 Loongson Technology Corporation Limited
*/
#include "qemu/osdep.h"
#include "qemu/typedefs.h"
#include "hw/intc/loongarch_extioi.h"
#include "linux/kvm.h"
#include "qapi/error.h"
#include "system/kvm.h"
static void kvm_extioi_access_reg(int fd, uint64_t addr, void *val, bool write)
{
kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
addr, val, write, &error_abort);
}
static void kvm_extioi_access_sw_state(int fd, uint64_t addr,
void *val, bool write)
{
kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS,
addr, val, write, &error_abort);
}
static void kvm_extioi_access_sw_status(void *opaque, bool write)
{
LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
int addr;
addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE;
kvm_extioi_access_sw_state(les->dev_fd, addr, &lecs->status, write);
}
static void kvm_extioi_access_regs(void *opaque, bool write)
{
LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
int fd = les->dev_fd;
int addr, offset, cpu;
for (addr = EXTIOI_NODETYPE_START; addr < EXTIOI_NODETYPE_END; addr += 4) {
offset = (addr - EXTIOI_NODETYPE_START) / 4;
kvm_extioi_access_reg(fd, addr, &lecs->nodetype[offset], write);
}
for (addr = EXTIOI_IPMAP_START; addr < EXTIOI_IPMAP_END; addr += 4) {
offset = (addr - EXTIOI_IPMAP_START) / 4;
kvm_extioi_access_reg(fd, addr, &lecs->ipmap[offset], write);
}
for (addr = EXTIOI_ENABLE_START; addr < EXTIOI_ENABLE_END; addr += 4) {
offset = (addr - EXTIOI_ENABLE_START) / 4;
kvm_extioi_access_reg(fd, addr, &lecs->enable[offset], write);
}
for (addr = EXTIOI_BOUNCE_START; addr < EXTIOI_BOUNCE_END; addr += 4) {
offset = (addr - EXTIOI_BOUNCE_START) / 4;
kvm_extioi_access_reg(fd, addr, &lecs->bounce[offset], write);
}
for (addr = EXTIOI_ISR_START; addr < EXTIOI_ISR_END; addr += 4) {
offset = (addr - EXTIOI_ISR_START) / 4;
kvm_extioi_access_reg(fd, addr, &lecs->isr[offset], write);
}
for (addr = EXTIOI_COREMAP_START; addr < EXTIOI_COREMAP_END; addr += 4) {
offset = (addr - EXTIOI_COREMAP_START) / 4;
kvm_extioi_access_reg(fd, addr, &lecs->coremap[offset], write);
}
for (cpu = 0; cpu < lecs->num_cpu; cpu++) {
for (addr = EXTIOI_COREISR_START;
addr < EXTIOI_COREISR_END; addr += 4) {
offset = (addr - EXTIOI_COREISR_START) / 4;
kvm_extioi_access_reg(fd, (cpu << 16) | addr,
&lecs->cpu[cpu].coreisr[offset], write);
}
}
}
int kvm_extioi_get(void *opaque)
{
kvm_extioi_access_regs(opaque, false);
kvm_extioi_access_sw_status(opaque, false);
return 0;
}
int kvm_extioi_put(void *opaque, int version_id)
{
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
int fd = les->dev_fd;
if (fd == 0) {
return 0;
}
kvm_extioi_access_regs(opaque, true);
kvm_extioi_access_sw_status(opaque, true);
kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED,
NULL, true, &error_abort);
return 0;
}
void kvm_extioi_realize(DeviceState *dev, Error **errp)
{
LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev);
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(dev);
int ret;
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_EIOINTC, false);
if (ret < 0) {
fprintf(stderr, "create KVM_LOONGARCH_EIOINTC failed: %s\n",
strerror(-ret));
abort();
}
les->dev_fd = ret;
ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU,
&lecs->num_cpu, true, NULL);
if (ret < 0) {
fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_NUM_CPU failed: %s\n",
strerror(-ret));
abort();
}
ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE,
&lecs->features, true, NULL);
if (ret < 0) {
fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_FEATURE failed: %s\n",
strerror(-ret));
abort();
}
}

View file

@ -11,6 +11,7 @@
#include "qapi/error.h"
#include "hw/intc/loongarch_ipi.h"
#include "hw/qdev-properties.h"
#include "system/kvm.h"
#include "target/loongarch/cpu.h"
static AddressSpace *get_iocsr_as(CPUState *cpu)
@ -91,6 +92,10 @@ static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
lics->cpu[i].ipi = lics;
qdev_init_gpio_out(dev, &lics->cpu[i].irq, 1);
}
if (kvm_irqchip_in_kernel()) {
kvm_ipi_realize(dev, errp);
}
}
static void loongarch_ipi_reset_hold(Object *obj, ResetType type)
@ -117,6 +122,10 @@ static void loongarch_ipi_reset_hold(Object *obj, ResetType type)
core->clear = 0;
memset(core->buf, 0, sizeof(core->buf));
}
if (kvm_irqchip_in_kernel()) {
kvm_ipi_put(obj, 0);
}
}
static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
@ -166,6 +175,24 @@ static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev,
core->cpu = NULL;
}
static int loongarch_ipi_pre_save(void *opaque)
{
if (kvm_irqchip_in_kernel()) {
return kvm_ipi_get(opaque);
}
return 0;
}
static int loongarch_ipi_post_load(void *opaque, int version_id)
{
if (kvm_irqchip_in_kernel()) {
return kvm_ipi_put(opaque, version_id);
}
return 0;
}
static void loongarch_ipi_class_init(ObjectClass *klass, const void *data)
{
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
@ -182,6 +209,8 @@ static void loongarch_ipi_class_init(ObjectClass *klass, const void *data)
licc->cpu_by_arch_id = loongarch_cpu_by_arch_id;
hc->plug = loongarch_ipi_cpu_plug;
hc->unplug = loongarch_ipi_cpu_unplug;
licc->pre_save = loongarch_ipi_pre_save;
licc->post_load = loongarch_ipi_post_load;
}
static const TypeInfo loongarch_ipi_types[] = {

View file

@ -0,0 +1,85 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* LoongArch IPI interrupt KVM support
*
* Copyright (C) 2025 Loongson Technology Corporation Limited
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/intc/loongarch_ipi.h"
#include "system/kvm.h"
#include "target/loongarch/cpu.h"
static void kvm_ipi_access_reg(int fd, uint64_t addr, uint32_t *val, bool write)
{
kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS,
addr, val, write, &error_abort);
}
static void kvm_ipi_access_regs(void *opaque, bool write)
{
LoongsonIPICommonState *ipi = (LoongsonIPICommonState *)opaque;
LoongarchIPIState *lis = LOONGARCH_IPI(opaque);
IPICore *core;
uint64_t attr;
int cpu, fd = lis->dev_fd;
if (fd == 0) {
return;
}
for (cpu = 0; cpu < ipi->num_cpu; cpu++) {
core = &ipi->cpu[cpu];
attr = (cpu << 16) | CORE_STATUS_OFF;
kvm_ipi_access_reg(fd, attr, &core->status, write);
attr = (cpu << 16) | CORE_EN_OFF;
kvm_ipi_access_reg(fd, attr, &core->en, write);
attr = (cpu << 16) | CORE_SET_OFF;
kvm_ipi_access_reg(fd, attr, &core->set, write);
attr = (cpu << 16) | CORE_CLEAR_OFF;
kvm_ipi_access_reg(fd, attr, &core->clear, write);
attr = (cpu << 16) | CORE_BUF_20;
kvm_ipi_access_reg(fd, attr, &core->buf[0], write);
attr = (cpu << 16) | CORE_BUF_28;
kvm_ipi_access_reg(fd, attr, &core->buf[2], write);
attr = (cpu << 16) | CORE_BUF_30;
kvm_ipi_access_reg(fd, attr, &core->buf[4], write);
attr = (cpu << 16) | CORE_BUF_38;
kvm_ipi_access_reg(fd, attr, &core->buf[6], write);
}
}
int kvm_ipi_get(void *opaque)
{
kvm_ipi_access_regs(opaque, false);
return 0;
}
int kvm_ipi_put(void *opaque, int version_id)
{
kvm_ipi_access_regs(opaque, true);
return 0;
}
void kvm_ipi_realize(DeviceState *dev, Error **errp)
{
LoongarchIPIState *lis = LOONGARCH_IPI(dev);
int ret;
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_IPI, false);
if (ret < 0) {
fprintf(stderr, "IPI KVM_CREATE_DEVICE failed: %s\n",
strerror(-ret));
abort();
}
lis->dev_fd = ret;
}

View file

@ -13,6 +13,7 @@
#include "hw/pci/msi.h"
#include "hw/misc/unimp.h"
#include "migration/vmstate.h"
#include "system/kvm.h"
#include "trace.h"
static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
@ -26,6 +27,15 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque;
int irq_num;
if (kvm_irqchip_in_kernel()) {
MSIMessage msg;
msg.address = addr;
msg.data = val;
kvm_irqchip_send_msi(kvm_state, msg);
return;
}
/*
* vector number is irq number from upper extioi intc
* need subtract irq base to get msi vector offset

View file

@ -10,6 +10,7 @@
#include "qemu/log.h"
#include "hw/irq.h"
#include "hw/intc/loongarch_pch_pic.h"
#include "system/kvm.h"
#include "trace.h"
#include "qapi/error.h"
@ -48,6 +49,11 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level)
assert(irq < s->irq_num);
trace_loongarch_pch_pic_irq_handler(irq, level);
if (kvm_irqchip_in_kernel()) {
kvm_set_irq(kvm_state, irq, !!level);
return;
}
if (s->intedge & mask) {
/* Edge triggered */
if (level) {
@ -258,6 +264,10 @@ static void loongarch_pic_reset_hold(Object *obj, ResetType type)
if (lpc->parent_phases.hold) {
lpc->parent_phases.hold(obj, type);
}
if (kvm_irqchip_in_kernel()) {
kvm_pic_put(obj, 0);
}
}
static void loongarch_pic_realize(DeviceState *dev, Error **errp)
@ -275,22 +285,49 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out(dev, s->parent_irq, s->irq_num);
qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num);
memory_region_init_io(&s->iomem, OBJECT(dev),
&loongarch_pch_pic_ops,
s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
if (kvm_irqchip_in_kernel()) {
kvm_pic_realize(dev, errp);
} else {
memory_region_init_io(&s->iomem, OBJECT(dev),
&loongarch_pch_pic_ops,
s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
}
}
static int loongarch_pic_pre_save(LoongArchPICCommonState *opaque)
{
if (kvm_irqchip_in_kernel()) {
return kvm_pic_get(opaque);
}
return 0;
}
static int loongarch_pic_post_load(LoongArchPICCommonState *opaque,
int version_id)
{
if (kvm_irqchip_in_kernel()) {
return kvm_pic_put(opaque, version_id);
}
return 0;
}
static void loongarch_pic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass);
LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
resettable_class_set_parent_phases(rc, NULL, loongarch_pic_reset_hold,
NULL, &lpc->parent_phases);
device_class_set_parent_realize(dc, loongarch_pic_realize,
&lpc->parent_realize);
lpcc->pre_save = loongarch_pic_pre_save;
lpcc->post_load = loongarch_pic_post_load;
}
static const TypeInfo loongarch_pic_types[] = {

View file

@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* LoongArch kvm pch pic interrupt support
*
* Copyright (C) 2025 Loongson Technology Corporation Limited
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/intc/loongarch_pch_pic.h"
#include "hw/loongarch/virt.h"
#include "hw/pci-host/ls7a.h"
#include "system/kvm.h"
static void kvm_pch_pic_access_reg(int fd, uint64_t addr, void *val, bool write)
{
kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS,
addr, val, write, &error_abort);
}
static void kvm_pch_pic_access(void *opaque, bool write)
{
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
LoongarchPICState *lps = LOONGARCH_PIC(opaque);
int fd = lps->dev_fd;
int addr, offset;
if (fd == 0) {
return;
}
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_MASK, &s->int_mask, write);
kvm_pch_pic_access_reg(fd, PCH_PIC_HTMSI_EN, &s->htmsi_en, write);
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_EDGE, &s->intedge, write);
kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL0, &s->auto_crtl0, write);
kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL1, &s->auto_crtl1, write);
for (addr = PCH_PIC_ROUTE_ENTRY;
addr < PCH_PIC_ROUTE_ENTRY_END; addr++) {
offset = addr - PCH_PIC_ROUTE_ENTRY;
kvm_pch_pic_access_reg(fd, addr, &s->route_entry[offset], write);
}
for (addr = PCH_PIC_HTMSI_VEC; addr < PCH_PIC_HTMSI_VEC_END; addr++) {
offset = addr - PCH_PIC_HTMSI_VEC;
kvm_pch_pic_access_reg(fd, addr, &s->htmsi_vector[offset], write);
}
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_REQUEST, &s->intirr, write);
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_STATUS, &s->intisr, write);
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_POL, &s->int_polarity, write);
}
int kvm_pic_get(void *opaque)
{
kvm_pch_pic_access(opaque, false);
return 0;
}
int kvm_pic_put(void *opaque, int version_id)
{
kvm_pch_pic_access(opaque, true);
return 0;
}
void kvm_pic_realize(DeviceState *dev, Error **errp)
{
LoongarchPICState *lps = LOONGARCH_PIC(dev);
uint64_t pch_pic_base = VIRT_PCH_REG_BASE;
int ret;
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_PCHPIC, false);
if (ret < 0) {
fprintf(stderr, "Create KVM_LOONGARCH_PCHPIC failed: %s\n",
strerror(-ret));
abort();
}
lps->dev_fd = ret;
ret = kvm_device_access(lps->dev_fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL,
KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT,
&pch_pic_base, true, NULL);
if (ret < 0) {
fprintf(stderr, "KVM_LOONGARCH_PCH_PIC_INIT failed: %s\n",
strerror(-ret));
abort();
}
}

View file

@ -11,6 +11,7 @@
#include "hw/irq.h"
#include "qemu/log.h"
#include "migration/vmstate.h"
#include "system/kvm.h"
#include "trace.h"
MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
@ -255,6 +256,10 @@ static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
if (kvm_irqchip_in_kernel()) {
return;
}
memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
&loongson_ipi_iocsr_ops,
s, "loongson_ipi_iocsr", 0x48);
@ -277,10 +282,38 @@ static void loongson_ipi_common_unrealize(DeviceState *dev)
g_free(s->cpu);
}
static int loongson_ipi_common_pre_save(void *opaque)
{
IPICore *ipicore = (IPICore *)opaque;
LoongsonIPICommonState *s = ipicore->ipi;
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s);
if (licc->pre_save) {
return licc->pre_save(s);
}
return 0;
}
static int loongson_ipi_common_post_load(void *opaque, int version_id)
{
IPICore *ipicore = (IPICore *)opaque;
LoongsonIPICommonState *s = ipicore->ipi;
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s);
if (licc->post_load) {
return licc->post_load(s, version_id);
}
return 0;
}
static const VMStateDescription vmstate_ipi_core = {
.name = "ipi-single",
.version_id = 2,
.minimum_version_id = 2,
.pre_save = loongson_ipi_common_pre_save,
.post_load = loongson_ipi_common_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(status, IPICore),
VMSTATE_UINT32(en, IPICore),

View file

@ -71,6 +71,12 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c'))
specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_IPI'],
if_true: files('loongarch_ipi_kvm.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c', 'loongarch_pic_common.c'))
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_PCH_PIC'],
if_true: files('loongarch_pic_kvm.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
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'))

View file

@ -414,12 +414,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
lvms->ipi = ipi;
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
/* IPI iocsr memory region */
memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
/* Create EXTIOI device */
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
lvms->extioi = extioi;
@ -427,12 +421,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
}
sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
if (virt_is_veiointc_enabled(lvms)) {
memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
}
virt_cpu_irq_init(lvms);
pch_pic = qdev_new(TYPE_LOONGARCH_PIC);
@ -440,13 +428,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
d = SYS_BUS_DEVICE(pch_pic);
sysbus_realize_and_unref(d, &error_fatal);
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
sysbus_mmio_get_region(d, 0));
/* Connect pch_pic irqs to extioi */
for (i = 0; i < num; i++) {
qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
}
pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
start = num;
@ -456,12 +437,40 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
d = SYS_BUS_DEVICE(pch_msi);
sysbus_realize_and_unref(d, &error_fatal);
sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
for (i = 0; i < num; i++) {
/* Connect pch_msi irqs to extioi */
qdev_connect_gpio_out(DEVICE(d), i,
qdev_get_gpio_in(extioi, i + start));
}
if (kvm_irqchip_in_kernel()) {
kvm_loongarch_init_irq_routing();
} else {
/* IPI iocsr memory region */
memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
/* EXTIOI iocsr memory region */
memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
if (virt_is_veiointc_enabled(lvms)) {
memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
}
/* PCH_PIC memory region */
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
sysbus_mmio_get_region(SYS_BUS_DEVICE(pch_pic), 0));
/* Connect pch_pic irqs to extioi */
for (i = 0; i < VIRT_PCH_PIC_IRQ_NUM; i++) {
qdev_connect_gpio_out(DEVICE(pch_pic), i,
qdev_get_gpio_in(extioi, i));
}
for (i = VIRT_PCH_PIC_IRQ_NUM; i < EXTIOI_IRQS; i++) {
/* Connect pch_msi irqs to extioi */
qdev_connect_gpio_out(DEVICE(pch_msi), i - VIRT_PCH_PIC_IRQ_NUM,
qdev_get_gpio_in(extioi, i));
}
}
virt_devices_init(pch_pic, lvms);
}
@ -522,6 +531,10 @@ static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
switch (addr) {
case MISC_FUNC_REG:
if (kvm_irqchip_in_kernel()) {
return MEMTX_OK;
}
if (!virt_is_veiointc_enabled(lvms)) {
return MEMTX_OK;
}
@ -572,6 +585,10 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
ret = 0x303030354133ULL; /* "3A5000" */
break;
case MISC_FUNC_REG:
if (kvm_irqchip_in_kernel()) {
return MEMTX_OK;
}
if (!virt_is_veiointc_enabled(lvms)) {
ret |= BIT_ULL(IOCSRM_EXTIOI_EN);
break;

View file

@ -15,6 +15,7 @@ OBJECT_DECLARE_TYPE(LoongArchExtIOIState, LoongArchExtIOIClass, LOONGARCH_EXTIOI
struct LoongArchExtIOIState {
LoongArchExtIOICommonState parent_obj;
int dev_fd;
};
struct LoongArchExtIOIClass {
@ -25,4 +26,8 @@ struct LoongArchExtIOIClass {
ResettablePhases parent_phases;
};
void kvm_extioi_realize(DeviceState *dev, Error **errp);
int kvm_extioi_get(void *opaque);
int kvm_extioi_put(void *opaque, int version_id);
#endif /* LOONGARCH_EXTIOI_H */

View file

@ -16,6 +16,7 @@ OBJECT_DECLARE_TYPE(LoongarchIPIState, LoongarchIPIClass, LOONGARCH_IPI)
struct LoongarchIPIState {
LoongsonIPICommonState parent_obj;
int dev_fd;
};
struct LoongarchIPIClass {
@ -24,4 +25,8 @@ struct LoongarchIPIClass {
ResettablePhases parent_phases;
};
void kvm_ipi_realize(DeviceState *dev, Error **errp);
int kvm_ipi_get(void *opaque);
int kvm_ipi_put(void *opaque, int version_id);
#endif

View file

@ -16,6 +16,7 @@ OBJECT_DECLARE_TYPE(LoongarchPICState, LoongarchPICClass, LOONGARCH_PIC)
struct LoongarchPICState {
LoongArchPICCommonState parent_obj;
int dev_fd;
};
struct LoongarchPICClass {
@ -25,4 +26,8 @@ struct LoongarchPICClass {
ResettablePhases parent_phases;
};
void kvm_pic_realize(DeviceState *dev, Error **errp);
int kvm_pic_get(void *opaque);
int kvm_pic_put(void *opaque, int version_id);
#endif /* HW_LOONGARCH_PCH_PIC_H */

View file

@ -23,6 +23,7 @@
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
#define PCH_PIC_HTMSI_VEC 0x200
#define PCH_PIC_HTMSI_VEC_END 0x23f
#define PCH_PIC_INT_REQUEST 0x380
#define PCH_PIC_INT_STATUS 0x3a0
#define PCH_PIC_INT_POL 0x3e0

View file

@ -48,6 +48,8 @@ struct LoongsonIPICommonClass {
AddressSpace *(*get_iocsr_as)(CPUState *cpu);
int (*cpu_by_arch_id)(LoongsonIPICommonState *lics, int64_t id,
int *index, CPUState **pcs);
int (*pre_save)(void *opaque);
int (*post_load)(void *opaque, int version_id);
};
MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,

View file

@ -503,5 +503,6 @@ static inline void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
{
}
#endif
void kvm_loongarch_init_irq_routing(void);
#endif /* LOONGARCH_CPU_H */

View file

@ -1240,6 +1240,22 @@ void kvm_arch_init_irq_routing(KVMState *s)
{
}
void kvm_loongarch_init_irq_routing(void)
{
int i;
kvm_async_interrupts_allowed = true;
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
if (kvm_has_gsi_routing()) {
for (i = 0; i < KVM_IRQCHIP_NUM_PINS; ++i) {
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
}
kvm_gsi_routing_allowed = true;
kvm_irqchip_commit_routes(kvm_state);
}
}
int kvm_arch_get_default_type(MachineState *ms)
{
return 0;
@ -1253,7 +1269,12 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
int kvm_arch_irqchip_create(KVMState *s)
{
return 0;
if (kvm_kernel_irqchip_split()) {
error_report("kernel_irqchip=split is not supported on LoongArch");
exit(1);
}
return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
}
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)

View file

@ -3465,7 +3465,7 @@ TRANS(xvmsknz_b, LASX, gen_xx, gen_helper_vmsknz_b)
static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm)
{
int mode;
uint64_t data, t;
uint64_t data = 0, t;
/*
* imm bit [11:8] is mode, mode value is 0-12.
@ -3570,17 +3570,26 @@ static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm)
}
break;
default:
generate_exception(ctx, EXCCODE_INE);
g_assert_not_reached();
}
return data;
}
static bool check_valid_vldi_mode(arg_vldi *a)
{
return extract32(a->imm, 8, 4) <= 12;
}
static bool gen_vldi(DisasContext *ctx, arg_vldi *a, uint32_t oprsz)
{
int sel, vece;
uint64_t value;
if (!check_valid_vldi_mode(a)) {
generate_exception(ctx, EXCCODE_INE);
return true;
}
if (!check_vec(ctx, oprsz)) {
return true;
}