All of lore.kernel.org
 help / color / mirror / Atom feed
From: guangrong.xiao@gmail.com
To: pbonzini@redhat.com, mst@redhat.com, mtosatti@redhat.com
Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org,
	Xiao Guangrong <xiaoguangrong@tencent.com>
Subject: [PATCH] qtest: add rtc periodic timer test
Date: Thu, 25 May 2017 11:19:36 +0800	[thread overview]
Message-ID: <20170525031936.8449-1-xiaoguangrong@tencent.com> (raw)

From: Xiao Guangrong <xiaoguangrong@tencent.com>

It tests the accuracy of rtc periodic timer which is recently
improved & fixed by:
      mc146818rtc: precisely count the clock for periodic timer
(commit id has not been decided yet)

Note: as qemu needs a precise timer to drive its rtc timer callbacks,
that means clock=vm is not suitable for us as it's driven by icount
for qtest, so that we use clock=host instead, it is why we put the
periodic timer test separately without mixing with rtc-test

Signed-off-by: Xiao Guangrong <xiaoguangrong@tencent.com>
---
 hw/timer/mc146818rtc.c         |  15 ++-----
 include/hw/timer/mc146818rtc.h |  19 ++++++++
 tests/Makefile.include         |   2 +
 tests/rtc-periodic-test.c      | 100 +++++++++++++++++++++++++++++++++++++++++
 tests/rtc-test.c               |  14 +-----
 tests/rtc-test.h               |  17 +++++++
 6 files changed, 142 insertions(+), 25 deletions(-)
 create mode 100644 tests/rtc-periodic-test.c
 create mode 100644 tests/rtc-test.h

diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 6d0a610..0aba66c 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -120,7 +120,7 @@ static void rtc_coalesced_timer_update(RTCState *s)
         /* divide each RTC interval to 2 - 8 smaller intervals */
         int c = MIN(s->irq_coalesced, 7) + 1; 
         int64_t next_clock = qemu_clock_get_ns(rtc_clock) +
-            muldiv64(s->period / c, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE);
+            periodic_clock_to_ns(s->period / c);
         timer_mod(s->coalesced_timer, next_clock);
     }
 }
@@ -178,16 +178,8 @@ static uint32_t rtc_periodic_clock_ticks(RTCState *s)
      }
 
     period_code = s->cmos_data[RTC_REG_A] & 0x0f;
-    if (!period_code) {
-        return 0;
-    }
-
-    if (period_code <= 2) {
-        period_code += 7;
-    }
 
-    /* period in 32 Khz cycles */
-    return 1 << (period_code - 1);
+    return periodic_period_to_clock(period_code);
 }
 
 /*
@@ -266,8 +258,7 @@ periodic_timer_update(RTCState *s, int64_t current_time, uint32_t old_period)
         assert(lost_clock >= 0 && lost_clock <= period);
 
         next_irq_clock = cur_clock + period - lost_clock;
-        s->next_periodic_time = muldiv64(next_irq_clock, NANOSECONDS_PER_SECOND,
-                                         RTC_CLOCK_RATE) + 1;
+        s->next_periodic_time = periodic_clock_to_ns(next_irq_clock) + 1;
         timer_mod(s->periodic_timer, s->next_periodic_time);
     } else {
         s->irq_coalesced = 0;
diff --git a/include/hw/timer/mc146818rtc.h b/include/hw/timer/mc146818rtc.h
index 7c8e64b..f23e734 100644
--- a/include/hw/timer/mc146818rtc.h
+++ b/include/hw/timer/mc146818rtc.h
@@ -10,4 +10,23 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq);
 void rtc_set_memory(ISADevice *dev, int addr, int val);
 int rtc_get_memory(ISADevice *dev, int addr);
 
+static inline uint32_t periodic_period_to_clock(int period_code)
+{
+    if (!period_code) {
+        return 0;
+   }
+
+    if (period_code <= 2) {
+        period_code += 7;
+    }
+    /* period in 32 Khz cycles */
+   return 1 << (period_code - 1);
+}
+
+#define RTC_CLOCK_RATE            32768
+
+static inline int64_t periodic_clock_to_ns(int64_t clocks)
+{
+    return muldiv64(clocks, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE);
+}
 #endif /* MC146818RTC_H */
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 31931c0..6958d91 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -218,6 +218,7 @@ check-qtest-i386-y += tests/bios-tables-test$(EXESUF)
 check-qtest-i386-y += tests/boot-serial-test$(EXESUF)
 check-qtest-i386-y += tests/pxe-test$(EXESUF)
 check-qtest-i386-y += tests/rtc-test$(EXESUF)
+check-qtest-i386-y += tests/rtc-periodic-test$(EXESUF)
 check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF)
 check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF)
 check-qtest-i386-y += tests/i440fx-test$(EXESUF)
@@ -677,6 +678,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
 tests/rtc-test$(EXESUF): tests/rtc-test.o
+tests/rtc-periodic-test$(EXESUF): tests/rtc-periodic-test.o
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/endianness-test$(EXESUF): tests/endianness-test.o
 tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
diff --git a/tests/rtc-periodic-test.c b/tests/rtc-periodic-test.c
new file mode 100644
index 0000000..8f3e4b5
--- /dev/null
+++ b/tests/rtc-periodic-test.c
@@ -0,0 +1,100 @@
+/*
+ * QTest testcase for the periodic timer of MC146818 real-time clock
+ *
+ * Copyright Tencent Corp. 2017
+ *
+ * Authors:
+ *  Xiao Guangrong <xiaoguangrong@tencent.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+
+#include "libqtest.h"
+
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/mc146818rtc_regs.h"
+
+#include "rtc-test.h"
+
+#define RTC_PERIOD_CODE1    13
+#define RTC_PERIOD_CODE2    15
+
+#define RTC_PERIOD_TEST_NR  50
+
+static void nsleep(int64_t nsecs)
+{
+    const struct timespec val = { .tv_nsec = nsecs };
+    nanosleep(&val, NULL);
+}
+
+static void wait_periodic_interrupt(void)
+{
+    while (1) {
+        if (get_irq(RTC_ISA_IRQ)) {
+            break;
+        }
+
+        /* 1 us.*/
+        nsleep(1000);
+    }
+
+    g_assert((cmos_read(RTC_REG_C) & REG_C_PF) != 0);
+}
+
+static void periodic_timer(void)
+{
+    int i;
+    int64_t period_clocks, period_time, real_time;
+
+    /* disable all interrupts. */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) &
+                                   ~(REG_B_PIE | REG_B_AIE | REG_B_UIE));
+    cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
+    /* enable periodic interrupt after properly configure the period. */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_PIE);
+
+    real_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+
+    for (i = 0; i < RTC_PERIOD_TEST_NR; i++) {
+        cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
+        wait_periodic_interrupt();
+        cmos_write(RTC_REG_A, RTC_PERIOD_CODE2);
+        wait_periodic_interrupt();
+    }
+
+    real_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - real_time;
+
+    period_clocks = periodic_period_to_clock(RTC_PERIOD_CODE1) +
+                       periodic_period_to_clock(RTC_PERIOD_CODE2);
+    period_clocks *= RTC_PERIOD_TEST_NR;
+    period_time = periodic_clock_to_ns(period_clocks);
+
+    g_assert_cmpint(ABS(real_time - period_time), <=,
+                    NANOSECONDS_PER_SECOND * 0.5);
+}
+
+int main(int argc, char **argv)
+{
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    s = qtest_start("-rtc clock=host");
+    qtest_irq_intercept_in(s, "ioapic");
+
+    qtest_add_func("/rtc/periodic/interrupt", periodic_timer);
+
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+
+    return ret;
+}
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index a086efd..9ec9ba4 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -16,25 +16,13 @@
 #include "libqtest.h"
 #include "hw/timer/mc146818rtc_regs.h"
 
-static uint8_t base = 0x70;
+#include "rtc-test.h"
 
 static int bcd2dec(int value)
 {
     return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
 }
 
-static uint8_t cmos_read(uint8_t reg)
-{
-    outb(base + 0, reg);
-    return inb(base + 1);
-}
-
-static void cmos_write(uint8_t reg, uint8_t val)
-{
-    outb(base + 0, reg);
-    outb(base + 1, val);
-}
-
 static int tm_cmp(struct tm *lhs, struct tm *rhs)
 {
     time_t a, b;
diff --git a/tests/rtc-test.h b/tests/rtc-test.h
new file mode 100644
index 0000000..5a63d68
--- /dev/null
+++ b/tests/rtc-test.h
@@ -0,0 +1,17 @@
+#ifndef TEST_RTC_H__
+#define TEST_RTC_H__
+
+#define RTC_BASE_REG    0x70
+
+static uint8_t cmos_read(uint8_t reg)
+{
+    outb(RTC_BASE_REG + 0, reg);
+    return inb(RTC_BASE_REG + 1);
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+    outb(RTC_BASE_REG + 0, reg);
+    outb(RTC_BASE_REG + 1, val);
+}
+#endif
-- 
2.9.4

WARNING: multiple messages have this Message-ID (diff)
From: guangrong.xiao@gmail.com
To: pbonzini@redhat.com, mst@redhat.com, mtosatti@redhat.com
Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org,
	Xiao Guangrong <xiaoguangrong@tencent.com>
Subject: [Qemu-devel] [PATCH] qtest: add rtc periodic timer test
Date: Thu, 25 May 2017 11:19:36 +0800	[thread overview]
Message-ID: <20170525031936.8449-1-xiaoguangrong@tencent.com> (raw)

From: Xiao Guangrong <xiaoguangrong@tencent.com>

It tests the accuracy of rtc periodic timer which is recently
improved & fixed by:
      mc146818rtc: precisely count the clock for periodic timer
(commit id has not been decided yet)

Note: as qemu needs a precise timer to drive its rtc timer callbacks,
that means clock=vm is not suitable for us as it's driven by icount
for qtest, so that we use clock=host instead, it is why we put the
periodic timer test separately without mixing with rtc-test

Signed-off-by: Xiao Guangrong <xiaoguangrong@tencent.com>
---
 hw/timer/mc146818rtc.c         |  15 ++-----
 include/hw/timer/mc146818rtc.h |  19 ++++++++
 tests/Makefile.include         |   2 +
 tests/rtc-periodic-test.c      | 100 +++++++++++++++++++++++++++++++++++++++++
 tests/rtc-test.c               |  14 +-----
 tests/rtc-test.h               |  17 +++++++
 6 files changed, 142 insertions(+), 25 deletions(-)
 create mode 100644 tests/rtc-periodic-test.c
 create mode 100644 tests/rtc-test.h

diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 6d0a610..0aba66c 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -120,7 +120,7 @@ static void rtc_coalesced_timer_update(RTCState *s)
         /* divide each RTC interval to 2 - 8 smaller intervals */
         int c = MIN(s->irq_coalesced, 7) + 1; 
         int64_t next_clock = qemu_clock_get_ns(rtc_clock) +
-            muldiv64(s->period / c, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE);
+            periodic_clock_to_ns(s->period / c);
         timer_mod(s->coalesced_timer, next_clock);
     }
 }
@@ -178,16 +178,8 @@ static uint32_t rtc_periodic_clock_ticks(RTCState *s)
      }
 
     period_code = s->cmos_data[RTC_REG_A] & 0x0f;
-    if (!period_code) {
-        return 0;
-    }
-
-    if (period_code <= 2) {
-        period_code += 7;
-    }
 
-    /* period in 32 Khz cycles */
-    return 1 << (period_code - 1);
+    return periodic_period_to_clock(period_code);
 }
 
 /*
@@ -266,8 +258,7 @@ periodic_timer_update(RTCState *s, int64_t current_time, uint32_t old_period)
         assert(lost_clock >= 0 && lost_clock <= period);
 
         next_irq_clock = cur_clock + period - lost_clock;
-        s->next_periodic_time = muldiv64(next_irq_clock, NANOSECONDS_PER_SECOND,
-                                         RTC_CLOCK_RATE) + 1;
+        s->next_periodic_time = periodic_clock_to_ns(next_irq_clock) + 1;
         timer_mod(s->periodic_timer, s->next_periodic_time);
     } else {
         s->irq_coalesced = 0;
diff --git a/include/hw/timer/mc146818rtc.h b/include/hw/timer/mc146818rtc.h
index 7c8e64b..f23e734 100644
--- a/include/hw/timer/mc146818rtc.h
+++ b/include/hw/timer/mc146818rtc.h
@@ -10,4 +10,23 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq);
 void rtc_set_memory(ISADevice *dev, int addr, int val);
 int rtc_get_memory(ISADevice *dev, int addr);
 
+static inline uint32_t periodic_period_to_clock(int period_code)
+{
+    if (!period_code) {
+        return 0;
+   }
+
+    if (period_code <= 2) {
+        period_code += 7;
+    }
+    /* period in 32 Khz cycles */
+   return 1 << (period_code - 1);
+}
+
+#define RTC_CLOCK_RATE            32768
+
+static inline int64_t periodic_clock_to_ns(int64_t clocks)
+{
+    return muldiv64(clocks, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE);
+}
 #endif /* MC146818RTC_H */
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 31931c0..6958d91 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -218,6 +218,7 @@ check-qtest-i386-y += tests/bios-tables-test$(EXESUF)
 check-qtest-i386-y += tests/boot-serial-test$(EXESUF)
 check-qtest-i386-y += tests/pxe-test$(EXESUF)
 check-qtest-i386-y += tests/rtc-test$(EXESUF)
+check-qtest-i386-y += tests/rtc-periodic-test$(EXESUF)
 check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF)
 check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF)
 check-qtest-i386-y += tests/i440fx-test$(EXESUF)
@@ -677,6 +678,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
 tests/rtc-test$(EXESUF): tests/rtc-test.o
+tests/rtc-periodic-test$(EXESUF): tests/rtc-periodic-test.o
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/endianness-test$(EXESUF): tests/endianness-test.o
 tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
diff --git a/tests/rtc-periodic-test.c b/tests/rtc-periodic-test.c
new file mode 100644
index 0000000..8f3e4b5
--- /dev/null
+++ b/tests/rtc-periodic-test.c
@@ -0,0 +1,100 @@
+/*
+ * QTest testcase for the periodic timer of MC146818 real-time clock
+ *
+ * Copyright Tencent Corp. 2017
+ *
+ * Authors:
+ *  Xiao Guangrong <xiaoguangrong@tencent.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+
+#include "libqtest.h"
+
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/mc146818rtc_regs.h"
+
+#include "rtc-test.h"
+
+#define RTC_PERIOD_CODE1    13
+#define RTC_PERIOD_CODE2    15
+
+#define RTC_PERIOD_TEST_NR  50
+
+static void nsleep(int64_t nsecs)
+{
+    const struct timespec val = { .tv_nsec = nsecs };
+    nanosleep(&val, NULL);
+}
+
+static void wait_periodic_interrupt(void)
+{
+    while (1) {
+        if (get_irq(RTC_ISA_IRQ)) {
+            break;
+        }
+
+        /* 1 us.*/
+        nsleep(1000);
+    }
+
+    g_assert((cmos_read(RTC_REG_C) & REG_C_PF) != 0);
+}
+
+static void periodic_timer(void)
+{
+    int i;
+    int64_t period_clocks, period_time, real_time;
+
+    /* disable all interrupts. */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) &
+                                   ~(REG_B_PIE | REG_B_AIE | REG_B_UIE));
+    cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
+    /* enable periodic interrupt after properly configure the period. */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_PIE);
+
+    real_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+
+    for (i = 0; i < RTC_PERIOD_TEST_NR; i++) {
+        cmos_write(RTC_REG_A, RTC_PERIOD_CODE1);
+        wait_periodic_interrupt();
+        cmos_write(RTC_REG_A, RTC_PERIOD_CODE2);
+        wait_periodic_interrupt();
+    }
+
+    real_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - real_time;
+
+    period_clocks = periodic_period_to_clock(RTC_PERIOD_CODE1) +
+                       periodic_period_to_clock(RTC_PERIOD_CODE2);
+    period_clocks *= RTC_PERIOD_TEST_NR;
+    period_time = periodic_clock_to_ns(period_clocks);
+
+    g_assert_cmpint(ABS(real_time - period_time), <=,
+                    NANOSECONDS_PER_SECOND * 0.5);
+}
+
+int main(int argc, char **argv)
+{
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    s = qtest_start("-rtc clock=host");
+    qtest_irq_intercept_in(s, "ioapic");
+
+    qtest_add_func("/rtc/periodic/interrupt", periodic_timer);
+
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+
+    return ret;
+}
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index a086efd..9ec9ba4 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -16,25 +16,13 @@
 #include "libqtest.h"
 #include "hw/timer/mc146818rtc_regs.h"
 
-static uint8_t base = 0x70;
+#include "rtc-test.h"
 
 static int bcd2dec(int value)
 {
     return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
 }
 
-static uint8_t cmos_read(uint8_t reg)
-{
-    outb(base + 0, reg);
-    return inb(base + 1);
-}
-
-static void cmos_write(uint8_t reg, uint8_t val)
-{
-    outb(base + 0, reg);
-    outb(base + 1, val);
-}
-
 static int tm_cmp(struct tm *lhs, struct tm *rhs)
 {
     time_t a, b;
diff --git a/tests/rtc-test.h b/tests/rtc-test.h
new file mode 100644
index 0000000..5a63d68
--- /dev/null
+++ b/tests/rtc-test.h
@@ -0,0 +1,17 @@
+#ifndef TEST_RTC_H__
+#define TEST_RTC_H__
+
+#define RTC_BASE_REG    0x70
+
+static uint8_t cmos_read(uint8_t reg)
+{
+    outb(RTC_BASE_REG + 0, reg);
+    return inb(RTC_BASE_REG + 1);
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+    outb(RTC_BASE_REG + 0, reg);
+    outb(RTC_BASE_REG + 1, val);
+}
+#endif
-- 
2.9.4

             reply	other threads:[~2017-05-25  3:19 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-25  3:19 guangrong.xiao [this message]
2017-05-25  3:19 ` [Qemu-devel] [PATCH] qtest: add rtc periodic timer test guangrong.xiao
2017-05-25 16:03 ` Paolo Bonzini
2017-05-25 16:03   ` [Qemu-devel] " Paolo Bonzini
2017-05-26  3:21   ` Xiao Guangrong
2017-05-26  3:21     ` [Qemu-devel] " Xiao Guangrong
2017-05-26 11:03     ` Paolo Bonzini
2017-05-26 11:03       ` [Qemu-devel] " Paolo Bonzini
2017-05-27  2:59       ` Xiao Guangrong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170525031936.8449-1-xiaoguangrong@tencent.com \
    --to=guangrong.xiao@gmail.com \
    --cc=kvm@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=mtosatti@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=xiaoguangrong@tencent.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.