From 5cb54000e87f40ec91d9d8606ae1fb271f8a4ded Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Mon, 7 Apr 2025 18:59:42 +0800 Subject: [PATCH] hw/rtc: Fixed loongson rtc emulation errors The expire time is sent to the timer only when the expire Time is greater than 0 or greater than now. Otherwise, the timer will trigger interruption continuously. Timer interrupts are sent using pulse functions. Signed-off-by: Xianglai Li --- hw/loongarch/virt.c | 9 +++++++-- hw/rtc/ls7a_rtc.c | 22 +++++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index f1953b9f82d..12d34b19d74 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -51,6 +51,11 @@ #include "qemu/guest-random.h" #include "sysemu/kvm.h" +#define FDT_IRQ_FLAGS_EDGE_LO_HI 1 +#define FDT_IRQ_FLAGS_EDGE_HI_LO 2 +#define FDT_IRQ_FLAGS_LEVEL_HI 4 +#define FDT_IRQ_FLAGS_LEVEL_LO 8 + static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms) { if (lvms->veiointc == ON_OFF_AUTO_OFF) { @@ -275,7 +280,7 @@ static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, "loongson,ls7a-rtc"); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", - VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4); + VIRT_RTC_IRQ - VIRT_GSI_BASE , FDT_IRQ_FLAGS_EDGE_LO_HI); qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", *pch_pic_phandle); g_free(nodename); @@ -334,7 +339,7 @@ static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); if (chosen) qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); - qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4); + qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, FDT_IRQ_FLAGS_LEVEL_HI); qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", *pch_pic_phandle); g_free(nodename); diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c index 1f9e38a735b..be9546c8505 100644 --- a/hw/rtc/ls7a_rtc.c +++ b/hw/rtc/ls7a_rtc.c @@ -145,20 +145,22 @@ static void toymatch_write(LS7ARtcState *s, uint64_t val, int num) now = qemu_clock_get_ms(rtc_clock); toymatch_val_to_time(s, val, &tm); expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; - timer_mod(s->toy_timer[num], expire_time); + if (expire_time > now) + timer_mod(s->toy_timer[num], expire_time); } } static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num) { - uint64_t expire_ns; + int64_t expire_ns; /* it do not support write when toy disabled */ if (rtc_enabled(s)) { s->rtcmatch[num] = val; /* calculate expire time */ expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc); - timer_mod_ns(s->rtc_timer[num], expire_ns); + if (expire_ns > 0) + timer_mod_ns(s->rtc_timer[num], expire_ns); } } @@ -185,7 +187,7 @@ static void ls7a_rtc_stop(LS7ARtcState *s) static void ls7a_toy_start(LS7ARtcState *s) { int i; - uint64_t expire_time, now; + int64_t expire_time, now; struct tm tm = {}; now = qemu_clock_get_ms(rtc_clock); @@ -194,19 +196,21 @@ static void ls7a_toy_start(LS7ARtcState *s) for (i = 0; i < TIMER_NUMS; i++) { toymatch_val_to_time(s, s->toymatch[i], &tm); expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; - timer_mod(s->toy_timer[i], expire_time); + if (expire_time > now) + timer_mod(s->toy_timer[i], expire_time); } } static void ls7a_rtc_start(LS7ARtcState *s) { int i; - uint64_t expire_time; + int64_t expire_time; /* recalculate expire time and enable timer */ for (i = 0; i < TIMER_NUMS; i++) { expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc); - timer_mod_ns(s->rtc_timer[i], expire_time); + if (expire_time > 0) + timer_mod_ns(s->rtc_timer[i], expire_time); } } @@ -370,7 +374,7 @@ static void toy_timer_cb(void *opaque) LS7ARtcState *s = opaque; if (toy_enabled(s)) { - qemu_irq_raise(s->irq); + qemu_irq_pulse(s->irq); } } @@ -379,7 +383,7 @@ static void rtc_timer_cb(void *opaque) LS7ARtcState *s = opaque; if (rtc_enabled(s)) { - qemu_irq_raise(s->irq); + qemu_irq_pulse(s->irq); } } -- Gitee