From ab9bbee3c7da3d5dcce03bd7379bc7d05243a9af Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:33 +0800 Subject: [PATCH 01/17] hw/intc/loongarch_pch: Modify name of some registers For some registers with width 8 bytes, its name is something like PCH_PIC_INT_ID_LO and PCH_PIC_INT_ID_HI. From hardware manual, register name is PCH_PIC_INT_ID instead. Here name PCH_PIC_INT_ID is used, and PCH_PIC_INT_ID + 4 is used for PCH_PIC_INT_ID_HI. Signed-off-by: Bibo Mao Reviewed-by: Clement Mathieu--Drif Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-2-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 50 +++++++++++++------------- hw/loongarch/virt.c | 2 +- include/hw/intc/loongarch_pic_common.h | 27 +++++--------- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 834096265a..748213d5a1 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -79,10 +79,10 @@ static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, uint32_t offset = addr & 0xfff; switch (offset) { - case PCH_PIC_INT_ID_LO: + case PCH_PIC_INT_ID: val = PCH_PIC_INT_ID_VAL; break; - case PCH_PIC_INT_ID_HI: + case PCH_PIC_INT_ID + 4: /* * With 7A1000 manual * bit 0-15 pch irqchip version @@ -90,28 +90,29 @@ static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, */ val = deposit32(PCH_PIC_INT_ID_VER, 16, 16, s->irq_num - 1); break; - case PCH_PIC_INT_MASK_LO: + case PCH_PIC_INT_MASK: val = (uint32_t)s->int_mask; break; - case PCH_PIC_INT_MASK_HI: + case PCH_PIC_INT_MASK + 4: val = s->int_mask >> 32; break; - case PCH_PIC_INT_EDGE_LO: + case PCH_PIC_INT_EDGE: val = (uint32_t)s->intedge; break; - case PCH_PIC_INT_EDGE_HI: + case PCH_PIC_INT_EDGE + 4: val = s->intedge >> 32; break; - case PCH_PIC_HTMSI_EN_LO: + case PCH_PIC_HTMSI_EN: val = (uint32_t)s->htmsi_en; break; - case PCH_PIC_HTMSI_EN_HI: + case PCH_PIC_HTMSI_EN + 4: val = s->htmsi_en >> 32; break; - case PCH_PIC_AUTO_CTRL0_LO: - case PCH_PIC_AUTO_CTRL0_HI: - case PCH_PIC_AUTO_CTRL1_LO: - case PCH_PIC_AUTO_CTRL1_HI: + case PCH_PIC_AUTO_CTRL0: + case PCH_PIC_AUTO_CTRL0 + 4: + case PCH_PIC_AUTO_CTRL1: + case PCH_PIC_AUTO_CTRL1 + 4: + /* PCH PIC connect to EXTIOI always, discard auto_ctrl access */ break; default: break; @@ -140,7 +141,7 @@ static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, trace_loongarch_pch_pic_low_writew(size, addr, data); switch (offset) { - case PCH_PIC_INT_MASK_LO: + case PCH_PIC_INT_MASK: old = s->int_mask; s->int_mask = get_writew_val(old, data, 0); old_valid = (uint32_t)old; @@ -151,7 +152,7 @@ static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, pch_pic_update_irq(s, (~old_valid & data), 0); } break; - case PCH_PIC_INT_MASK_HI: + case PCH_PIC_INT_MASK + 4: old = s->int_mask; s->int_mask = get_writew_val(old, data, 1); old_valid = (uint32_t)(old >> 32); @@ -164,20 +165,20 @@ static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, pch_pic_update_irq(s, int_mask << 32, 0); } break; - case PCH_PIC_INT_EDGE_LO: + case PCH_PIC_INT_EDGE: s->intedge = get_writew_val(s->intedge, data, 0); break; - case PCH_PIC_INT_EDGE_HI: + case PCH_PIC_INT_EDGE + 4: s->intedge = get_writew_val(s->intedge, data, 1); break; - case PCH_PIC_INT_CLEAR_LO: + case PCH_PIC_INT_CLEAR: if (s->intedge & data) { s->intirr &= (~data); pch_pic_update_irq(s, data, 0); s->intisr &= (~data); } break; - case PCH_PIC_INT_CLEAR_HI: + case PCH_PIC_INT_CLEAR + 4: value <<= 32; if (s->intedge & value) { s->intirr &= (~value); @@ -185,16 +186,17 @@ static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, s->intisr &= (~value); } break; - case PCH_PIC_HTMSI_EN_LO: + case PCH_PIC_HTMSI_EN: s->htmsi_en = get_writew_val(s->htmsi_en, data, 0); break; - case PCH_PIC_HTMSI_EN_HI: + case PCH_PIC_HTMSI_EN + 4: s->htmsi_en = get_writew_val(s->htmsi_en, data, 1); break; - case PCH_PIC_AUTO_CTRL0_LO: - case PCH_PIC_AUTO_CTRL0_HI: - case PCH_PIC_AUTO_CTRL1_LO: - case PCH_PIC_AUTO_CTRL1_HI: + case PCH_PIC_AUTO_CTRL0: + case PCH_PIC_AUTO_CTRL0 + 4: + case PCH_PIC_AUTO_CTRL1: + case PCH_PIC_AUTO_CTRL1 + 4: + /* discard auto_ctrl access */ break; default: break; diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 7ad7fb68ff..8a4958aade 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -433,7 +433,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, sysbus_mmio_get_region(d, 1)); memory_region_add_subregion(get_system_memory(), - VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, + VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS, sysbus_mmio_get_region(d, 2)); /* Connect pch_pic irqs to extioi */ diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index d301377cd7..8826d15aa7 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -12,28 +12,19 @@ #define PCH_PIC_INT_ID_VAL 0x7000000UL #define PCH_PIC_INT_ID_VER 0x1UL -#define PCH_PIC_INT_ID_LO 0x00 -#define PCH_PIC_INT_ID_HI 0x04 -#define PCH_PIC_INT_MASK_LO 0x20 -#define PCH_PIC_INT_MASK_HI 0x24 -#define PCH_PIC_HTMSI_EN_LO 0x40 -#define PCH_PIC_HTMSI_EN_HI 0x44 -#define PCH_PIC_INT_EDGE_LO 0x60 -#define PCH_PIC_INT_EDGE_HI 0x64 -#define PCH_PIC_INT_CLEAR_LO 0x80 -#define PCH_PIC_INT_CLEAR_HI 0x84 -#define PCH_PIC_AUTO_CTRL0_LO 0xc0 -#define PCH_PIC_AUTO_CTRL0_HI 0xc4 -#define PCH_PIC_AUTO_CTRL1_LO 0xe0 -#define PCH_PIC_AUTO_CTRL1_HI 0xe4 +#define PCH_PIC_INT_ID 0x00 +#define PCH_PIC_INT_MASK 0x20 +#define PCH_PIC_HTMSI_EN 0x40 +#define PCH_PIC_INT_EDGE 0x60 +#define PCH_PIC_INT_CLEAR 0x80 +#define PCH_PIC_AUTO_CTRL0 0xc0 +#define PCH_PIC_AUTO_CTRL1 0xe0 #define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100 #define PCH_PIC_ROUTE_ENTRY_END 0x13f #define PCH_PIC_HTMSI_VEC_OFFSET 0x200 #define PCH_PIC_HTMSI_VEC_END 0x23f -#define PCH_PIC_INT_STATUS_LO 0x3a0 -#define PCH_PIC_INT_STATUS_HI 0x3a4 -#define PCH_PIC_INT_POL_LO 0x3e0 -#define PCH_PIC_INT_POL_HI 0x3e4 +#define PCH_PIC_INT_STATUS 0x3a0 +#define PCH_PIC_INT_POL 0x3e0 #define STATUS_LO_START 0 #define STATUS_HI_START 0x4 From 4f0f2ab5640efe7f27b193f2bf66656890d6143f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:34 +0800 Subject: [PATCH 02/17] hw/intc/loongarch_pch: Modify register name PCH_PIC_xxx_OFFSET with PCH_PIC_xxx Macro PCH_PIC_HTMSI_VEC_OFFSET and PCH_PIC_ROUTE_ENTRY_OFFSET is renamed as PCH_PIC_HTMSI_VEC and PCH_PIC_ROUTE_ENTRY separately, it is easier to understand. Signed-off-by: Bibo Mao Reviewed-by: Clement Mathieu--Drif Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-3-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 20 ++++++++++---------- hw/loongarch/virt.c | 2 +- include/hw/intc/loongarch_pic_common.h | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 748213d5a1..52ae360fdc 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -263,18 +263,18 @@ static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint64_t val = 0; - uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY; int64_t offset_tmp; switch (offset) { - case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: - offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; + case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: + offset_tmp = offset - PCH_PIC_HTMSI_VEC; if (offset_tmp >= 0 && offset_tmp < 64) { val = s->htmsi_vector[offset_tmp]; } break; - case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: - offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; + case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY; if (offset_tmp >= 0 && offset_tmp < 64) { val = s->route_entry[offset_tmp]; } @@ -292,19 +292,19 @@ static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); int32_t offset_tmp; - uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY; trace_loongarch_pch_pic_writeb(size, addr, data); switch (offset) { - case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: - offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; + case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: + offset_tmp = offset - PCH_PIC_HTMSI_VEC; if (offset_tmp >= 0 && offset_tmp < 64) { s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); } break; - case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: - offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; + case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY; if (offset_tmp >= 0 && offset_tmp < 64) { s->route_entry[offset_tmp] = (uint8_t)(data & 0xff); } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 8a4958aade..ebcef0a92b 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -430,7 +430,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, sysbus_mmio_get_region(d, 0)); memory_region_add_subregion(get_system_memory(), - VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, + VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY, sysbus_mmio_get_region(d, 1)); memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS, diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index 8826d15aa7..caf712eae0 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -19,9 +19,9 @@ #define PCH_PIC_INT_CLEAR 0x80 #define PCH_PIC_AUTO_CTRL0 0xc0 #define PCH_PIC_AUTO_CTRL1 0xe0 -#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100 +#define PCH_PIC_ROUTE_ENTRY 0x100 #define PCH_PIC_ROUTE_ENTRY_END 0x13f -#define PCH_PIC_HTMSI_VEC_OFFSET 0x200 +#define PCH_PIC_HTMSI_VEC 0x200 #define PCH_PIC_HTMSI_VEC_END 0x23f #define PCH_PIC_INT_STATUS 0x3a0 #define PCH_PIC_INT_POL 0x3e0 From e95e4e818b7821a66c4346761c6f63b93177685a Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:35 +0800 Subject: [PATCH 03/17] hw/intc/loongarch_pch: Remove some duplicate macro The meaning of macro definition STATUS_LO_START is simliar with PCH_PIC_INT_STATUS, only that offset is different, the same for macro POL_LO_START. Now remove these duplicated macro definitions. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-4-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 20 ++++++++++---------- include/hw/intc/loongarch_pic_common.h | 5 ----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 52ae360fdc..17ab071a6b 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -208,19 +208,19 @@ static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint64_t val = 0; - uint32_t offset = addr & 0xfff; + uint32_t offset = addr + PCH_PIC_INT_STATUS; switch (offset) { - case STATUS_LO_START: + case PCH_PIC_INT_STATUS: val = (uint32_t)(s->intisr & (~s->int_mask)); break; - case STATUS_HI_START: + case PCH_PIC_INT_STATUS + 4: val = (s->intisr & (~s->int_mask)) >> 32; break; - case POL_LO_START: + case PCH_PIC_INT_POL: val = (uint32_t)s->int_polarity; break; - case POL_HI_START: + case PCH_PIC_INT_POL + 4: val = s->int_polarity >> 32; break; default: @@ -236,21 +236,21 @@ static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint32_t offset, data = (uint32_t)value; - offset = addr & 0xfff; + offset = addr + PCH_PIC_INT_STATUS; trace_loongarch_pch_pic_high_writew(size, addr, data); switch (offset) { - case STATUS_LO_START: + case PCH_PIC_INT_STATUS: s->intisr = get_writew_val(s->intisr, data, 0); break; - case STATUS_HI_START: + case PCH_PIC_INT_STATUS + 4: s->intisr = get_writew_val(s->intisr, data, 1); break; - case POL_LO_START: + case PCH_PIC_INT_POL: s->int_polarity = get_writew_val(s->int_polarity, data, 0); break; - case POL_HI_START: + case PCH_PIC_INT_POL + 4: s->int_polarity = get_writew_val(s->int_polarity, data, 1); break; default: diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index caf712eae0..2b4b483c63 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -26,11 +26,6 @@ #define PCH_PIC_INT_STATUS 0x3a0 #define PCH_PIC_INT_POL 0x3e0 -#define STATUS_LO_START 0 -#define STATUS_HI_START 0x4 -#define POL_LO_START 0x40 -#define POL_HI_START 0x44 - #define TYPE_LOONGARCH_PIC_COMMON "loongarch_pic_common" OBJECT_DECLARE_TYPE(LoongArchPICCommonState, LoongArchPICCommonClass, LOONGARCH_PIC_COMMON) From c2658b0de5cb24b6eb49751c92380d30f1d9258f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:36 +0800 Subject: [PATCH 04/17] hw/intc/loongarch_pch: Set version information at initial stage Register PCH_PIC_INT_ID constains version and supported irq number information, and it is read only register. The detailed value can be set at initial stage, rather than read callback. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-5-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 9 ++------- hw/intc/loongarch_pic_common.c | 13 +++++++++++++ include/hw/intc/loongarch_pic_common.h | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 17ab071a6b..f732c292f8 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -80,15 +80,10 @@ static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, switch (offset) { case PCH_PIC_INT_ID: - val = PCH_PIC_INT_ID_VAL; + val = s->id.data & UINT_MAX; break; case PCH_PIC_INT_ID + 4: - /* - * With 7A1000 manual - * bit 0-15 pch irqchip version - * bit 16-31 irq number supported with pch irqchip - */ - val = deposit32(PCH_PIC_INT_ID_VER, 16, 16, s->irq_num - 1); + val = s->id.data >> 32; break; case PCH_PIC_INT_MASK: val = (uint32_t)s->int_mask; diff --git a/hw/intc/loongarch_pic_common.c b/hw/intc/loongarch_pic_common.c index 6dccacc741..de170501cf 100644 --- a/hw/intc/loongarch_pic_common.c +++ b/hw/intc/loongarch_pic_common.c @@ -49,6 +49,19 @@ static void loongarch_pic_common_reset_hold(Object *obj, ResetType type) LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(obj); int i; + /* + * With Loongson 7A1000 user manual + * Chapter 5.2 "Description of Interrupt-related Registers" + * + * Interrupt controller identification register 1 + * Bit 24-31 Interrupt Controller ID + * Interrupt controller identification register 2 + * Bit 0-7 Interrupt Controller version number + * Bit 16-23 The number of interrupt sources supported + */ + s->id.desc.id = PCH_PIC_INT_ID_VAL; + s->id.desc.version = PCH_PIC_INT_ID_VER; + s->id.desc.irq_num = s->irq_num - 1; s->int_mask = UINT64_MAX; s->htmsi_en = 0x0; s->intedge = 0x0; diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index 2b4b483c63..7a9a2bdd46 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -10,9 +10,9 @@ #include "hw/pci-host/ls7a.h" #include "hw/sysbus.h" -#define PCH_PIC_INT_ID_VAL 0x7000000UL -#define PCH_PIC_INT_ID_VER 0x1UL #define PCH_PIC_INT_ID 0x00 +#define PCH_PIC_INT_ID_VAL 0x7 +#define PCH_PIC_INT_ID_VER 0x1 #define PCH_PIC_INT_MASK 0x20 #define PCH_PIC_HTMSI_EN 0x40 #define PCH_PIC_INT_EDGE 0x60 @@ -30,10 +30,23 @@ OBJECT_DECLARE_TYPE(LoongArchPICCommonState, LoongArchPICCommonClass, LOONGARCH_PIC_COMMON) +union LoongArchPIC_ID { + struct { + uint8_t _reserved_0[3]; + uint8_t id; + uint8_t version; + uint8_t _reserved_1; + uint8_t irq_num; + uint8_t _reserved_2; + } QEMU_PACKED desc; + uint64_t data; +}; + struct LoongArchPICCommonState { SysBusDevice parent_obj; qemu_irq parent_irq[64]; + union LoongArchPIC_ID id; /* 0x00 interrupt ID register */ uint64_t int_mask; /* 0x020 interrupt mask register */ uint64_t htmsi_en; /* 0x040 1=msi */ uint64_t intedge; /* 0x060 edge=1 level=0 */ From ab3ab67348b1e34630272b05f9f7f187fd6a1f8f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:37 +0800 Subject: [PATCH 05/17] hw/intc/loongarch_pch: Use relative address in MemoryRegionOps Parameter address for read and write callback in MemoryRegionOps is relative offset with base address of this MemoryRegionOps. It can be directly used as offset and offset calculation can be removed. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-6-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index f732c292f8..9b64bf938f 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -76,9 +76,8 @@ static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint64_t val = 0; - uint32_t offset = addr & 0xfff; - switch (offset) { + switch (addr) { case PCH_PIC_INT_ID: val = s->id.data & UINT_MAX; break; @@ -129,13 +128,12 @@ static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, uint64_t value, unsigned size) { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); - uint32_t offset, old_valid, data = (uint32_t)value; + uint32_t old_valid, data = (uint32_t)value; uint64_t old, int_mask; - offset = addr & 0xfff; trace_loongarch_pch_pic_low_writew(size, addr, data); - switch (offset) { + switch (addr) { case PCH_PIC_INT_MASK: old = s->int_mask; s->int_mask = get_writew_val(old, data, 0); @@ -203,9 +201,9 @@ static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint64_t val = 0; - uint32_t offset = addr + PCH_PIC_INT_STATUS; - switch (offset) { + addr += PCH_PIC_INT_STATUS; + switch (addr) { case PCH_PIC_INT_STATUS: val = (uint32_t)(s->intisr & (~s->int_mask)); break; @@ -230,12 +228,12 @@ static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, uint64_t value, unsigned size) { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); - uint32_t offset, data = (uint32_t)value; - offset = addr + PCH_PIC_INT_STATUS; + uint32_t data = (uint32_t)value; + addr += PCH_PIC_INT_STATUS; trace_loongarch_pch_pic_high_writew(size, addr, data); - switch (offset) { + switch (addr) { case PCH_PIC_INT_STATUS: s->intisr = get_writew_val(s->intisr, data, 0); break; @@ -258,18 +256,18 @@ static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint64_t val = 0; - uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY; int64_t offset_tmp; - switch (offset) { + addr += PCH_PIC_ROUTE_ENTRY; + switch (addr) { case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: - offset_tmp = offset - PCH_PIC_HTMSI_VEC; + offset_tmp = addr - PCH_PIC_HTMSI_VEC; if (offset_tmp >= 0 && offset_tmp < 64) { val = s->htmsi_vector[offset_tmp]; } break; case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: - offset_tmp = offset - PCH_PIC_ROUTE_ENTRY; + offset_tmp = addr - PCH_PIC_ROUTE_ENTRY; if (offset_tmp >= 0 && offset_tmp < 64) { val = s->route_entry[offset_tmp]; } @@ -287,19 +285,19 @@ static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); int32_t offset_tmp; - uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY; + addr += PCH_PIC_ROUTE_ENTRY; trace_loongarch_pch_pic_writeb(size, addr, data); - switch (offset) { + switch (addr) { case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: - offset_tmp = offset - PCH_PIC_HTMSI_VEC; + offset_tmp = addr - PCH_PIC_HTMSI_VEC; if (offset_tmp >= 0 && offset_tmp < 64) { s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); } break; case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: - offset_tmp = offset - PCH_PIC_ROUTE_ENTRY; + offset_tmp = addr - PCH_PIC_ROUTE_ENTRY; if (offset_tmp >= 0 && offset_tmp < 64) { s->route_entry[offset_tmp] = (uint8_t)(data & 0xff); } From 53339a8120d9be6a448f29dd1138bab2fa15e34d Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:38 +0800 Subject: [PATCH 06/17] hw/intc/loongarch_pch: Discard write operation with ISR register With the latest 7A1000 user manual, interrupt status register ISR is read only. Here discard write operation with ISR register. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-7-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 9b64bf938f..e6fcf645eb 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -234,12 +234,6 @@ static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, trace_loongarch_pch_pic_high_writew(size, addr, data); switch (addr) { - case PCH_PIC_INT_STATUS: - s->intisr = get_writew_val(s->intisr, data, 0); - break; - case PCH_PIC_INT_STATUS + 4: - s->intisr = get_writew_val(s->intisr, data, 1); - break; case PCH_PIC_INT_POL: s->int_polarity = get_writew_val(s->int_polarity, data, 0); break; From 9e29bf4e4c5d34ace0c75737f740f1f86236dba9 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:39 +0800 Subject: [PATCH 07/17] hw/intc/loongarch_pch: Use generic read callback for iomem32_low region For memory region iomem32_low, generic read callback is used. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-8-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 67 ++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index e6fcf645eb..599a27197f 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -7,6 +7,7 @@ #include "qemu/osdep.h" #include "qemu/bitops.h" +#include "qemu/log.h" #include "hw/irq.h" #include "hw/intc/loongarch_pch_pic.h" #include "trace.h" @@ -71,47 +72,73 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level) pch_pic_update_irq(s, mask, level); } -static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, - unsigned size) +static uint64_t pch_pic_read(void *opaque, hwaddr addr, uint64_t field_mask) { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint64_t val = 0; + uint32_t offset; + offset = addr & 7; + addr -= offset; switch (addr) { case PCH_PIC_INT_ID: - val = s->id.data & UINT_MAX; - break; - case PCH_PIC_INT_ID + 4: - val = s->id.data >> 32; + val = s->id.data; break; case PCH_PIC_INT_MASK: - val = (uint32_t)s->int_mask; - break; - case PCH_PIC_INT_MASK + 4: - val = s->int_mask >> 32; + val = s->int_mask; break; case PCH_PIC_INT_EDGE: - val = (uint32_t)s->intedge; - break; - case PCH_PIC_INT_EDGE + 4: - val = s->intedge >> 32; + val = s->intedge; break; case PCH_PIC_HTMSI_EN: - val = (uint32_t)s->htmsi_en; - break; - case PCH_PIC_HTMSI_EN + 4: - val = s->htmsi_en >> 32; + val = s->htmsi_en; break; case PCH_PIC_AUTO_CTRL0: - case PCH_PIC_AUTO_CTRL0 + 4: case PCH_PIC_AUTO_CTRL1: - case PCH_PIC_AUTO_CTRL1 + 4: /* PCH PIC connect to EXTIOI always, discard auto_ctrl access */ break; default: + qemu_log_mask(LOG_GUEST_ERROR, + "pch_pic_read: Bad address 0x%"PRIx64"\n", addr); break; } + return (val >> (offset * 8)) & field_mask; +} + +static uint64_t loongarch_pch_pic_read(void *opaque, hwaddr addr, + unsigned size) +{ + uint64_t val = 0; + + switch (size) { + case 1: + val = pch_pic_read(opaque, addr, UCHAR_MAX); + break; + case 2: + val = pch_pic_read(opaque, addr, USHRT_MAX); + break; + case 4: + val = pch_pic_read(opaque, addr, UINT_MAX); + break; + case 8: + val = pch_pic_read(opaque, addr, UINT64_MAX); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "loongarch_pch_pic_read: Bad size %d\n", size); + break; + } + + return val; +} + +static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, + unsigned size) +{ + uint64_t val; + + val = loongarch_pch_pic_read(opaque, addr, size); trace_loongarch_pch_pic_low_readw(size, addr, val); return val; } From 6dab13c4152b5b3c35b627483bfdce2d331d95f2 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:40 +0800 Subject: [PATCH 08/17] hw/intc/loongarch_pch: Use generic read callback for iomem32_high region Add register read operation emulation in generic read function loongarch_pch_pic_read(), and use this function for iomem32_high region. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-9-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 599a27197f..e477a6033b 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -97,6 +97,12 @@ static uint64_t pch_pic_read(void *opaque, hwaddr addr, uint64_t field_mask) case PCH_PIC_AUTO_CTRL1: /* PCH PIC connect to EXTIOI always, discard auto_ctrl access */ break; + case PCH_PIC_INT_STATUS: + val = s->intisr & (~s->int_mask); + break; + case PCH_PIC_INT_POL: + val = s->int_polarity; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "pch_pic_read: Bad address 0x%"PRIx64"\n", addr); @@ -226,27 +232,10 @@ static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, unsigned size) { - LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); - uint64_t val = 0; + uint64_t val; addr += PCH_PIC_INT_STATUS; - switch (addr) { - case PCH_PIC_INT_STATUS: - val = (uint32_t)(s->intisr & (~s->int_mask)); - break; - case PCH_PIC_INT_STATUS + 4: - val = (s->intisr & (~s->int_mask)) >> 32; - break; - case PCH_PIC_INT_POL: - val = (uint32_t)s->int_polarity; - break; - case PCH_PIC_INT_POL + 4: - val = s->int_polarity >> 32; - break; - default: - break; - } - + val = loongarch_pch_pic_read(opaque, addr, size); trace_loongarch_pch_pic_high_readw(size, addr, val); return val; } From 81de67213d29a401bc341abe75abd120ad22b25a Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:41 +0800 Subject: [PATCH 09/17] hw/intc/loongarch_pch: Use generic read callback for iomem8 region Add iomem8 region register read operation emulation in generic read function loongarch_pch_pic_read(), and use this function for iomem8 region. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-10-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index e477a6033b..dbfc178e5d 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -103,6 +103,12 @@ static uint64_t pch_pic_read(void *opaque, hwaddr addr, uint64_t field_mask) case PCH_PIC_INT_POL: val = s->int_polarity; break; + case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: + val = *(uint64_t *)(s->htmsi_vector + addr - PCH_PIC_HTMSI_VEC); + break; + case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: + val = *(uint64_t *)(s->route_entry + addr - PCH_PIC_ROUTE_ENTRY); + break; default: qemu_log_mask(LOG_GUEST_ERROR, "pch_pic_read: Bad address 0x%"PRIx64"\n", addr); @@ -264,28 +270,10 @@ static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, unsigned size) { - LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); - uint64_t val = 0; - int64_t offset_tmp; + uint64_t val; addr += PCH_PIC_ROUTE_ENTRY; - switch (addr) { - case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: - offset_tmp = addr - PCH_PIC_HTMSI_VEC; - if (offset_tmp >= 0 && offset_tmp < 64) { - val = s->htmsi_vector[offset_tmp]; - } - break; - case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: - offset_tmp = addr - PCH_PIC_ROUTE_ENTRY; - if (offset_tmp >= 0 && offset_tmp < 64) { - val = s->route_entry[offset_tmp]; - } - break; - default: - break; - } - + val = loongarch_pch_pic_read(opaque, addr, size); trace_loongarch_pch_pic_readb(size, addr, val); return val; } From f5dc4993fc5cee1a6fcfca1e4728af2fe965f98e Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:42 +0800 Subject: [PATCH 10/17] hw/intc/loongarch_pch: Use generic write callback for iomem32_low region For memory region iomem32_low, generic write callback is used. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-11-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 140 +++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 67 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index dbfc178e5d..07f9b07b09 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -118,6 +118,53 @@ static uint64_t pch_pic_read(void *opaque, hwaddr addr, uint64_t field_mask) return (val >> (offset * 8)) & field_mask; } +static void pch_pic_write(void *opaque, hwaddr addr, uint64_t value, + uint64_t field_mask) +{ + LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); + uint32_t offset; + uint64_t old, mask, data; + + offset = addr & 7; + addr -= offset; + mask = field_mask << (offset * 8); + data = (value & field_mask) << (offset * 8); + switch (addr) { + case PCH_PIC_INT_MASK: + old = s->int_mask; + s->int_mask = (old & ~mask) | data; + if (old & ~data) { + pch_pic_update_irq(s, old & ~data, 1); + } + + if (~old & data) { + pch_pic_update_irq(s, ~old & data, 0); + } + break; + case PCH_PIC_INT_EDGE: + s->intedge = (s->intedge & ~mask) | data; + break; + case PCH_PIC_INT_CLEAR: + if (s->intedge & data) { + s->intirr &= ~data; + pch_pic_update_irq(s, data, 0); + s->intisr &= ~data; + } + break; + case PCH_PIC_HTMSI_EN: + s->htmsi_en = (s->htmsi_en & ~mask) | data; + break; + case PCH_PIC_AUTO_CTRL0: + case PCH_PIC_AUTO_CTRL1: + /* Discard auto_ctrl access */ + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "pch_pic_write: Bad address 0x%"PRIx64"\n", addr); + break; + } +} + static uint64_t loongarch_pch_pic_read(void *opaque, hwaddr addr, unsigned size) { @@ -145,6 +192,30 @@ static uint64_t loongarch_pch_pic_read(void *opaque, hwaddr addr, return val; } +static void loongarch_pch_pic_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + switch (size) { + case 1: + pch_pic_write(opaque, addr, value, UCHAR_MAX); + break; + case 2: + pch_pic_write(opaque, addr, value, USHRT_MAX); + break; + break; + case 4: + pch_pic_write(opaque, addr, value, UINT_MAX); + break; + case 8: + pch_pic_write(opaque, addr, value, UINT64_MAX); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "loongarch_pch_pic_write: Bad size %d\n", size); + break; + } +} + static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, unsigned size) { @@ -166,73 +237,8 @@ static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi) static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); - uint32_t old_valid, data = (uint32_t)value; - uint64_t old, int_mask; - - trace_loongarch_pch_pic_low_writew(size, addr, data); - - switch (addr) { - case PCH_PIC_INT_MASK: - old = s->int_mask; - s->int_mask = get_writew_val(old, data, 0); - old_valid = (uint32_t)old; - if (old_valid & ~data) { - pch_pic_update_irq(s, (old_valid & ~data), 1); - } - if (~old_valid & data) { - pch_pic_update_irq(s, (~old_valid & data), 0); - } - break; - case PCH_PIC_INT_MASK + 4: - old = s->int_mask; - s->int_mask = get_writew_val(old, data, 1); - old_valid = (uint32_t)(old >> 32); - int_mask = old_valid & ~data; - if (int_mask) { - pch_pic_update_irq(s, int_mask << 32, 1); - } - int_mask = ~old_valid & data; - if (int_mask) { - pch_pic_update_irq(s, int_mask << 32, 0); - } - break; - case PCH_PIC_INT_EDGE: - s->intedge = get_writew_val(s->intedge, data, 0); - break; - case PCH_PIC_INT_EDGE + 4: - s->intedge = get_writew_val(s->intedge, data, 1); - break; - case PCH_PIC_INT_CLEAR: - if (s->intedge & data) { - s->intirr &= (~data); - pch_pic_update_irq(s, data, 0); - s->intisr &= (~data); - } - break; - case PCH_PIC_INT_CLEAR + 4: - value <<= 32; - if (s->intedge & value) { - s->intirr &= (~value); - pch_pic_update_irq(s, value, 0); - s->intisr &= (~value); - } - break; - case PCH_PIC_HTMSI_EN: - s->htmsi_en = get_writew_val(s->htmsi_en, data, 0); - break; - case PCH_PIC_HTMSI_EN + 4: - s->htmsi_en = get_writew_val(s->htmsi_en, data, 1); - break; - case PCH_PIC_AUTO_CTRL0: - case PCH_PIC_AUTO_CTRL0 + 4: - case PCH_PIC_AUTO_CTRL1: - case PCH_PIC_AUTO_CTRL1 + 4: - /* discard auto_ctrl access */ - break; - default: - break; - } + trace_loongarch_pch_pic_low_writew(size, addr, value); + loongarch_pch_pic_write(opaque, addr, value, size); } static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, From 2618d65036d4c05771727784ec665132689e2608 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:31:43 +0800 Subject: [PATCH 11/17] hw/intc/loongarch_pch: Use generic write callback for iomem32_high region Add iomem32_high region register write operation emulation in generic write function loongarch_pch_pic_write(), and use this function for iomem32_high region. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023148.1877287-12-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 07f9b07b09..50bcc23d7d 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -158,6 +158,9 @@ static void pch_pic_write(void *opaque, hwaddr addr, uint64_t value, case PCH_PIC_AUTO_CTRL1: /* Discard auto_ctrl access */ break; + case PCH_PIC_INT_POL: + s->int_polarity = (s->int_polarity & ~mask) | data; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "pch_pic_write: Bad address 0x%"PRIx64"\n", addr); @@ -226,14 +229,6 @@ static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, return val; } -static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi) -{ - uint64_t mask = 0xffffffff00000000; - uint64_t data = target; - - return hi ? (value & ~mask) | (data << 32) : (value & mask) | data; -} - static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, uint64_t value, unsigned size) { @@ -255,22 +250,9 @@ static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); - uint32_t data = (uint32_t)value; - addr += PCH_PIC_INT_STATUS; - trace_loongarch_pch_pic_high_writew(size, addr, data); - - switch (addr) { - case PCH_PIC_INT_POL: - s->int_polarity = get_writew_val(s->int_polarity, data, 0); - break; - case PCH_PIC_INT_POL + 4: - s->int_polarity = get_writew_val(s->int_polarity, data, 1); - break; - default: - break; - } + trace_loongarch_pch_pic_high_writew(size, addr, value); + loongarch_pch_pic_write(opaque, addr, value, size); } static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, From a6fdd0032ce5c7cd5c49a1bfbcedf6c08e136682 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:37:50 +0800 Subject: [PATCH 12/17] hw/intc/loongarch_pch: Use generic write callback for iomem8 region Add iomem8 region register write operation emulation in generic write function loongarch_pch_pic_write(), and use this function for iomem8 region. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 50bcc23d7d..556349a150 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -123,7 +123,7 @@ static void pch_pic_write(void *opaque, hwaddr addr, uint64_t value, { LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); uint32_t offset; - uint64_t old, mask, data; + uint64_t old, mask, data, *ptemp; offset = addr & 7; addr -= offset; @@ -161,6 +161,14 @@ static void pch_pic_write(void *opaque, hwaddr addr, uint64_t value, case PCH_PIC_INT_POL: s->int_polarity = (s->int_polarity & ~mask) | data; break; + case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: + ptemp = (uint64_t *)(s->htmsi_vector + addr - PCH_PIC_HTMSI_VEC); + *ptemp = (*ptemp & ~mask) | data; + break; + case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: + ptemp = (uint64_t *)(s->route_entry + addr - PCH_PIC_ROUTE_ENTRY); + *ptemp = (*ptemp & ~mask) | data; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "pch_pic_write: Bad address 0x%"PRIx64"\n", addr); @@ -269,28 +277,9 @@ static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); - int32_t offset_tmp; - addr += PCH_PIC_ROUTE_ENTRY; trace_loongarch_pch_pic_writeb(size, addr, data); - - switch (addr) { - case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: - offset_tmp = addr - PCH_PIC_HTMSI_VEC; - if (offset_tmp >= 0 && offset_tmp < 64) { - s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); - } - break; - case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: - offset_tmp = addr - PCH_PIC_ROUTE_ENTRY; - if (offset_tmp >= 0 && offset_tmp < 64) { - s->route_entry[offset_tmp] = (uint8_t)(data & 0xff); - } - break; - default: - break; - } + loongarch_pch_pic_write(opaque, addr, data, size); } static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = { From ba23cce0dcc75d2211f875e758305e3636e7c0a4 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:37:51 +0800 Subject: [PATCH 13/17] hw/intc/loongarch_pch: Use unified trace event for memory region ops Add trace event trace_loongarch_pch_pic_read(), replaces the following three events: trace_loongarch_pch_pic_low_readw() trace_loongarch_pch_pic_high_readw() trace_loongarch_pch_pic_readb() The similiar with write trace event. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-2-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 24 ++++++------------------ hw/intc/trace-events | 8 ++------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 556349a150..c06ef0df3f 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -200,12 +200,15 @@ static uint64_t loongarch_pch_pic_read(void *opaque, hwaddr addr, break; } + trace_loongarch_pch_pic_read(size, addr, val); return val; } static void loongarch_pch_pic_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { + trace_loongarch_pch_pic_write(size, addr, value); + switch (size) { case 1: pch_pic_write(opaque, addr, value, UCHAR_MAX); @@ -230,55 +233,40 @@ static void loongarch_pch_pic_write(void *opaque, hwaddr addr, static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, unsigned size) { - uint64_t val; - - val = loongarch_pch_pic_read(opaque, addr, size); - trace_loongarch_pch_pic_low_readw(size, addr, val); - return val; + return loongarch_pch_pic_read(opaque, addr, size); } static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - trace_loongarch_pch_pic_low_writew(size, addr, value); loongarch_pch_pic_write(opaque, addr, value, size); } static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, unsigned size) { - uint64_t val; - addr += PCH_PIC_INT_STATUS; - val = loongarch_pch_pic_read(opaque, addr, size); - trace_loongarch_pch_pic_high_readw(size, addr, val); - return val; + return loongarch_pch_pic_read(opaque, addr, size); } static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, uint64_t value, unsigned size) { addr += PCH_PIC_INT_STATUS; - trace_loongarch_pch_pic_high_writew(size, addr, value); loongarch_pch_pic_write(opaque, addr, value, size); } static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, unsigned size) { - uint64_t val; - addr += PCH_PIC_ROUTE_ENTRY; - val = loongarch_pch_pic_read(opaque, addr, size); - trace_loongarch_pch_pic_readb(size, addr, val); - return val; + return loongarch_pch_pic_read(opaque, addr, size); } static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, uint64_t data, unsigned size) { addr += PCH_PIC_ROUTE_ENTRY; - trace_loongarch_pch_pic_writeb(size, addr, data); loongarch_pch_pic_write(opaque, addr, data, size); } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 0ba9a02e73..334aa6a97b 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -314,12 +314,8 @@ loongson_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x loongson_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 # loongarch_pch_pic.c loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d" -loongarch_pch_pic_low_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 -loongarch_pch_pic_low_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 -loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 -loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 -loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 -loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 # loongarch_pch_msi.c loongarch_msi_set_irq(int irq_num) "set msi irq %d" From ce5efc2f44d1a2809c4adb2bad2083db29a03c71 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:37:52 +0800 Subject: [PATCH 14/17] hw/intc/loongarch_pch: Rename memory region iomem32_low with iomem Rename memory region iomem32_low with iomem, also change ops name as follows: loongarch_pch_pic_reg32_low_ops --> loongarch_pch_pic_ops loongarch_pch_pic_low_readw --> loongarch_pch_pic_read loongarch_pch_pic_low_writew --> loongarch_pch_pic_write Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-3-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 26 +++++++------------------- include/hw/intc/loongarch_pic_common.h | 2 +- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index c06ef0df3f..076b984d93 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -230,18 +230,6 @@ static void loongarch_pch_pic_write(void *opaque, hwaddr addr, } } -static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, - unsigned size) -{ - return loongarch_pch_pic_read(opaque, addr, size); -} - -static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - loongarch_pch_pic_write(opaque, addr, value, size); -} - static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, unsigned size) { @@ -270,9 +258,9 @@ static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, loongarch_pch_pic_write(opaque, addr, data, size); } -static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = { - .read = loongarch_pch_pic_low_readw, - .write = loongarch_pch_pic_low_writew, +static const MemoryRegionOps loongarch_pch_pic_ops = { + .read = loongarch_pch_pic_read, + .write = loongarch_pch_pic_write, .valid = { .min_access_size = 4, .max_access_size = 8, @@ -336,15 +324,15 @@ 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->iomem32_low, OBJECT(dev), - &loongarch_pch_pic_reg32_low_ops, - s, PCH_PIC_NAME(.reg32_part1), 0x100); + memory_region_init_io(&s->iomem, OBJECT(dev), + &loongarch_pch_pic_ops, + s, TYPE_LOONGARCH_PIC, 0x100); memory_region_init_io(&s->iomem8, OBJECT(dev), &loongarch_pch_pic_reg8_ops, s, PCH_PIC_NAME(.reg8), 0x2a0); memory_region_init_io(&s->iomem32_high, OBJECT(dev), &loongarch_pch_pic_reg32_high_ops, s, PCH_PIC_NAME(.reg32_part2), 0xc60); - sysbus_init_mmio(sbd, &s->iomem32_low); + sysbus_init_mmio(sbd, &s->iomem); sysbus_init_mmio(sbd, &s->iomem8); sysbus_init_mmio(sbd, &s->iomem32_high); diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index 7a9a2bdd46..dc03056227 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -65,7 +65,7 @@ struct LoongArchPICCommonState { uint8_t route_entry[64]; /* 0x100 - 0x138 */ uint8_t htmsi_vector[64]; /* 0x200 - 0x238 */ - MemoryRegion iomem32_low; + MemoryRegion iomem; MemoryRegion iomem32_high; MemoryRegion iomem8; unsigned int irq_num; From 2493ff01dc7c9b06a0579f6e66c3df69da4d5d23 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:37:53 +0800 Subject: [PATCH 15/17] hw/intc/loongarch_pch: Set flexible memory access size with iomem region The original iomem region only supports 4 bytes access size, set it ok with 1/2/4/8 bytes. Also unaligned memory access is not supported. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-4-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 076b984d93..e9126a0c1f 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -262,12 +262,19 @@ static const MemoryRegionOps loongarch_pch_pic_ops = { .read = loongarch_pch_pic_read, .write = loongarch_pch_pic_write, .valid = { - .min_access_size = 4, + .min_access_size = 1, .max_access_size = 8, + /* + * PCH PIC device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ + .unaligned = false, }, .impl = { - .min_access_size = 4, - .max_access_size = 4, + .min_access_size = 1, + .max_access_size = 8, }, .endianness = DEVICE_LITTLE_ENDIAN, }; From f4881c67ba8a852687566610949d8e9ab0542a31 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:37:54 +0800 Subject: [PATCH 16/17] hw/intc/loongarch_pch: Merge three memory region into one Since memory region iomem supports memory access size with 1/2/4/8, it can be used for memory region iomem8 and iomem32_high. Now remove memory region iomem8 and iomem32_high, merge them into iomem together. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-5-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 66 +------------------------- hw/loongarch/virt.c | 6 --- include/hw/intc/loongarch_pic_common.h | 2 - 3 files changed, 1 insertion(+), 73 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index e9126a0c1f..cbba2fc284 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -230,34 +230,6 @@ static void loongarch_pch_pic_write(void *opaque, hwaddr addr, } } -static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, - unsigned size) -{ - addr += PCH_PIC_INT_STATUS; - return loongarch_pch_pic_read(opaque, addr, size); -} - -static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - addr += PCH_PIC_INT_STATUS; - loongarch_pch_pic_write(opaque, addr, value, size); -} - -static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, - unsigned size) -{ - addr += PCH_PIC_ROUTE_ENTRY; - return loongarch_pch_pic_read(opaque, addr, size); -} - -static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - addr += PCH_PIC_ROUTE_ENTRY; - loongarch_pch_pic_write(opaque, addr, data, size); -} - static const MemoryRegionOps loongarch_pch_pic_ops = { .read = loongarch_pch_pic_read, .write = loongarch_pch_pic_write, @@ -279,34 +251,6 @@ static const MemoryRegionOps loongarch_pch_pic_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = { - .read = loongarch_pch_pic_high_readw, - .write = loongarch_pch_pic_high_writew, - .valid = { - .min_access_size = 4, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static const MemoryRegionOps loongarch_pch_pic_reg8_ops = { - .read = loongarch_pch_pic_readb, - .write = loongarch_pch_pic_writeb, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - static void loongarch_pic_reset_hold(Object *obj, ResetType type) { LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(obj); @@ -333,16 +277,8 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp) 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, 0x100); - memory_region_init_io(&s->iomem8, OBJECT(dev), &loongarch_pch_pic_reg8_ops, - s, PCH_PIC_NAME(.reg8), 0x2a0); - memory_region_init_io(&s->iomem32_high, OBJECT(dev), - &loongarch_pch_pic_reg32_high_ops, - s, PCH_PIC_NAME(.reg32_part2), 0xc60); + s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE); sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_mmio(sbd, &s->iomem8); - sysbus_init_mmio(sbd, &s->iomem32_high); - } static void loongarch_pic_class_init(ObjectClass *klass, const void *data) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index ebcef0a92b..1b504047db 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -429,12 +429,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) sysbus_realize_and_unref(d, &error_fatal); memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, sysbus_mmio_get_region(d, 0)); - memory_region_add_subregion(get_system_memory(), - VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY, - sysbus_mmio_get_region(d, 1)); - memory_region_add_subregion(get_system_memory(), - VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS, - sysbus_mmio_get_region(d, 2)); /* Connect pch_pic irqs to extioi */ for (i = 0; i < num; i++) { diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index dc03056227..9349a055d0 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -66,8 +66,6 @@ struct LoongArchPICCommonState { uint8_t htmsi_vector[64]; /* 0x200 - 0x238 */ MemoryRegion iomem; - MemoryRegion iomem32_high; - MemoryRegion iomem8; unsigned int irq_num; }; From a3d5f62254a48b7c260d5aa7bd8e8467a0bb8ea3 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Tue, 6 May 2025 16:09:46 +0800 Subject: [PATCH 17/17] hw/loongarch/boot: Adjust the loading position of the initrd When only the -kernel parameter is used to load the elf kernel, the initrd is loaded in the ram. If the initrd size is too large, the loading fails, resulting in a VM startup failure. This patch first loads initrd near the kernel. When the nearby memory space of the kernel is insufficient, it tries to load it to the starting position of high memory. If there is still not enough, qemu will report an error and ask the user to increase the memory space for the virtual machine to boot. Signed-off-by: Xianglai Li Message-Id: <20250506080946.817092-1-lixianglai@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/boot.c | 52 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index 0324d6adcb..9b6292eaa1 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -235,6 +235,45 @@ static int64_t load_loongarch_linux_image(const char *filename, return size; } +static ram_addr_t alloc_initrd_memory(struct loongarch_boot_info *info, + uint64_t advice_start, ssize_t rd_size) +{ + hwaddr base, ram_size, gap, low_end; + ram_addr_t initrd_end, initrd_start; + + base = VIRT_LOWMEM_BASE; + gap = VIRT_LOWMEM_SIZE; + initrd_start = advice_start; + initrd_end = initrd_start + rd_size; + + ram_size = info->ram_size; + low_end = base + MIN(ram_size, gap); + if (initrd_end <= low_end) { + return initrd_start; + } + + if (ram_size <= gap) { + error_report("The low memory too small for initial ram disk '%s'," + "You need to expand the ram", + info->initrd_filename); + exit(1); + } + + /* + * Try to load initrd in the high memory + */ + ram_size -= gap; + initrd_start = VIRT_HIGHMEM_BASE; + if (rd_size <= ram_size) { + return initrd_start; + } + + error_report("The high memory too small for initial ram disk '%s'," + "You need to expand the ram", + info->initrd_filename); + exit(1); +} + static int64_t load_kernel_info(struct loongarch_boot_info *info) { uint64_t kernel_entry, kernel_low, kernel_high; @@ -263,15 +302,10 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) initrd_size = get_image_size(info->initrd_filename); if (initrd_size > 0) { initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); - - if (initrd_offset + initrd_size > info->ram_size) { - error_report("memory too small for initial ram disk '%s'", - info->initrd_filename); - exit(1); - } - - initrd_size = load_image_targphys(info->initrd_filename, initrd_offset, - info->ram_size - initrd_offset); + initrd_offset = alloc_initrd_memory(info, initrd_offset, + initrd_size); + initrd_size = load_image_targphys(info->initrd_filename, + initrd_offset, initrd_size); } if (initrd_size == (target_ulong)-1) {