summaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_rtc.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2015-02-06 14:55:52 +1100
committerAlexander Graf <agraf@suse.de>2015-03-09 14:59:58 +0100
commit880ae7de5958a765699386777de0f3841d635e1d (patch)
tree243ff22a3874a8293659146ad1acad9d65411e03 /hw/ppc/spapr_rtc.c
parent28df36a13a3b0b792d9df64f8db8a392df5e0b35 (diff)
downloadqemu-880ae7de5958a765699386777de0f3841d635e1d.tar.gz
pseries: Move rtc_offset into RTC device's state structure
The initial creation of the PAPR RTC qdev class left a wart - the rtc's offset was left in the sPAPREnvironment structure, accessed via a global. This patch moves it into the RTC device's own state structure, were it belongs. This requires a small change to the migration stream format. In order to handle incoming streams from older versions, we also need to retain the rtc_offset field in the sPAPREnvironment structure, so that it can be loaded into via the vmsd, then pushed into the RTC device. Since we're changing the migration format, this also takes the opportunity to: * Change the rtc offset from a value in seconds to a value in nanoseconds, allowing nanosecond offsets between host and guest rtc time, if desired. * Remove both the already unused "next_irq" field and now unused "rtc_offset" field from the new version of the spapr migration stream Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/ppc/spapr_rtc.c')
-rw-r--r--hw/ppc/spapr_rtc.c41
1 files changed, 37 insertions, 4 deletions
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);