diff options
-rw-r--r-- | hw/ppc/spapr.c | 30 | ||||
-rw-r--r-- | hw/ppc/spapr_rtc.c | 41 | ||||
-rw-r--r-- | include/hw/ppc/spapr.h | 3 |
3 files changed, 66 insertions, 8 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1908988dbc..6e8248d01e 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1019,15 +1019,39 @@ static int spapr_vga_init(PCIBus *pci_bus) } } +static int spapr_post_load(void *opaque, int version_id) +{ + sPAPREnvironment *spapr = (sPAPREnvironment *)opaque; + int err = 0; + + /* In earlier versions, there was no seperate qdev for the PAPR + * RTC, so the RTC offset was stored directly in sPAPREnvironment. + * So when migrating from those versions, poke the incoming offset + * value into the RTC device */ + if (version_id < 3) { + err = spapr_rtc_import_offset(spapr->rtc, spapr->rtc_offset); + } + + return err; +} + +static bool version_before_3(void *opaque, int version_id) +{ + return version_id < 3; +} + static const VMStateDescription vmstate_spapr = { .name = "spapr", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, + .post_load = spapr_post_load, .fields = (VMStateField[]) { - VMSTATE_UNUSED(4), /* used to be @next_irq */ + /* used to be @next_irq */ + VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4), /* RTC offset */ - VMSTATE_UINT64(rtc_offset, sPAPREnvironment), + VMSTATE_UINT64_TEST(rtc_offset, sPAPREnvironment, version_before_3), + VMSTATE_PPC_TIMEBASE_V(tb, sPAPREnvironment, 2), VMSTATE_END_OF_LIST() }, diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c index b9f4704784..5ad0823d3b 100644 --- a/hw/ppc/spapr_rtc.c +++ b/hw/ppc/spapr_rtc.c @@ -37,6 +37,7 @@ typedef struct sPAPRRTCState sPAPRRTCState; struct sPAPRRTCState { /*< private >*/ SysBusDevice parent_obj; + int64_t ns_offset; }; #define NSEC_PER_SEC 1000000000LL @@ -45,20 +46,37 @@ void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns) { sPAPRRTCState *rtc = SPAPR_RTC(dev); int64_t host_ns = qemu_clock_get_ns(rtc_clock); + int64_t guest_ns; time_t guest_s; assert(rtc); - guest_s = host_ns / NSEC_PER_SEC + spapr->rtc_offset; + guest_ns = host_ns + rtc->ns_offset; + guest_s = guest_ns / NSEC_PER_SEC; if (tm) { gmtime_r(&guest_s, tm); } if (ns) { - *ns = host_ns % NSEC_PER_SEC; + *ns = guest_ns; } } +int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset) +{ + sPAPRRTCState *rtc; + + if (!dev) { + return -ENODEV; + } + + rtc = SPAPR_RTC(dev); + + rtc->ns_offset = legacy_offset * NSEC_PER_SEC; + + return 0; +} + static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, @@ -94,6 +112,7 @@ static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong args, uint32_t nret, target_ulong rets) { + sPAPRRTCState *rtc; struct tm tm; time_t new_s; int64_t host_ns; @@ -124,15 +143,18 @@ static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr, /* Generate a monitor event for the change */ qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort); + rtc = SPAPR_RTC(spapr->rtc); + host_ns = qemu_clock_get_ns(rtc_clock); - spapr->rtc_offset = new_s - host_ns / NSEC_PER_SEC; + rtc->ns_offset = (new_s * NSEC_PER_SEC) - host_ns; rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void spapr_rtc_realize(DeviceState *dev, Error **errp) { + sPAPRRTCState *rtc = SPAPR_RTC(dev); struct tm tm; time_t host_s; int64_t rtc_ns; @@ -142,14 +164,25 @@ static void spapr_rtc_realize(DeviceState *dev, Error **errp) qemu_get_timedate(&tm, 0); host_s = mktimegm(&tm); rtc_ns = qemu_clock_get_ns(rtc_clock); - spapr->rtc_offset = host_s - rtc_ns / NSEC_PER_SEC; + rtc->ns_offset = host_s * NSEC_PER_SEC - rtc_ns; } +static const VMStateDescription vmstate_spapr_rtc = { + .name = "spapr/rtc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(ns_offset, sPAPRRTCState), + VMSTATE_END_OF_LIST() + }, +}; + static void spapr_rtc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = spapr_rtc_realize; + dc->vmsd = &vmstate_spapr_rtc; spapr_rtas_register(RTAS_GET_TIME_OF_DAY, "get-time-of-day", rtas_get_time_of_day); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 80c6e4f178..a8e6817cb8 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -27,7 +27,7 @@ typedef struct sPAPREnvironment { void *rtas_blob; void *fdt_skel; target_ulong entry_point; - uint64_t rtc_offset; + uint64_t rtc_offset; /* Now used only during incoming migration */ struct PPCTimebase tb; bool has_graphics; @@ -485,5 +485,6 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, #define TYPE_SPAPR_RTC "spapr-rtc" void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns); +int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset); #endif /* !defined (__HW_SPAPR_H__) */ |