From patchwork Fri Jul 20 10:53:50 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 172205 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id A64D82C0091 for ; Fri, 20 Jul 2012 21:24:43 +1000 (EST) Received: from localhost ([::1]:59886 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SsArJ-0006Xf-QH for incoming@patchwork.ozlabs.org; Fri, 20 Jul 2012 06:54:57 -0400 Received: from eggs.gnu.org ([208.118.235.92]:42937) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SsAql-0005Ra-K7 for qemu-devel@nongnu.org; Fri, 20 Jul 2012 06:54:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SsAqg-0001a9-7h for qemu-devel@nongnu.org; Fri, 20 Jul 2012 06:54:23 -0400 Received: from mail-gh0-f173.google.com ([209.85.160.173]:58949) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SsAqg-0001a5-1y for qemu-devel@nongnu.org; Fri, 20 Jul 2012 06:54:18 -0400 Received: by ghrr14 with SMTP id r14so3906422ghr.4 for ; Fri, 20 Jul 2012 03:54:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=FSfq828ov2xYHZTHqM32IcaIfXpkiSgB3VN1dyIk+9A=; b=Lm8xI8tufiwh6HiC/wwjI0XTu2FR2o0lrnJRpvAq+WVJS/dcH3ym+9q7rSsjW2qV3W s6/S7ymywLWDnEizAxkcT05Yiqe+vy9/lgP5TFAA1pICm3Bg1X1Lo36riCJMW1I5nJya w8J0eiBB24bdYU6TWG4OZj7CzIJ/V6xCYB/SqHtbMxLXr1DBoH+6m5hrkObPkcgzNxIW NWulvXnDHIl8molA1bOIILW1jT5oiipiKKlp2byxOFTCdj9yI1ZcXm85+PbQRrfXj8Py ES7O5t81RttCLJXTosf0N6RTgf8inf+ZZJH58Wje1ugHLJTzpQdhy8cLCieSXmhTpxF4 F2UQ== Received: by 10.66.76.196 with SMTP id m4mr10533701paw.61.1342781656716; Fri, 20 Jul 2012 03:54:16 -0700 (PDT) Received: from yakj.usersys.redhat.com (93-34-189-113.ip51.fastwebnet.it. [93.34.189.113]) by mx.google.com with ESMTPS id oi5sm3758710pbb.39.2012.07.20.03.54.13 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 20 Jul 2012 03:54:15 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Fri, 20 Jul 2012 12:53:50 +0200 Message-Id: <1342781633-7288-5-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1342781633-7288-1-git-send-email-pbonzini@redhat.com> References: <1342781633-7288-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.160.173 Cc: "Zhang, Yang Z" Subject: [Qemu-devel] [PATCH 4/7] RTC: Update the RTC clock only when reading it X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: "Zhang, Yang Z" Calculate guest RTC based on the time of the last update, instead of using timers. The formula is (base_rtc + guest_time_now - guest_time_last_update + offset) Base_rtc is the RTC value when the RTC was last updated. Guest_time_now is the guest time when the access happens. Guest_time_last_update was the guest time when the RTC was last updated. Offset is used when divider reset happens or the set bit is toggled. The timer is kept in order to signal interrupts, but it only needs to run when either UF or AF is cleared. When the bits are both set, the timer does not run. UIP is now synthesized when reading register A. If the timer is not set, or if there is more than one second before it (as is the case at the end of this series), the leading edge of UIP is computed and the rising edge occurs 220us later. If the update timer occurs within one second, however, the rising edge of the AF and UF bits should coincide withe the falling edge of UIP. We do not know exactly when this will happen because there could be delays in the servicing of the timer. Hence, in this case reading register A only computes for the rising edge of UIP, and latches the bit until the timer is fired and clears it. Signed-off-by: Yang Zhang Signed-off-by: Paolo Bonzini --- hw/mc146818rtc.c | 315 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 183 insertions(+), 132 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 46f0c10..3a99605 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -45,6 +45,8 @@ # define DPRINTF_C(format, ...) do { } while (0) #endif +#define NSEC_PER_SEC 1000000000LL + #define RTC_REINJECT_ON_ACK_COUNT 20 typedef struct RTCState { @@ -54,27 +56,40 @@ typedef struct RTCState { uint8_t cmos_index; struct tm current_tm; int32_t base_year; + uint64_t base_rtc; + uint64_t last_update; + int64_t offset; qemu_irq irq; qemu_irq sqw_irq; int it_shift; /* periodic timer */ QEMUTimer *periodic_timer; int64_t next_periodic_time; - /* second update */ - int64_t next_second_time; + /* update-ended timer */ + QEMUTimer *update_timer; uint16_t irq_reinject_on_ack_count; uint32_t irq_coalesced; uint32_t period; QEMUTimer *coalesced_timer; - QEMUTimer *second_timer; - QEMUTimer *second_timer2; Notifier clock_reset_notifier; LostTickPolicy lost_tick_policy; Notifier suspend_notifier; } RTCState; static void rtc_set_time(RTCState *s); -static void rtc_copy_date(RTCState *s); +static void rtc_update_time(RTCState *s); +static void rtc_set_cmos(RTCState *s); +static inline int rtc_from_bcd(RTCState *s, int a); + +static uint64_t get_guest_rtc_ns(RTCState *s) +{ + uint64_t guest_rtc; + uint64_t guest_clock = qemu_get_clock_ns(rtc_clock); + + guest_rtc = s->base_rtc * NSEC_PER_SEC + + guest_clock - s->last_update + s->offset; + return guest_rtc; +} #ifdef TARGET_I386 static void rtc_coalesced_timer_update(RTCState *s) @@ -110,6 +125,7 @@ static void rtc_coalesced_timer(void *opaque) } #endif +/* handle periodic timer */ static void periodic_timer_update(RTCState *s, int64_t current_time) { int period_code, period; @@ -175,6 +191,100 @@ static void rtc_periodic_timer(void *opaque) } } +/* handle update-ended timer */ +static void check_update_timer(RTCState *s) +{ + uint64_t next_update_time; + uint64_t guest_nsec; + + /* From the data sheet: setting the SET bit does not prevent + * interrupts from occurring! However, it will prevent an + * alarm interrupt from occurring, because the time of day is + * not updated. + */ + if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && + (s->cmos_data[RTC_REG_B] & REG_B_SET)) { + qemu_del_timer(s->update_timer); + return; + } + if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && + (s->cmos_data[RTC_REG_C] & REG_C_AF)) { + qemu_del_timer(s->update_timer); + return; + } + + guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC; + /* reprogram to next second */ + next_update_time = qemu_get_clock_ns(rtc_clock) + + NSEC_PER_SEC - guest_nsec; + if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) { + qemu_mod_timer(s->update_timer, next_update_time); + } +} + +static inline uint8_t convert_hour(RTCState *s, uint8_t hour) +{ + if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) { + hour %= 12; + if (s->cmos_data[RTC_HOURS] & 0x80) { + hour += 12; + } + } + return hour; +} + +static uint32_t check_alarm(RTCState *s) +{ + uint8_t alarm_hour, alarm_min, alarm_sec; + uint8_t cur_hour, cur_min, cur_sec; + + alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]); + alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]); + alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]); + alarm_hour = convert_hour(s, alarm_hour); + + cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); + cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); + cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]); + cur_hour = convert_hour(s, cur_hour); + + if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 + || alarm_sec == cur_sec) && + ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 + || alarm_min == cur_min) && + ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 + || alarm_hour == cur_hour)) { + return 1; + } + return 0; + +} + +static void rtc_update_timer(void *opaque) +{ + RTCState *s = opaque; + int32_t irqs = REG_C_UF; + int32_t new_irqs; + + /* UIP might have been latched, update time and clear it. */ + rtc_update_time(s); + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + + if (check_alarm(s)) { + irqs |= REG_C_AF; + if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); + } + } + new_irqs = irqs & ~s->cmos_data[RTC_REG_C]; + s->cmos_data[RTC_REG_C] |= irqs; + if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) { + s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + qemu_irq_raise(s->irq); + } + check_update_timer(s); +} + static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) { RTCState *s = opaque; @@ -189,6 +299,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: s->cmos_data[s->cmos_index] = data; + check_update_timer(s); break; case RTC_SECONDS: case RTC_MINUTES: @@ -201,6 +312,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) /* if in set mode, do not update the time */ if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { rtc_set_time(s); + check_update_timer(s); } break; case RTC_REG_A: @@ -208,15 +320,21 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); + check_update_timer(s); break; case RTC_REG_B: if (data & REG_B_SET) { + /* update cmos to when the rtc was stopping */ + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + rtc_update_time(s); + } /* set mode: reset UIP mode */ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; data &= ~REG_B_UIE; } else { /* if disabling set mode, update the time */ if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC; rtc_set_time(s); } } @@ -231,6 +349,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) } s->cmos_data[RTC_REG_B] = data; periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); + check_update_timer(s); break; case RTC_REG_C: case RTC_REG_D: @@ -279,10 +398,13 @@ static void rtc_set_time(RTCState *s) tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900; + s->base_rtc = mktimegm(tm); + s->last_update = qemu_get_clock_ns(rtc_clock); + rtc_change_mon_event(tm); } -static void rtc_copy_date(RTCState *s) +static void rtc_set_cmos(RTCState *s) { const struct tm *tm = &s->current_tm; int year; @@ -308,122 +430,41 @@ static void rtc_copy_date(RTCState *s) s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year); } -/* month is between 0 and 11. */ -static int get_days_in_month(int month, int year) +static void rtc_update_time(RTCState *s) { - static const int days_tab[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - int d; - if ((unsigned )month >= 12) - return 31; - d = days_tab[month]; - if (month == 1) { - if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) - d++; - } - return d; + struct tm *ret; + time_t guest_sec; + int64_t guest_nsec; + + guest_nsec = get_guest_rtc_ns(s); + guest_sec = guest_nsec / NSEC_PER_SEC; + ret = gmtime(&guest_sec); + s->current_tm = *ret; + rtc_set_cmos(s); } -/* update 'tm' to the next second */ -static void rtc_next_second(struct tm *tm) +static int update_in_progress(RTCState *s) { - int days_in_month; - - tm->tm_sec++; - if ((unsigned)tm->tm_sec >= 60) { - tm->tm_sec = 0; - tm->tm_min++; - if ((unsigned)tm->tm_min >= 60) { - tm->tm_min = 0; - tm->tm_hour++; - if ((unsigned)tm->tm_hour >= 24) { - tm->tm_hour = 0; - /* next day */ - tm->tm_wday++; - if ((unsigned)tm->tm_wday >= 7) - tm->tm_wday = 0; - days_in_month = get_days_in_month(tm->tm_mon, - tm->tm_year + 1900); - tm->tm_mday++; - if (tm->tm_mday < 1) { - tm->tm_mday = 1; - } else if (tm->tm_mday > days_in_month) { - tm->tm_mday = 1; - tm->tm_mon++; - if (tm->tm_mon >= 12) { - tm->tm_mon = 0; - tm->tm_year++; - } - } - } - } - } -} - - -static void rtc_update_second(void *opaque) -{ - RTCState *s = opaque; - int64_t delay; - - /* if the oscillator is not in normal operation, we do not update */ - if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { - s->next_second_time += get_ticks_per_sec(); - qemu_mod_timer(s->second_timer, s->next_second_time); - } else { - rtc_next_second(&s->current_tm); - - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - /* update in progress bit */ - s->cmos_data[RTC_REG_A] |= REG_A_UIP; - } - /* should be 244 us = 8 / 32768 seconds, but currently the - timers do not have the necessary resolution. */ - delay = (get_ticks_per_sec() * 1) / 100; - if (delay < 1) - delay = 1; - qemu_mod_timer(s->second_timer2, - s->next_second_time + delay); - } -} - -static void rtc_update_second2(void *opaque) -{ - RTCState *s = opaque; + int64_t guest_nsec; - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - rtc_copy_date(s); + if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + return 0; } - - /* check alarm */ - if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) && - ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) && - ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) { - - s->cmos_data[RTC_REG_C] |= REG_C_AF; - if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); - qemu_irq_raise(s->irq); - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + if (qemu_timer_pending(s->update_timer)) { + int64_t next_update_time = qemu_timer_expire_time_ns(s->update_timer); + /* Latch UIP until the timer expires. */ + if (qemu_get_clock_ns(rtc_clock) >= (next_update_time - 244000)) { + s->cmos_data[RTC_REG_A] |= REG_A_UIP; + return 1; } } - /* update ended interrupt */ - s->cmos_data[RTC_REG_C] |= REG_C_UF; - if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; - qemu_irq_raise(s->irq); + guest_nsec = get_guest_rtc_ns(s); + /* UIP bit will be set at last 244us of every second. */ + if ((guest_nsec % NSEC_PER_SEC) >= (NSEC_PER_SEC - 244000)) { + return 1; } - - /* clear update in progress bit */ - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - - s->next_second_time += get_ticks_per_sec(); - qemu_mod_timer(s->second_timer, s->next_second_time); + return 0; } static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) @@ -441,15 +482,28 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_DAY_OF_MONTH: case RTC_MONTH: case RTC_YEAR: + /* if not in set mode, calibrate cmos before + * reading*/ + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + rtc_update_time(s); + } ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_A: + if (update_in_progress(s)) { + s->cmos_data[s->cmos_index] |= REG_A_UIP; + } else { + s->cmos_data[s->cmos_index] &= ~REG_A_UIP; + } ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); s->cmos_data[RTC_REG_C] = 0x00; + if (ret & (REG_C_UF | REG_C_AF)) { + check_update_timer(s); + } #ifdef TARGET_I386 if(s->irq_coalesced && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && @@ -484,13 +538,6 @@ void rtc_set_memory(ISADevice *dev, int addr, int val) s->cmos_data[addr] = val; } -void rtc_set_date(ISADevice *dev, const struct tm *tm) -{ - RTCState *s = DO_UPCAST(RTCState, dev, dev); - s->current_tm = *tm; - rtc_copy_date(s); -} - /* PC cmos mappings */ #define REG_IBM_CENTURY_BYTE 0x32 #define REG_IBM_PS2_CENTURY_BYTE 0x37 @@ -501,9 +548,15 @@ static void rtc_set_date_from_host(ISADevice *dev) struct tm tm; int val; - /* set the CMOS date */ qemu_get_timedate(&tm, 0); - rtc_set_date(dev, &tm); + + s->base_rtc = mktimegm(&tm); + s->last_update = qemu_get_clock_ns(rtc_clock); + s->offset = 0; + + /* set the CMOS date */ + s->current_tm = tm; + rtc_set_cmos(s); val = rtc_to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val); @@ -540,11 +593,12 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_INT32(current_tm.tm_mday, RTCState), VMSTATE_INT32(current_tm.tm_mon, RTCState), VMSTATE_INT32(current_tm.tm_year, RTCState), + VMSTATE_UINT64(base_rtc, RTCState), + VMSTATE_UINT64(last_update, RTCState), + VMSTATE_INT64(offset, RTCState), VMSTATE_TIMER(periodic_timer, RTCState), VMSTATE_INT64(next_periodic_time, RTCState), - VMSTATE_INT64(next_second_time, RTCState), - VMSTATE_TIMER(second_timer, RTCState), - VMSTATE_TIMER(second_timer2, RTCState), + VMSTATE_TIMER(update_timer, RTCState), VMSTATE_UINT32_V(irq_coalesced, RTCState, 2), VMSTATE_UINT32_V(period, RTCState, 2), VMSTATE_END_OF_LIST() @@ -557,9 +611,8 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data) int64_t now = *(int64_t *)data; rtc_set_date_from_host(&s->dev); - s->next_second_time = now + (get_ticks_per_sec() * 99) / 100; - qemu_mod_timer(s->second_timer2, s->next_second_time); periodic_timer_update(s, now); + check_update_timer(s); #ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); @@ -581,6 +634,7 @@ static void rtc_reset(void *opaque) s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); + check_update_timer(s); qemu_irq_lower(s->irq); @@ -613,6 +667,7 @@ static void rtc_get_date(Object *obj, Visitor *v, void *opaque, ISADevice *isa = ISA_DEVICE(obj); RTCState *s = DO_UPCAST(RTCState, dev, isa); + rtc_update_time(s); visit_start_struct(v, NULL, "struct tm", name, 0, errp); visit_type_int32(v, &s->current_tm.tm_year, "tm_year", errp); visit_type_int32(v, &s->current_tm.tm_mon, "tm_mon", errp); @@ -649,8 +704,8 @@ static int rtc_initfn(ISADevice *dev) #endif s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s); - s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s); - s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s); + s->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s); + check_update_timer(s); s->clock_reset_notifier.notify = rtc_notify_clock_reset; qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier); @@ -658,10 +713,6 @@ static int rtc_initfn(ISADevice *dev) s->suspend_notifier.notify = rtc_notify_suspend; qemu_register_suspend_notifier(&s->suspend_notifier); - s->next_second_time = - qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100; - qemu_mod_timer(s->second_timer2, s->next_second_time); - memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2); isa_register_ioport(dev, &s->io, base);