"Pavel Dovgalyuk" <dovga...@ispras.ru> wrote:
> Ping?
>
> Pavel Dovgalyuk
>
>> -----Original Message-----
>> From: Pavel Dovgalyuk [mailto:pavel.dovga...@ispras.ru]
>> Sent: Wednesday, December 20, 2017 1:02 PM
>> To: qemu-devel@nongnu.org
>> Cc: quint...@redhat.com; m...@redhat.com; dgilb...@redhat.com; 
>> maria.klimushenk...@ispras.ru;
>> dovga...@ispras.ru; pavel.dovga...@ispras.ru; pbonz...@redhat.com
>> Subject: [PATCH v2] hpet: recover timer offset correctly
>> 
>> HPET saves its state by calculating the current time and recovers timer
>> offset using this calculated value. But these calculations include
>> divisions and multiplications. Therefore the timer state cannot be recovered
>> precise enough.
>> This patch introduces saving of the original value of the offset to
>> preserve the determinism of the timer.

Hi

How have you tested this?


>> Signed-off-by: Maria Klimushenkova <maria.klimushenk...@ispras.ru>
>> Signed-off-by: Pavel Dovgalyuk <pavel.dovga...@ispras.ru>
>> ---
>>  hw/timer/hpet.c |   32 ++++++++++++++++++++++++++++++--
>>  1 file changed, 30 insertions(+), 2 deletions(-)
>> 
>> diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
>> index 577371b..4904a60 100644
>> --- a/hw/timer/hpet.c
>> +++ b/hw/timer/hpet.c
>> @@ -70,6 +70,7 @@ typedef struct HPETState {
>> 
>>      MemoryRegion iomem;
>>      uint64_t hpet_offset;
>> +    bool hpet_offset_loaded;
>>      qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
>>      uint32_t flags;
>>      uint8_t rtc_irq_level;
>> @@ -221,7 +222,9 @@ static int hpet_pre_save(void *opaque)
>>      HPETState *s = opaque;
>> 
>>      /* save current counter value */
>> -    s->hpet_counter = hpet_get_ticks(s);
>> +    if (hpet_enabled(s)) {
>> +        s->hpet_counter = hpet_get_ticks(s);

Why do we want to save it only when hpet is enabled?  We used to save it always.

>> +    }
>> 
>>      return 0;
>>  }
>> @@ -232,6 +235,8 @@ static int hpet_pre_load(void *opaque)
>> 
>>      /* version 1 only supports 3, later versions will load the actual value 
>> */
>>      s->num_timers = HPET_MIN_TIMERS;
>> +    /* for checking whether the hpet_offset section is loaded */
>> +    s->hpet_offset_loaded = false;

This is made false everytime that we start incoming migration.

>>      return 0;
>>  }
>> 
>> @@ -252,7 +257,10 @@ static int hpet_post_load(void *opaque, int version_id)
>>      HPETState *s = opaque;
>> 
>>      /* Recalculate the offset between the main counter and guest time */
>> -    s->hpet_offset = ticks_to_ns(s->hpet_counter) - 
>> qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +    if (!s->hpet_offset_loaded) {
>> +        s->hpet_offset = ticks_to_ns(s->hpet_counter)
>> +                        - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +    }

So, at this point it is going to always be false.

>> 
>>      /* Push number of timers into capability returned via HPET_ID */
>>      s->capability &= ~HPET_ID_NUM_TIM_MASK;
>> @@ -267,6 +275,14 @@ static int hpet_post_load(void *opaque, int version_id)
>>      return 0;
>>  }
>> 
>> +static int hpet_offset_post_load(void *opaque, int version_id)
>> +{
>> +    HPETState *s = opaque;
>> +
>> +    s->hpet_offset_loaded = true;
>> +    return 0;
>> +}
>> +
>>  static bool hpet_rtc_irq_level_needed(void *opaque)
>>  {
>>      HPETState *s = opaque;
>> @@ -285,6 +301,17 @@ static const VMStateDescription 
>> vmstate_hpet_rtc_irq_level = {
>>      }
>>  };
>> 
>> +static const VMStateDescription vmstate_hpet_offset = {
>> +    .name = "hpet/offset",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .post_load = hpet_offset_post_load,

You are missing here a .needed function.  Se how
vmstate_hpet_rtc_irq_level_needed().
I am commeting from migration/vmstate point of view.  I don't understand
hpet well enough to comment about that.

Just to be sure that I am understanding what you want/need.

- You want to transport hpet_offset just in the cases that hpet_is_enabled()?

So your _needed() function needs to do something like
   return hpet_enabled();


So, we have two cases:
- hpet is enabled -> we need your changes, but then we can just have
hpet_counter directly



>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT64(hpet_offset, HPETState),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>>  static const VMStateDescription vmstate_hpet_timer = {
>>      .name = "hpet_timer",
>>      .version_id = 1,
>> @@ -320,6 +347,7 @@ static const VMStateDescription vmstate_hpet = {
>>      },
>>      .subsections = (const VMStateDescription*[]) {
>>          &vmstate_hpet_rtc_irq_level,
>> +        &vmstate_hpet_offset,
>>          NULL
>>      }
>>  };

I think that the following patch does what you want, no?  And it is a
bit simpler.

Later, Juan.


Head:     master Merge remote-tracking branch 
'remotes/elmarco/tags/dump-pull-request' into staging
Merge:    qemu/master Merge remote-tracking branch 
'remotes/elmarco/tags/dump-pull-request' into staging
Tag:      v2.11.0 (454)

Unstaged changes (1)
modified   hw/timer/hpet.c
@@ -216,16 +216,6 @@ static void update_irq(struct HPETTimer *timer, int set)
     }
 }
 
-static int hpet_pre_save(void *opaque)
-{
-    HPETState *s = opaque;
-
-    /* save current counter value */
-    s->hpet_counter = hpet_get_ticks(s);
-
-    return 0;
-}
-
 static int hpet_pre_load(void *opaque)
 {
     HPETState *s = opaque;
@@ -251,9 +241,6 @@ static int hpet_post_load(void *opaque, int version_id)
 {
     HPETState *s = opaque;
 
-    /* Recalculate the offset between the main counter and guest time */
-    s->hpet_offset = ticks_to_ns(s->hpet_counter) - 
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
     /* Push number of timers into capability returned via HPET_ID */
     s->capability &= ~HPET_ID_NUM_TIM_MASK;
     s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
@@ -285,6 +272,24 @@ static const VMStateDescription vmstate_hpet_rtc_irq_level 
= {
     }
 };
 
+static bool hpet_offset_needed(void *opaque)
+{
+    HPETState *s = opaque;
+
+    return hpet_enabled(s);
+}
+
+static const VMStateDescription vmstate_hpet_offset = {
+    .name = "hpet/offset",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = hpet_offset_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(hpet_offset, HPETState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_hpet_timer = {
     .name = "hpet_timer",
     .version_id = 1,
@@ -320,6 +325,7 @@ static const VMStateDescription vmstate_hpet = {
     },
     .subsections = (const VMStateDescription*[]) {
         &vmstate_hpet_rtc_irq_level,
+        &vmstate_hpet_offset,
         NULL
     }
 };



Reply via email to