From patchwork Wed May 9 07:22:49 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhang, Yang Z" X-Patchwork-Id: 157881 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 9368AB6FA0 for ; Wed, 9 May 2012 17:51:23 +1000 (EST) Received: from localhost ([::1]:47288 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SS1FI-0000mN-Ft for incoming@patchwork.ozlabs.org; Wed, 09 May 2012 03:23:36 -0400 Received: from eggs.gnu.org ([208.118.235.92]:37647) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SS1Ek-0007li-2x for qemu-devel@nongnu.org; Wed, 09 May 2012 03:23:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SS1Ed-0002sS-FS for qemu-devel@nongnu.org; Wed, 09 May 2012 03:23:01 -0400 Received: from mga03.intel.com ([143.182.124.21]:53514) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SS1Ed-0002sJ-2v for qemu-devel@nongnu.org; Wed, 09 May 2012 03:22:55 -0400 Received: from azsmga002.ch.intel.com ([10.2.17.35]) by azsmga101.ch.intel.com with ESMTP; 09 May 2012 00:22:52 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.71,315,1320652800"; d="scan'208";a="97985650" Received: from azsmsx601.amr.corp.intel.com ([10.2.121.193]) by AZSMGA002.ch.intel.com with ESMTP; 09 May 2012 00:22:52 -0700 Received: from shsmsx102.ccr.corp.intel.com (10.239.4.154) by azsmsx601.amr.corp.intel.com (10.2.121.193) with Microsoft SMTP Server (TLS) id 8.2.255.0; Wed, 9 May 2012 00:22:51 -0700 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.6]) by SHSMSX102.ccr.corp.intel.com ([169.254.2.133]) with mapi id 14.01.0355.002; Wed, 9 May 2012 15:22:49 +0800 From: "Zhang, Yang Z" To: "'qemu-devel@nongnu.org'" Thread-Topic: [PATCH v5 4/7] RTC: Set internal millisecond register to 500ms when reset divider Thread-Index: Ac0ttImq+lvMHJSZRMuWJx76L7ZeZw== Date: Wed, 9 May 2012 07:22:49 +0000 Message-ID: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 143.182.124.21 Cc: 'Paolo Bonzini' , "'aliguori@us.ibm.com'" , "'qemu-devel@nongnu.org'" Subject: [Qemu-devel] [PATCH v5 4/7] RTC: Set internal millisecond register to 500ms when reset divider 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 The first update cycle begins one - half seconds later when divider reset is removing. Signed-off-by: Yang Zhang --- hw/mc146818rtc.c | 61 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 51 insertions(+), 10 deletions(-) -- 1.7.1 diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index b70422a..c9b5232 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -113,6 +113,14 @@ static void rtc_set_time(RTCState *s); static void rtc_calibrate_time(RTCState *s); static void rtc_set_cmos(RTCState *s); +static int32_t divider_reset; + +static inline bool rtc_running(RTCState *s) +{ + return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) && + (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20); +} + static uint64_t get_guest_rtc_us(RTCState *s) { int64_t host_usec, offset_usec, guest_usec; @@ -223,16 +231,24 @@ static void rtc_periodic_timer(void *opaque) } } -static void rtc_set_offset(RTCState *s) +static void rtc_set_offset(RTCState *s, int32_t start_usec) { struct tm *tm = &s->current_tm; - int64_t host_usec, guest_sec, guest_usec; + int64_t host_usec, guest_sec, guest_usec, offset_usec, old_guest_usec; host_usec = qemu_get_clock_ns(rtc_clock) / NS_PER_USEC; + offset_usec = s->offset_sec * USEC_PER_SEC + s->offset_usec; + old_guest_usec = (host_usec + offset_usec) % USEC_PER_SEC; guest_sec = mktimegm(tm); - guest_usec = guest_sec * USEC_PER_SEC; + /* start_usec equal 0 means rtc internal millisecond is + * same with before */ + if (start_usec == 0) { + guest_usec = guest_sec * USEC_PER_SEC + old_guest_usec; + } else { + guest_usec = guest_sec * USEC_PER_SEC + start_usec; + } s->offset_sec = (guest_usec - host_usec) / USEC_PER_SEC; s->offset_usec = (guest_usec - host_usec) % USEC_PER_SEC; } @@ -261,12 +277,29 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_YEAR: s->cmos_data[s->cmos_index] = data; /* if in set mode, do not update the time */ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + if (rtc_running(s)) { rtc_set_time(s); - rtc_set_offset(s); + rtc_set_offset(s, 0); } break; case RTC_REG_A: + if (((data & 0x60) == 0x60) && + (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { + rtc_calibrate_time(s); + rtc_set_cmos(s); + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) && + (data & 0x70) <= 0x20) { + /* when the divider reset is removed, the first update cycle + * begins one-half second later*/ + divider_reset = 1; + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + rtc_set_time(s); + rtc_set_offset(s, 500000); + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + divider_reset = 0; + } + } /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); @@ -275,7 +308,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) 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)) { + if (rtc_running(s)) { rtc_calibrate_time(s); rtc_set_cmos(s); } @@ -284,9 +317,16 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) data &= ~REG_B_UIE; } else { /* if disabling set mode, update the time */ - if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + if ((s->cmos_data[RTC_REG_B] & REG_B_SET) && + (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { rtc_set_time(s); - rtc_set_offset(s); + if (divider_reset == 1) { + rtc_set_offset(s, 500000); + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + divider_reset = 0; + } else { + rtc_set_offset(s, 0); + } } } s->cmos_data[RTC_REG_B] = data; @@ -384,7 +424,8 @@ static int update_in_progress(RTCState *s) { int64_t guest_usec; - if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + if ((s->cmos_data[RTC_REG_B] & REG_B_SET) || + ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60)) { return 0; } guest_usec = get_guest_rtc_us(s); @@ -412,7 +453,7 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_YEAR: /* if not in set mode, calibrate cmos before * reading*/ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + if (rtc_running(s)) { rtc_calibrate_time(s); rtc_set_cmos(s); }