From owner-svn-src-head@freebsd.org Fri Apr 15 14:36:39 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 863DEAEDF44; Fri, 15 Apr 2016 14:36:39 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 595B21770; Fri, 15 Apr 2016 14:36:39 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u3FEacF5062182; Fri, 15 Apr 2016 14:36:38 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u3FEactk062181; Fri, 15 Apr 2016 14:36:38 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201604151436.u3FEactk062181@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Fri, 15 Apr 2016 14:36:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r298056 - head/sys/x86/x86 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Apr 2016 14:36:39 -0000 Author: kib Date: Fri Apr 15 14:36:38 2016 New Revision: 298056 URL: https://svnweb.freebsd.org/changeset/base/298056 Log: Always calculate divisor for the counter mode of LAPIC timer. Even if initially configured in the TSC deadline mode, eventtimer subsystem can be switched to periodic, and then DCR register is loaded with unitialized value. Reset the LAPIC eventtimer frequency and min/max periods when changing between deadline and counted periodic modes. Reported and tested by: Vladimir Zakharov Sponsored by: The FreeBSD Foundation Modified: head/sys/x86/x86/local_apic.c Modified: head/sys/x86/x86/local_apic.c ============================================================================== --- head/sys/x86/x86/local_apic.c Fri Apr 15 14:30:40 2016 (r298055) +++ head/sys/x86/x86/local_apic.c Fri Apr 15 14:36:38 2016 (r298056) @@ -170,7 +170,7 @@ vm_paddr_t lapic_paddr; int x2apic_mode; int lapic_eoi_suppression; static int lapic_timer_tsc_deadline; -static u_long lapic_timer_divisor; +static u_long lapic_timer_divisor, count_freq; static struct eventtimer lapic_et; #ifdef SMP static uint64_t lapic_ipi_wait_mult; @@ -814,20 +814,46 @@ lapic_calibrate_initcount(struct eventti printf("lapic: Divisor %lu, Frequency %lu Hz\n", lapic_timer_divisor, value); } - et->et_frequency = value; + count_freq = value; } static void lapic_calibrate_deadline(struct eventtimer *et, struct lapic *la __unused) { - et->et_frequency = tsc_freq; if (bootverbose) { printf("lapic: deadline tsc mode, Frequency %ju Hz\n", - (uintmax_t)et->et_frequency); + (uintmax_t)tsc_freq); } } +static void +lapic_change_mode(struct eventtimer *et, struct lapic *la, + enum lat_timer_mode newmode) +{ + + if (la->la_timer_mode == newmode) + return; + switch (newmode) { + case LAT_MODE_PERIODIC: + lapic_timer_set_divisor(lapic_timer_divisor); + et->et_frequency = count_freq; + break; + case LAT_MODE_DEADLINE: + et->et_frequency = tsc_freq; + break; + case LAT_MODE_ONESHOT: + lapic_timer_set_divisor(lapic_timer_divisor); + et->et_frequency = count_freq; + break; + default: + panic("lapic_change_mode %d", newmode); + } + la->la_timer_mode = newmode; + et->et_min_period = (0x00000002LLU << 32) / et->et_frequency; + et->et_max_period = (0xfffffffeLLU << 32) / et->et_frequency; +} + static int lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { @@ -835,28 +861,21 @@ lapic_et_start(struct eventtimer *et, sb la = &lapics[PCPU_GET(apic_id)]; if (et->et_frequency == 0) { + lapic_calibrate_initcount(et, la); if (lapic_timer_tsc_deadline) lapic_calibrate_deadline(et, la); - else - lapic_calibrate_initcount(et, la); - et->et_min_period = (0x00000002LLU << 32) / et->et_frequency; - et->et_max_period = (0xfffffffeLLU << 32) / et->et_frequency; } if (period != 0) { - if (la->la_timer_mode == LAT_MODE_UNDEF) - lapic_timer_set_divisor(lapic_timer_divisor); - la->la_timer_mode = LAT_MODE_PERIODIC; + lapic_change_mode(et, la, LAT_MODE_PERIODIC); la->la_timer_period = ((uint32_t)et->et_frequency * period) >> 32; lapic_timer_periodic(la); } else if (lapic_timer_tsc_deadline) { - la->la_timer_mode = LAT_MODE_DEADLINE; + lapic_change_mode(et, la, LAT_MODE_DEADLINE); la->la_timer_period = (et->et_frequency * first) >> 32; lapic_timer_deadline(la); } else { - if (la->la_timer_mode == LAT_MODE_UNDEF) - lapic_timer_set_divisor(lapic_timer_divisor); - la->la_timer_mode = LAT_MODE_ONESHOT; + lapic_change_mode(et, la, LAT_MODE_ONESHOT); la->la_timer_period = ((uint32_t)et->et_frequency * first) >> 32; lapic_timer_oneshot(la);